libmicrohttpd

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

commit f7ae5a3412f828cb9a7622f21b28b584b65adc32
parent 45a0a30893f77a38a8add8a64c3650387840a335
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  4 Mar 2011 09:33:32 +0000

adding API to handle #1661 (allow externally created connections)

Diffstat:
MChangeLog | 6++++++
Mconfigure.ac | 4++--
Mdoc/microhttpd-tutorial.texi | 4++--
Mdoc/microhttpd.texi | 32+++++++++++++++++++++++++++++++-
Msrc/daemon/daemon.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/include/microhttpd.h | 29++++++++++++++++++++++++++++-
6 files changed, 163 insertions(+), 58 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,9 @@ +Fri Mar 4 10:24:04 CET 2011 + Added new API to allow MHD server to initiate connection to + client (special use-case for servers behind NAT), thereby + addressing #1661 (externally created connections). + Releasing libmicrohttpd 0.9.8. -CG + Fri Mar 4 10:07:18 CET 2011 Avoid using a pipe for signalling as well, just use server socket shutdown (also for thread-per-connection). -CG diff --git a/configure.ac b/configure.ac @@ -27,9 +27,9 @@ AM_CONFIG_HEADER([MHD_config.h]) AC_CONFIG_MACRO_DIR([m4]) AH_TOP([#define _GNU_SOURCE 1]) -LIB_VERSION_CURRENT=15 +LIB_VERSION_CURRENT=16 LIB_VERSION_REVISION=0 -LIB_VERSION_AGE=5 +LIB_VERSION_AGE=6 AC_SUBST(LIB_VERSION_CURRENT) AC_SUBST(LIB_VERSION_REVISION) AC_SUBST(LIB_VERSION_AGE) diff --git a/doc/microhttpd-tutorial.texi b/doc/microhttpd-tutorial.texi @@ -3,8 +3,8 @@ @setfilename microhttpd-tutorial.info @set UPDATED 28 Feb 2010 @set UPDATED-MONTH Feb 2010 -@set EDITION 0.9.7 -@set VERSION 0.9.7 +@set EDITION 0.9.8 +@set VERSION 0.9.8 @settitle A tutorial for GNU libmicrohttpd @dircategory GNU Libraries diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi @@ -9,7 +9,7 @@ header file @file{microhttpd.h}. @noindent -Copyright @copyright{} 2007, 2008, 2009, 2010 Christian Grothoff +Copyright @copyright{} 2007, 2008, 2009, 2010, 2011 Christian Grothoff @quotation Permission is granted to copy, distribute and/or modify this document @@ -1100,6 +1100,36 @@ started with the right options for this call. @end deftypefun +@deftypefun void MHD_add_connection (struct MHD_Daemon *daemon, int client_socket, const struct sockaddr *addr, socklen_t addrlen) +Add another client connection to the set of connections +managed by MHD. This API is usually not needed (since +MHD will accept inbound connections on the server socket). +Use this API in special cases, for example if your HTTP +server is behind NAT and needs to connect out to the +HTTP client. + +The given client socket will be managed (and closed!) by MHD after +this call and must no longer be used directly by the application +afterwards. + +@table @var +@item daemon +daemon that manages the connection +@item client_socket +socket to manage (MHD will expect to receive an HTTP request from this socket next). +@item addr +IP address of the client +@item addrlen +number of bytes in addr +@end table + +This function will return @code{MHD_YES} on success, +@code{MHD_NO} if this daemon could +not handle the connection (i.e. malloc failed, etc). +The socket will be closed in any case. +@end deftypefun + + @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @c ----------------------------------------------------------- diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -860,60 +860,52 @@ create_thread (pthread_t * thread, /** - * Accept an incoming connection and create the MHD_Connection object for - * it. This function also enforces policy by way of checking with the - * accept policy callback. - * - * @param daemon handle with the listen socket - * @return MHD_YES on success + * Add another client connection to the set of connections + * managed by MHD. This API is usually not needed (since + * MHD will accept inbound connections on the server socket). + * Use this API in special cases, for example if your HTTP + * server is behind NAT and needs to connect out to the + * HTTP client. + * + * The given client socket will be managed (and closed!) by MHD after + * this call and must no longer be used directly by the application + * afterwards. + * + * Per-IP connection limits are ignored when using this API. + * + * @param daemon daemon that manages the connection + * @param client_socket socket to manage (MHD will expect + * to receive an HTTP request from this socket next). + * @param addr IP address of the client + * @param addrlen number of bytes in addr + * @return MHD_YES on success, MHD_NO if this daemon could + * not handle the connection (i.e. malloc failed, etc). + * The socket will be closed in any case. */ -static int -MHD_accept_connection (struct MHD_Daemon *daemon) +int +MHD_add_connection (struct MHD_Daemon *daemon, + int client_socket, + const struct sockaddr *addr, + socklen_t addrlen) { struct MHD_Connection *connection; -#if HAVE_INET6 - struct sockaddr_in6 addrstorage; -#else - struct sockaddr_in addrstorage; -#endif - struct sockaddr *addr = (struct sockaddr *) &addrstorage; - socklen_t addrlen; - int s; int res_thread_create; #if OSX static int on = 1; #endif - addrlen = sizeof (addrstorage); - memset (addr, 0, sizeof (addrstorage)); - - s = ACCEPT (daemon->socket_fd, addr, &addrlen); - if ((s == -1) || (addrlen <= 0)) - { -#if HAVE_MESSAGES - /* This could be a common occurance with multiple worker threads */ - if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) - MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); -#endif - if (s != -1) - { - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); - /* just in case */ - } - return MHD_NO; - } #ifndef WINDOWS - if ( (s >= FD_SETSIZE) && + if ( (client_socket >= FD_SETSIZE) && (0 == (daemon->options & MHD_USE_POLL)) ) { #if HAVE_MESSAGES MHD_DLOG (daemon, "Socket descriptor larger than FD_SETSIZE: %d > %d\n", - s, + client_socket, FD_SETSIZE); #endif - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); return MHD_NO; } #endif @@ -932,8 +924,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) MHD_DLOG (daemon, "Server reached connection limit (closing inbound connection)\n"); #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); return MHD_NO; } @@ -946,11 +938,12 @@ MHD_accept_connection (struct MHD_Daemon *daemon) MHD_DLOG (daemon, "Connection rejected, closing connection\n"); #endif #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); MHD_ip_limit_del (daemon, addr, addrlen); return MHD_YES; } + #if OSX #ifdef SOL_SOCKET #ifdef SO_NOSIGPIPE @@ -958,14 +951,15 @@ MHD_accept_connection (struct MHD_Daemon *daemon) #endif #endif #endif + connection = malloc (sizeof (struct MHD_Connection)); if (NULL == connection) { #if HAVE_MESSAGES MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); MHD_ip_limit_del (daemon, addr, addrlen); return MHD_NO; } @@ -977,15 +971,15 @@ MHD_accept_connection (struct MHD_Daemon *daemon) #if HAVE_MESSAGES MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); MHD_ip_limit_del (daemon, addr, addrlen); free (connection); return MHD_NO; } memcpy (connection->addr, addr, addrlen); connection->addr_len = addrlen; - connection->socket_fd = s; + connection->socket_fd = client_socket; connection->daemon = daemon; connection->last_activity = time (NULL); @@ -1022,8 +1016,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) "Failed to setup TLS credentials: unknown credential type %d\n", connection->daemon->cred_type); #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); MHD_ip_limit_del (daemon, addr, addrlen); free (connection->addr); free (connection); @@ -1062,8 +1056,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) MHD_DLOG (daemon, "Failed to create a thread: %s\n", STRERROR (res_thread_create)); #endif - SHUTDOWN (s, SHUT_RDWR); - CLOSE (s); + SHUTDOWN (client_socket, SHUT_RDWR); + CLOSE (client_socket); MHD_ip_limit_del (daemon, addr, addrlen); free (connection->addr); free (connection); @@ -1073,7 +1067,55 @@ MHD_accept_connection (struct MHD_Daemon *daemon) connection->next = daemon->connections; daemon->connections = connection; daemon->max_connections--; - return MHD_YES; + return MHD_YES; +} + + +/** + * Accept an incoming connection and create the MHD_Connection object for + * it. This function also enforces policy by way of checking with the + * accept policy callback. + * + * @param daemon handle with the listen socket + * @return MHD_YES on success + */ +static int +MHD_accept_connection (struct MHD_Daemon *daemon) +{ +#if HAVE_INET6 + struct sockaddr_in6 addrstorage; +#else + struct sockaddr_in addrstorage; +#endif + struct sockaddr *addr = (struct sockaddr *) &addrstorage; + socklen_t addrlen; + int s; + + addrlen = sizeof (addrstorage); + memset (addr, 0, sizeof (addrstorage)); + s = ACCEPT (daemon->socket_fd, addr, &addrlen); + if ((s == -1) || (addrlen <= 0)) + { +#if HAVE_MESSAGES + /* This could be a common occurance with multiple worker threads */ + if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) + MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); +#endif + if (s != -1) + { + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + /* just in case */ + } + return MHD_NO; + } +#if HAVE_MESSAGES +#if DEBUG_CONNECT + MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); +#endif +#endif + return MHD_add_connection (daemon, s, + addr, addrlen); } /** diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -106,7 +106,7 @@ extern "C" /** * Current version of the library. */ -#define MHD_VERSION 0x00090703 +#define MHD_VERSION 0x00090800 /** * MHD-internal return code for "YES". @@ -1035,6 +1035,33 @@ void MHD_stop_daemon (struct MHD_Daemon *daemon); /** + * Add another client connection to the set of connections + * managed by MHD. This API is usually not needed (since + * MHD will accept inbound connections on the server socket). + * Use this API in special cases, for example if your HTTP + * server is behind NAT and needs to connect out to the + * HTTP client. + * + * The given client socket will be managed (and closed!) by MHD after + * this call and must no longer be used directly by the application + * afterwards. + * + * @param daemon daemon that manages the connection + * @param client_socket socket to manage (MHD will expect + * to receive an HTTP request from this socket next). + * @param addr IP address of the client + * @param addrlen number of bytes in addr + * @return MHD_YES on success, MHD_NO if this daemon could + * not handle the connection (i.e. malloc failed, etc). + * The socket will be closed in any case. + */ +int MHD_add_connection (struct MHD_Daemon *daemon, + int client_socket, + const struct sockaddr *addr, + socklen_t addrlen); + + +/** * Obtain the select sets for this daemon. * * @param daemon daemon to get sets from