commit 5c8fbeb97b01f8d4bb25a01e8ad70ebcd95bb822
parent 9562d1656d683cce2a2557fc0c2e5573fabfc6bb
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 15 Feb 2018 07:38:38 +0100
implementing thread_main_connection_upgrade
Diffstat:
5 files changed, 218 insertions(+), 0 deletions(-)
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c
@@ -24,6 +24,48 @@
#include "internal.h"
#include "connection_add.h"
#include "daemon_ip_limit.h"
+#include "daemon_select.h"
+#include "daemon_poll.h"
+
+
+#ifdef UPGRADE_SUPPORT
+/**
+ * Main function of the thread that handles an individual connection
+ * after it was "upgraded" when #MHD_USE_THREAD_PER_CONNECTION is set.
+ * @remark To be called only from thread that process
+ * connection's recv(), send() and response.
+ *
+ * @param con the connection this thread will handle
+ */
+static void
+thread_main_connection_upgrade (struct MHD_Connection *con)
+{
+#ifdef HTTPS_SUPPORT
+ struct MHD_UpgradeResponseHandle *urh = con->request.urh;
+ struct MHD_Daemon *daemon = con->daemon;
+
+ /* Here, we need to bi-directionally forward
+ until the application tells us that it is done
+ with the socket; */
+ if ( (NULL != daemon->tls_api) &&
+ (MHD_ELS_POLL != daemon->event_loop_syscall) )
+ {
+ MHD_daemon_upgrade_connection_with_select (con);
+ }
+#ifdef HAVE_POLL
+ else if (NULL != daemon->tls_api)
+ {
+ MHD_daemon_upgrade_connection_with_poll_ (con);
+ }
+#endif
+ /* end HTTPS */
+#endif /* HTTPS_SUPPORT */
+ /* TLS forwarding was finished. Cleanup socketpair. */
+ MHD_connection_finish_forward_ (con);
+ /* Do not set 'urh->clean_ready' yet as 'urh' will be used
+ * in connection thread for a little while. */
+}
+#endif /* UPGRADE_SUPPORT */
/**
diff --git a/src/lib/daemon_poll.c b/src/lib/daemon_poll.c
@@ -450,4 +450,64 @@ MHD_daemon_poll_ (struct MHD_Daemon *daemon,
#endif
}
+
+#ifdef HTTPS_SUPPORT
+/**
+ * Process upgraded connection with a poll() loop.
+ * We are in our own thread, only processing @a con
+ *
+ * @param con connection to process
+ */
+void
+MHD_daemon_upgrade_connection_with_poll_ (struct MHD_Connection *con)
+{
+ struct MHD_UpgradeResponseHandle *urh = con->request.urh;
+ struct MHD_Daemon *daemon = con->daemon;
+ struct pollfd p[2];
+
+ memset (p,
+ 0,
+ sizeof (p));
+ p[0].fd = urh->connection->socket_fd;
+ p[1].fd = urh->mhd.socket;
+
+ while ( (0 != urh->in_buffer_size) ||
+ (0 != urh->out_buffer_size) ||
+ (0 != urh->in_buffer_used) ||
+ (0 != urh->out_buffer_used) )
+ {
+ int timeout;
+
+ urh_update_pollfd (urh,
+ p);
+
+ if ( (con->tls_read_ready) &&
+ (urh->in_buffer_used < urh->in_buffer_size))
+ timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */
+ else
+ timeout = -1;
+
+ if (MHD_sys_poll_ (p,
+ 2,
+ timeout) < 0)
+ {
+ const int err = MHD_socket_get_error_ ();
+
+ if (MHD_SCKT_ERR_IS_EINTR_ (err))
+ continue;
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (con->daemon,
+ MHD_SC_UNEXPECTED_POLL_ERROR,
+ _("Error during poll: `%s'\n"),
+ MHD_socket_strerr_ (err));
+#endif
+ break;
+ }
+ urh_from_pollfd (urh,
+ p);
+ process_urh (urh);
+ }
+}
+#endif
+
/* end of daemon_poll.c */
diff --git a/src/lib/daemon_poll.h b/src/lib/daemon_poll.h
@@ -68,4 +68,16 @@ MHD_daemon_poll_ (struct MHD_Daemon *daemon,
#endif
+#ifdef HTTPS_SUPPORT
+/**
+ * Process upgraded connection with a poll() loop.
+ * We are in our own thread, only processing @a con
+ *
+ * @param con connection to process
+ */
+void
+MHD_daemon_upgrade_connection_with_poll_ (struct MHD_Connection *con)
+ MHD_NONNULL(1);
+#endif
+
#endif
diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c
@@ -477,6 +477,98 @@ internal_run_from_select (struct MHD_Daemon *daemon,
}
+#ifdef HTTPS_SUPPORT
+/**
+ * Process upgraded connection with a select loop.
+ * We are in our own thread, only processing @a con
+ *
+ * @param con connection to process
+ */
+void
+MHD_daemon_upgrade_connection_with_select_ (struct MHD_Connection *con)
+{
+ struct MHD_UpgradeResponseHandle *urh = con->request.urh;
+ struct MHD_Daemon *daemon = con->daemon;
+
+ while ( (0 != urh->in_buffer_size) ||
+ (0 != urh->out_buffer_size) ||
+ (0 != urh->in_buffer_used) ||
+ (0 != urh->out_buffer_used) )
+ {
+ /* use select */
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ MHD_socket max_fd;
+ int num_ready;
+ bool result;
+
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ max_fd = MHD_INVALID_SOCKET;
+ result = urh_to_fdset (urh,
+ &rs,
+ &ws,
+ &es,
+ &max_fd,
+ FD_SETSIZE);
+ if (! result)
+ {
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (con->daemon,
+ MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE,
+ _("Error preparing select\n"));
+#endif
+ break;
+ }
+ /* FIXME: does this check really needed? */
+ if (MHD_INVALID_SOCKET != max_fd)
+ {
+ struct timeval* tvp;
+ struct timeval tv;
+ if ( (con->tls_read_ready) &&
+ (urh->in_buffer_used < urh->in_buffer_size))
+ { /* No need to wait if incoming data is already pending in TLS buffers. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+ else
+ tvp = NULL;
+ num_ready = MHD_SYS_select_ (max_fd + 1,
+ &rs,
+ &ws,
+ &es,
+ tvp);
+ }
+ else
+ num_ready = 0;
+ if (num_ready < 0)
+ {
+ const int err = MHD_socket_get_error_();
+
+ if (MHD_SCKT_ERR_IS_EINTR_(err))
+ continue;
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (con->daemon,
+ MHD_SC_UNEXPECTED_SELECT_ERROR,
+ _("Error during select (%d): `%s'\n"),
+ err,
+ MHD_socket_strerr_ (err));
+#endif
+ break;
+ }
+ urh_from_fdset (urh,
+ &rs,
+ &ws,
+ &es);
+ process_urh (urh);
+ }
+}
+#endif
+
+
/**
* Run webserver operations. This method should be called by clients
* in combination with #MHD_get_fdset and #MHD_get_timeout() if the
diff --git a/src/lib/daemon_select.h b/src/lib/daemon_select.h
@@ -40,4 +40,16 @@ MHD_daemon_select_ (struct MHD_Daemon *daemon,
MHD_NONNULL(1);
+#ifdef HTTPS_SUPPORT
+/**
+ * Process upgraded connection with a select loop.
+ * We are in our own thread, only processing @a con
+ *
+ * @param con connection to process
+ */
+void
+MHD_daemon_upgrade_connection_with_select_ (struct MHD_Connection *con)
+ MHD_NONNULL(1);
+#endif
+
#endif