diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-08-15 08:07:57 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-08-15 08:07:57 +0000 |
commit | c9c5dfbefd0a3e219b17174fe43b51cdc0cabb67 (patch) | |
tree | 6c6cdd95bbf4e64081dc9d9eaf626408e6166de9 | |
parent | 08ad843b6af71224fb6a37856b67a4dd8a25ebcc (diff) |
API changes -- allow timeout, client-specified block size
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/daemon/Makefile.am | 2 | ||||
-rw-r--r-- | src/daemon/daemon.c | 53 | ||||
-rw-r--r-- | src/daemon/daemontest_get.c | 13 | ||||
-rw-r--r-- | src/daemon/daemontest_post.c | 12 | ||||
-rw-r--r-- | src/daemon/daemontest_put.c | 12 | ||||
-rw-r--r-- | src/daemon/fileserver_example.c | 1 | ||||
-rw-r--r-- | src/daemon/internal.h | 14 | ||||
-rw-r--r-- | src/daemon/response.c | 23 | ||||
-rw-r--r-- | src/include/microhttpd.h | 15 |
11 files changed, 127 insertions, 27 deletions
@@ -1,3 +1,8 @@ +Wed Aug 15 01:46:44 MDT 2007 + Extending API to allow timeout of connections. + Changed API (MHD_create_response_from_callback) to + allow user to specify IO buffer size. - CG + Tue Aug 14 19:45:49 MDT 2007 Changed license to LGPL (with consent from all contributors). Released libmicrohttpd 0.0.2. - CG diff --git a/configure.ac b/configure.ac index b87f8d95..44afee9e 100644 --- a/configure.ac +++ b/configure.ac @@ -21,8 +21,8 @@ # # AC_PREREQ(2.57) -AC_INIT([libmicrohttpd], [0.0.1],[libmicrohttpd@gnunet.org]) -AM_INIT_AUTOMAKE([libmicrohttpd], [0.0.1]) +AC_INIT([libmicrohttpd], [0.0.3],[libmicrohttpd@gnunet.org]) +AM_INIT_AUTOMAKE([libmicrohttpd], [0.0.3]) AM_CONFIG_HEADER([config.h]) AH_TOP([#define _GNU_SOURCE 1]) diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index 0f11b662..8a0aa4b2 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = \ libmicrohttpd.la libmicrohttpd_la_LDFLAGS = \ - -export-dynamic -version-info 0:1:0 + -export-dynamic -version-info 1:0:0 libmicrohttpd_la_SOURCES = \ connection.c connection.h \ daemon.c \ diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 3caade12..0c198454 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c @@ -163,20 +163,35 @@ MHD_handle_connection (void *data) fd_set ws; fd_set es; int max; + struct timeval tv; + unsigned int timeout; + time_t now; if (con == NULL) abort (); - while ((!con->daemon->shutdown) && (con->socket_fd != -1)) + timeout = con->daemon->connection_timeout; + now = time(NULL); + while ( (!con->daemon->shutdown) && + (con->socket_fd != -1) && + ( (timeout == 0) || + (now - timeout > con->last_activity) ) ) { FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); max = 0; MHD_connection_get_fdset (con, &rs, &ws, &es, &max); - num_ready = SELECT (max + 1, &rs, &ws, &es, NULL); - if (num_ready <= 0) + tv.tv_usec = 0; + tv.tv_sec = timeout - (now - con->last_activity); + num_ready = SELECT (max + 1, + &rs, + &ws, + &es, + (tv.tv_sec != 0) ? &tv : NULL); + now = time(NULL); + if (num_ready < 0) { - if (errno == EINTR) + if (errno == EINTR) continue; break; } @@ -188,6 +203,10 @@ MHD_handle_connection (void *data) break; if ((con->headersReceived == 1) && (con->response == NULL)) MHD_call_connection_handler (con); + if ( (con->socket_fd != -1) && + ( (FD_ISSET (con->socket_fd, &rs)) || + (FD_ISSET (con->socket_fd, &ws)) ) ) + con->last_activity = now; } if (con->socket_fd != -1) { @@ -261,6 +280,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon) free (connection); return MHD_NO; } + connection->last_activity = time(NULL); connection->next = daemon->connections; daemon->connections = connection; daemon->max_connections--; @@ -284,11 +304,22 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) struct MHD_Connection *pos; struct MHD_Connection *prev; void *unused; + time_t timeout; + timeout = time(NULL); + if (daemon->connection_timeout != 0) + timeout -= daemon->connection_timeout; + else + timeout = 0; pos = daemon->connections; prev = NULL; while (pos != NULL) { + if ( (pos->last_activity < timeout) && + (pos->socket_fd != -1) ) { + CLOSE(pos->socket_fd); + pos->socket_fd = -1; + } if (pos->socket_fd == -1) { if (prev == NULL) @@ -339,6 +370,7 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) int max; struct timeval timeout; int ds; + time_t now; timeout.tv_sec = 0; timeout.tv_usec = 0; @@ -378,6 +410,7 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) { /* do not have a thread per connection, process all connections now */ + now = time(NULL); pos = daemon->connections; while (pos != NULL) { @@ -387,10 +420,14 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) pos = pos->next; continue; } - if (FD_ISSET (ds, &rs)) + if (FD_ISSET (ds, &rs)) { + pos->last_activity = now; MHD_connection_handle_read (pos); - if (FD_ISSET (ds, &ws)) + } + if (FD_ISSET (ds, &ws)) { + pos->last_activity = now; MHD_connection_handle_write (pos); + } pos = pos->next; } } @@ -530,6 +567,7 @@ MHD_start_daemon (unsigned int options, retVal->default_handler.next = NULL; retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; retVal->pool_size = MHD_POOL_SIZE_DEFAULT; + retVal->connection_timeout = 0; /* no timeout */ va_start (ap, dh_cls); while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) { @@ -541,6 +579,9 @@ MHD_start_daemon (unsigned int options, case MHD_OPTION_CONNECTION_LIMIT: retVal->max_connections = va_arg (ap, unsigned int); break; + case MHD_OPTION_CONNECTION_TIMEOUT: + retVal->connection_timeout = va_arg (ap, unsigned int); + break; default: fprintf (stderr, "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n"); diff --git a/src/daemon/daemontest_get.c b/src/daemon/daemontest_get.c index c144d368..daea7a39 100644 --- a/src/daemon/daemontest_get.c +++ b/src/daemon/daemontest_get.c @@ -86,6 +86,7 @@ testInternalGet () CURL *c; char buf[2048]; struct CBC cbc; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -109,8 +110,11 @@ testInternalGet () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; @@ -139,6 +143,7 @@ testMultithreadedGet () CURL *c; char buf[2048]; struct CBC cbc; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -162,8 +167,12 @@ testMultithreadedGet () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); + curl_easy_cleanup (c); MHD_stop_daemon (d); return 32; } diff --git a/src/daemon/daemontest_post.c b/src/daemon/daemontest_post.c index 19c79556..eed25e1d 100644 --- a/src/daemon/daemontest_post.c +++ b/src/daemon/daemontest_post.c @@ -105,6 +105,7 @@ testInternalPost () CURL *c; char buf[2048]; struct CBC cbc; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -131,8 +132,11 @@ testInternalPost () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; @@ -161,6 +165,7 @@ testMultithreadedPost () CURL *c; char buf[2048]; struct CBC cbc; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -187,8 +192,11 @@ testMultithreadedPost () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 32; diff --git a/src/daemon/daemontest_put.c b/src/daemon/daemontest_put.c index 17a2f1c4..7c047887 100644 --- a/src/daemon/daemontest_put.c +++ b/src/daemon/daemontest_put.c @@ -117,6 +117,7 @@ testInternalPut () struct CBC cbc; unsigned int pos = 0; int done_flag = 0; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -145,8 +146,11 @@ testInternalPut () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; @@ -177,6 +181,7 @@ testMultithreadedPut () struct CBC cbc; unsigned int pos = 0; int done_flag = 0; + CURLcode errornum; cbc.buf = buf; cbc.size = 2048; @@ -205,8 +210,11 @@ testMultithreadedPut () // setting NOSIGNAL results in really weird // crashes on my system! curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); - if (CURLE_OK != curl_easy_perform (c)) + if (CURLE_OK != (errornum = curl_easy_perform (c))) { + fprintf(stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror(errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 32; diff --git a/src/daemon/fileserver_example.c b/src/daemon/fileserver_example.c index 6f39f491..7574cd20 100644 --- a/src/daemon/fileserver_example.c +++ b/src/daemon/fileserver_example.c @@ -74,6 +74,7 @@ ahc_echo (void *cls, { stat (&url[1], &buf); response = MHD_create_response_from_callback (buf.st_size, + 32 * 1024, /* 32k page size */ &file_reader, file, (MHD_ContentReaderFreeCallback) diff --git a/src/daemon/internal.h b/src/daemon/internal.h index b4e3698e..c4180d3b 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h @@ -54,6 +54,8 @@ /** * Size by which MHD usually tries to increment read/write buffers. + * TODO: we should probably get rid of this magic constant and + * put in code to automatically determine a good value. */ #define MHD_BUF_INC_SIZE 2048 @@ -294,6 +296,12 @@ struct MHD_Connection socklen_t addr_len; /** + * Last time this connection had any activity + * (reading or writing). + */ + time_t last_activity; + + /** * Socket for this connection. Set to -1 if * this connection has died (daemon should clean * up in that case). @@ -385,6 +393,12 @@ struct MHD_Daemon unsigned int max_connections; /** + * After how many seconds of inactivity should + * connections time out? Zero for no timeout. + */ + unsigned int connection_timeout; + + /** * Daemon's options. */ enum MHD_OPTION options; diff --git a/src/daemon/response.c b/src/daemon/response.c index f52bb2df..3adb6bc9 100644 --- a/src/daemon/response.c +++ b/src/daemon/response.c @@ -148,6 +148,11 @@ MHD_get_response_header (struct MHD_Response *response, const char *key) * header information and then be used any number of times. * * @param size size of the data portion of the response, -1 for unknown + * @param block_size preferred block size for querying crc (advisory only, + * MHD may still call crc using smaller chunks); this + * is essentially the buffer size used for IO, clients + * should pick a value that is appropriate for IO and + * memory performance requirements * @param crc callback to use to obtain response data * @param crc_cls extra argument to crc * @param crfc callback to call to free crc_cls resources @@ -155,26 +160,24 @@ MHD_get_response_header (struct MHD_Response *response, const char *key) */ struct MHD_Response * MHD_create_response_from_callback (size_t size, + unsigned int block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc) { struct MHD_Response *retVal; - if (crc == NULL) + if ( (crc == NULL) || + (block_size == 0) ) + return NULL; + retVal = malloc (sizeof (struct MHD_Response) + block_size); + if (retVal == NULL) return NULL; - retVal = malloc (sizeof (struct MHD_Response)); memset (retVal, 0, sizeof (struct MHD_Response)); - retVal->data = malloc (MHD_BUF_INC_SIZE); - if (retVal->data == NULL) - { - free (retVal); - return NULL; - } + retVal->data = (void*) &retVal[1]; retVal->data_buffer_size = MHD_BUF_INC_SIZE; if (pthread_mutex_init (&retVal->mutex, NULL) != 0) { - free (retVal->data); free (retVal); return NULL; } @@ -262,8 +265,6 @@ MHD_destroy_response (struct MHD_Response *response) free (pos->value); free (pos); } - if (response->crc != NULL) - free (response->data); free (response); } diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index eb96e807..76c1be0b 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h @@ -62,7 +62,7 @@ extern "C" /** * Current version of the library. */ -#define MHD_VERSION 0x00000000 +#define MHD_VERSION 0x00000003 /** * MHD-internal return codes. @@ -279,6 +279,13 @@ enum MHD_OPTION */ MHD_OPTION_CONNECTION_LIMIT = 2, + /** + * After how many seconds of inactivity should a + * connection automatically be timed out? (followed + * by an unsigned int; use zero for no timeout). + */ + MHD_OPTION_CONNECTION_TIMEOUT = 3, + }; /** @@ -560,12 +567,18 @@ MHD_queue_response (struct MHD_Connection *connection, * header information and then be used any number of times. * * @param size size of the data portion of the response, -1 for unknown + * @param block_size preferred block size for querying crc (advisory only, + * MHD may still call crc using smaller chunks); this + * is essentially the buffer size used for IO, clients + * should pick a value that is appropriate for IO and + * memory performance requirements * @param crc callback to use to obtain response data * @param crc_cls extra argument to crc * @param crfc callback to call to free crc_cls resources * @return NULL on error (i.e. invalid arguments, out of memory) */ struct MHD_Response *MHD_create_response_from_callback (size_t size, + unsigned int block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback |