mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-26 04:09:30 +03:00
-setup IO buffers for upgraded connections from memory pool - if possible
This commit is contained in:
+29
-37
@@ -2174,22 +2174,15 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
|
||||
static void
|
||||
process_urh (struct MHD_UpgradeResponseHandle *urh)
|
||||
{
|
||||
#if FIXME_BUFFERS
|
||||
// FIXME: we need buffer/buffer_size/buffer_off for
|
||||
// both directions to be somehow stored within urh.
|
||||
// (Note that despite using the same variable names
|
||||
// below, we need actually different buffers for each
|
||||
// direction.)
|
||||
|
||||
/* handle reading from HTTPS client and writing to application */
|
||||
/* handle reading from TLS client and writing to application */
|
||||
if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) &&
|
||||
(buffer_off < buffer_size) )
|
||||
(urh->in_buffer_off < urh->in_buffer_size) )
|
||||
{
|
||||
ssize_t res;
|
||||
|
||||
res = gnutls_record_recv (uri->connection->tls_session,
|
||||
&buffer[buffer_off],
|
||||
buffer_size - buffer_off);
|
||||
res = gnutls_record_recv (urh->connection->tls_session,
|
||||
&urh->in_buffer[urh->in_buffer_off],
|
||||
urh->in_buffer_size - urh->in_buffer_off);
|
||||
if ( (GNUTLS_E_AGAIN == res) ||
|
||||
(GNUTLS_E_INTERRUPTED == res) )
|
||||
{
|
||||
@@ -2197,17 +2190,17 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
|
||||
}
|
||||
else if (res > 0)
|
||||
{
|
||||
buffer_off += res;
|
||||
urh->in_buffer_off += res;
|
||||
}
|
||||
}
|
||||
if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) &&
|
||||
(buffer_off > 0) )
|
||||
(urh->in_buffer_off > 0) )
|
||||
{
|
||||
size_t res;
|
||||
|
||||
res = write (urh->mhd_socket,
|
||||
buffer,
|
||||
buffer_off);
|
||||
urh->in_buffer,
|
||||
urh->in_buffer_off);
|
||||
if (-1 == res)
|
||||
{
|
||||
/* FIXME: differenciate by errno? */
|
||||
@@ -2215,29 +2208,29 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer_off != res)
|
||||
if (urh->in_buffer_off != res)
|
||||
{
|
||||
memmove (buffer,
|
||||
&buffer[res],
|
||||
buffer_off - res);
|
||||
buffer_off -= res;
|
||||
memmove (urh->in_buffer,
|
||||
&urh->in_buffer[res],
|
||||
urh->in_buffer_off - res);
|
||||
urh->in_buffer_off -= res;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_off = 0;
|
||||
urh->in_buffer_off = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* handle reading from application and writing to HTTPS client */
|
||||
if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) &&
|
||||
(buffer_off < buffer_size) )
|
||||
(urh->out_buffer_off < urh->out_buffer_size) )
|
||||
{
|
||||
size_t res;
|
||||
|
||||
res = read (urh->mhd_socket,
|
||||
&buffer[buffer_off],
|
||||
buffer_size - buffer_off);
|
||||
&urh->out_buffer[urh->out_buffer_off],
|
||||
urh->out_buffer_size - urh->out_buffer_off);
|
||||
if (-1 == res)
|
||||
{
|
||||
/* FIXME: differenciate by errno? */
|
||||
@@ -2245,17 +2238,17 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_off += res;
|
||||
urh->out_buffer_off += res;
|
||||
}
|
||||
}
|
||||
if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) &&
|
||||
(buffer_off > 0) )
|
||||
(urh->out_buffer_off > 0) )
|
||||
{
|
||||
ssize_t res;
|
||||
|
||||
res = gnutls_record_send (uri->connection->tls_session,
|
||||
buffer,
|
||||
buffer_off);
|
||||
res = gnutls_record_send (urh->connection->tls_session,
|
||||
urh->out_buffer,
|
||||
urh->out_buffer_off);
|
||||
if ( (GNUTLS_E_AGAIN == res) ||
|
||||
(GNUTLS_E_INTERRUPTED == res) )
|
||||
{
|
||||
@@ -2263,20 +2256,19 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
|
||||
}
|
||||
else if (res > 0)
|
||||
{
|
||||
if (buffer_off != res)
|
||||
if (urh->out_buffer_off != res)
|
||||
{
|
||||
memmove (buffer,
|
||||
&buffer[res],
|
||||
buffer_off - res);
|
||||
buffer_off -= res;
|
||||
memmove (urh->out_buffer,
|
||||
&urh->out_buffer[res],
|
||||
urh->out_buffer_off - res);
|
||||
urh->out_buffer_off -= res;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_off = 0;
|
||||
urh->out_buffer_off = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -887,6 +887,17 @@ struct MHD_Connection
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Buffer we use for upgrade response handling in the unlikely
|
||||
* case where the memory pool was so small it had no buffer
|
||||
* capacity left. Note that we don't expect to _ever_ use this
|
||||
* buffer, so it's mostly wasted memory (except that it allows
|
||||
* us to handle a tricky error condition nicely). So no need to
|
||||
* make this one big. Applications that want to perform well
|
||||
* should just pick an adequate size for the memory pools.
|
||||
*/
|
||||
#define RESERVE_EBUF_SIZE 8
|
||||
|
||||
/**
|
||||
* Handle given to the application to manage special
|
||||
* actions relating to MHD responses that "upgrade"
|
||||
@@ -912,6 +923,40 @@ struct MHD_UpgradeResponseHandle
|
||||
*/
|
||||
struct MHD_UpgradeResponseHandle *prev;
|
||||
|
||||
/**
|
||||
* The buffer for receiving data from TLS to
|
||||
* be passed to the application. Contains @e in_buffer_size
|
||||
* bytes. Do not free!
|
||||
*/
|
||||
char *in_buffer;
|
||||
|
||||
/**
|
||||
* The buffer for receiving data from the application to
|
||||
* be passed to TLS. Contains @e out_buffer_size
|
||||
* bytes. Do not free!
|
||||
*/
|
||||
char *out_buffer;
|
||||
|
||||
/**
|
||||
* Size of the @e in_buffer
|
||||
*/
|
||||
size_t in_buffer_size;
|
||||
|
||||
/**
|
||||
* Size of the @e out_buffer
|
||||
*/
|
||||
size_t out_buffer_size;
|
||||
|
||||
/**
|
||||
* Number of bytes actually in use in the @e in_buffer
|
||||
*/
|
||||
size_t in_buffer_off;
|
||||
|
||||
/**
|
||||
* Number of bytes actually in use in the @e out_buffer
|
||||
*/
|
||||
size_t out_buffer_off;
|
||||
|
||||
/**
|
||||
* The socket we gave to the application (r/w).
|
||||
*/
|
||||
@@ -932,6 +977,12 @@ struct MHD_UpgradeResponseHandle
|
||||
* IO-state of the @e connection's socket.
|
||||
*/
|
||||
enum MHD_EpollState celi_client;
|
||||
|
||||
/**
|
||||
* Emergency IO buffer we use in case the memory pool has literally
|
||||
* nothing left.
|
||||
*/
|
||||
char e_buf[RESERVE_EBUF_SIZE];
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -150,6 +150,19 @@ MHD_pool_destroy (struct MemoryPool *pool)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check how much memory is left in the @a pool
|
||||
*
|
||||
* @param pool pool to check
|
||||
* @return number of bytes still available in @a pool
|
||||
*/
|
||||
size_t
|
||||
MHD_pool_get_free (struct MemoryPool *pool)
|
||||
{
|
||||
return (pool->end - pool->pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate size bytes from the pool.
|
||||
*
|
||||
@@ -163,7 +176,8 @@ MHD_pool_destroy (struct MemoryPool *pool)
|
||||
*/
|
||||
void *
|
||||
MHD_pool_allocate (struct MemoryPool *pool,
|
||||
size_t size, int from_end)
|
||||
size_t size,
|
||||
int from_end)
|
||||
{
|
||||
void *ret;
|
||||
size_t asize;
|
||||
@@ -171,7 +185,8 @@ MHD_pool_allocate (struct MemoryPool *pool,
|
||||
asize = ROUND_TO_ALIGN (size);
|
||||
if ( (0 == asize) && (0 != size) )
|
||||
return NULL; /* size too close to SIZE_MAX */
|
||||
if ((pool->pos + asize > pool->end) || (pool->pos + asize < pool->pos))
|
||||
if ( (pool->pos + asize > pool->end) ||
|
||||
(pool->pos + asize < pool->pos))
|
||||
return NULL;
|
||||
if (from_end == MHD_YES)
|
||||
{
|
||||
|
||||
@@ -70,7 +70,8 @@ MHD_pool_destroy (struct MemoryPool *pool);
|
||||
*/
|
||||
void *
|
||||
MHD_pool_allocate (struct MemoryPool *pool,
|
||||
size_t size, int from_end);
|
||||
size_t size,
|
||||
int from_end);
|
||||
|
||||
|
||||
/**
|
||||
@@ -97,6 +98,16 @@ MHD_pool_reallocate (struct MemoryPool *pool,
|
||||
size_t new_size);
|
||||
|
||||
|
||||
/**
|
||||
* Check how much memory is left in the @a pool
|
||||
*
|
||||
* @param pool pool to check
|
||||
* @return number of bytes still available in @a pool
|
||||
*/
|
||||
size_t
|
||||
MHD_pool_get_free (struct MemoryPool *pool);
|
||||
|
||||
|
||||
/**
|
||||
* Clear all entries from the memory pool except
|
||||
* for @a keep of the given @a copy_bytes. The pointer
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "mhd_sockets.h"
|
||||
#include "mhd_itc.h"
|
||||
#include "connection.h"
|
||||
#include "memorypool.h"
|
||||
|
||||
|
||||
#if defined(_WIN32) && defined(MHD_W32_MUTEX_)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
@@ -667,12 +669,19 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
|
||||
urh = malloc (sizeof (struct MHD_UpgradeResponseHandle));
|
||||
if (NULL == urh)
|
||||
return MHD_NO;
|
||||
memset (urh,
|
||||
0,
|
||||
sizeof (struct MHD_UpgradeResponseHandle));
|
||||
urh->connection = connection;
|
||||
rbo = connection->read_buffer_offset;
|
||||
connection->read_buffer_offset = 0;
|
||||
#if HTTPS_SUPPORT
|
||||
if (0 != (daemon->options & MHD_USE_SSL) )
|
||||
{
|
||||
struct MemoryPool *pool;
|
||||
size_t avail;
|
||||
char *buf;
|
||||
|
||||
/* FIXME: this is non-portable for now; W32 port pending... */
|
||||
if (0 != socketpair (AF_UNIX,
|
||||
SOCK_STREAM,
|
||||
@@ -698,9 +707,34 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
|
||||
free (urh);
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
urh->app_socket = sv[0];
|
||||
urh->mhd_socket = sv[1];
|
||||
pool = connection->pool;
|
||||
avail = MHD_pool_get_free (pool);
|
||||
if (avail < 8)
|
||||
{
|
||||
/* connection's pool is totally at the limit,
|
||||
use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
|
||||
avail = RESERVE_EBUF_SIZE;
|
||||
buf = urh->e_buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal case: grab all remaining memory from the
|
||||
connection's pool for the IO buffers; the connection
|
||||
certainly won't need it anymore as we've upgraded
|
||||
to another protocol. */
|
||||
buf = MHD_pool_allocate (pool,
|
||||
avail,
|
||||
MHD_NO);
|
||||
}
|
||||
/* use half the buffer for inbound, half for outbound */
|
||||
avail /= 2;
|
||||
urh->in_buffer_size = avail;
|
||||
urh->out_buffer_size = avail;
|
||||
urh->in_buffer = buf;
|
||||
urh->out_buffer = &buf[avail];
|
||||
/* hand over internal socket to application */
|
||||
response->upgrade_handler (response->upgrade_handler_cls,
|
||||
connection,
|
||||
connection->client_context,
|
||||
@@ -717,6 +751,8 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
|
||||
/* FIXME: is it possible we did not fully drain the client
|
||||
socket yet and are thus read-ready already? This may
|
||||
matter if we are in epoll() edge triggered mode... */
|
||||
/* Launch IO processing by the event loop */
|
||||
/* FIXME: this will not work (yet) for thread-per-connection processing */
|
||||
DLL_insert (connection->daemon->urh_head,
|
||||
connection->daemon->urh_tail,
|
||||
urh);
|
||||
|
||||
Reference in New Issue
Block a user