| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /*
- 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_close_all_connections.c
- * @brief function to close all connections open at a daemon
- * @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"
- /**
- * Close the given connection, remove it from all of its
- * DLLs and move it into the cleanup queue.
- * @remark To be called only from thread that
- * process daemon's select()/poll()/etc.
- *
- * @param pos connection to move to cleanup
- */
- static void
- close_connection (struct MHD_Connection *pos)
- {
- struct MHD_Daemon *daemon = pos->daemon;
- if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode)
- {
- MHD_connection_mark_closed_ (pos);
- return; /* must let thread to do the rest */
- }
- MHD_connection_close_ (pos,
- MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
- MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
- mhd_assert (! pos->suspended);
- mhd_assert (! pos->resuming);
- if (pos->connection_timeout ==
- pos->daemon->connection_default_timeout)
- XDLL_remove (daemon->normal_timeout_head,
- daemon->normal_timeout_tail,
- pos);
- else
- XDLL_remove (daemon->manual_timeout_head,
- daemon->manual_timeout_tail,
- pos);
- DLL_remove (daemon->connections_head,
- daemon->connections_tail,
- pos);
- DLL_insert (daemon->cleanup_head,
- daemon->cleanup_tail,
- pos);
- MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
- }
- /**
- * Close all connections for the daemon. Must only be called when
- * MHD_Daemon::shutdown was set to true.
- *
- * @remark To be called only from thread that process daemon's
- * select()/poll()/etc.
- *
- * @param daemon daemon to close down
- */
- void
- MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon)
- {
- struct MHD_Connection *pos;
- const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION ==
- daemon->threading_mode);
- #ifdef UPGRADE_SUPPORT
- const bool upg_allowed = (! daemon->disallow_upgrade);
- #endif /* UPGRADE_SUPPORT */
- #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
- struct MHD_UpgradeResponseHandle *urh;
- struct MHD_UpgradeResponseHandle *urhn;
- const bool used_tls = (NULL != daemon->tls_api);
- mhd_assert (NULL == daemon->worker_pool);
- mhd_assert (daemon->shutdown);
- /* give upgraded HTTPS connections a chance to finish */
- /* 'daemon->urh_head' is not used in thread-per-connection mode. */
- for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
- {
- urhn = urh->prev;
- /* call generic forwarding function for passing data
- with chance to detect that application is done. */
- MHD_upgrade_response_handle_process_ (urh);
- MHD_connection_finish_forward_ (urh->connection);
- urh->clean_ready = true;
- /* Resuming will move connection to cleanup list. */
- MHD_request_resume (&urh->connection->request);
- }
- #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
- /* Give suspended connections a chance to resume to avoid
- running into the check for there not being any suspended
- connections left in case of a tight race with a recently
- resumed connection. */
- if (! daemon->disallow_suspend_resume)
- {
- daemon->resuming = true; /* Force check for pending resume. */
- MHD_resume_suspended_connections_ (daemon);
- }
- /* first, make sure all threads are aware of shutdown; need to
- traverse DLLs in peace... */
- MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
- #ifdef UPGRADE_SUPPORT
- if (upg_allowed)
- {
- struct MHD_Connection *susp;
- susp = daemon->suspended_connections_tail;
- while (NULL != susp)
- {
- if (NULL == susp->request.urh) /* "Upgraded" connection? */
- MHD_PANIC (_ (
- "MHD_stop_daemon() called while we have suspended connections.\n"));
- #ifdef HTTPS_SUPPORT
- else if (used_tls &&
- used_thr_p_c &&
- (! susp->request.urh->clean_ready) )
- shutdown (susp->request.urh->app.socket,
- SHUT_RDWR); /* Wake thread by shutdown of app socket. */
- #endif /* HTTPS_SUPPORT */
- else
- {
- #ifdef HAVE_MESSAGES
- if (! susp->request.urh->was_closed)
- MHD_DLOG (daemon,
- MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION,
- _ (
- "Initiated daemon shutdown while \"upgraded\" connection was not closed.\n"));
- #endif
- susp->request.urh->was_closed = true;
- /* If thread-per-connection is used, connection's thread
- * may still processing "upgrade" (exiting). */
- if (! used_thr_p_c)
- MHD_connection_finish_forward_ (susp);
- /* Do not use MHD_resume_connection() as mutex is
- * already locked. */
- susp->resuming = true;
- daemon->resuming = true;
- }
- susp = susp->prev;
- }
- }
- else /* This 'else' is combined with next 'if' */
- #endif /* UPGRADE_SUPPORT */
- if (NULL != daemon->suspended_connections_head)
- MHD_PANIC (_ (
- "MHD_stop_daemon() called while we have suspended connections.\n"));
- for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
- {
- shutdown (pos->socket_fd,
- SHUT_RDWR);
- #if MHD_WINSOCK_SOCKETS
- if ( (used_thr_p_c) &&
- (MHD_ITC_IS_VALID_ (daemon->itc)) &&
- (! MHD_itc_activate_ (daemon->itc,
- "e")) )
- MHD_PANIC (_ (
- "Failed to signal shutdown via inter-thread communication channel"));
- #endif
- }
- /* now, collect per-connection threads */
- if (used_thr_p_c)
- {
- pos = daemon->connections_tail;
- while (NULL != pos)
- {
- if (! pos->thread_joined)
- {
- MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
- if (! MHD_join_thread_ (pos->pid.handle))
- MHD_PANIC (_ ("Failed to join a thread\n"));
- MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
- pos->thread_joined = true;
- /* The thread may have concurrently modified the DLL,
- need to restart from the beginning */
- pos = daemon->connections_tail;
- continue;
- }
- pos = pos->prev;
- }
- }
- MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
- #ifdef UPGRADE_SUPPORT
- /* Finished threads with "upgraded" connections need to be moved
- * to cleanup list by resume_suspended_connections(). */
- /* "Upgraded" connections that were not closed explicitly by
- * application should be moved to cleanup list too. */
- if (upg_allowed)
- {
- daemon->resuming = true; /* Force check for pending resume. */
- MHD_resume_suspended_connections_ (daemon);
- }
- #endif /* UPGRADE_SUPPORT */
- /* now that we're alone, move everyone to cleanup */
- while (NULL != (pos = daemon->connections_tail))
- {
- if ( (used_thr_p_c) &&
- (! pos->thread_joined) )
- MHD_PANIC (_ ("Failed to join a thread\n"));
- close_connection (pos);
- }
- MHD_connection_cleanup_ (daemon);
- }
- /* end of daemon_close_all_connections.c */
|