libmicrohttpd

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

commit b8d6c063fe9e425e08652f74cb617514e6a8440d
parent 6e07994a8bfa4227444ad5b178b4a54cb4ec69da
Author: Andrey Uzunov <andrey.uzunov@gmail.com>
Date:   Fri,  5 Jul 2013 14:04:26 +0000

spdy: TLS functions are called via callbacks now

Diffstat:
Msrc/microspdy/Makefile.am | 3++-
Msrc/microspdy/daemon.c | 18++++++++++--------
Asrc/microspdy/io.h | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microspdy/session.c | 27+++++++++++++++++----------
Msrc/microspdy/structures.h | 44++++++++++++++++++++++++++++++++++++++++----
Msrc/microspdy/tls.c | 52++++++++++++++++++++++++++--------------------------
Msrc/microspdy/tls.h | 4++--
7 files changed, 259 insertions(+), 51 deletions(-)

diff --git a/src/microspdy/Makefile.am b/src/microspdy/Makefile.am @@ -5,7 +5,7 @@ endif AM_CPPFLAGS = \ $(PLIBC_INCLUDE) \ -I$(top_srcdir)/src/include \ - -I$(top_srcdir)/src/microspdy + -I$(top_srcdir)/src/microspdy EXTRA_DIST = EXPORT.sym @@ -15,6 +15,7 @@ lib_LTLIBRARIES = \ libmicrospdy.la libmicrospdy_la_SOURCES = \ + io.h \ tls.h tls.c \ structures.h structures.c \ internal.h internal.c \ diff --git a/src/microspdy/daemon.c b/src/microspdy/daemon.c @@ -191,6 +191,8 @@ SPDYF_start_daemon_va (uint16_t port, memset (daemon, 0, sizeof (struct SPDY_Daemon)); daemon->socket_fd = -1; daemon->port = port; + daemon->fio_init = &SPDYF_tls_init; + daemon->fio_deinit = &SPDYF_tls_deinit; if (NULL == (daemon->certfile = strdup (certfile))) { SPDYF_DEBUG("str"); @@ -229,7 +231,9 @@ SPDYF_start_daemon_va (uint16_t port, SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but IPv4 address provided"); goto free_and_fail; } - + + addrlen = sizeof (struct sockaddr_in6); + if(NULL == daemon->address) { if (NULL == (servaddr6 = malloc (addrlen))) @@ -247,12 +251,10 @@ SPDYF_start_daemon_va (uint16_t port, if(AF_INET6 == daemon->address->sa_family) { afamily = PF_INET6; - addrlen = sizeof (struct sockaddr_in6); } else { afamily = PF_INET; - addrlen = sizeof (struct sockaddr_in); } #else //handling IPv4 @@ -319,7 +321,7 @@ SPDYF_start_daemon_va (uint16_t port, goto free_and_fail; } - if(SPDY_YES != SPDYF_tls_init(daemon)) + if(SPDY_YES != daemon->fio_init(daemon)) { SPDYF_DEBUG("tls"); goto free_and_fail; @@ -349,7 +351,7 @@ SPDYF_start_daemon_va (uint16_t port, void SPDYF_stop_daemon (struct SPDY_Daemon *daemon) { - SPDYF_tls_deinit(daemon); + daemon->fio_deinit(daemon); shutdown (daemon->socket_fd, SHUT_RDWR); spdyf_close_all_sessions (daemon); @@ -387,7 +389,7 @@ SPDYF_get_timeout (struct SPDY_Daemon *daemon, have_timeout = true; - if (SPDY_YES == SPDYF_tls_is_pending(pos)) + if (SPDY_YES == pos->fio_is_pending(pos)) { earliest_deadline = 0; break; @@ -436,7 +438,7 @@ SPDYF_get_fdset (struct SPDY_Daemon *daemon, || (SPDY_SESSION_STATUS_CLOSING == pos->status) //the session is about to be closed || (daemon->session_timeout //timeout passed for the session && (pos->last_activity + daemon->session_timeout < SPDYF_monotonic_time())) - || (SPDY_YES == SPDYF_tls_is_pending(pos)) //data in TLS' read buffer pending + || (SPDY_YES == pos->fio_is_pending(pos)) //data in TLS' read buffer pending || ((pos->read_buffer_offset - pos->read_buffer_beginning) > 0) // data in lib's read buffer pending ) FD_SET(fd, write_fd_set); @@ -487,7 +489,7 @@ SPDYF_run (struct SPDY_Daemon *daemon) if (ds != -1) { //fill the read buffer - if (FD_ISSET (ds, &rs) || SPDYF_tls_is_pending(pos)){ + if (FD_ISSET (ds, &rs) || pos->fio_is_pending(pos)){ SPDYF_session_read(pos); } diff --git a/src/microspdy/io.h b/src/microspdy/io.h @@ -0,0 +1,162 @@ +/* + This file is part of libmicrospdy + Copyright (C) 2013 Andrey Uzunov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file io.h + * @brief Signatures for IO functions. + * @author Andrey Uzunov + */ + +#ifndef IO_H +#define IO_H + +#include "platform.h" + + +/** + * Used for return code when reading and writing to the TLS socket. + */ +enum SPDY_IO_ERROR +{ + /** + * The connection was closed by the other party. + */ + SPDY_IO_ERROR_CLOSED = 0, + + /** + * Any kind of error ocurred. The session has to be closed. + */ + SPDY_IO_ERROR_ERROR = -2, + + /** + * The function had to return without processing any data. The whole + * cycle of events has to be called again (SPDY_run) as something + * either has to be written or read or the the syscall was + * interrupted by a signal. + */ + SPDY_IO_ERROR_AGAIN = -3, +}; + + +/** + * Global initializing. Must be called only once in the program. + * + */ +typedef void +(*SPDYF_IOGlobalInit) (); + + +/** + * Global deinitializing for the whole program. Should be called + * at the end of the program. + * + */ +typedef void +(*SPDYF_IOGlobalDeinit) (); + + +/** + * Initializing of io context for a specific daemon. + * Must be called when the daemon starts. + * + * @param daemon SPDY_Daemon for which io will be used. Daemon's + * certificate and key file are used for tls. + * @return SPDY_YES on success or SPDY_NO on error + */ +typedef int +(*SPDYF_IOInit) (struct SPDY_Daemon *daemon); + + +/** + * Deinitializing io context for a daemon. Should be called + * when the deamon is stopped. + * + * @param daemon SPDY_Daemon which is being stopped + */ +typedef void +(*SPDYF_IODeinit) (struct SPDY_Daemon *daemon); + + +/** + * Initializing io for a specific connection. Must be called + * after the connection has been accepted. + * + * @param session SPDY_Session whose socket will be used + * @return SPDY_NO if some funcs inside fail. SPDY_YES otherwise + */ +typedef int +(*SPDYF_IONewSession) (struct SPDY_Session *session); + + +/** + * Deinitializing io for a specific connection. Should be called + * closing session's socket. + * + * @param session SPDY_Session whose socket is used + */ +typedef void +(*SPDYF_IOCloseSession) (struct SPDY_Session *session); + + +/** + * Reading from session's socket. Reads available data and put it to the + * buffer. + * + * @param session for which data is received + * @param buffer where data from the socket will be written to + * @param size of the buffer + * @return number of bytes (at most size) read from the connection + * 0 if the other party has closed the connection + * SPDY_IO_ERROR code on error + */ +typedef int +(*SPDYF_IORecv) (struct SPDY_Session *session, + void * buffer, + size_t size); + + +/** + * Writing to session's socket. Writes the data given into the buffer to the + * socket. + * + * @param session whose context is used + * @param buffer from where data will be written to the socket + * @param size number of bytes to be taken from the buffer + * @return number of bytes (at most size) from the buffer that has been + * written to the connection + * 0 if the other party has closed the connection + * SPDY_IO_ERROR code on error + */ +typedef int +(*SPDYF_IOSend) (struct SPDY_Session *session, + const void * buffer, + size_t size); + + +/** + * Checks if there is data staying in the buffers of the underlying + * system that waits to be read. In case of TLS, this will call + * something like SSL_pending(). + * + * @param session which is checked + * @return SPDY_YES if data is pending or SPDY_NO otherwise + */ +typedef int +(*SPDYF_IOIsPending) (struct SPDY_Session *session); + +#endif diff --git a/src/microspdy/session.c b/src/microspdy/session.c @@ -30,7 +30,7 @@ #include "compression.h" #include "tls.h" #include "stream.h" - + /** * Handler for reading the full SYN_STREAM frame after we know that @@ -820,7 +820,7 @@ SPDYF_session_read (struct SPDY_Session *session) session->last_activity = SPDYF_monotonic_time(); //actual read from the TLS socket - bytes_read = SPDYF_tls_recv(session, + bytes_read = session->fio_recv(session, session->read_buffer + session->read_buffer_offset, session->read_buffer_size - session->read_buffer_offset); @@ -952,7 +952,7 @@ SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame) session->last_activity = SPDYF_monotonic_time(); //actual write to the TLS socket - bytes_written = SPDYF_tls_send(session, + bytes_written = session->fio_send(session, session->write_buffer + session->write_buffer_beginning, session->write_buffer_offset - session->write_buffer_beginning); @@ -1016,11 +1016,12 @@ SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame) SPDYF_response_queue_destroy(queue_head); } } - + if(SPDY_SESSION_STATUS_FLUSHING == session->status && NULL == session->response_queue_head) session->status = SPDY_SESSION_STATUS_CLOSING; + return i>0 ? SPDY_YES : SPDY_NO; } @@ -1237,7 +1238,7 @@ SPDYF_session_close (struct SPDY_Session *session) int by_client = session->read_closed ? SPDY_YES : SPDY_NO; //shutdown the tls and deinit the tls context - SPDYF_tls_close_session(session); + session->fio_close_session(session); shutdown (session->socket_fd, session->read_closed ? SHUT_WR : SHUT_RDWR); session->read_closed = true; @@ -1304,9 +1305,15 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon) session->daemon = daemon; session->socket_fd = new_socket_fd; + + session->fio_new_session = &SPDYF_tls_new_session; + session->fio_close_session = &SPDYF_tls_close_session; + session->fio_is_pending = &SPDYF_tls_is_pending; + session->fio_recv = &SPDYF_tls_recv; + session->fio_send = &SPDYF_tls_send; //init TLS context, handshake will be done - if(SPDY_YES != SPDYF_tls_new_session(session)) + if(SPDY_YES != session->fio_new_session(session)) { goto free_and_fail; } @@ -1315,14 +1322,14 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon) session->read_buffer_size = SPDYF_BUFFER_SIZE; if (NULL == (session->read_buffer = malloc (session->read_buffer_size))) { - SPDYF_tls_close_session(session); + session->fio_close_session(session); goto free_and_fail; } //address of the client if (NULL == (session->addr = malloc (addr_len))) { - SPDYF_tls_close_session(session); + session->fio_close_session(session); goto free_and_fail; } memcpy (session->addr, addr, addr_len); @@ -1333,12 +1340,12 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon) //init zlib context for the whole session if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream)) { - SPDYF_tls_close_session(session); + session->fio_close_session(session); goto free_and_fail; } if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream)) { - SPDYF_tls_close_session(session); + session->fio_close_session(session); SPDYF_zlib_deflate_end(&session->zlib_send_stream); goto free_and_fail; } diff --git a/src/microspdy/structures.h b/src/microspdy/structures.h @@ -29,6 +29,7 @@ #include "platform.h" #include "microspdy.h" #include "tls.h" +#include "io.h" /** @@ -617,10 +618,10 @@ struct SPDY_Session struct SPDYF_Stream *streams_tail; /** - * Unique TLS context for the session. Initialized on each creation + * Unique IO context for the session. Initialized on each creation * (actually when the TCP connection is established). */ - SPDYF_TLS_SESSION_CONTEXT *tls_context; + void *io_context; /** * Head of doubly-linked list of the responses. @@ -659,6 +660,31 @@ struct SPDY_Session void *user_cls; /** + * Function to initialize the IO context for a new session. + */ + SPDYF_IONewSession fio_new_session; + + /** + * Function to deinitialize the IO context for a session. + */ + SPDYF_IOCloseSession fio_close_session; + + /** + * Function to read data from socket. + */ + SPDYF_IORecv fio_recv; + + /** + * Function to write data to socket. + */ + SPDYF_IOSend fio_send; + + /** + * Function to check for pending data in IO buffers. + */ + SPDYF_IOIsPending fio_is_pending; + + /** * Number of bytes that the lib must ignore immediately after they * are read from the TLS socket without adding them to the read buf. * This is needed, for instance, when receiving frame bigger than @@ -805,9 +831,9 @@ struct SPDY_Daemon struct SPDY_Session *cleanup_tail; /** - * Unique TLS context for the daemon. Initialized on daemon start. + * Unique IO context for the daemon. Initialized on daemon start. */ - SPDYF_TLS_DAEMON_CONTEXT *tls_context; + void *io_context; /** * Certificate file of the server. File path is kept here. @@ -864,6 +890,16 @@ struct SPDY_Daemon void *fcls; /** + * Function to initialize the IO context for the daemon. + */ + SPDYF_IOInit fio_init; + + /** + * Function to deinitialize the IO context for the daemon. + */ + SPDYF_IODeinit fio_deinit; + + /** * After how many seconds of inactivity should * connections time out? Zero for no timeout. */ diff --git a/src/microspdy/tls.c b/src/microspdy/tls.c @@ -78,37 +78,37 @@ int SPDYF_tls_init(struct SPDY_Daemon *daemon) { //create ssl context. TLSv1 used - if(NULL == (daemon->tls_context = SSL_CTX_new(TLSv1_server_method()))) + if(NULL == (daemon->io_context = SSL_CTX_new(TLSv1_server_method()))) { SPDYF_DEBUG("Couldn't create ssl context"); return SPDY_NO; } //set options for tls //TODO DH is not enabled for easier debugging - //SSL_CTX_set_options(daemon->tls_context, SSL_OP_SINGLE_DH_USE); + //SSL_CTX_set_options(daemon->io_context, SSL_OP_SINGLE_DH_USE); //TODO here session tickets are disabled for easier debuging with //wireshark when using Chrome //SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack - SSL_CTX_set_options(daemon->tls_context, SSL_OP_NO_TICKET | SSL_OP_NO_COMPRESSION); - if(1 != SSL_CTX_use_certificate_file(daemon->tls_context, daemon->certfile , SSL_FILETYPE_PEM)) + SSL_CTX_set_options(daemon->io_context, SSL_OP_NO_TICKET | SSL_OP_NO_COMPRESSION); + if(1 != SSL_CTX_use_certificate_file(daemon->io_context, daemon->certfile , SSL_FILETYPE_PEM)) { SPDYF_DEBUG("Couldn't load the cert file"); - SSL_CTX_free(daemon->tls_context); + SSL_CTX_free(daemon->io_context); return SPDY_NO; } - if(1 != SSL_CTX_use_PrivateKey_file(daemon->tls_context, daemon->keyfile, SSL_FILETYPE_PEM)) + if(1 != SSL_CTX_use_PrivateKey_file(daemon->io_context, daemon->keyfile, SSL_FILETYPE_PEM)) { SPDYF_DEBUG("Couldn't load the name file"); - SSL_CTX_free(daemon->tls_context); + SSL_CTX_free(daemon->io_context); return SPDY_NO; } - SSL_CTX_set_next_protos_advertised_cb(daemon->tls_context, &spdyf_next_protos_advertised_cb, NULL); + SSL_CTX_set_next_protos_advertised_cb(daemon->io_context, &spdyf_next_protos_advertised_cb, NULL); //TODO only RC4-SHA is used to make it easy to debug with wireshark - if (1 != SSL_CTX_set_cipher_list(daemon->tls_context, "RC4-SHA")) + if (1 != SSL_CTX_set_cipher_list(daemon->io_context, "RC4-SHA")) { SPDYF_DEBUG("Couldn't set the desired cipher list"); - SSL_CTX_free(daemon->tls_context); + SSL_CTX_free(daemon->io_context); return SPDY_NO; } @@ -119,7 +119,7 @@ SPDYF_tls_init(struct SPDY_Daemon *daemon) void SPDYF_tls_deinit(struct SPDY_Daemon *daemon) { - SSL_CTX_free(daemon->tls_context); + SSL_CTX_free(daemon->io_context); } @@ -128,30 +128,30 @@ SPDYF_tls_new_session(struct SPDY_Session *session) { int ret; - if(NULL == (session->tls_context = SSL_new(session->daemon->tls_context))) + if(NULL == (session->io_context = SSL_new(session->daemon->io_context))) { SPDYF_DEBUG("Couldn't create ssl structure"); return SPDY_NO; } - if(1 != (ret = SSL_set_fd(session->tls_context, session->socket_fd))) + if(1 != (ret = SSL_set_fd(session->io_context, session->socket_fd))) { SPDYF_DEBUG("SSL_set_fd %i",ret); - SSL_free(session->tls_context); - session->tls_context = NULL; + SSL_free(session->io_context); + session->io_context = NULL; return SPDY_NO; } //for non-blocking I/O SSL_accept may return -1 //and this function won't work - if(1 != (ret = SSL_accept(session->tls_context))) + if(1 != (ret = SSL_accept(session->io_context))) { SPDYF_DEBUG("SSL_accept %i",ret); - SSL_free(session->tls_context); - session->tls_context = NULL; + SSL_free(session->io_context); + session->io_context = NULL; return SPDY_NO; } /* alternatively - SSL_set_accept_state(session->tls_context); + SSL_set_accept_state(session->io_context); * may be called and then the negotiation will be done on reading */ @@ -167,9 +167,9 @@ SPDYF_tls_close_session(struct SPDY_Session *session) //the TLS session. The lib just sends it and will close the socket //after that because the browsers don't seem to care much about //"close notify" - SSL_shutdown(session->tls_context); + SSL_shutdown(session->io_context); - SSL_free(session->tls_context); + SSL_free(session->io_context); } @@ -179,13 +179,13 @@ SPDYF_tls_recv(struct SPDY_Session *session, size_t size) { int ret; - int n = SSL_read(session->tls_context, + int n = SSL_read(session->io_context, buffer, size); //if(n > 0) SPDYF_DEBUG("recvd: %i",n); if (n <= 0) { - ret = SSL_get_error(session->tls_context, n); + ret = SSL_get_error(session->io_context, n); switch(ret) { case SSL_ERROR_ZERO_RETURN: @@ -215,13 +215,13 @@ SPDYF_tls_send(struct SPDY_Session *session, { int ret; - int n = SSL_write(session->tls_context, + int n = SSL_write(session->io_context, buffer, size); //if(n > 0) SPDYF_DEBUG("sent: %i",n); if (n <= 0) { - ret = SSL_get_error(session->tls_context, n); + ret = SSL_get_error(session->io_context, n); switch(ret) { case SSL_ERROR_ZERO_RETURN: @@ -251,5 +251,5 @@ SPDYF_tls_is_pending(struct SPDY_Session *session) * BUGS SSL_pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). If the SSL object's read_ahead flag is set, additional protocol bytes may have been read containing more TLS/SSL records; these are ignored by SSL_pending(). */ - return SSL_pending(session->tls_context) > 0 ? SPDY_YES : SPDY_NO; + return SSL_pending(session->io_context) > 0 ? SPDY_YES : SPDY_NO; } diff --git a/src/microspdy/tls.h b/src/microspdy/tls.h @@ -34,8 +34,8 @@ /* macros used in other files instead of types. * useful in case of changing openssl to something else */ -#define SPDYF_TLS_SESSION_CONTEXT SSL -#define SPDYF_TLS_DAEMON_CONTEXT SSL_CTX +//#define SPDYF_TLS_SESSION_CONTEXT SSL +//#define SPDYF_TLS_DAEMON_CONTEXT SSL_CTX /**