| /* |
| 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/daemon_quiesce.c |
| * @brief main functions to quiesce a daemon |
| * @author Christian Grothoff |
| */ |
| #include "internal.h" |
| |
| |
| /** |
| * Stop accepting connections from the listening socket. Allows |
| * clients to continue processing, but stops accepting new |
| * connections. Note that the caller is responsible for closing the |
| * returned socket; however, if MHD is run using threads (anything but |
| * external select mode), it must not be closed until AFTER |
| * #MHD_stop_daemon has been called (as it is theoretically possible |
| * that an existing thread is still using it). |
| * |
| * Note that some thread modes require the caller to have passed |
| * #MHD_USE_ITC when using this API. If this daemon is |
| * in one of those modes and this option was not given to |
| * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. |
| * |
| * @param daemon daemon to stop accepting new connections for |
| * @return old listen socket on success, #MHD_INVALID_SOCKET if |
| * the daemon was already not listening anymore, or |
| * was never started |
| * @ingroup specialized |
| */ |
| MHD_socket |
| MHD_daemon_quiesce (struct MHD_Daemon *daemon) |
| { |
| MHD_socket listen_socket; |
| |
| if (MHD_INVALID_SOCKET == (listen_socket = daemon->listen_socket)) |
| return MHD_INVALID_SOCKET; |
| if ( (daemon->disable_itc) && |
| (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode) ) |
| { |
| #ifdef HAVE_MESSAGES |
| MHD_DLOG (daemon, |
| MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC, |
| "Using MHD_quiesce_daemon in this mode requires ITC.\n"); |
| #endif |
| return MHD_INVALID_SOCKET; |
| } |
| |
| if (NULL != daemon->worker_pool) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < daemon->worker_pool_size; i++) |
| { |
| struct MHD_Daemon *worker = &daemon->worker_pool[i]; |
| |
| worker->was_quiesced = true; |
| #ifdef EPOLL_SUPPORT |
| if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && |
| (-1 != worker->epoll_fd) && |
| (worker->listen_socket_in_epoll) ) |
| { |
| if (0 != epoll_ctl (worker->epoll_fd, |
| EPOLL_CTL_DEL, |
| listen_socket, |
| NULL)) |
| MHD_PANIC (_ ("Failed to remove listen FD from epoll set.\n")); |
| worker->listen_socket_in_epoll = false; |
| } |
| else |
| #endif |
| if (MHD_ITC_IS_VALID_ (worker->itc)) |
| { |
| if (! MHD_itc_activate_ (worker->itc, |
| "q")) |
| MHD_PANIC (_ ( |
| "Failed to signal quiesce via inter-thread communication channel.\n")); |
| } |
| } |
| daemon->was_quiesced = true; |
| #ifdef EPOLL_SUPPORT |
| if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && |
| (-1 != daemon->epoll_fd) && |
| (daemon->listen_socket_in_epoll) ) |
| { |
| if (0 != epoll_ctl (daemon->epoll_fd, |
| EPOLL_CTL_DEL, |
| listen_socket, |
| NULL)) |
| MHD_PANIC ("Failed to remove listen FD from epoll set.\n"); |
| daemon->listen_socket_in_epoll = false; |
| } |
| #endif |
| } |
| |
| if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && |
| (! MHD_itc_activate_ (daemon->itc, |
| "q")) ) |
| MHD_PANIC (_ ( |
| "Failed to signal quiesce via inter-thread communication channel.\n")); |
| |
| /* FIXME: we might want some bi-directional communication here |
| (in both the thread-pool and single-thread case!) |
| to be sure that the threads have stopped using the listen |
| socket, otherwise there is still the possibility of a race |
| between a thread accept()ing and the caller closing and |
| re-binding the socket. */return listen_socket; |
| } |
| |
| |
| /* end of daemon_quiesce.c */ |