implementing thread_main_connection_upgrade

This commit is contained in:
Christian Grothoff
2018-02-15 07:38:38 +01:00
parent 9562d1656d
commit 5c8fbeb97b
5 changed files with 218 additions and 0 deletions
+42
View File
@@ -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 */
/**
+60
View File
@@ -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 */
+12
View File
@@ -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
+92
View File
@@ -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
+12
View File
@@ -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