mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
test case for external event loop
This commit is contained in:
@@ -4728,7 +4728,7 @@ MHD_FN_PAR_NONNULL_ALL_;
|
||||
* error code otherwise
|
||||
*/
|
||||
#define MHD_daemon_set_option(daemon, option_ptr) \
|
||||
MHD_daemon_set_options (daemon, options_ptr, 1)
|
||||
MHD_daemon_set_options (daemon, option_ptr, 1)
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
@@ -6098,10 +6098,10 @@ MHD_response_from_callback (enum MHD_HTTP_StatusCode sc,
|
||||
* needs to be valid while the response is used
|
||||
* @param free_cb the callback to free any allocated data, called
|
||||
* when response is being destroyed, can be NULL
|
||||
* to skip the free/cleanup callback
|
||||
* to skip the free/cleanup callback;
|
||||
* @param free_cb_cls the parameter for @a free_cb
|
||||
* @return NULL on error (i.e. invalid arguments, out of memory)
|
||||
* FIXME: Call free callback on error?
|
||||
* on error, @a free_cb is NOT called
|
||||
* @ingroup response
|
||||
*/
|
||||
MHD_EXTERN_ struct MHD_Response *
|
||||
|
||||
@@ -741,6 +741,19 @@ MHDT_server_setup_minimal (const void *cls,
|
||||
struct MHD_Daemon *d);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize MHD daemon for an external event loop.
|
||||
* Must be used together with #MHDT_server_run_external().
|
||||
*
|
||||
* @param cls closure (use NULL)
|
||||
* @param[in,out] d daemon to initialize
|
||||
* @return error message, NULL on success
|
||||
*/
|
||||
const char *
|
||||
MHDT_server_setup_external (const void *cls,
|
||||
struct MHD_Daemon *d);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize MHD daemon with TLS support, binding to any free port.
|
||||
*
|
||||
@@ -824,6 +837,20 @@ MHDT_server_run_blocking (void *cls,
|
||||
struct MHD_Daemon *d);
|
||||
|
||||
|
||||
/**
|
||||
* Function that runs an MHD daemon with an external event loop until
|
||||
* a read() against @a finsig succeeds.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param finsig fd to read from to detect termination request
|
||||
* @param[in,out] d daemon to run
|
||||
*/
|
||||
void
|
||||
MHDT_server_run_external (void *cls,
|
||||
int finsig,
|
||||
struct MHD_Daemon *d);
|
||||
|
||||
|
||||
/**
|
||||
* Run test suite with @a phases for a daemon initialized
|
||||
* using @a ss_cb on the local machine.
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <curl/curl.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
|
||||
const char *
|
||||
@@ -290,3 +291,200 @@ MHDT_server_run_blocking (void *cls,
|
||||
"Failed to drain termination signal\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int my_epoll_fd = -1;
|
||||
|
||||
|
||||
/**
|
||||
* The callback for registration/de-registration of the sockets to watch.
|
||||
*
|
||||
* This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(),
|
||||
* #MHD_daemon_add_connection().
|
||||
*
|
||||
* @param cls the closure
|
||||
* @param fd the socket to watch
|
||||
* @param watch_for the states of the @a fd to watch, if set to
|
||||
* #MHD_FD_STATE_NONE the socket must be de-registred
|
||||
* @param app_cntx_old the old application defined context for the socket,
|
||||
* NULL if @a fd socket was not registered before
|
||||
* @param ecb_cntx the context handle to be used
|
||||
* with #MHD_daemon_event_update()
|
||||
* @return NULL if error (to connection will be aborted),
|
||||
* or the new socket context
|
||||
* @ingroup event
|
||||
*/
|
||||
static void *
|
||||
update_fd (
|
||||
void *cls,
|
||||
MHD_Socket fd,
|
||||
enum MHD_FdState watch_for,
|
||||
MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old,
|
||||
struct MHD_EventUpdateContext *ecb_cntx)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
|
||||
if (watch_for == MHD_FD_STATE_NONE)
|
||||
{
|
||||
epoll_ctl (my_epoll_fd,
|
||||
EPOLL_CTL_DEL,
|
||||
fd,
|
||||
&ev /* for Linux 2.6.9-compatibility */);
|
||||
return NULL;
|
||||
}
|
||||
ev.data.ptr = ecb_cntx;
|
||||
ev.events = 0;
|
||||
if (0 != (watch_for & MHD_FD_STATE_RECV))
|
||||
ev.events |= EPOLLIN;
|
||||
if (0 != (watch_for & MHD_FD_STATE_SEND))
|
||||
ev.events |= EPOLLOUT;
|
||||
if (0 != (watch_for & MHD_FD_STATE_EXCEPT))
|
||||
ev.events |= EPOLLRDHUP | EPOLLHUP | EPOLLERR;
|
||||
if (0 !=
|
||||
epoll_ctl (my_epoll_fd,
|
||||
NULL == app_cntx_old
|
||||
? EPOLL_CTL_ADD
|
||||
: EPOLL_CTL_MOD,
|
||||
fd,
|
||||
&ev))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"epoll_ctl failed: %s\n",
|
||||
strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
return ecb_cntx;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
MHDT_server_setup_external (const void *cls,
|
||||
struct MHD_Daemon *d)
|
||||
{
|
||||
(void) cls;
|
||||
if (MHD_SC_OK !=
|
||||
MHD_DAEMON_SET_OPTIONS (
|
||||
d,
|
||||
MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL (&update_fd,
|
||||
NULL)))
|
||||
return "Failed to configure external mode!";
|
||||
if (MHD_SC_OK !=
|
||||
MHD_DAEMON_SET_OPTIONS (
|
||||
d,
|
||||
MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO,
|
||||
0)))
|
||||
return "Failed to bind to port 0!";
|
||||
my_epoll_fd = epoll_create1 (0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MHDT_server_run_external (void *cls,
|
||||
int finsig,
|
||||
struct MHD_Daemon *d)
|
||||
{
|
||||
fd_set r;
|
||||
|
||||
(void) cls; /* Unused */
|
||||
if (-1 == my_epoll_fd)
|
||||
abort ();
|
||||
while (1)
|
||||
{
|
||||
uint_fast64_t next_wait;
|
||||
struct timeval timeout;
|
||||
|
||||
if (MHD_SC_OK !=
|
||||
MHD_daemon_process_reg_events (d,
|
||||
&next_wait))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"MHD_daemon_process_reg_events() failed\n");
|
||||
break;
|
||||
}
|
||||
timeout.tv_usec = next_wait;
|
||||
|
||||
FD_ZERO (&r);
|
||||
FD_SET (finsig,
|
||||
&r);
|
||||
FD_SET (my_epoll_fd,
|
||||
&r);
|
||||
if ( (-1 ==
|
||||
select ((my_epoll_fd > finsig ? my_epoll_fd : finsig) + 1,
|
||||
&r,
|
||||
NULL,
|
||||
NULL,
|
||||
&timeout)) &&
|
||||
(EAGAIN != errno) )
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failure in select(): %s\n",
|
||||
strerror (errno));
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET (finsig,
|
||||
&r))
|
||||
break;
|
||||
if (FD_ISSET (my_epoll_fd,
|
||||
&r))
|
||||
{
|
||||
int maxevents = 40;
|
||||
struct epoll_event events[maxevents];
|
||||
int n;
|
||||
int i;
|
||||
|
||||
n = epoll_wait (my_epoll_fd,
|
||||
events,
|
||||
maxevents,
|
||||
0);
|
||||
if (-1 == n)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"epoll_wait() failed: %s\n",
|
||||
strerror (errno));
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
enum MHD_FdState state = MHD_FD_STATE_NONE;
|
||||
|
||||
if (0 != (events[i].events & EPOLLIN))
|
||||
state |= MHD_FD_STATE_RECV;
|
||||
if (0 != (events[i].events & EPOLLOUT))
|
||||
state |= MHD_FD_STATE_SEND;
|
||||
if (0 != (events[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) )
|
||||
state |= MHD_FD_STATE_EXCEPT;
|
||||
MHD_daemon_event_update (d,
|
||||
events[i].data.ptr,
|
||||
state);
|
||||
}
|
||||
|
||||
if (MHD_SC_OK !=
|
||||
MHD_daemon_process_blocking (d,
|
||||
1000))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failure running MHD_daemon_process_blocking()\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char c;
|
||||
|
||||
if ( (FD_ISSET (finsig,
|
||||
&r)) &&
|
||||
(1 != read (finsig,
|
||||
&c,
|
||||
1)) )
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to drain termination signal\n");
|
||||
}
|
||||
}
|
||||
|
||||
close (my_epoll_fd);
|
||||
my_epoll_fd = -1;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,12 @@ main (int argc, char *argv[])
|
||||
.server_setup_cls = external0auto,
|
||||
.server_runner = &MHDT_server_run_blocking,
|
||||
},
|
||||
{
|
||||
.label = "auto-selected external event loop mode, no threads",
|
||||
.server_setup = &MHDT_server_setup_external,
|
||||
.server_setup_cls = NULL,
|
||||
.server_runner = &MHDT_server_run_external,
|
||||
},
|
||||
{
|
||||
.label = "END"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user