aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/microhttpd.h35
-rw-r--r--src/microhttpd/daemon.c201
-rw-r--r--src/testcurl/.gitignore2
-rw-r--r--src/testcurl/Makefile.am20
-rw-r--r--src/testcurl/test_get_wait.c238
5 files changed, 434 insertions, 62 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 59170dfe..a4ba9bf1 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -135,7 +135,7 @@ typedef intptr_t ssize_t;
135 * they are parsed as decimal numbers. 135 * they are parsed as decimal numbers.
136 * Example: 0x01093001 = 1.9.30-1. 136 * Example: 0x01093001 = 1.9.30-1.
137 */ 137 */
138#define MHD_VERSION 0x00097205 138#define MHD_VERSION 0x00097206
139 139
140/** 140/**
141 * Operational results from MHD calls. 141 * Operational results from MHD calls.
@@ -2699,6 +2699,39 @@ MHD_run (struct MHD_Daemon *daemon);
2699 2699
2700 2700
2701/** 2701/**
2702 * Run websever operation with possible blocking.
2703 * This function do the following: waits for any network event not more than
2704 * specified number of milliseconds, processes all incoming and outgoing
2705 * data, processes new connections, processes any timed-out connection, and
2706 * do other things required to run webserver.
2707 * Once all connections are processed, function returns.
2708 * This function is useful for quick and simple webserver implementation if
2709 * application needs to run a single thread only and does not have any other
2710 * network activity.
2711 * @param daemon the daemon to run
2712 * @param millisec the maximum time in milliseconds to wait for network and
2713 * other events. Note: there is no guarantee that function
2714 * blocks for specified amount of time. The real processing
2715 * time can be shorter (if some data comes earlier) or
2716 * longer (if data processing requires more time, especially
2717 * in the user callbacks).
2718 * If set to '0' then function does not block and processes
2719 * only already available data (if any).
2720 * If set to '-1' then function waits for events
2721 * indefinitely (blocks until next network activity).
2722 * @return #MHD_YES on success, #MHD_NO if this
2723 * daemon was not started with the right
2724 * options for this call or some serious
2725 * unrecoverable error occurs.
2726 * @note Available since #MHD_VERSION 0x00097206
2727 * @ingroup event
2728 */
2729enum MHD_Result
2730MHD_run_wait (struct MHD_Daemon *daemon,
2731 int32_t millisec);
2732
2733
2734/**
2702 * Run webserver operations. This method should be called by clients 2735 * Run webserver operations. This method should be called by clients
2703 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the 2736 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
2704 * client-controlled select method is used. 2737 * client-controlled select method is used.
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 0fe47228..59eaf953 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -101,16 +101,17 @@ close_all_connections (struct MHD_Daemon *daemon);
101#ifdef EPOLL_SUPPORT 101#ifdef EPOLL_SUPPORT
102 102
103/** 103/**
104 * Do epoll()-based processing (this function is allowed to 104 * Do epoll()-based processing.
105 * block if @a may_block is set to #MHD_YES).
106 * 105 *
107 * @param daemon daemon to run poll loop for 106 * @param daemon daemon to run poll loop for
108 * @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking 107 * @param millisec the maximum time in milliseconds to wait for events,
108 * set to '0' for non-blocking processing,
109 * set to '-1' to wait indefinitely.
109 * @return #MHD_NO on serious errors, #MHD_YES on success 110 * @return #MHD_NO on serious errors, #MHD_YES on success
110 */ 111 */
111static enum MHD_Result 112static enum MHD_Result
112MHD_epoll (struct MHD_Daemon *daemon, 113MHD_epoll (struct MHD_Daemon *daemon,
113 int may_block); 114 int32_t millisec);
114 115
115#endif /* EPOLL_SUPPORT */ 116#endif /* EPOLL_SUPPORT */
116 117
@@ -3835,6 +3836,35 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
3835 3836
3836 3837
3837/** 3838/**
3839 * Obtain timeout value for polling function for this daemon.
3840 * @remark To be called only from the thread that processes
3841 * daemon's select()/poll()/etc.
3842 *
3843 * @param daemon the daemon to query for timeout
3844 * @param max_timeout the maximum return value (in milliseconds),
3845 * ignored if set to '-1'
3846 * @return timeout value in milliseconds or -1 if no timeout is expected.
3847 */
3848static int
3849get_timeout_millisec_ (struct MHD_Daemon *daemon,
3850 int32_t max_timeout)
3851{
3852 MHD_UNSIGNED_LONG_LONG ulltimeout;
3853 if (0 == max_timeout)
3854 return 0;
3855
3856 if (MHD_NO == MHD_get_timeout (daemon, &ulltimeout))
3857 return (INT_MAX < max_timeout) ? INT_MAX : (int) max_timeout;
3858
3859 if ( (0 > max_timeout) ||
3860 ((uint32_t) max_timeout > ulltimeout) )
3861 return (INT_MAX < ulltimeout) ? INT_MAX : (int) ulltimeout;
3862
3863 return (INT_MAX < max_timeout) ? INT_MAX : (int) max_timeout;
3864}
3865
3866
3867/**
3838 * Internal version of #MHD_run_from_select(). 3868 * Internal version of #MHD_run_from_select().
3839 * 3869 *
3840 * @param daemon daemon to run select loop for 3870 * @param daemon daemon to run select loop for
@@ -3978,7 +4008,7 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
3978 { 4008 {
3979#ifdef EPOLL_SUPPORT 4009#ifdef EPOLL_SUPPORT
3980 enum MHD_Result ret = MHD_epoll (daemon, 4010 enum MHD_Result ret = MHD_epoll (daemon,
3981 MHD_NO); 4011 0);
3982 4012
3983 MHD_cleanup_connections (daemon); 4013 MHD_cleanup_connections (daemon);
3984 return ret; 4014 return ret;
@@ -4003,12 +4033,14 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
4003 * and then #internal_run_from_select with the result. 4033 * and then #internal_run_from_select with the result.
4004 * 4034 *
4005 * @param daemon daemon to run select() loop for 4035 * @param daemon daemon to run select() loop for
4006 * @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking 4036 * @param millisec the maximum time in milliseconds to wait for events,
4037 * set to '0' for non-blocking processing,
4038 * set to '-1' to wait indefinitely.
4007 * @return #MHD_NO on serious errors, #MHD_YES on success 4039 * @return #MHD_NO on serious errors, #MHD_YES on success
4008 */ 4040 */
4009static enum MHD_Result 4041static enum MHD_Result
4010MHD_select (struct MHD_Daemon *daemon, 4042MHD_select (struct MHD_Daemon *daemon,
4011 int may_block) 4043 int32_t millisec)
4012{ 4044{
4013 int num_ready; 4045 int num_ready;
4014 fd_set rs; 4046 fd_set rs;
@@ -4017,7 +4049,6 @@ MHD_select (struct MHD_Daemon *daemon,
4017 MHD_socket maxsock; 4049 MHD_socket maxsock;
4018 struct timeval timeout; 4050 struct timeval timeout;
4019 struct timeval *tv; 4051 struct timeval *tv;
4020 MHD_UNSIGNED_LONG_LONG ltimeout;
4021 int err_state; 4052 int err_state;
4022 MHD_socket ls; 4053 MHD_socket ls;
4023 4054
@@ -4033,7 +4064,7 @@ MHD_select (struct MHD_Daemon *daemon,
4033 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) && 4064 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
4034 (MHD_NO != resume_suspended_connections (daemon)) && 4065 (MHD_NO != resume_suspended_connections (daemon)) &&
4035 (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ) 4066 (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) )
4036 may_block = MHD_NO; 4067 millisec = 0;
4037 4068
4038 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 4069 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4039 { 4070 {
@@ -4118,25 +4149,47 @@ MHD_select (struct MHD_Daemon *daemon,
4118 FD_CLR (ls, 4149 FD_CLR (ls,
4119 &rs); 4150 &rs);
4120 } 4151 }
4121 tv = NULL; 4152
4122 if (MHD_NO != err_state) 4153 if (MHD_NO != err_state)
4123 may_block = MHD_NO; 4154 millisec = 0;
4124 if (MHD_NO == may_block) 4155 tv = NULL;
4156 if (0 == millisec)
4125 { 4157 {
4126 timeout.tv_usec = 0; 4158 timeout.tv_usec = 0;
4127 timeout.tv_sec = 0; 4159 timeout.tv_sec = 0;
4128 tv = &timeout; 4160 tv = &timeout;
4129 } 4161 }
4130 else if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 4162 else
4131 (MHD_NO != MHD_get_timeout (daemon, &ltimeout)) )
4132 { 4163 {
4133 /* ltimeout is in ms */ 4164 MHD_UNSIGNED_LONG_LONG ltimeout;
4134 timeout.tv_usec = (ltimeout % 1000) * 1000; 4165
4135 if (ltimeout / 1000 > TIMEVAL_TV_SEC_MAX) 4166 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
4136 timeout.tv_sec = TIMEVAL_TV_SEC_MAX; 4167 (MHD_NO != MHD_get_timeout (daemon, &ltimeout)) )
4137 else 4168 {
4138 timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) (ltimeout / 1000); 4169 tv = &timeout; /* have timeout value */
4139 tv = &timeout; 4170 if ( (0 < millisec) &&
4171 (ltimeout > (MHD_UNSIGNED_LONG_LONG) millisec) )
4172 ltimeout = (MHD_UNSIGNED_LONG_LONG) millisec;
4173 }
4174 else if (0 < millisec)
4175 {
4176 tv = &timeout; /* have timeout value */
4177 ltimeout = (MHD_UNSIGNED_LONG_LONG) millisec;
4178 }
4179
4180 if (NULL != tv)
4181 { /* have timeout value */
4182 if (ltimeout / 1000 > TIMEVAL_TV_SEC_MAX)
4183 {
4184 timeout.tv_sec = TIMEVAL_TV_SEC_MAX;
4185 timeout.tv_usec = 0;
4186 }
4187 else
4188 {
4189 timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) (ltimeout / 1000);
4190 timeout.tv_usec = (ltimeout % 1000) * 1000;
4191 }
4192 }
4140 } 4193 }
4141 num_ready = MHD_SYS_select_ (maxsock + 1, 4194 num_ready = MHD_SYS_select_ (maxsock + 1,
4142 &rs, 4195 &rs,
@@ -4172,12 +4225,14 @@ MHD_select (struct MHD_Daemon *daemon,
4172 * socket using poll(). 4225 * socket using poll().
4173 * 4226 *
4174 * @param daemon daemon to run poll loop for 4227 * @param daemon daemon to run poll loop for
4175 * @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking 4228 * @param millisec the maximum time in milliseconds to wait for events,
4229 * set to '0' for non-blocking processing,
4230 * set to '-1' to wait indefinitely.
4176 * @return #MHD_NO on serious errors, #MHD_YES on success 4231 * @return #MHD_NO on serious errors, #MHD_YES on success
4177 */ 4232 */
4178static enum MHD_Result 4233static enum MHD_Result
4179MHD_poll_all (struct MHD_Daemon *daemon, 4234MHD_poll_all (struct MHD_Daemon *daemon,
4180 int may_block) 4235 int32_t millisec)
4181{ 4236{
4182 unsigned int num_connections; 4237 unsigned int num_connections;
4183 struct MHD_Connection *pos; 4238 struct MHD_Connection *pos;
@@ -4189,7 +4244,7 @@ MHD_poll_all (struct MHD_Daemon *daemon,
4189 4244
4190 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) && 4245 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
4191 (MHD_NO != resume_suspended_connections (daemon)) ) 4246 (MHD_NO != resume_suspended_connections (daemon)) )
4192 may_block = MHD_NO; 4247 millisec = 0;
4193 4248
4194 /* count number of connections and thus determine poll set size */ 4249 /* count number of connections and thus determine poll set size */
4195 num_connections = 0; 4250 num_connections = 0;
@@ -4200,7 +4255,6 @@ MHD_poll_all (struct MHD_Daemon *daemon,
4200 num_connections += 2; 4255 num_connections += 2;
4201#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4256#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4202 { 4257 {
4203 MHD_UNSIGNED_LONG_LONG ltimeout;
4204 unsigned int i; 4258 unsigned int i;
4205 int timeout; 4259 int timeout;
4206 unsigned int poll_server; 4260 unsigned int poll_server;
@@ -4243,14 +4297,8 @@ MHD_poll_all (struct MHD_Daemon *daemon,
4243 poll_itc_idx = (int) poll_server; 4297 poll_itc_idx = (int) poll_server;
4244 poll_server++; 4298 poll_server++;
4245 } 4299 }
4246 if (may_block == MHD_NO) 4300
4247 timeout = 0; 4301 timeout = get_timeout_millisec_ (daemon, millisec);
4248 else if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
4249 (MHD_NO == MHD_get_timeout (daemon,
4250 &ltimeout)) )
4251 timeout = -1;
4252 else
4253 timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
4254 4302
4255 i = 0; 4303 i = 0;
4256 for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev) 4304 for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
@@ -4494,7 +4542,7 @@ MHD_poll (struct MHD_Daemon *daemon,
4494 return MHD_NO; 4542 return MHD_NO;
4495 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 4543 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4496 return MHD_poll_all (daemon, 4544 return MHD_poll_all (daemon,
4497 may_block); 4545 may_block ? -1 : 0);
4498 return MHD_poll_listen_socket (daemon, 4546 return MHD_poll_listen_socket (daemon,
4499 may_block); 4547 may_block);
4500#else 4548#else
@@ -4685,16 +4733,17 @@ static const char *const epoll_itc_marker = "itc_marker";
4685 4733
4686 4734
4687/** 4735/**
4688 * Do epoll()-based processing (this function is allowed to 4736 * Do epoll()-based processing.
4689 * block if @a may_block is set to #MHD_YES).
4690 * 4737 *
4691 * @param daemon daemon to run poll loop for 4738 * @param daemon daemon to run poll loop for
4692 * @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking 4739 * @param millisec the maximum time in milliseconds to wait for events,
4740 * set to '0' for non-blocking processing,
4741 * set to '-1' to wait indefinitely.
4693 * @return #MHD_NO on serious errors, #MHD_YES on success 4742 * @return #MHD_NO on serious errors, #MHD_YES on success
4694 */ 4743 */
4695static enum MHD_Result 4744static enum MHD_Result
4696MHD_epoll (struct MHD_Daemon *daemon, 4745MHD_epoll (struct MHD_Daemon *daemon,
4697 int may_block) 4746 int32_t millisec)
4698{ 4747{
4699#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4748#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4700 static const char *const upgrade_marker = "upgrade_ptr"; 4749 static const char *const upgrade_marker = "upgrade_ptr";
@@ -4704,7 +4753,6 @@ MHD_epoll (struct MHD_Daemon *daemon,
4704 struct epoll_event events[MAX_EVENTS]; 4753 struct epoll_event events[MAX_EVENTS];
4705 struct epoll_event event; 4754 struct epoll_event event;
4706 int timeout_ms; 4755 int timeout_ms;
4707 MHD_UNSIGNED_LONG_LONG timeout_ll;
4708 int num_events; 4756 int num_events;
4709 unsigned int i; 4757 unsigned int i;
4710 MHD_socket ls; 4758 MHD_socket ls;
@@ -4790,23 +4838,9 @@ MHD_epoll (struct MHD_Daemon *daemon,
4790 4838
4791 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) && 4839 if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
4792 (MHD_NO != resume_suspended_connections (daemon)) ) 4840 (MHD_NO != resume_suspended_connections (daemon)) )
4793 may_block = MHD_NO; 4841 millisec = 0;
4794 4842
4795 if (MHD_NO != may_block) 4843 timeout_ms = get_timeout_millisec_ (daemon, millisec);
4796 {
4797 if (MHD_NO != MHD_get_timeout (daemon,
4798 &timeout_ll))
4799 {
4800 if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
4801 timeout_ms = INT_MAX;
4802 else
4803 timeout_ms = (int) timeout_ll;
4804 }
4805 else
4806 timeout_ms = -1;
4807 }
4808 else
4809 timeout_ms = 0;
4810 4844
4811 /* Reset. New value will be set when connections are processed. */ 4845 /* Reset. New value will be set when connections are processed. */
4812 /* Note: Used mostly for uniformity here as same situation is 4846 /* Note: Used mostly for uniformity here as same situation is
@@ -5026,24 +5060,69 @@ MHD_run (struct MHD_Daemon *daemon)
5026 if ( (daemon->shutdown) || 5060 if ( (daemon->shutdown) ||
5027 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) ) 5061 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
5028 return MHD_NO; 5062 return MHD_NO;
5063
5064 (void) MHD_run_wait (daemon, 0);
5065 return MHD_YES;
5066}
5067
5068
5069/**
5070 * Run websever operation with possible blocking.
5071 * This function do the following: waits for any network event not more than
5072 * specified number of milliseconds, processes all incoming and outgoing
5073 * data, processes new connections, processes any timed-out connection, and
5074 * do other things required to run webserver.
5075 * Once all connections are processed, function returns.
5076 * This function is useful for quick and simple webserver implementation if
5077 * application needs to run a single thread only and does not have any other
5078 * network activity.
5079 * @param daemon the daemon to run
5080 * @param millisec the maximum time in milliseconds to wait for network and
5081 * other events. Note: there is no guarantee that function
5082 * blocks for specified amount of time. The real processing
5083 * time can be shorter (if some data comes earlier) or
5084 * longer (if data processing requires more time, especially
5085 * in the user callbacks).
5086 * If set to '0' then function does not block and processes
5087 * only already available data (if any).
5088 * If set to '-1' then function waits for events
5089 * indefinitely (blocks until next network activity).
5090 * @return #MHD_YES on success, #MHD_NO if this
5091 * daemon was not started with the right
5092 * options for this call or some serious
5093 * unrecoverable error occurs.
5094 * @note Available since #MHD_VERSION 0x00097206
5095 * @ingroup event
5096 */
5097enum MHD_Result
5098MHD_run_wait (struct MHD_Daemon *daemon,
5099 int32_t millisec)
5100{
5101 enum MHD_Result res;
5102 if ( (daemon->shutdown) ||
5103 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
5104 return MHD_NO;
5105
5106 if (0 > millisec)
5107 millisec = -1;
5029 if (0 != (daemon->options & MHD_USE_POLL)) 5108 if (0 != (daemon->options & MHD_USE_POLL))
5030 { 5109 {
5031 MHD_poll (daemon, MHD_NO); 5110 res = MHD_poll_all (daemon, millisec);
5032 MHD_cleanup_connections (daemon); 5111 MHD_cleanup_connections (daemon);
5033 } 5112 }
5034#ifdef EPOLL_SUPPORT 5113#ifdef EPOLL_SUPPORT
5035 else if (0 != (daemon->options & MHD_USE_EPOLL)) 5114 else if (0 != (daemon->options & MHD_USE_EPOLL))
5036 { 5115 {
5037 MHD_epoll (daemon, MHD_NO); 5116 res = MHD_epoll (daemon, millisec);
5038 MHD_cleanup_connections (daemon); 5117 MHD_cleanup_connections (daemon);
5039 } 5118 }
5040#endif 5119#endif
5041 else 5120 else
5042 { 5121 {
5043 MHD_select (daemon, MHD_NO); 5122 res = MHD_select (daemon, millisec);
5044 /* MHD_select does MHD_cleanup_connections already */ 5123 /* MHD_select does MHD_cleanup_connections already */
5045 } 5124 }
5046 return MHD_YES; 5125 return res;
5047} 5126}
5048 5127
5049 5128
@@ -5139,10 +5218,10 @@ MHD_polling_thread (void *cls)
5139 MHD_poll (daemon, MHD_YES); 5218 MHD_poll (daemon, MHD_YES);
5140#ifdef EPOLL_SUPPORT 5219#ifdef EPOLL_SUPPORT
5141 else if (0 != (daemon->options & MHD_USE_EPOLL)) 5220 else if (0 != (daemon->options & MHD_USE_EPOLL))
5142 MHD_epoll (daemon, MHD_YES); 5221 MHD_epoll (daemon, -1);
5143#endif 5222#endif
5144 else 5223 else
5145 MHD_select (daemon, MHD_YES); 5224 MHD_select (daemon, -1);
5146 MHD_cleanup_connections (daemon); 5225 MHD_cleanup_connections (daemon);
5147 } 5226 }
5148 5227
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index 008262bd..bbc1b2a9 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -118,3 +118,5 @@ test_patch11
118core 118core
119/test_get_iovec 119/test_get_iovec
120/test_get_iovec11 120/test_get_iovec11
121/test_get_wait
122/test_get_wait11
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index d0580554..66aebe3e 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -46,6 +46,8 @@ THREAD_ONLY_TESTS += \
46endif 46endif
47 47
48THREAD_ONLY_TESTS += \ 48THREAD_ONLY_TESTS += \
49 test_get_wait \
50 test_get_wait11 \
49 test_quiesce \ 51 test_quiesce \
50 $(EMPTY_ITEM) 52 $(EMPTY_ITEM)
51 53
@@ -232,6 +234,24 @@ test_get_sendfile_LDADD = \
232 $(top_builddir)/src/microhttpd/libmicrohttpd.la \ 234 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
233 @LIBCURL@ 235 @LIBCURL@
234 236
237test_get_wait_SOURCES = \
238 test_get_wait.c \
239 mhd_has_in_name.h
240test_get_wait_CFLAGS = \
241 $(PTHREAD_CFLAGS) $(AM_CFLAGS)
242test_get_wait_LDADD = \
243 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
244 $(PTHREAD_LIBS) @LIBCURL@
245
246test_get_wait11_SOURCES = \
247 test_get_wait.c \
248 mhd_has_in_name.h
249test_get_wait11_CFLAGS = \
250 $(PTHREAD_CFLAGS) $(AM_CFLAGS)
251test_get_wait11_LDADD = \
252 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
253 $(PTHREAD_LIBS) @LIBCURL@
254
235test_urlparse_SOURCES = \ 255test_urlparse_SOURCES = \
236 test_urlparse.c mhd_has_in_name.h 256 test_urlparse.c mhd_has_in_name.h
237test_urlparse_LDADD = \ 257test_urlparse_LDADD = \
diff --git a/src/testcurl/test_get_wait.c b/src/testcurl/test_get_wait.c
new file mode 100644
index 00000000..cfabd2d1
--- /dev/null
+++ b/src/testcurl/test_get_wait.c
@@ -0,0 +1,238 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2009, 2011 Christian Grothoff
4 Copyright (C) 2016-2021 Karlson2k (Evgeny Grin)
5
6 libmicrohttpd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
10
11 libmicrohttpd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with libmicrohttpd; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file test_get_wait.c
24 * @brief Test 'MHD_run_wait()' function.
25 * @author Christian Grothoff
26 * @author Karlson2k (Evgeny Grin)
27 */
28
29#include "MHD_config.h"
30#include "platform.h"
31#include <curl/curl.h>
32#include <microhttpd.h>
33#include <stdlib.h>
34#include <string.h>
35#include <time.h>
36#include <pthread.h>
37#include "mhd_has_in_name.h"
38
39#if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
40#undef MHD_CPU_COUNT
41#endif
42#if ! defined(MHD_CPU_COUNT)
43#define MHD_CPU_COUNT 2
44#endif
45
46/**
47 * How many rounds of operations do we do for each
48 * test.
49 * Check all three types of requests for HTTP/1.1:
50 * * first request, new connection;
51 * * "middle" request, existing connection with stay-alive;
52 * * final request, no data processed after.
53 */
54#define ROUNDS 3
55
56/**
57 * Do we use HTTP 1.1?
58 */
59static int oneone;
60
61/**
62 * Response to return (re-used).
63 */
64static struct MHD_Response *response;
65
66/**
67 * Set to 1 if the worker threads are done.
68 */
69static volatile int signal_done;
70
71
72static size_t
73copyBuffer (void *ptr,
74 size_t size, size_t nmemb,
75 void *ctx)
76{
77 (void) ptr; (void) ctx; /* Unused. Silent compiler warning. */
78 return size * nmemb;
79}
80
81
82static enum MHD_Result
83ahc_echo (void *cls,
84 struct MHD_Connection *connection,
85 const char *url,
86 const char *method,
87 const char *version,
88 const char *upload_data, size_t *upload_data_size,
89 void **unused)
90{
91 static int ptr;
92 const char *me = cls;
93 enum MHD_Result ret;
94 (void) url; (void) version; /* Unused. Silent compiler warning. */
95 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
96
97 if (0 != strcmp (me, method))
98 return MHD_NO; /* unexpected method */
99 if (&ptr != *unused)
100 {
101 *unused = &ptr;
102 return MHD_YES;
103 }
104 *unused = NULL;
105 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
106 if (ret == MHD_NO)
107 abort ();
108 return ret;
109}
110
111
112static void *
113thread_gets (void *param)
114{
115 CURL *c;
116 CURLcode errornum;
117 unsigned int i;
118 char url[64];
119 int port = (int) (intptr_t) param;
120
121 snprintf (url,
122 sizeof (url),
123 "http://127.0.0.1:%d/hello_world",
124 port);
125
126 c = curl_easy_init ();
127 if (NULL == c)
128 _exit (99);
129 curl_easy_setopt (c, CURLOPT_URL, url);
130 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
131 curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
132 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
133 curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
134 if (oneone)
135 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
136 else
137 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
138 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
139 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
140 for (i = 0; i < ROUNDS; i++)
141 {
142 if (CURLE_OK != (errornum = curl_easy_perform (c)))
143 {
144 signal_done = 1;
145 fprintf (stderr,
146 "curl_easy_perform failed: `%s'\n",
147 curl_easy_strerror (errornum));
148 curl_easy_cleanup (c);
149 abort ();
150 }
151 }
152 curl_easy_cleanup (c);
153 signal_done = 1;
154
155 return NULL;
156}
157
158
159static int
160testRunWaitGet (int port, int poll_flag)
161{
162 pthread_t get_tid;
163 struct MHD_Daemon *d;
164 const char *const test_desc = ((poll_flag & MHD_USE_AUTO) ?
165 "MHD_USE_AUTO" :
166 (poll_flag & MHD_USE_POLL) ?
167 "MHD_USE_POLL" :
168 (poll_flag & MHD_USE_EPOLL) ?
169 "MHD_USE_EPOLL" :
170 "select()");
171
172 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
173 port = 0;
174
175 printf ("Starting MHD_run_wait() test with MHD in %s polling mode.\n",
176 test_desc);
177 signal_done = 0;
178 d = MHD_start_daemon (MHD_USE_ERROR_LOG | poll_flag,
179 port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
180 if (d == NULL)
181 abort ();
182 if (0 == port)
183 {
184 const union MHD_DaemonInfo *dinfo;
185 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
186 if ((NULL == dinfo) || (0 == dinfo->port) )
187 abort ();
188 port = (int) dinfo->port;
189 }
190
191 if (0 != pthread_create (&get_tid, NULL,
192 &thread_gets, (void*) (intptr_t) port))
193 _exit (99);
194
195 /* As another thread sets "done" flag after ending of network
196 * activity, it's required to set positive timeout value for MHD_run_wait().
197 * Alternatively, to use timeout value "-1" here, another thread should start
198 * additional connection to wake MHD after setting "done" flag. */
199 do
200 {
201 if (MHD_NO == MHD_run_wait (d, 50))
202 abort ();
203 } while (0 == signal_done);
204
205 if (0 != pthread_join (get_tid, NULL))
206 _exit (99);
207
208 MHD_stop_daemon (d);
209 printf ("Test succeeded.\n");
210 return 0;
211}
212
213
214int
215main (int argc, char *const *argv)
216{
217 int port = 1675;
218 (void) argc; /* Unused. Silent compiler warning. */
219
220 if ((NULL == argv) || (0 == argv[0]))
221 return 99;
222 oneone = has_in_name (argv[0], "11");
223 if (oneone)
224 port += 5;
225 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
226 return 2;
227 response = MHD_create_response_from_buffer (strlen ("/hello_world"),
228 "/hello_world",
229 MHD_RESPMEM_MUST_COPY);
230 testRunWaitGet (port++, 0);
231 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
232 testRunWaitGet (port++, MHD_USE_EPOLL);
233 testRunWaitGet (port++, MHD_USE_AUTO);
234
235 MHD_destroy_response (response);
236 curl_global_cleanup ();
237 return 0; /* Errors produce abort() or _exit() */
238}