libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit d8211f1b223bbfee1fbe42106efd7b8157308408
parent c9c5dfbefd0a3e219b17174fe43b51cdc0cabb67
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 15 Aug 2007 08:36:06 +0000

even more APIs for timeout and improved timeout handling

Diffstat:
Msrc/daemon/daemon.c | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/daemon/daemontest_get.c | 2++
Msrc/include/microhttpd.h | 16++++++++++++++++
3 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -125,17 +125,21 @@ MHD_get_fdset (struct MHD_Daemon *daemon, fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) { struct MHD_Connection *pos; + int fd; + fd = daemon->socket_fd; if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) || (except_fd_set == NULL) || (max_fd == NULL) || + (fd == -1) || + (daemon->shutdown == MHD_YES) || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0)) return MHD_NO; - FD_SET (daemon->socket_fd, read_fd_set); - if ((*max_fd) < daemon->socket_fd) - *max_fd = daemon->socket_fd; + FD_SET (fd, read_fd_set); + if ((*max_fd) < fd) + *max_fd = fd; pos = daemon->connections; while (pos != NULL) { @@ -352,6 +356,46 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) } } +/** + * Obtain timeout value for select for this daemon + * (only needed if connection timeout is used). The + * returned value is how long select should at most + * block, not the timeout value set for connections. + * + * @param timeout set to the timeout (in milliseconds) + * @return MHD_YES on success, MHD_NO if timeouts are + * not used (or no connections exist that would + * necessiate the use of a timeout right now). + */ +int +MHD_get_timeout(struct MHD_Daemon * daemon, + unsigned long long * timeout) { + time_t earliest_deadline; + time_t now; + struct MHD_Connection *pos; + unsigned int dto; + + dto = daemon->connection_timeout; + if (0 == dto) + return MHD_NO; + pos = daemon->connections; + if (pos == NULL) + return MHD_NO; /* no connections */ + now = time(NULL); + /* start with conservative estimate */ + earliest_deadline = now + dto; + while (pos != NULL) + { + if (earliest_deadline > pos->last_activity + dto) + earliest_deadline = pos->last_activity + dto; + pos = pos->next; + } + if (earliest_deadline < now) + *timeout = 0; + else + *timeout = (earliest_deadline - now); + return MHD_YES; +} /** * Main select call. @@ -369,13 +413,16 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) fd_set es; int max; struct timeval timeout; + unsigned long long ltimeout; int ds; time_t now; timeout.tv_sec = 0; timeout.tv_usec = 0; - if (daemon == NULL) + if (daemon == NULL) abort (); + if (daemon->shutdown == MHD_YES) + return MHD_NO; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); @@ -391,10 +438,24 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) { /* accept only, have one thread per connection */ max = daemon->socket_fd; - FD_SET (daemon->socket_fd, &rs); + if (max != -1) + FD_SET (max, &rs); } + if (may_block == MHD_NO) { + timeout.tv_usec = 0; + timeout.tv_sec = 0; + } else { + /* ltimeout is in ms */ + if (MHD_YES == MHD_get_timeout(daemon, &ltimeout)) { + timeout.tv_usec = (ltimeout % 1000) * 1000 * 1000; + timeout.tv_sec = ltimeout / 1000; + may_block = MHD_NO; + } + } num_ready = SELECT (max + 1, &rs, &ws, &es, may_block == MHD_NO ? &timeout : NULL); + if (daemon->shutdown == MHD_YES) + return MHD_NO; if (num_ready < 0) { if (errno == EINTR) @@ -448,7 +509,7 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) int MHD_run (struct MHD_Daemon *daemon) { - if ((daemon->shutdown != 0) || + if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) return MHD_NO; @@ -466,7 +527,7 @@ static void * MHD_select_thread (void *cls) { struct MHD_Daemon *daemon = cls; - while (daemon->shutdown == 0) + while (daemon->shutdown == MHD_NO) { MHD_select (daemon, MHD_YES); MHD_cleanup_connections (daemon); @@ -609,12 +670,14 @@ void MHD_stop_daemon (struct MHD_Daemon *daemon) { void *unused; + int fd; if (daemon == NULL) return; - daemon->shutdown = 1; - CLOSE (daemon->socket_fd); + daemon->shutdown = MHD_YES; + fd = daemon->socket_fd; daemon->socket_fd = -1; + CLOSE (fd); if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) { diff --git a/src/daemon/daemontest_get.c b/src/daemon/daemontest_get.c @@ -321,11 +321,13 @@ int main (int argc, char *const *argv) { unsigned int errorCount = 0; + // int i; oneone = NULL != strstr (argv[0], "11"); if (0 != curl_global_init (CURL_GLOBAL_WIN32)) return 2; errorCount += testInternalGet (); + // for (i=0;i<10000;i++) errorCount += testMultithreadedGet (); errorCount += testExternalGet (); if (errorCount != 0) diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -486,6 +486,22 @@ MHD_get_fdset (struct MHD_Daemon *daemon, fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd); /** + * Obtain timeout value for select for this daemon + * (only needed if connection timeout is used). The + * returned value is how long select should at most + * block, not the timeout value set for connections. + * + * @param timeout set to the timeout (in milliseconds) + * @return MHD_YES on success, MHD_NO if timeouts are + * not used (or no connections exist that would + * necessiate the use of a timeout right now). + */ +int +MHD_get_timeout(struct MHD_Daemon * daemon, + unsigned long long * timeout); + + +/** * Run webserver operations (without blocking unless * in client callbacks). This method should be called * by clients in combination with MHD_get_fdset