libmicrohttpd

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

commit f4355ac34bb1fad42ccb650038bddddb65d70443
parent 5c8fbeb97b01f8d4bb25a01e8ad70ebcd95bb822
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 15 Feb 2018 07:49:56 +0100

implement MHD_resume_suspended_connections_

Diffstat:
Msrc/lib/connection_add.c | 2+-
Msrc/lib/daemon_destroy.c | 3++-
Msrc/lib/daemon_epoll.c | 3++-
Msrc/lib/daemon_ip_limit.c | 20++++++++++++++++++--
Msrc/lib/daemon_poll.c | 5+++--
Msrc/lib/daemon_select.c | 7+++++--
Msrc/lib/request_resume.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/request_resume.h | 43+++++++++++++++++++++++++++++++++++++++++++
8 files changed, 195 insertions(+), 9 deletions(-)

diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c @@ -50,7 +50,7 @@ thread_main_connection_upgrade (struct MHD_Connection *con) if ( (NULL != daemon->tls_api) && (MHD_ELS_POLL != daemon->event_loop_syscall) ) { - MHD_daemon_upgrade_connection_with_select (con); + MHD_daemon_upgrade_connection_with_select_ (con); } #ifdef HAVE_POLL else if (NULL != daemon->tls_api) diff --git a/src/lib/daemon_destroy.c b/src/lib/daemon_destroy.c @@ -23,6 +23,7 @@ * @author Christian Grothoff */ #include "internal.h" +#include "request_resume.h" /** @@ -113,7 +114,7 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon) { /* Worker daemon or single daemon with internal thread(s). */ if (! daemon->disallow_suspend_resume) - resume_suspended_connections (daemon); + (void) MHD_resume_suspended_connections_ (daemon); /* Separate thread(s) is used for polling sockets. */ if (MHD_ITC_IS_VALID_(daemon->itc)) diff --git a/src/lib/daemon_epoll.c b/src/lib/daemon_epoll.c @@ -24,6 +24,7 @@ */ #include "internal.h" #include "daemon_epoll.h" +#include "request_resume.h" #ifdef EPOLL_SUPPORT @@ -301,7 +302,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon, } if ( (! daemon->disallow_suspend_resume) && - (MHD_YES == resume_suspended_connections (daemon)) ) + (MHD_resume_suspended_connections_ (daemon)) ) may_block = false; if (may_block) diff --git a/src/lib/daemon_ip_limit.c b/src/lib/daemon_ip_limit.c @@ -60,6 +60,22 @@ struct MHD_IPCount /** + * Trace up to and return master daemon. If the supplied daemon + * is a master, then return the daemon itself. + * + * @param daemon handle to a daemon + * @return master daemon handle + */ +static struct MHD_Daemon* +get_master (struct MHD_Daemon *daemon) +{ + while (NULL != daemon->master) + daemon = daemon->master; + return daemon; +} + + +/** * Lock shared structure for IP connection counts and connection DLLs. * * @param daemon handle to daemon where lock is @@ -172,7 +188,7 @@ MHD_ip_limit_add (struct MHD_Daemon *daemon, void *node; int result; - daemon = MHD_get_master (daemon); + daemon = get_master (daemon); /* Ignore if no connection limit assigned */ if (0 == daemon->ip_connection_limit) return MHD_YES; @@ -238,7 +254,7 @@ MHD_ip_limit_del (struct MHD_Daemon *daemon, struct MHD_IPCount *found_key; void **nodep; - daemon = MHD_get_master (daemon); + daemon = get_master (daemon); /* Ignore if no connection limit assigned */ if (0 == daemon->ip_connection_limit) return; diff --git a/src/lib/daemon_poll.c b/src/lib/daemon_poll.c @@ -23,6 +23,7 @@ */ #include "internal.h" #include "daemon_poll.h" +#include "request_resume.h" #ifdef HAVE_POLL @@ -143,7 +144,7 @@ MHD_daemon_poll_all_ (struct MHD_Daemon *daemon, #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ if ( (! daemon->disallow_suspend_resume) && - (MHD_YES == resume_suspended_connections (daemon)) ) + (MHD_resume_suspended_connections_ (daemon)) ) may_block = false; /* count number of connections and thus determine poll set size */ @@ -385,7 +386,7 @@ MHD_daemon_poll_listen_socket_ (struct MHD_Daemon *daemon, } if (! daemon->disallow_suspend_resume) - (void) resume_suspended_connections (daemon); + (void) MHD_resume_suspended_connections_ (daemon); if (! may_block) timeout = 0; diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c @@ -24,6 +24,8 @@ */ #include "internal.h" #include "daemon_select.h" +#include "request_resume.h" + /** * We defined a macro with the same name as a function we @@ -595,6 +597,7 @@ enum MHD_StatusCode MHD_daemon_run_from_select (struct MHD_Daemon *daemon, const fd_set *read_fd_set, + const fd_set *write_fd_set, const fd_set *except_fd_set) { @@ -617,7 +620,7 @@ MHD_daemon_run_from_select (struct MHD_Daemon *daemon, /* Resuming external connections when using an extern mainloop */ if (! daemon->disallow_suspend_resume) - resume_suspended_connections (daemon); + (void) MHD_resume_suspended_connections_ (daemon); return internal_run_from_select (daemon, read_fd_set, @@ -661,7 +664,7 @@ MHD_daemon_select_ (struct MHD_Daemon *daemon, maxsock = MHD_INVALID_SOCKET; sc = MHD_SC_OK; if ( (! daemon->disallow_suspend_resume) && - (MHD_YES == resume_suspended_connections (daemon)) && + (MHD_resume_suspended_connections_ (daemon)) && (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) ) may_block = MHD_NO; diff --git a/src/lib/request_resume.c b/src/lib/request_resume.c @@ -62,4 +62,125 @@ MHD_request_resume (struct MHD_Request *request) } } + +/** + * Run through the suspended connections and move any that are no + * longer suspended back to the active state. + * @remark To be called only from thread that process + * daemon's select()/poll()/etc. + * + * @param daemon daemon context + * @return true if a connection was actually resumed + */ +bool +MHD_resume_suspended_connections_ (struct MHD_Daemon *daemon) +{ + struct MHD_Connection *pos; + struct MHD_Connection *prev = NULL; + bool ret; + const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model); + + mhd_assert (NULL == daemon->worker_pool); + ret = false; + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + + if (daemon->resuming) + { + prev = daemon->suspended_connections_tail; + /* During shutdown check for resuming is forced. */ + mhd_assert((NULL != prev) || (daemon->shutdown)); + } + + daemon->resuming = false; + + while (NULL != (pos = prev)) + { +#ifdef UPGRADE_SUPPORT + struct MHD_UpgradeResponseHandle * const urh = pos->request.urh; +#else /* ! UPGRADE_SUPPORT */ + static const void * const urh = NULL; +#endif /* ! UPGRADE_SUPPORT */ + prev = pos->prev; + if ( (! pos->resuming) +#ifdef UPGRADE_SUPPORT + || ( (NULL != urh) && + ( (! urh->was_closed) || + (! urh->clean_ready) ) ) +#endif /* UPGRADE_SUPPORT */ + ) + continue; + ret = true; + mhd_assert (pos->suspended); + DLL_remove (daemon->suspended_connections_head, + daemon->suspended_connections_tail, + pos); + pos->suspended = false; + if (NULL == urh) + { + DLL_insert (daemon->connections_head, + daemon->connections_tail, + pos); + if (! used_thr_p_c) + { + /* Reset timeout timer on resume. */ + if (0 != pos->connection_timeout) + pos->last_activity = MHD_monotonic_sec_counter(); + + if (pos->connection_timeout == daemon->connection_default_timeout) + XDLL_insert (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + pos); + else + XDLL_insert (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + pos); + } +#ifdef EPOLL_SUPPORT + if (MHD_ELS_EPOLL == daemon->event_loop_syscall) + { + if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + MHD_PANIC ("Resumed connection was already in EREADY set\n"); + /* we always mark resumed connections as ready, as we + might have missed the edge poll event during suspension */ + EDLL_insert (daemon->eready_head, + daemon->eready_tail, + pos); + pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL | \ + MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; + pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED; + } +#endif + } +#ifdef UPGRADE_SUPPORT + else + { + /* Data forwarding was finished (for TLS connections) AND + * application was closed upgraded connection. + * Insert connection into cleanup list. */ + DLL_insert (daemon->cleanup_head, + daemon->cleanup_tail, + pos); + + } +#endif /* UPGRADE_SUPPORT */ + pos->resuming = false; + } + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + if ( (used_thr_p_c) && + (ret) ) + { /* Wake up suspended connections. */ + if (! MHD_itc_activate_(daemon->itc, + "w")) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + MHD_SC_ITC_USE_FAILED, + _("Failed to signal resume of connection via inter-thread communication channel.")); +#endif + } + } + return ret; +} + + /* end of request_resume.c */ diff --git a/src/lib/request_resume.h b/src/lib/request_resume.h @@ -0,0 +1,43 @@ +/* + 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/request_resume.h + * @brief implementation of MHD_request_resume() + * @author Christian Grothoff + */ + + +#ifndef REQUEST_RESUME_H +#define REQUEST_RESUME_H + +/** + * Run through the suspended connections and move any that are no + * longer suspended back to the active state. + * @remark To be called only from thread that process + * daemon's select()/poll()/etc. + * + * @param daemon daemon context + * @return true if a connection was actually resumed + */ +bool +MHD_resume_suspended_connections_ (struct MHD_Daemon *daemon) + MHD_NONNULL(1); + +#endif