libmicrohttpd

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

commit 5e64daa0305d86f25983572e4666099968999a6e
parent a0339d2458867dbe9485499265641ff205063445
Author: lv-426 <oxcafebaby@yahoo.com>
Date:   Sun, 22 Jun 2008 18:46:25 +0000

- added read, write & idle connection callback functions to enable HTTPS specifice connection handling
- some include issues

Diffstat:
Msrc/daemon/connection.c | 195++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/daemon/connection.h | 16+++++++++-------
Msrc/daemon/daemon.c | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/daemon/internal.h | 42+++++++++++++++++++++++++++++++-----------
4 files changed, 258 insertions(+), 83 deletions(-)

diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -31,13 +31,20 @@ #include "response.h" #include "reason_phrase.h" +// get opaque type +#include "gnutls_int.h" +// TODO clean +#undef MAX +#define MAX(a,b) ((a)<(b)) ? (b) : (a) +#undef MIN +#define MIN(a,b) ((a)<(b)) ? (a) : (b) + #ifndef LINUX #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #endif - /** * Message to transmit when http 1.1 request is received */ @@ -1207,7 +1214,7 @@ do_read (struct MHD_Connection *connection) } int -http_con_read (struct MHD_Connection *connection) +MHD_con_read (struct MHD_Connection *connection) { return RECV (connection->socket_fd, &connection->read_buffer[connection->read_buffer_offset], @@ -1216,15 +1223,14 @@ http_con_read (struct MHD_Connection *connection) } #if HTTPS_SUPPORT -int -https_con_read (struct MHD_Connection *connection) +ssize_t +MHDS_con_read (struct MHD_Connection * connection) { - return gnutls_record_recv (connection->tls_session, - &connection->write_buffer[connection-> - write_buffer_send_offset], - connection->write_buffer_append_offset - - connection->write_buffer_send_offset); - + ssize_t size = gnutls_record_recv (connection->tls_session, + connection->read_buffer[connection-> + read_buffer_offset], + connection->read_buffer_size); + return size; } #endif @@ -1457,41 +1463,62 @@ MHD_connection_handle_read (struct MHD_Connection *connection) return MHD_YES; } -// TODO rm +#if HTTPS_SUPPORT int -attemptLoopBackConnection (struct MHD_Connection *connection, int port) +MHDS_connection_handle_read (struct MHD_Connection *connection) { - /* loopback HTTP socket */ - int *loopback_sd; - int err; - struct sockaddr_in servaddr4; - const struct sockaddr *servaddr; - struct sockaddr_in loopback_sa; - socklen_t addrlen; + connection->last_activity = time (NULL); - /* initialize loopback socket */ - loopback_sd = socket (AF_LOCAL, SOCK_STREAM, 0); + if (connection->s_state == MHDS_CONNECTION_CLOSED) + return MHD_NO; + + if (MHD_NO == do_read (connection)) + return MHD_YES; - memset (&loopback_sa, '\0', sizeof (loopback_sa)); + while (1) + { + switch (connection->s_state) + { + case MHDS_CONNECTION_INIT: + case MHDS_HANDSHAKE_COMPLETE: + case MHDS_REQUEST_READ: + if (MHD_YES == connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + case MHDS_REQUEST_READING: + do_read (connection); + break; - loopback_sa.sin_family = AF_LOCAL; + /* thest cases shouldn't occur */ + case MHDS_REPLY_READY: + case MHDS_REPLY_SENDING: + case MHDS_HANDSHAKE_FAILED: +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "MHDS reached case: %d\n", + connection->s_state); +#endif + return MHD_NO; - // TODO solve magic number issue - the http's daemons port must be shared with the https daemon - rosolve data sharing point - loopback_sa.sin_port = htons (port); - inet_pton (AF_LOCAL, "127.0.0.1", &loopback_sa.sin_addr); + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + return MHD_NO; - /* connect loopback socket */ - err = connect (loopback_sd, (struct sockaddr *) &loopback_sa, - sizeof (loopback_sa)); - if (err < 0) - { - // TODO err handle - fprintf (stderr, "Error : failed to create TLS loopback socket\n"); - return MHD_NO; + default: + /* shrink read buffer to how much is actually used */ + MHD_pool_reallocate (connection->pool, connection->read_buffer, + connection->read_buffer_size + 1, + connection->read_buffer_offset); + break; + } + break; } - return loopback_sd; - + return MHD_YES; } +#endif /** * Try writing data to the socket from the @@ -1504,7 +1531,7 @@ static int do_write (struct MHD_Connection *connection) { int ret; - + ret = connection->send_cls (connection); if (ret < 0) @@ -1529,7 +1556,7 @@ do_write (struct MHD_Connection *connection) } int -http_con_write (struct MHD_Connection *connection) +MHD_con_write (struct MHD_Connection *connection) { return SEND (connection->socket_fd, &connection->write_buffer[connection-> @@ -1539,8 +1566,8 @@ http_con_write (struct MHD_Connection *connection) } #if HTTPS_SUPPORT -int -https_con_write (struct MHD_Connection *connection) +ssize_t +MHDS_con_write (struct MHD_Connection * connection) { return gnutls_record_send (connection->tls_session, &connection->write_buffer[connection-> @@ -1566,8 +1593,7 @@ check_write_done (struct MHD_Connection *connection, connection->write_buffer_append_offset = 0; connection->write_buffer_send_offset = 0; connection->state = next_state; - MHD_pool_reallocate (connection->pool, - connection->write_buffer, + MHD_pool_reallocate (connection->pool, connection->write_buffer, connection->write_buffer_size, 0); connection->write_buffer = NULL; connection->write_buffer_size = 0; @@ -1722,6 +1748,36 @@ MHD_connection_handle_write (struct MHD_Connection *connection) return MHD_YES; } +#if HTTPS_SUPPORT +int +MHDS_connection_handle_write (struct MHD_Connection *connection) +{ + while (1) + { + switch (connection->s_state) + { + + case MHDS_CONNECTION_INIT: + case MHDS_HANDSHAKE_FAILED: + case MHDS_HANDSHAKE_COMPLETE: + abort (); + break; + + case MHDS_CONNECTION_CLOSED: + do_write (connection); + break; + + case MHDS_REPLY_READY: + return MHD_connection_handle_idle (connection); + + break; + + } + } + return MHD_YES; +} +#endif + /** * This function was created to handle per-connection processing that * has to happen even if the socket cannot be read or written to. All @@ -2051,4 +2107,59 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } +int +MHDS_connection_handle_idle (struct MHD_Connection *connection) +{ + unsigned int timeout; + const char *end; + char *line; + + while (1) + { +#if DEBUG_STATES + fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state); +#endif + switch (connection->s_state) + { + case MHDS_CONNECTION_INIT: + break; + case MHDS_REQUEST_READ: + /* pipe data to HTTP state machine */ + + memcpy (connection->tls_session->internals.application_data_buffer. + data, connection->read_buffer, + connection->tls_session->internals.application_data_buffer. + length); + break; + + case MHDS_REPLY_READY: + /* send data for encryption */ + memcpy (connection->write_buffer, + connection->tls_session->internals.application_data_buffer. + data, connection->write_buffer_size); + break; + + case MHDS_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + break; + + default: + EXTRA_CHECK (0); + break; + } + break; + } + + timeout = connection->daemon->connection_timeout; + + if ((connection->socket_fd != -1) && (timeout != 0) + && (time (NULL) - timeout > connection->last_activity)) + { + connection_close_error (connection); + return MHD_NO; + } + return MHD_YES; +} + /* end of connection.c */ diff --git a/src/daemon/connection.h b/src/daemon/connection.h @@ -74,13 +74,15 @@ int MHD_connection_handle_write (struct MHD_Connection *connection); */ int MHD_connection_handle_idle (struct MHD_Connection *connection); -int http_con_read(struct MHD_Connection *connection); -int http_con_write(struct MHD_Connection *connection); +int MHD_con_read(struct MHD_Connection *connection); +int MHD_con_write(struct MHD_Connection *connection); -// TODO rm static -#if HTTPS_SUPPORT -int https_con_read(struct MHD_Connection *connection); -int https_con_write(struct MHD_Connection *connection); -#endif +#ifdef HTTPS_SUPPORT +int MHDS_connection_handle_read(struct MHD_Connection *connection); +int MHDS_connection_handle_write(struct MHD_Connection *connection); +int MHDS_connection_handle_idle(struct MHD_Connection *connection); +ssize_t MHDS_con_read(struct MHD_Connection *connection); +ssize_t MHDS_con_write(struct MHD_Connection *connection); +#endif #endif diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -24,12 +24,13 @@ * @author Daniel Pittman * @author Christian Grothoff */ - #include "internal.h" #include "response.h" #include "connection.h" #include "memorypool.h" -#include <gnutls/gnutls.h> +#include "gnutls.h" + +// TODO rm #include <unistd.h> /** * Default connection limit. @@ -149,12 +150,13 @@ MHD_handle_connection (void *data) #endif break; } + /* call appropriate connection handler if necessary */ if (FD_ISSET (con->socket_fd, &rs)) - MHD_connection_handle_read (con); + con->read_handler (con); if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) - MHD_connection_handle_write (con); + con->write_handler (con); if (con->socket_fd != -1) - MHD_connection_handle_idle (con); + con->idle_handler (con); } if (con->socket_fd != -1) { @@ -171,11 +173,29 @@ MHD_handle_connection (void *data) return NULL; } -/* gnutls parameter adapter */ +/* TODO rm if unused - gnutls parameter adapter , used to set gnutls pull function */ long -gnutls_pull_param_adapter (void *con, void *other, int i) +gnutls_pull_param_adapter (void *connection, void *other, unsigned long i) { - return MHD_handle_connection (con); + ssize_t bytes; + bytes = ((struct MHD_Connection *) connection)->read_buffer_offset; + MHD_handle_connection (connection); + bytes = ((struct MHD_Connection *) connection)->read_buffer_offset - bytes; + return bytes; + +} + +long +gnutls_push_param_adapter (void *connection, + const void *other, unsigned long i) +{ + ssize_t bytes; + bytes = ((struct MHD_Connection *) connection)->write_buffer_send_offset; + MHD_handle_connection (connection); + bytes = ((struct MHD_Connection *) connection)->write_buffer_send_offset + - bytes; + return bytes; + } /** @@ -184,30 +204,32 @@ gnutls_pull_param_adapter (void *con, void *other, int i) static void * MHDS_handle_connection (void *data) { - // TODO check compatibility with socket_fd - gnutls_session_t session; + gnutls_session_t tls_session; struct MHD_Connection *con = data; int ret; if (con == NULL) abort (); - con->tls_session = &session; + gnutls_init (&tls_session, GNUTLS_SERVER); - gnutls_init (&session, GNUTLS_SERVER); + con->tls_session = tls_session; /* sets cipher priorities */ - gnutls_priority_set (session, con->daemon->priority_cache); + gnutls_priority_set (tls_session, con->daemon->priority_cache); /* set needed credentials for certificate authentication. */ - gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, + gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, con->daemon->x509_cret); - gnutls_transport_set_pull_function (session, &gnutls_pull_param_adapter); + /* avoid gnutls blocking recv / write calls */ + // gnutls_transport_set_pull_function(tls_session, &recv); + // gnutls_transport_set_push_function(tls_session, &send); + + gnutls_transport_set_ptr (tls_session, con->socket_fd); - gnutls_transport_set_ptr (session, con); + ret = gnutls_handshake (tls_session); - ret = gnutls_handshake (session); if (ret == 0) { con->state = MHDS_HANDSHAKE_COMPLETE; @@ -217,10 +239,11 @@ MHDS_handle_connection (void *data) /* set connection as closed */ fprintf (stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror (ret)); - gnutls_deinit (session); + gnutls_deinit (tls_session); con->state = MHDS_HANDSHAKE_FAILED; con->socket_fd = 1; return MHD_NO; + } // printf ("TLS Handshake completed\n"); @@ -366,14 +389,21 @@ MHD_accept_connection (struct MHD_Daemon *daemon) connection->daemon = daemon; /* set default connection handlers */ - connection->recv_cls = &http_con_read; - connection->send_cls = &http_con_write; + connection->recv_cls = &MHD_con_read; + connection->send_cls = &MHD_con_write; + connection->read_handler = &MHD_connection_handle_read; + connection->write_handler = &MHD_connection_handle_write; + connection->idle_handler = &MHD_connection_handle_idle; #if HTTPS_SUPPORT if (daemon->options & MHD_USE_SSL) { - connection->recv_cls = &https_con_read; - connection->send_cls = &https_con_write; + /* set HTTPS connection handlers */ + connection->recv_cls = &MHDS_con_read; + connection->send_cls = &MHDS_con_write; + connection->read_handler = &MHDS_connection_handle_read; + connection->write_handler = &MHDS_connection_handle_write; + connection->idle_handler = &MHDS_connection_handle_idle; } #endif @@ -760,7 +790,6 @@ MHD_start_daemon (unsigned int options, /* initializes the argument pointer variable */ va_start (ap, dh_cls); - /* * loop through daemon options */ @@ -911,11 +940,24 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) free (daemon); } +// TODO rm +static void +tls_log_func (int level, const char *str) +{ + fprintf (stdout, "|<%d>| %s", level, str); +} + int MHDS_init (struct MHD_Daemon *daemon) { + // TODO rm + gnutls_global_set_log_level (11); + gnutls_global_set_log_function (tls_log_func); + gnutls_global_init (); + /* Generate Diffie Hellman parameters - for use with DHE kx algorithms. */ + // TODO should we be initializing RSA params or DH params ? gnutls_dh_params_init (&daemon->dh_params); gnutls_dh_params_generate2 (daemon->dh_params, DH_BITS); diff --git a/src/daemon/internal.h b/src/daemon/internal.h @@ -35,7 +35,7 @@ #include <errno.h> #include <fcntl.h> #include <signal.h> -#include <gnutls/gnutls.h> +#include "gnutls.h" #include "config.h" #include "plibc.h" @@ -49,6 +49,7 @@ #include <pthread.h> +// TODO unify with other dec #define MAX(a,b) ((a)<(b)) ? (b) : (a) #define MIN(a,b) ((a)<(b)) ? (a) : (b) @@ -289,15 +290,25 @@ enum MHD_CONNECTION_STATE enum MHDS_CONNECTION_STATE { + /* initial HTTPS state */ MHDS_CONNECTION_INIT = 0, - /** - * 1: We got the URL (and request type and version). Wait for a header line. - */ MHDS_HANDSHAKE_FAILED, - + MHDS_HANDSHAKE_COMPLETE, + /* while receiving an HTTP request through the encrypted channel */ + MHDS_REQUEST_READING, + + /* msg waiting to be forwarded to the internal HTTP daemon */ + MHDS_REQUEST_READ, + + /* http msg waiting to be sent */ + MHDS_REPLY_READY, + + /* while receiving an HTTP request through the encrypted channel */ + MHDS_REPLY_SENDING, + MHDS_CONNECTION_CLOSED }; @@ -484,6 +495,8 @@ struct MHD_Connection */ enum MHD_CONNECTION_STATE state; + enum MHDS_CONNECTION_STATE s_state; + /** * HTTP response code. Only valid if response object * is already set. @@ -527,18 +540,25 @@ struct MHD_Connection */ unsigned int current_chunk_offset; + /* handlers used for processing read, write & idle connection operations */ + int (*read_handler) (struct MHD_Connection * connection); + + int (*write_handler) (struct MHD_Connection * connection); + + int (*idle_handler) (struct MHD_Connection * connection); + /* * function pointers to the appropriate send & receive funtions * according to whether this is a HTTPS / HTTP daemon */ - int (* recv_cls) (struct MHD_Connection *connection); - - int (* send_cls) (struct MHD_Connection *connection); - + int (*recv_cls) (struct MHD_Connection * connection); + + int (*send_cls) (struct MHD_Connection * connection); + #if HTTPS_SUPPORT - gnutls_session_t * tls_session; + gnutls_session_t tls_session; #endif - + }; typedef struct MHD_Connection MHD_Connection_t;