libmicrohttpd

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

commit e101aeb4a9e18d506bd93afc87ea55183128f2cd
parent a104a2a46a8d3ef1787f7171295af3acc63c4912
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri, 16 Feb 2018 07:13:34 +0100

implement connection_cleanup.c

Diffstat:
Msrc/include/microhttpd_tls.h | 1+
Msrc/lib/Makefile.am | 1+
Asrc/lib/connection_cleanup.c | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/connection_cleanup.h | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/daemon_close_all_connections.c | 8+++++---
Msrc/lib/daemon_destroy.c | 1+
Msrc/lib/daemon_epoll.c | 2+-
Msrc/lib/daemon_info.c | 3++-
Msrc/lib/daemon_run.c | 7++++---
Msrc/lib/daemon_select.c | 11++++++-----
Msrc/lib/daemon_start.c | 5++++-
Msrc/microhttpd/connection_https.c | 2+-
12 files changed, 226 insertions(+), 15 deletions(-)

diff --git a/src/include/microhttpd_tls.h b/src/include/microhttpd_tls.h @@ -19,6 +19,7 @@ struct MHD_TLS_ConnectionState; + /** * Callback functions to use for TLS operations. */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -59,6 +59,7 @@ libmicrohttpd_la_SOURCES = \ action_process_upload.c \ action_suspend.c \ connection_add.c connection_add.h \ + connection_cleanup.c connection_cleanup.h \ connection_close.c connection_close.h \ connection_finish_forward.c connection_finish_forward.h \ connection_info.c \ diff --git a/src/lib/connection_cleanup.c b/src/lib/connection_cleanup.c @@ -0,0 +1,158 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file lib/connection_cleanup.c + * @brief function to clean up completed connections + * @author Christian Grothoff + */ +#include "internal.h" +#include "connection_cleanup.h" +#include "daemon_ip_limit.h" + + +#ifdef UPGRADE_SUPPORT +/** + * Finally cleanup upgrade-related resources. It should + * be called when TLS buffers have been drained and + * application signaled MHD by #MHD_UPGRADE_ACTION_CLOSE. + * + * @param connection handle to the upgraded connection to clean + */ +static void +cleanup_upgraded_connection (struct MHD_Connection *connection) +{ + struct MHD_UpgradeResponseHandle *urh = connection->request.urh; + + if (NULL == urh) + return; +#ifdef HTTPS_SUPPORT + /* Signal remote client the end of TLS connection by + * gracefully closing TLS session. */ + { + struct MHD_TLS_Plugin *tls; + + if (NULL != (tls = connection->daemon->tls_api)) + (void) tls->shutdown_connection (tls->cls, + connection->tls_cs); + } + if (MHD_INVALID_SOCKET != urh->mhd.socket) + MHD_socket_close_chk_ (urh->mhd.socket); + if (MHD_INVALID_SOCKET != urh->app.socket) + MHD_socket_close_chk_ (urh->app.socket); +#endif /* HTTPS_SUPPORT */ + connection->request.urh = NULL; + free (urh); +} +#endif /* UPGRADE_SUPPORT */ + + +/** + * Free resources associated with all closed connections. (destroy + * responses, free buffers, etc.). All closed connections are kept in + * the "cleanup" doubly-linked list. + * + * @remark To be called only from thread that process daemon's + * select()/poll()/etc. + * + * @param daemon daemon to clean up + */ +void +MHD_connection_cleanup_ (struct MHD_Daemon *daemon) +{ + struct MHD_Connection *pos; + + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + while (NULL != (pos = daemon->cleanup_tail)) + { + DLL_remove (daemon->cleanup_head, + daemon->cleanup_tail, + pos); + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + + if ( (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) && + (! pos->thread_joined) && + (! MHD_join_thread_ (pos->pid.handle)) ) + MHD_PANIC (_("Failed to join a thread\n")); +#ifdef UPGRADE_SUPPORT + cleanup_upgraded_connection (pos); +#endif /* UPGRADE_SUPPORT */ + MHD_pool_destroy (pos->request.pool); +#ifdef HTTPS_SUPPORT + { + struct MHD_TLS_Plugin *tls; + + if (NULL != (tls = daemon->tls_api)) + tls->teardown_connection (tls->cls, + pos->tls_cs); + } +#endif /* HTTPS_SUPPORT */ + + /* clean up the connection */ + if (NULL != daemon->notify_connection_cb) + daemon->notify_connection_cb (daemon->notify_connection_cb_cls, + pos, + MHD_CONNECTION_NOTIFY_CLOSED); + MHD_ip_limit_del (daemon, + (const struct sockaddr *) &pos->addr, + pos->addr_len); +#ifdef EPOLL_SUPPORT + if (MHD_ELS_EPOLL == daemon->event_loop_syscall) + { + if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + { + EDLL_remove (daemon->eready_head, + daemon->eready_tail, + pos); + pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL; + } + if ( (-1 != daemon->epoll_fd) && + (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) ) + { + /* epoll documentation suggests that closing a FD + automatically removes it from the epoll set; however, + this is not true as if we fail to do manually remove it, + we are still seeing an event for this fd in epoll, + causing grief (use-after-free...) --- at least on my + system. */ + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_DEL, + pos->socket_fd, + NULL)) + MHD_PANIC (_("Failed to remove FD from epoll set\n")); + pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; + } + } +#endif + if (NULL != pos->request.response) + { + MHD_response_queue_for_destroy (pos->request.response); + pos->request.response = NULL; + } + if (MHD_INVALID_SOCKET != pos->socket_fd) + MHD_socket_close_chk_ (pos->socket_fd); + free (pos); + + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + daemon->connections--; + daemon->at_limit = false; + } + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); +} + +/* end of connection_cleanup.c */ diff --git a/src/lib/connection_cleanup.h b/src/lib/connection_cleanup.h @@ -0,0 +1,42 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file lib/connection_cleanup.h + * @brief functions to cleanup completed connection + * @author Christian Grothoff + */ +#ifndef CONNECTION_CLEANUP_H +#define CONNECTION_CLEANUP_H + + +/** + * Free resources associated with all closed connections. (destroy + * responses, free buffers, etc.). All closed connections are kept in + * the "cleanup" doubly-linked list. + * + * @remark To be called only from thread that process daemon's + * select()/poll()/etc. + * + * @param daemon daemon to clean up + */ +void +MHD_connection_cleanup_ (struct MHD_Daemon *daemon) + MHD_NONNULL (1); + +#endif diff --git a/src/lib/daemon_close_all_connections.c b/src/lib/daemon_close_all_connections.c @@ -23,9 +23,11 @@ * @author Christian Grothoff */ #include "internal.h" +#include "connection_cleanup.h" #include "connection_close.h" #include "connection_finish_forward.h" #include "daemon_close_all_connections.h" +#include "request_resume.h" #include "upgrade_process.h" @@ -120,7 +122,7 @@ MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon) if (! daemon->disallow_suspend_resume) { daemon->resuming = true; /* Force check for pending resume. */ - resume_suspended_connections (daemon); + MHD_resume_suspended_connections_ (daemon); } /* first, make sure all threads are aware of shutdown; need to traverse DLLs in peace... */ @@ -211,7 +213,7 @@ MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon) if (upg_allowed) { daemon->resuming = true; /* Force check for pending resume. */ - resume_suspended_connections (daemon); + MHD_resume_suspended_connections_ (daemon); } #endif /* UPGRADE_SUPPORT */ @@ -223,7 +225,7 @@ MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon) MHD_PANIC (_("Failed to join a thread\n")); close_connection (pos); } - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); } /* end of daemon_close_all_connections.c */ diff --git a/src/lib/daemon_destroy.c b/src/lib/daemon_destroy.c @@ -24,6 +24,7 @@ */ #include "internal.h" #include "request_resume.h" +#include "daemon_close_all_connections.h" /** diff --git a/src/lib/daemon_epoll.c b/src/lib/daemon_epoll.c @@ -388,7 +388,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon, * Do not accept more then 10 connections at once. The rest will * be accepted on next turn (level trigger is used for listen * socket). */ - while ( (MHD_YES == + while ( (MHD_SC_OK == MHD_accept_connection_ (daemon)) && (series_length < 10) && (daemon->connections < daemon->global_connection_limit) && diff --git a/src/lib/daemon_info.c b/src/lib/daemon_info.c @@ -23,6 +23,7 @@ * @author Christian Grothoff */ #include "internal.h" +#include "connection_cleanup.h" /** @@ -69,7 +70,7 @@ MHD_daemon_get_information_sz (struct MHD_Daemon *daemon, { /* Assumes that MHD_run() in not called in other thread (of the application) at the same time. */ - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); return_value->num_connections = daemon->connections; } diff --git a/src/lib/daemon_run.c b/src/lib/daemon_run.c @@ -23,6 +23,7 @@ * @author Christian Grothoff */ #include "internal.h" +#include "connection_cleanup.h" #include "daemon_epoll.h" #include "daemon_poll.h" #include "daemon_select.h" @@ -60,19 +61,19 @@ MHD_daemon_run (struct MHD_Daemon *daemon) case MHD_ELS_POLL: sc = MHD_daemon_poll_ (daemon, MHD_NO); - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); return sc; #ifdef EPOLL_SUPPORT case MHD_ELS_EPOLL: sc = MHD_daemon_epoll_ (daemon, MHD_NO); - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); return sc; #endif case MHD_ELS_SELECT: return MHD_daemon_select_ (daemon, MHD_NO); - /* MHD_select does MHD_cleanup_connections already */ + /* MHD_select does MHD_connection_cleanup_ already */ default: return MHD_SC_CONFIGURATION_UNEXPECTED_ELS; } diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c @@ -23,10 +23,13 @@ * @author Christian Grothoff */ #include "internal.h" +#include "connection_add.h" +#include "connection_cleanup.h" +#include "connection_finish_forward.h" #include "daemon_select.h" +#include "daemon_epoll.h" #include "request_resume.h" #include "upgrade_process.h" -#include "connection_finish_forward.h" /** @@ -476,7 +479,7 @@ internal_run_from_select (struct MHD_Daemon *daemon, } } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); return MHD_SC_OK; } @@ -492,7 +495,6 @@ void MHD_daemon_upgrade_connection_with_select_ (struct MHD_Connection *con) { struct MHD_UpgradeResponseHandle *urh = con->request.urh; - struct MHD_Daemon *daemon = con->daemon; while ( (0 != urh->in_buffer_size) || (0 != urh->out_buffer_size) || @@ -613,7 +615,7 @@ MHD_daemon_run_from_select (struct MHD_Daemon *daemon, sc = MHD_daemon_epoll_ (daemon, MHD_NO); - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); return sc; #else /* ! EPOLL_SUPPORT */ return MHD_NO; @@ -651,7 +653,6 @@ MHD_daemon_select_ (struct MHD_Daemon *daemon, struct timeval timeout; struct timeval *tv; MHD_UNSIGNED_LONG_LONG ltimeout; - int err_state; MHD_socket ls; enum MHD_StatusCode sc; enum MHD_StatusCode sc2; diff --git a/src/lib/daemon_start.c b/src/lib/daemon_start.c @@ -23,8 +23,11 @@ * @author Christian Grothoff */ #include "internal.h" +#include "connection_cleanup.h" #include "daemon_close_all_connections.h" #include "daemon_select.h" +#include "daemon_poll.h" +#include "daemon_epoll.h" /** @@ -635,7 +638,7 @@ MHD_polling_thread (void *cls) #endif break; } - MHD_cleanup_connections (daemon); + MHD_connection_cleanup_ (daemon); } /* Resume any pending for resume connections, join * all connection's threads (if any) and finally cleanup diff --git a/src/microhttpd/connection_https.c b/src/microhttpd/connection_https.c @@ -207,7 +207,7 @@ MHD_tls_connection_shutdown (struct MHD_Connection *connection) if (MHD_TLS_CONN_WR_CLOSED > connection->tls_state) { const int res = - gnutls_bye(connection->tls_session, GNUTLS_SHUT_WR); + gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); if (GNUTLS_E_SUCCESS == res) { connection->tls_state = MHD_TLS_CONN_WR_CLOSED;