commit dcaf43e3230f725a6ec0b406c205b7a87b7e3368
parent 7d740904c403a0bdbf473b16025799ba03f89536
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 18 Feb 2018 11:08:36 +0100
more work towards getting lib to build nicely (currently FTBFS)
Diffstat:
8 files changed, 385 insertions(+), 7 deletions(-)
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -65,6 +65,7 @@ libmicrohttpd_la_SOURCES = \
connection_finish_forward.c connection_finish_forward.h \
connection_info.c \
connection_options.c \
+ connection_update_event_loop_info.c connection_update_event_loop_info.h \
connection_update_last_activity.c connection_update_last_activity.h \
daemon_close_all_connections.c daemon_close_all_connections.h \
daemon_create.c \
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c
@@ -193,7 +193,7 @@ thread_main_handle_connection (void *data)
{
MHD_connection_update_last_activity_ (con); /* Reset timeout timer. */
/* Process response queued during suspend and update states. */
- MHD_connection_handle_idle (con);
+ MHD_request_handle_idle_ (&con->request);
was_suspended = false;
}
@@ -433,7 +433,7 @@ thread_main_handle_connection (void *data)
(daemon->shutdown) ?
MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN:
MHD_REQUEST_TERMINATED_WITH_ERROR);
- MHD_connection_handle_idle (con);
+ MHD_request_handle_idle_ (&con->request);
}
exit:
if (NULL != con->request.response)
diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c
@@ -23,6 +23,7 @@
*/
#include "internal.h"
#include "connection_call_handlers.h"
+#include "connection_update_event_loop_info.h"
#include "connection_update_last_activity.h"
#include "connection_close.h"
@@ -2767,6 +2768,127 @@ process_request_body (struct MHD_Request *request)
/**
+ * Clean up the state of the given connection and move it into the
+ * clean up queue for final disposal.
+ * @remark To be called only from thread that process connection's
+ * recv(), send() and response.
+ *
+ * @param connection handle for the connection to clean up
+ */
+static void
+cleanup_connection (struct MHD_Connection *connection)
+{
+ struct MHD_Daemon *daemon = connection->daemon;
+
+ if (connection->request.in_cleanup)
+ return; /* Prevent double cleanup. */
+ connection->request.in_cleanup = true;
+ if (NULL != connection->request.response)
+ {
+ MHD_response_queue_for_destroy (connection->request.response);
+ connection->request.response = NULL;
+ }
+ MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+ if (connection->suspended)
+ {
+ DLL_remove (daemon->suspended_connections_head,
+ daemon->suspended_connections_tail,
+ connection);
+ connection->suspended = false;
+ }
+ else
+ {
+ if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model)
+ {
+ 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);
+ }
+ DLL_insert (daemon->cleanup_head,
+ daemon->cleanup_tail,
+ connection);
+ connection->resuming = false;
+ connection->request.in_idle = false;
+ MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+ if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
+ {
+ /* if we were at the connection limit before and are in
+ thread-per-connection mode, signal the main thread
+ to resume accepting connections */
+ if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
+ (! MHD_itc_activate_ (daemon->itc,
+ "c")) )
+ {
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (daemon,
+ MHD_SC_ITC_USE_FAILED,
+ _("Failed to signal end of connection via inter-thread communication channel"));
+#endif
+ }
+ }
+}
+
+
+#ifdef EPOLL_SUPPORT
+/**
+ * Perform epoll() processing, possibly moving the connection back into
+ * the epoll() set if needed.
+ *
+ * @param connection connection to process
+ * @return true if we should continue to process the
+ * connection (not dead yet), false if it died
+ */
+static bool
+connection_epoll_update_ (struct MHD_Connection *connection)
+{
+ struct MHD_Daemon *daemon = connection->daemon;
+
+ if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
+ (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
+ (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
+ ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->request.event_loop_info) &&
+ (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
+ ( (MHD_EVENT_LOOP_INFO_READ == connection->request.event_loop_info) &&
+ (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
+ {
+ /* add to epoll set */
+ struct epoll_event event;
+
+ event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
+ event.data.ptr = connection;
+ if (0 != epoll_ctl (daemon->epoll_fd,
+ EPOLL_CTL_ADD,
+ connection->socket_fd,
+ &event))
+ {
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (daemon,
+ MHD_SC_EPOLL_CTL_ADD_FAILED,
+ _("Call to epoll_ctl failed: %s\n"),
+ MHD_socket_last_strerr_ ());
+#endif
+ connection->request.state = MHD_REQUEST_CLOSED;
+ cleanup_connection (connection);
+ return false;
+ }
+ connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
+ }
+ return true;
+}
+#endif
+
+
+/**
* This function was created to handle per-request processing that
* has to happen even if the socket cannot be read or written to.
* @remark To be called only from thread that process request's
@@ -3064,6 +3186,7 @@ MHD_request_handle_idle_ (struct MHD_Request *request)
{
socket_start_normal_buffering (connection);
request->state = MHD_REQUEST_UPGRADE;
+#if FIXME_LEGACY_STYLE
/* This request is "upgraded". Pass socket to application. */
if (! MHD_response_execute_upgrade_ (request->response,
request))
@@ -3074,6 +3197,7 @@ MHD_request_handle_idle_ (struct MHD_Request *request)
NULL);
continue;
}
+#endif
/* Response is not required anymore for this request. */
if (NULL != request->response)
{
@@ -3262,13 +3386,13 @@ MHD_request_handle_idle_ (struct MHD_Request *request)
return true;
}
}
- MHD_connection_update_event_loop_info (connection);
+ MHD_connection_update_event_loop_info_ (connection);
ret = true;
#ifdef EPOLL_SUPPORT
if ( (! connection->suspended) &&
(MHD_ELS_EPOLL == daemon->event_loop_syscall) )
{
- ret = MHD_connection_epoll_update_ (connection);
+ ret = connection_epoll_update_ (connection);
}
#endif /* EPOLL_SUPPORT */
request->in_idle = false;
diff --git a/src/lib/connection_call_handlers.h b/src/lib/connection_call_handlers.h
@@ -45,4 +45,20 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con,
bool force_close)
MHD_NONNULL (1);
+
+/**
+ * This function was created to handle per-request processing that
+ * has to happen even if the socket cannot be read or written to.
+ * @remark To be called only from thread that process request's
+ * recv(), send() and response.
+ *
+ * @param request the request to handle
+ * @return true if we should continue to process the
+ * request (not dead yet), false if it died
+ */
+bool
+MHD_request_handle_idle_ (struct MHD_Request *request)
+ MHD_NONNULL (1);
+
+
#endif
diff --git a/src/lib/connection_cleanup.c b/src/lib/connection_cleanup.c
@@ -35,7 +35,7 @@
* @param connection handle to the upgraded connection to clean
*/
static void
-cleanup_upgraded_connection (struct MHD_Connection *connection)
+connection_cleanup_upgraded (struct MHD_Connection *connection)
{
struct MHD_UpgradeResponseHandle *urh = connection->request.urh;
@@ -90,7 +90,7 @@ MHD_connection_cleanup_ (struct MHD_Daemon *daemon)
(! MHD_join_thread_ (pos->pid.handle)) )
MHD_PANIC (_("Failed to join a thread\n"));
#ifdef UPGRADE_SUPPORT
- cleanup_upgraded_connection (pos);
+ connection_cleanup_upgraded (pos);
#endif /* UPGRADE_SUPPORT */
MHD_pool_destroy (pos->pool);
#ifdef HTTPS_SUPPORT
diff --git a/src/lib/connection_update_event_loop_info.c b/src/lib/connection_update_event_loop_info.c
@@ -0,0 +1,195 @@
+/*
+ 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/connection_update_event_loop_info.c
+ * @brief update the set of network events this connection is waiting for
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+#include "connection_update_event_loop_info.h"
+
+
+/**
+ * Update the 'event_loop_info' field of this connection based on the
+ * state that the connection is now in. May also close the connection
+ * or perform other updates to the connection if needed to prepare for
+ * the next round of the event loop.
+ *
+ * @param connection connection to get poll set for
+ */
+void
+MHD_connection_update_event_loop_info_ (struct MHD_Connection *connection)
+{
+ /* Do not update states of suspended connection */
+ if (connection->suspended)
+ return; /* States will be updated after resume. */
+#ifdef HTTPS_SUPPORT
+ if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
+ { /* HTTPS connection. */
+ switch (connection->tls_state)
+ {
+ case MHD_TLS_CONN_INIT:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+ return;
+ case MHD_TLS_CONN_HANDSHAKING:
+ if (0 == gnutls_record_get_direction (connection->tls_session))
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+ else
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ return;
+ default:
+ break;
+ }
+ }
+#endif /* HTTPS_SUPPORT */
+ while (1)
+ {
+#if DEBUG_STATES
+ MHD_DLOG (connection->daemon,
+ _("In function %s handling connection at state: %s\n"),
+ __FUNCTION__,
+ MHD_state_to_string (connection->state));
+#endif
+ switch (connection->state)
+ {
+ case MHD_CONNECTION_INIT:
+ case MHD_CONNECTION_URL_RECEIVED:
+ case MHD_CONNECTION_HEADER_PART_RECEIVED:
+ /* while reading headers, we always grow the
+ read buffer if needed, no size-check required */
+ if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
+ (MHD_NO == try_grow_read_buffer (connection)) )
+ {
+ transmit_error_response (connection,
+ (connection->url != NULL)
+ ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
+ : MHD_HTTP_URI_TOO_LONG,
+ REQUEST_TOO_BIG);
+ continue;
+ }
+ if (! connection->read_closed)
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+ else
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+ break;
+ case MHD_CONNECTION_HEADERS_RECEIVED:
+ mhd_assert (0);
+ break;
+ case MHD_CONNECTION_HEADERS_PROCESSED:
+ mhd_assert (0);
+ break;
+ case MHD_CONNECTION_CONTINUE_SENDING:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ break;
+ case MHD_CONNECTION_CONTINUE_SENT:
+ if (connection->read_buffer_offset == connection->read_buffer_size)
+ {
+ if ((MHD_YES != try_grow_read_buffer (connection)) &&
+ (0 != (connection->daemon->options &
+ MHD_USE_INTERNAL_POLLING_THREAD)))
+ {
+ /* failed to grow the read buffer, and the
+ client which is supposed to handle the
+ received data in a *blocking* fashion
+ (in this mode) did not handle the data as
+ it was supposed to!
+ => we would either have to do busy-waiting
+ (on the client, which would likely fail),
+ or if we do nothing, we would just timeout
+ on the connection (if a timeout is even
+ set!).
+ Solution: we kill the connection with an error */
+ transmit_error_response (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ INTERNAL_ERROR);
+ continue;
+ }
+ }
+ if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
+ (! connection->read_closed) )
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+ else
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+ break;
+ case MHD_CONNECTION_BODY_RECEIVED:
+ case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+ /* while reading footers, we always grow the
+ read buffer if needed, no size-check required */
+ if (connection->read_closed)
+ {
+ CONNECTION_CLOSE_ERROR (connection,
+ NULL);
+ continue;
+ }
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+ /* transition to FOOTERS_RECEIVED
+ happens in read handler */
+ break;
+ case MHD_CONNECTION_FOOTERS_RECEIVED:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+ break;
+ case MHD_CONNECTION_HEADERS_SENDING:
+ /* headers in buffer, keep writing */
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ break;
+ case MHD_CONNECTION_HEADERS_SENT:
+ mhd_assert (0);
+ break;
+ case MHD_CONNECTION_NORMAL_BODY_READY:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ break;
+ case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+ break;
+ case MHD_CONNECTION_CHUNKED_BODY_READY:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ break;
+ case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+ break;
+ case MHD_CONNECTION_BODY_SENT:
+ mhd_assert (0);
+ break;
+ case MHD_CONNECTION_FOOTERS_SENDING:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+ break;
+ case MHD_CONNECTION_FOOTERS_SENT:
+ mhd_assert (0);
+ break;
+ case MHD_CONNECTION_CLOSED:
+ connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
+ return; /* do nothing, not even reading */
+ case MHD_CONNECTION_IN_CLEANUP:
+ mhd_assert (0);
+ break;
+#ifdef UPGRADE_SUPPORT
+ case MHD_CONNECTION_UPGRADE:
+ mhd_assert (0);
+ break;
+#endif /* UPGRADE_SUPPORT */
+ default:
+ mhd_assert (0);
+ }
+ break;
+ }
+}
+
+
+/* end of connection_update_event_loop_info.c */
+
diff --git a/src/lib/connection_update_event_loop_info.h b/src/lib/connection_update_event_loop_info.h
@@ -0,0 +1,42 @@
+/*
+ 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/connection_update_event_loop_info.h
+ * @brief function to update last activity of a connection
+ * @author Christian Grothoff
+ */
+
+#ifndef CONNECTION_UPDATE_EVENT_LOOP_INFO_H
+#define CONNECTION_UPDATE_EVENT_LOOP_INFO_H
+
+
+/**
+ * Update the 'event_loop_info' field of this connection based on the
+ * state that the connection is now in. May also close the connection
+ * or perform other updates to the connection if needed to prepare for
+ * the next round of the event loop.
+ *
+ * @param connection connection to get poll set for
+ */
+void
+MHD_connection_update_event_loop_info_ (struct MHD_Connection *connection)
+ MHD_NONNULL (1);
+
+
+#endif
diff --git a/src/lib/connection_update_last_activity.c b/src/lib/connection_update_last_activity.c
@@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
- * @file lib/connection_add.c
+ * @file lib/connection_update_last_activity.c
* @brief functions to add connection to our active set
* @author Christian Grothoff
*/