mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
Implemented new API function MHD_run_wait().
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
Thu 01 Apr 2021 17:46:00 MSK
|
||||
Added new function MHD_run_wait() useful for single-threaded applications
|
||||
without other network activity.
|
||||
Added tests for the new function. -EG
|
||||
|
||||
Wed 17 Mar 2021 20:53:33 MSK
|
||||
Re-factored startup log parameters processing. Warn user if wrong logger
|
||||
could be used potentially.
|
||||
|
||||
@@ -135,7 +135,7 @@ typedef intptr_t ssize_t;
|
||||
* they are parsed as decimal numbers.
|
||||
* Example: 0x01093001 = 1.9.30-1.
|
||||
*/
|
||||
#define MHD_VERSION 0x00097205
|
||||
#define MHD_VERSION 0x00097206
|
||||
|
||||
/**
|
||||
* Operational results from MHD calls.
|
||||
@@ -2698,6 +2698,39 @@ _MHD_EXTERN enum MHD_Result
|
||||
MHD_run (struct MHD_Daemon *daemon);
|
||||
|
||||
|
||||
/**
|
||||
* Run websever operation with possible blocking.
|
||||
* This function do the following: waits for any network event not more than
|
||||
* specified number of milliseconds, processes all incoming and outgoing
|
||||
* data, processes new connections, processes any timed-out connection, and
|
||||
* do other things required to run webserver.
|
||||
* Once all connections are processed, function returns.
|
||||
* This function is useful for quick and simple webserver implementation if
|
||||
* application needs to run a single thread only and does not have any other
|
||||
* network activity.
|
||||
* @param daemon the daemon to run
|
||||
* @param millisec the maximum time in milliseconds to wait for network and
|
||||
* other events. Note: there is no guarantee that function
|
||||
* blocks for specified amount of time. The real processing
|
||||
* time can be shorter (if some data comes earlier) or
|
||||
* longer (if data processing requires more time, especially
|
||||
* in the user callbacks).
|
||||
* If set to '0' then function does not block and processes
|
||||
* only already available data (if any).
|
||||
* If set to '-1' then function waits for events
|
||||
* indefinitely (blocks until next network activity).
|
||||
* @return #MHD_YES on success, #MHD_NO if this
|
||||
* daemon was not started with the right
|
||||
* options for this call or some serious
|
||||
* unrecoverable error occurs.
|
||||
* @note Available since #MHD_VERSION 0x00097206
|
||||
* @ingroup event
|
||||
*/
|
||||
enum MHD_Result
|
||||
MHD_run_wait (struct MHD_Daemon *daemon,
|
||||
int32_t millisec);
|
||||
|
||||
|
||||
/**
|
||||
* Run webserver operations. This method should be called by clients
|
||||
* in combination with #MHD_get_fdset and #MHD_get_timeout() if the
|
||||
|
||||
+140
-61
@@ -101,16 +101,17 @@ close_all_connections (struct MHD_Daemon *daemon);
|
||||
#ifdef EPOLL_SUPPORT
|
||||
|
||||
/**
|
||||
* Do epoll()-based processing (this function is allowed to
|
||||
* block if @a may_block is set to #MHD_YES).
|
||||
* Do epoll()-based processing.
|
||||
*
|
||||
* @param daemon daemon to run poll loop for
|
||||
* @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking
|
||||
* @param millisec the maximum time in milliseconds to wait for events,
|
||||
* set to '0' for non-blocking processing,
|
||||
* set to '-1' to wait indefinitely.
|
||||
* @return #MHD_NO on serious errors, #MHD_YES on success
|
||||
*/
|
||||
static enum MHD_Result
|
||||
MHD_epoll (struct MHD_Daemon *daemon,
|
||||
int may_block);
|
||||
int32_t millisec);
|
||||
|
||||
#endif /* EPOLL_SUPPORT */
|
||||
|
||||
@@ -3834,6 +3835,35 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain timeout value for polling function for this daemon.
|
||||
* @remark To be called only from the thread that processes
|
||||
* daemon's select()/poll()/etc.
|
||||
*
|
||||
* @param daemon the daemon to query for timeout
|
||||
* @param max_timeout the maximum return value (in milliseconds),
|
||||
* ignored if set to '-1'
|
||||
* @return timeout value in milliseconds or -1 if no timeout is expected.
|
||||
*/
|
||||
static int
|
||||
get_timeout_millisec_ (struct MHD_Daemon *daemon,
|
||||
int32_t max_timeout)
|
||||
{
|
||||
MHD_UNSIGNED_LONG_LONG ulltimeout;
|
||||
if (0 == max_timeout)
|
||||
return 0;
|
||||
|
||||
if (MHD_NO == MHD_get_timeout (daemon, &ulltimeout))
|
||||
return (INT_MAX < max_timeout) ? INT_MAX : (int) max_timeout;
|
||||
|
||||
if ( (0 > max_timeout) ||
|
||||
((uint32_t) max_timeout > ulltimeout) )
|
||||
return (INT_MAX < ulltimeout) ? INT_MAX : (int) ulltimeout;
|
||||
|
||||
return (INT_MAX < max_timeout) ? INT_MAX : (int) max_timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal version of #MHD_run_from_select().
|
||||
*
|
||||
@@ -3978,7 +4008,7 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
|
||||
{
|
||||
#ifdef EPOLL_SUPPORT
|
||||
enum MHD_Result ret = MHD_epoll (daemon,
|
||||
MHD_NO);
|
||||
0);
|
||||
|
||||
MHD_cleanup_connections (daemon);
|
||||
return ret;
|
||||
@@ -4003,12 +4033,14 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
|
||||
* and then #internal_run_from_select with the result.
|
||||
*
|
||||
* @param daemon daemon to run select() loop for
|
||||
* @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking
|
||||
* @param millisec the maximum time in milliseconds to wait for events,
|
||||
* set to '0' for non-blocking processing,
|
||||
* set to '-1' to wait indefinitely.
|
||||
* @return #MHD_NO on serious errors, #MHD_YES on success
|
||||
*/
|
||||
static enum MHD_Result
|
||||
MHD_select (struct MHD_Daemon *daemon,
|
||||
int may_block)
|
||||
int32_t millisec)
|
||||
{
|
||||
int num_ready;
|
||||
fd_set rs;
|
||||
@@ -4017,7 +4049,6 @@ MHD_select (struct MHD_Daemon *daemon,
|
||||
MHD_socket maxsock;
|
||||
struct timeval timeout;
|
||||
struct timeval *tv;
|
||||
MHD_UNSIGNED_LONG_LONG ltimeout;
|
||||
int err_state;
|
||||
MHD_socket ls;
|
||||
|
||||
@@ -4033,7 +4064,7 @@ MHD_select (struct MHD_Daemon *daemon,
|
||||
if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
|
||||
(MHD_NO != resume_suspended_connections (daemon)) &&
|
||||
(0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) )
|
||||
may_block = MHD_NO;
|
||||
millisec = 0;
|
||||
|
||||
if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
|
||||
{
|
||||
@@ -4118,25 +4149,47 @@ MHD_select (struct MHD_Daemon *daemon,
|
||||
FD_CLR (ls,
|
||||
&rs);
|
||||
}
|
||||
tv = NULL;
|
||||
|
||||
if (MHD_NO != err_state)
|
||||
may_block = MHD_NO;
|
||||
if (MHD_NO == may_block)
|
||||
millisec = 0;
|
||||
tv = NULL;
|
||||
if (0 == millisec)
|
||||
{
|
||||
timeout.tv_usec = 0;
|
||||
timeout.tv_sec = 0;
|
||||
tv = &timeout;
|
||||
}
|
||||
else if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
|
||||
(MHD_NO != MHD_get_timeout (daemon, <imeout)) )
|
||||
else
|
||||
{
|
||||
/* ltimeout is in ms */
|
||||
timeout.tv_usec = (ltimeout % 1000) * 1000;
|
||||
if (ltimeout / 1000 > TIMEVAL_TV_SEC_MAX)
|
||||
timeout.tv_sec = TIMEVAL_TV_SEC_MAX;
|
||||
else
|
||||
timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) (ltimeout / 1000);
|
||||
tv = &timeout;
|
||||
MHD_UNSIGNED_LONG_LONG ltimeout;
|
||||
|
||||
if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
|
||||
(MHD_NO != MHD_get_timeout (daemon, <imeout)) )
|
||||
{
|
||||
tv = &timeout; /* have timeout value */
|
||||
if ( (0 < millisec) &&
|
||||
(ltimeout > (MHD_UNSIGNED_LONG_LONG) millisec) )
|
||||
ltimeout = (MHD_UNSIGNED_LONG_LONG) millisec;
|
||||
}
|
||||
else if (0 < millisec)
|
||||
{
|
||||
tv = &timeout; /* have timeout value */
|
||||
ltimeout = (MHD_UNSIGNED_LONG_LONG) millisec;
|
||||
}
|
||||
|
||||
if (NULL != tv)
|
||||
{ /* have timeout value */
|
||||
if (ltimeout / 1000 > TIMEVAL_TV_SEC_MAX)
|
||||
{
|
||||
timeout.tv_sec = TIMEVAL_TV_SEC_MAX;
|
||||
timeout.tv_usec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) (ltimeout / 1000);
|
||||
timeout.tv_usec = (ltimeout % 1000) * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
num_ready = MHD_SYS_select_ (maxsock + 1,
|
||||
&rs,
|
||||
@@ -4172,12 +4225,14 @@ MHD_select (struct MHD_Daemon *daemon,
|
||||
* socket using poll().
|
||||
*
|
||||
* @param daemon daemon to run poll loop for
|
||||
* @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking
|
||||
* @param millisec the maximum time in milliseconds to wait for events,
|
||||
* set to '0' for non-blocking processing,
|
||||
* set to '-1' to wait indefinitely.
|
||||
* @return #MHD_NO on serious errors, #MHD_YES on success
|
||||
*/
|
||||
static enum MHD_Result
|
||||
MHD_poll_all (struct MHD_Daemon *daemon,
|
||||
int may_block)
|
||||
int32_t millisec)
|
||||
{
|
||||
unsigned int num_connections;
|
||||
struct MHD_Connection *pos;
|
||||
@@ -4189,7 +4244,7 @@ MHD_poll_all (struct MHD_Daemon *daemon,
|
||||
|
||||
if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
|
||||
(MHD_NO != resume_suspended_connections (daemon)) )
|
||||
may_block = MHD_NO;
|
||||
millisec = 0;
|
||||
|
||||
/* count number of connections and thus determine poll set size */
|
||||
num_connections = 0;
|
||||
@@ -4200,7 +4255,6 @@ MHD_poll_all (struct MHD_Daemon *daemon,
|
||||
num_connections += 2;
|
||||
#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
|
||||
{
|
||||
MHD_UNSIGNED_LONG_LONG ltimeout;
|
||||
unsigned int i;
|
||||
int timeout;
|
||||
unsigned int poll_server;
|
||||
@@ -4243,14 +4297,8 @@ MHD_poll_all (struct MHD_Daemon *daemon,
|
||||
poll_itc_idx = (int) poll_server;
|
||||
poll_server++;
|
||||
}
|
||||
if (may_block == MHD_NO)
|
||||
timeout = 0;
|
||||
else if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
|
||||
(MHD_NO == MHD_get_timeout (daemon,
|
||||
<imeout)) )
|
||||
timeout = -1;
|
||||
else
|
||||
timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
|
||||
|
||||
timeout = get_timeout_millisec_ (daemon, millisec);
|
||||
|
||||
i = 0;
|
||||
for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
|
||||
@@ -4494,7 +4542,7 @@ MHD_poll (struct MHD_Daemon *daemon,
|
||||
return MHD_NO;
|
||||
if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
|
||||
return MHD_poll_all (daemon,
|
||||
may_block);
|
||||
may_block ? -1 : 0);
|
||||
return MHD_poll_listen_socket (daemon,
|
||||
may_block);
|
||||
#else
|
||||
@@ -4685,16 +4733,17 @@ static const char *const epoll_itc_marker = "itc_marker";
|
||||
|
||||
|
||||
/**
|
||||
* Do epoll()-based processing (this function is allowed to
|
||||
* block if @a may_block is set to #MHD_YES).
|
||||
* Do epoll()-based processing.
|
||||
*
|
||||
* @param daemon daemon to run poll loop for
|
||||
* @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking
|
||||
* @param millisec the maximum time in milliseconds to wait for events,
|
||||
* set to '0' for non-blocking processing,
|
||||
* set to '-1' to wait indefinitely.
|
||||
* @return #MHD_NO on serious errors, #MHD_YES on success
|
||||
*/
|
||||
static enum MHD_Result
|
||||
MHD_epoll (struct MHD_Daemon *daemon,
|
||||
int may_block)
|
||||
int32_t millisec)
|
||||
{
|
||||
#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
|
||||
static const char *const upgrade_marker = "upgrade_ptr";
|
||||
@@ -4704,7 +4753,6 @@ MHD_epoll (struct MHD_Daemon *daemon,
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
struct epoll_event event;
|
||||
int timeout_ms;
|
||||
MHD_UNSIGNED_LONG_LONG timeout_ll;
|
||||
int num_events;
|
||||
unsigned int i;
|
||||
MHD_socket ls;
|
||||
@@ -4790,23 +4838,9 @@ MHD_epoll (struct MHD_Daemon *daemon,
|
||||
|
||||
if ( (0 != (daemon->options & MHD_TEST_ALLOW_SUSPEND_RESUME)) &&
|
||||
(MHD_NO != resume_suspended_connections (daemon)) )
|
||||
may_block = MHD_NO;
|
||||
millisec = 0;
|
||||
|
||||
if (MHD_NO != may_block)
|
||||
{
|
||||
if (MHD_NO != MHD_get_timeout (daemon,
|
||||
&timeout_ll))
|
||||
{
|
||||
if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
|
||||
timeout_ms = INT_MAX;
|
||||
else
|
||||
timeout_ms = (int) timeout_ll;
|
||||
}
|
||||
else
|
||||
timeout_ms = -1;
|
||||
}
|
||||
else
|
||||
timeout_ms = 0;
|
||||
timeout_ms = get_timeout_millisec_ (daemon, millisec);
|
||||
|
||||
/* Reset. New value will be set when connections are processed. */
|
||||
/* Note: Used mostly for uniformity here as same situation is
|
||||
@@ -5026,24 +5060,69 @@ MHD_run (struct MHD_Daemon *daemon)
|
||||
if ( (daemon->shutdown) ||
|
||||
(0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
|
||||
return MHD_NO;
|
||||
|
||||
(void) MHD_run_wait (daemon, 0);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run websever operation with possible blocking.
|
||||
* This function do the following: waits for any network event not more than
|
||||
* specified number of milliseconds, processes all incoming and outgoing
|
||||
* data, processes new connections, processes any timed-out connection, and
|
||||
* do other things required to run webserver.
|
||||
* Once all connections are processed, function returns.
|
||||
* This function is useful for quick and simple webserver implementation if
|
||||
* application needs to run a single thread only and does not have any other
|
||||
* network activity.
|
||||
* @param daemon the daemon to run
|
||||
* @param millisec the maximum time in milliseconds to wait for network and
|
||||
* other events. Note: there is no guarantee that function
|
||||
* blocks for specified amount of time. The real processing
|
||||
* time can be shorter (if some data comes earlier) or
|
||||
* longer (if data processing requires more time, especially
|
||||
* in the user callbacks).
|
||||
* If set to '0' then function does not block and processes
|
||||
* only already available data (if any).
|
||||
* If set to '-1' then function waits for events
|
||||
* indefinitely (blocks until next network activity).
|
||||
* @return #MHD_YES on success, #MHD_NO if this
|
||||
* daemon was not started with the right
|
||||
* options for this call or some serious
|
||||
* unrecoverable error occurs.
|
||||
* @note Available since #MHD_VERSION 0x00097206
|
||||
* @ingroup event
|
||||
*/
|
||||
enum MHD_Result
|
||||
MHD_run_wait (struct MHD_Daemon *daemon,
|
||||
int32_t millisec)
|
||||
{
|
||||
enum MHD_Result res;
|
||||
if ( (daemon->shutdown) ||
|
||||
(0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
|
||||
return MHD_NO;
|
||||
|
||||
if (0 > millisec)
|
||||
millisec = -1;
|
||||
if (0 != (daemon->options & MHD_USE_POLL))
|
||||
{
|
||||
MHD_poll (daemon, MHD_NO);
|
||||
res = MHD_poll_all (daemon, millisec);
|
||||
MHD_cleanup_connections (daemon);
|
||||
}
|
||||
#ifdef EPOLL_SUPPORT
|
||||
else if (0 != (daemon->options & MHD_USE_EPOLL))
|
||||
{
|
||||
MHD_epoll (daemon, MHD_NO);
|
||||
res = MHD_epoll (daemon, millisec);
|
||||
MHD_cleanup_connections (daemon);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
MHD_select (daemon, MHD_NO);
|
||||
res = MHD_select (daemon, millisec);
|
||||
/* MHD_select does MHD_cleanup_connections already */
|
||||
}
|
||||
return MHD_YES;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -5139,10 +5218,10 @@ MHD_polling_thread (void *cls)
|
||||
MHD_poll (daemon, MHD_YES);
|
||||
#ifdef EPOLL_SUPPORT
|
||||
else if (0 != (daemon->options & MHD_USE_EPOLL))
|
||||
MHD_epoll (daemon, MHD_YES);
|
||||
MHD_epoll (daemon, -1);
|
||||
#endif
|
||||
else
|
||||
MHD_select (daemon, MHD_YES);
|
||||
MHD_select (daemon, -1);
|
||||
MHD_cleanup_connections (daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,3 +118,5 @@ test_patch11
|
||||
core
|
||||
/test_get_iovec
|
||||
/test_get_iovec11
|
||||
/test_get_wait
|
||||
/test_get_wait11
|
||||
|
||||
@@ -46,6 +46,8 @@ THREAD_ONLY_TESTS += \
|
||||
endif
|
||||
|
||||
THREAD_ONLY_TESTS += \
|
||||
test_get_wait \
|
||||
test_get_wait11 \
|
||||
test_quiesce \
|
||||
$(EMPTY_ITEM)
|
||||
|
||||
@@ -232,6 +234,24 @@ test_get_sendfile_LDADD = \
|
||||
$(top_builddir)/src/microhttpd/libmicrohttpd.la \
|
||||
@LIBCURL@
|
||||
|
||||
test_get_wait_SOURCES = \
|
||||
test_get_wait.c \
|
||||
mhd_has_in_name.h
|
||||
test_get_wait_CFLAGS = \
|
||||
$(PTHREAD_CFLAGS) $(AM_CFLAGS)
|
||||
test_get_wait_LDADD = \
|
||||
$(top_builddir)/src/microhttpd/libmicrohttpd.la \
|
||||
$(PTHREAD_LIBS) @LIBCURL@
|
||||
|
||||
test_get_wait11_SOURCES = \
|
||||
test_get_wait.c \
|
||||
mhd_has_in_name.h
|
||||
test_get_wait11_CFLAGS = \
|
||||
$(PTHREAD_CFLAGS) $(AM_CFLAGS)
|
||||
test_get_wait11_LDADD = \
|
||||
$(top_builddir)/src/microhttpd/libmicrohttpd.la \
|
||||
$(PTHREAD_LIBS) @LIBCURL@
|
||||
|
||||
test_urlparse_SOURCES = \
|
||||
test_urlparse.c mhd_has_in_name.h
|
||||
test_urlparse_LDADD = \
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
This file is part of libmicrohttpd
|
||||
Copyright (C) 2007, 2009, 2011 Christian Grothoff
|
||||
Copyright (C) 2016-2021 Karlson2k (Evgeny Grin)
|
||||
|
||||
libmicrohttpd is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 2, or (at your
|
||||
option) any later version.
|
||||
|
||||
libmicrohttpd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libmicrohttpd; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_get_wait.c
|
||||
* @brief Test 'MHD_run_wait()' function.
|
||||
* @author Christian Grothoff
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#include "MHD_config.h"
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include <microhttpd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include "mhd_has_in_name.h"
|
||||
|
||||
#if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
|
||||
#undef MHD_CPU_COUNT
|
||||
#endif
|
||||
#if ! defined(MHD_CPU_COUNT)
|
||||
#define MHD_CPU_COUNT 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* How many rounds of operations do we do for each
|
||||
* test.
|
||||
* Check all three types of requests for HTTP/1.1:
|
||||
* * first request, new connection;
|
||||
* * "middle" request, existing connection with stay-alive;
|
||||
* * final request, no data processed after.
|
||||
*/
|
||||
#define ROUNDS 3
|
||||
|
||||
/**
|
||||
* Do we use HTTP 1.1?
|
||||
*/
|
||||
static int oneone;
|
||||
|
||||
/**
|
||||
* Response to return (re-used).
|
||||
*/
|
||||
static struct MHD_Response *response;
|
||||
|
||||
/**
|
||||
* Set to 1 if the worker threads are done.
|
||||
*/
|
||||
static volatile int signal_done;
|
||||
|
||||
|
||||
static size_t
|
||||
copyBuffer (void *ptr,
|
||||
size_t size, size_t nmemb,
|
||||
void *ctx)
|
||||
{
|
||||
(void) ptr; (void) ctx; /* Unused. Silent compiler warning. */
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
|
||||
static enum MHD_Result
|
||||
ahc_echo (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data, size_t *upload_data_size,
|
||||
void **unused)
|
||||
{
|
||||
static int ptr;
|
||||
const char *me = cls;
|
||||
enum MHD_Result ret;
|
||||
(void) url; (void) version; /* Unused. Silent compiler warning. */
|
||||
(void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
|
||||
|
||||
if (0 != strcmp (me, method))
|
||||
return MHD_NO; /* unexpected method */
|
||||
if (&ptr != *unused)
|
||||
{
|
||||
*unused = &ptr;
|
||||
return MHD_YES;
|
||||
}
|
||||
*unused = NULL;
|
||||
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
|
||||
if (ret == MHD_NO)
|
||||
abort ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
thread_gets (void *param)
|
||||
{
|
||||
CURL *c;
|
||||
CURLcode errornum;
|
||||
unsigned int i;
|
||||
char url[64];
|
||||
int port = (int) (intptr_t) param;
|
||||
|
||||
snprintf (url,
|
||||
sizeof (url),
|
||||
"http://127.0.0.1:%d/hello_world",
|
||||
port);
|
||||
|
||||
c = curl_easy_init ();
|
||||
if (NULL == c)
|
||||
_exit (99);
|
||||
curl_easy_setopt (c, CURLOPT_URL, url);
|
||||
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
|
||||
curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
|
||||
if (oneone)
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
else
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
|
||||
for (i = 0; i < ROUNDS; i++)
|
||||
{
|
||||
if (CURLE_OK != (errornum = curl_easy_perform (c)))
|
||||
{
|
||||
signal_done = 1;
|
||||
fprintf (stderr,
|
||||
"curl_easy_perform failed: `%s'\n",
|
||||
curl_easy_strerror (errornum));
|
||||
curl_easy_cleanup (c);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
curl_easy_cleanup (c);
|
||||
signal_done = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
testRunWaitGet (int port, int poll_flag)
|
||||
{
|
||||
pthread_t get_tid;
|
||||
struct MHD_Daemon *d;
|
||||
const char *const test_desc = ((poll_flag & MHD_USE_AUTO) ?
|
||||
"MHD_USE_AUTO" :
|
||||
(poll_flag & MHD_USE_POLL) ?
|
||||
"MHD_USE_POLL" :
|
||||
(poll_flag & MHD_USE_EPOLL) ?
|
||||
"MHD_USE_EPOLL" :
|
||||
"select()");
|
||||
|
||||
if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
|
||||
port = 0;
|
||||
|
||||
printf ("Starting MHD_run_wait() test with MHD in %s polling mode.\n",
|
||||
test_desc);
|
||||
signal_done = 0;
|
||||
d = MHD_start_daemon (MHD_USE_ERROR_LOG | poll_flag,
|
||||
port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
abort ();
|
||||
if (0 == port)
|
||||
{
|
||||
const union MHD_DaemonInfo *dinfo;
|
||||
dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
|
||||
if ((NULL == dinfo) || (0 == dinfo->port) )
|
||||
abort ();
|
||||
port = (int) dinfo->port;
|
||||
}
|
||||
|
||||
if (0 != pthread_create (&get_tid, NULL,
|
||||
&thread_gets, (void*) (intptr_t) port))
|
||||
_exit (99);
|
||||
|
||||
/* As another thread sets "done" flag after ending of network
|
||||
* activity, it's required to set positive timeout value for MHD_run_wait().
|
||||
* Alternatively, to use timeout value "-1" here, another thread should start
|
||||
* additional connection to wake MHD after setting "done" flag. */
|
||||
do
|
||||
{
|
||||
if (MHD_NO == MHD_run_wait (d, 50))
|
||||
abort ();
|
||||
} while (0 == signal_done);
|
||||
|
||||
if (0 != pthread_join (get_tid, NULL))
|
||||
_exit (99);
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
printf ("Test succeeded.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
int port = 1675;
|
||||
(void) argc; /* Unused. Silent compiler warning. */
|
||||
|
||||
if ((NULL == argv) || (0 == argv[0]))
|
||||
return 99;
|
||||
oneone = has_in_name (argv[0], "11");
|
||||
if (oneone)
|
||||
port += 5;
|
||||
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
|
||||
return 2;
|
||||
response = MHD_create_response_from_buffer (strlen ("/hello_world"),
|
||||
"/hello_world",
|
||||
MHD_RESPMEM_MUST_COPY);
|
||||
testRunWaitGet (port++, 0);
|
||||
if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
|
||||
testRunWaitGet (port++, MHD_USE_EPOLL);
|
||||
testRunWaitGet (port++, MHD_USE_AUTO);
|
||||
|
||||
MHD_destroy_response (response);
|
||||
curl_global_cleanup ();
|
||||
return 0; /* Errors produce abort() or _exit() */
|
||||
}
|
||||
Reference in New Issue
Block a user