summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-08-15 08:07:57 +0000
committerChristian Grothoff <christian@grothoff.org>2007-08-15 08:07:57 +0000
commitc9c5dfbefd0a3e219b17174fe43b51cdc0cabb67 (patch)
tree6c6cdd95bbf4e64081dc9d9eaf626408e6166de9
parent08ad843b6af71224fb6a37856b67a4dd8a25ebcc (diff)
API changes -- allow timeout, client-specified block size
-rw-r--r--ChangeLog5
-rw-r--r--configure.ac4
-rw-r--r--src/daemon/Makefile.am2
-rw-r--r--src/daemon/daemon.c53
-rw-r--r--src/daemon/daemontest_get.c13
-rw-r--r--src/daemon/daemontest_post.c12
-rw-r--r--src/daemon/daemontest_put.c12
-rw-r--r--src/daemon/fileserver_example.c1
-rw-r--r--src/daemon/internal.h14
-rw-r--r--src/daemon/response.c23
-rw-r--r--src/include/microhttpd.h15
11 files changed, 127 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 405a772c..cc6ae7b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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