blob: b9956d5b62b2fd973fc2ea8cffcfd334f9763315 [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/action_suspend.c
* @brief implementation of MHD_action_suspend()
* @author Christian Grothoff
*/
#include "internal.h"
/**
* The suspend action is being run. Suspend handling
* of the given request.
*
* @param cls NULL
* @param request the request to apply the action to
* @return #MHD_SC_OK on success
*/
static enum MHD_StatusCode
suspend_action (void *cls,
struct MHD_Request *request)
{
(void) cls;
struct MHD_Connection *connection = request->connection;
struct MHD_Daemon *daemon = connection->daemon;
MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
if (connection->resuming)
{
/* suspending again while we didn't even complete resuming yet */
connection->resuming = false;
MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
return MHD_SC_OK;
}
if (daemon->threading_mode != MHD_TM_THREAD_PER_CONNECTION)
{
if (connection->connection_timeout ==
daemon->connection_default_timeout)
XDLL_remove (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
connection);
else
XDLL_remove (daemon->manual_timeout_head,
daemon->manual_timeout_tail,
connection);
}
DLL_remove (daemon->connections_head,
daemon->connections_tail,
connection);
mhd_assert (! connection->suspended);
DLL_insert (daemon->suspended_connections_head,
daemon->suspended_connections_tail,
connection);
connection->suspended = true;
#ifdef EPOLL_SUPPORT
if (MHD_ELS_EPOLL == daemon->event_loop_syscall)
{
if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
{
EDLL_remove (daemon->eready_head,
daemon->eready_tail,
connection);
connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL;
}
if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET))
{
if (0 != epoll_ctl (daemon->epoll_fd,
EPOLL_CTL_DEL,
connection->socket_fd,
NULL))
MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET;
}
connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED;
}
#endif
MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
return MHD_SC_OK;
}
/**
* Suspend handling of network data for a given request. This can
* be used to dequeue a request from MHD's event loop for a while.
*
* If you use this API in conjunction with a internal select or a
* thread pool, you must set the option #MHD_USE_ITC to
* ensure that a resumed request is immediately processed by MHD.
*
* Suspended requests continue to count against the total number of
* requests allowed (per daemon, as well as per IP, if such limits
* are set). Suspended requests will NOT time out; timeouts will
* restart when the request handling is resumed. While a
* request is suspended, MHD will not detect disconnects by the
* client.
*
* The only safe time to suspend a request is from either a
* #MHD_RequestHeaderCallback, #MHD_UploadCallback, or a
* #MHD_RequestfetchResponseCallback. Suspending a request
* at any other time will cause an assertion failure.
*
* Finally, it is an API violation to call #MHD_daemon_stop() while
* having suspended requests (this will at least create memory and
* socket leaks or lead to undefined behavior). You must explicitly
* resume all requests before stopping the daemon.
*
* @return action to cause a request to be suspended.
*/
const struct MHD_Action *
MHD_action_suspend (void)
{
static const struct MHD_Action suspend = {
.action = &suspend_action,
.action_cls = NULL
};
return &suspend;
}
/* end of action_suspend.c */