blob: 07cd71587af27f8a4f842f186f3f5ef3ca5e0cc9 [file] [log] [blame]
/*
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_destroy.c
* @brief main functions to destroy a daemon
* @author Christian Grothoff
*/
#include "internal.h"
#include "request_resume.h"
#include "daemon_close_all_connections.h"
/**
* Stop all worker threads from the worker pool.
*
* @param daemon master daemon controlling the workers
*/
static void
stop_workers (struct MHD_Daemon *daemon)
{
MHD_socket fd;
unsigned int i;
mhd_assert (1 < daemon->worker_pool_size);
mhd_assert (1 < daemon->threading_mode);
if (daemon->was_quiesced)
fd = MHD_INVALID_SOCKET; /* Do not use FD if daemon was quiesced */
else
fd = daemon->listen_socket;
/* Let workers shutdown in parallel. */
for (i = 0; i < daemon->worker_pool_size; i++)
{
daemon->worker_pool[i].shutdown = true;
if (MHD_ITC_IS_VALID_ (daemon->worker_pool[i].itc))
{
if (! MHD_itc_activate_ (daemon->worker_pool[i].itc,
"e"))
MHD_PANIC (_ (
"Failed to signal shutdown via inter-thread communication channel.\n"));
}
else
{
/* Better hope shutdown() works... */
mhd_assert (MHD_INVALID_SOCKET != fd);
}
}
#ifdef HAVE_LISTEN_SHUTDOWN
if (MHD_INVALID_SOCKET != fd)
{
(void) shutdown (fd,
SHUT_RDWR);
}
#endif /* HAVE_LISTEN_SHUTDOWN */
for (i = 0; i < daemon->worker_pool_size; ++i)
{
MHD_daemon_destroy (&daemon->worker_pool[i]);
}
free (daemon->worker_pool);
daemon->worker_pool = NULL;
/* FIXME: does this still hold? */
mhd_assert (MHD_ITC_IS_INVALID_ (daemon->itc));
#ifdef EPOLL_SUPPORT
mhd_assert (-1 == daemon->epoll_fd);
#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
mhd_assert (-1 == daemon->epoll_upgrade_fd);
#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
#endif /* EPOLL_SUPPORT */
}
/**
* Shutdown and destroy an HTTP daemon.
*
* @param daemon daemon to stop
* @ingroup event
*/
void
MHD_daemon_destroy (struct MHD_Daemon *daemon)
{
MHD_socket fd;
daemon->shutdown = true;
if (daemon->was_quiesced)
fd = MHD_INVALID_SOCKET; /* Do not use FD if daemon was quiesced */
else
fd = daemon->listen_socket;
/* FIXME: convert from here to microhttpd2-style API! */
if (NULL != daemon->worker_pool)
{ /* Master daemon with worker pool. */
stop_workers (daemon);
}
else
{
mhd_assert (0 == daemon->worker_pool_size);
/* Worker daemon or single-thread daemon. */
if (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode)
{
/* Worker daemon or single daemon with internal thread(s). */
/* Separate thread(s) is used for polling sockets. */
if (MHD_ITC_IS_VALID_ (daemon->itc))
{
if (! MHD_itc_activate_ (daemon->itc,
"e"))
MHD_PANIC (_ (
"Failed to signal shutdown via inter-thread communication channel.\n"));
}
else
{
#ifdef HAVE_LISTEN_SHUTDOWN
if (MHD_INVALID_SOCKET != fd)
{
if (NULL == daemon->master)
(void) shutdown (fd,
SHUT_RDWR);
}
else
#endif /* HAVE_LISTEN_SHUTDOWN */
mhd_assert (false); /* Should never happen */
}
if (! MHD_join_thread_ (daemon->pid.handle))
{
MHD_PANIC (_ ("Failed to join a thread.\n"));
}
/* close_all_connections() was called in daemon thread. */
}
else
{
/* No internal threads are used for polling sockets
(external event loop) */
MHD_daemon_close_all_connections_ (daemon);
}
if (MHD_ITC_IS_VALID_ (daemon->itc))
MHD_itc_destroy_chk_ (daemon->itc);
#ifdef EPOLL_SUPPORT
if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
(-1 != daemon->epoll_fd) )
MHD_socket_close_chk_ (daemon->epoll_fd);
#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
(-1 != daemon->epoll_upgrade_fd) )
MHD_socket_close_chk_ (daemon->epoll_upgrade_fd);
#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
#endif /* EPOLL_SUPPORT */
MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
}
if (NULL != daemon->master)
return;
/* Cleanup that should be done only one time in master/single daemon.
* Do not perform this cleanup in worker daemons. */
if (MHD_INVALID_SOCKET != fd)
MHD_socket_close_chk_ (fd);
/* TLS clean up */
#ifdef HTTPS_SUPPORT
if (NULL != daemon->tls_api)
{
#if FIXME_TLS_API
if (daemon->have_dhparams)
{
gnutls_dh_params_deinit (daemon->https_mem_dhparams);
daemon->have_dhparams = false;
}
gnutls_priority_deinit (daemon->priority_cache);
if (daemon->x509_cred)
gnutls_certificate_free_credentials (daemon->x509_cred);
#endif
}
#endif /* HTTPS_SUPPORT */
#ifdef DAUTH_SUPPORT
free (daemon->nnc);
MHD_mutex_destroy_chk_ (&daemon->nnc_lock);
#endif
MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex);
free (daemon);
}
/* end of daemon_destroy.c */