aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-28 20:51:54 +0000
committerChristian Grothoff <christian@grothoff.org>2016-08-28 20:51:54 +0000
commitaf90b3cd5169fbc49d376f4b96df1f231a577fdc (patch)
treea29ce09b6676ba7c7175178a99780397b3d4d090
parent404538a7cf03d11bbb433e381744a6055bfb72ea (diff)
downloadlibmicrohttpd-af90b3cd5169fbc49d376f4b96df1f231a577fdc.tar.gz
libmicrohttpd-af90b3cd5169fbc49d376f4b96df1f231a577fdc.zip
-setup IO buffers for upgraded connections from memory pool - if possible
-rw-r--r--src/microhttpd/daemon.c66
-rw-r--r--src/microhttpd/internal.h51
-rw-r--r--src/microhttpd/memorypool.c19
-rw-r--r--src/microhttpd/memorypool.h13
-rw-r--r--src/microhttpd/response.c38
5 files changed, 146 insertions, 41 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index dbf21e18..a25fe358 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -2174,22 +2174,15 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
2174static void 2174static void
2175process_urh (struct MHD_UpgradeResponseHandle *urh) 2175process_urh (struct MHD_UpgradeResponseHandle *urh)
2176{ 2176{
2177#if FIXME_BUFFERS 2177 /* handle reading from TLS client and writing to application */
2178 // FIXME: we need buffer/buffer_size/buffer_off for
2179 // both directions to be somehow stored within urh.
2180 // (Note that despite using the same variable names
2181 // below, we need actually different buffers for each
2182 // direction.)
2183
2184 /* handle reading from HTTPS client and writing to application */
2185 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) && 2178 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) &&
2186 (buffer_off < buffer_size) ) 2179 (urh->in_buffer_off < urh->in_buffer_size) )
2187 { 2180 {
2188 ssize_t res; 2181 ssize_t res;
2189 2182
2190 res = gnutls_record_recv (uri->connection->tls_session, 2183 res = gnutls_record_recv (urh->connection->tls_session,
2191 &buffer[buffer_off], 2184 &urh->in_buffer[urh->in_buffer_off],
2192 buffer_size - buffer_off); 2185 urh->in_buffer_size - urh->in_buffer_off);
2193 if ( (GNUTLS_E_AGAIN == res) || 2186 if ( (GNUTLS_E_AGAIN == res) ||
2194 (GNUTLS_E_INTERRUPTED == res) ) 2187 (GNUTLS_E_INTERRUPTED == res) )
2195 { 2188 {
@@ -2197,17 +2190,17 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2197 } 2190 }
2198 else if (res > 0) 2191 else if (res > 0)
2199 { 2192 {
2200 buffer_off += res; 2193 urh->in_buffer_off += res;
2201 } 2194 }
2202 } 2195 }
2203 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) && 2196 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) &&
2204 (buffer_off > 0) ) 2197 (urh->in_buffer_off > 0) )
2205 { 2198 {
2206 size_t res; 2199 size_t res;
2207 2200
2208 res = write (urh->mhd_socket, 2201 res = write (urh->mhd_socket,
2209 buffer, 2202 urh->in_buffer,
2210 buffer_off); 2203 urh->in_buffer_off);
2211 if (-1 == res) 2204 if (-1 == res)
2212 { 2205 {
2213 /* FIXME: differenciate by errno? */ 2206 /* FIXME: differenciate by errno? */
@@ -2215,29 +2208,29 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2215 } 2208 }
2216 else 2209 else
2217 { 2210 {
2218 if (buffer_off != res) 2211 if (urh->in_buffer_off != res)
2219 { 2212 {
2220 memmove (buffer, 2213 memmove (urh->in_buffer,
2221 &buffer[res], 2214 &urh->in_buffer[res],
2222 buffer_off - res); 2215 urh->in_buffer_off - res);
2223 buffer_off -= res; 2216 urh->in_buffer_off -= res;
2224 } 2217 }
2225 else 2218 else
2226 { 2219 {
2227 buffer_off = 0; 2220 urh->in_buffer_off = 0;
2228 } 2221 }
2229 } 2222 }
2230 } 2223 }
2231 2224
2232 /* handle reading from application and writing to HTTPS client */ 2225 /* handle reading from application and writing to HTTPS client */
2233 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) && 2226 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) &&
2234 (buffer_off < buffer_size) ) 2227 (urh->out_buffer_off < urh->out_buffer_size) )
2235 { 2228 {
2236 size_t res; 2229 size_t res;
2237 2230
2238 res = read (urh->mhd_socket, 2231 res = read (urh->mhd_socket,
2239 &buffer[buffer_off], 2232 &urh->out_buffer[urh->out_buffer_off],
2240 buffer_size - buffer_off); 2233 urh->out_buffer_size - urh->out_buffer_off);
2241 if (-1 == res) 2234 if (-1 == res)
2242 { 2235 {
2243 /* FIXME: differenciate by errno? */ 2236 /* FIXME: differenciate by errno? */
@@ -2245,17 +2238,17 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2245 } 2238 }
2246 else 2239 else
2247 { 2240 {
2248 buffer_off += res; 2241 urh->out_buffer_off += res;
2249 } 2242 }
2250 } 2243 }
2251 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) && 2244 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) &&
2252 (buffer_off > 0) ) 2245 (urh->out_buffer_off > 0) )
2253 { 2246 {
2254 ssize_t res; 2247 ssize_t res;
2255 2248
2256 res = gnutls_record_send (uri->connection->tls_session, 2249 res = gnutls_record_send (urh->connection->tls_session,
2257 buffer, 2250 urh->out_buffer,
2258 buffer_off); 2251 urh->out_buffer_off);
2259 if ( (GNUTLS_E_AGAIN == res) || 2252 if ( (GNUTLS_E_AGAIN == res) ||
2260 (GNUTLS_E_INTERRUPTED == res) ) 2253 (GNUTLS_E_INTERRUPTED == res) )
2261 { 2254 {
@@ -2263,20 +2256,19 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2263 } 2256 }
2264 else if (res > 0) 2257 else if (res > 0)
2265 { 2258 {
2266 if (buffer_off != res) 2259 if (urh->out_buffer_off != res)
2267 { 2260 {
2268 memmove (buffer, 2261 memmove (urh->out_buffer,
2269 &buffer[res], 2262 &urh->out_buffer[res],
2270 buffer_off - res); 2263 urh->out_buffer_off - res);
2271 buffer_off -= res; 2264 urh->out_buffer_off -= res;
2272 } 2265 }
2273 else 2266 else
2274 { 2267 {
2275 buffer_off = 0; 2268 urh->out_buffer_off = 0;
2276 } 2269 }
2277 } 2270 }
2278 } 2271 }
2279#endif
2280} 2272}
2281#endif 2273#endif
2282 2274
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 01d72950..9f0faba7 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -888,6 +888,17 @@ struct MHD_Connection
888 888
889 889
890/** 890/**
891 * Buffer we use for upgrade response handling in the unlikely
892 * case where the memory pool was so small it had no buffer
893 * capacity left. Note that we don't expect to _ever_ use this
894 * buffer, so it's mostly wasted memory (except that it allows
895 * us to handle a tricky error condition nicely). So no need to
896 * make this one big. Applications that want to perform well
897 * should just pick an adequate size for the memory pools.
898 */
899#define RESERVE_EBUF_SIZE 8
900
901/**
891 * Handle given to the application to manage special 902 * Handle given to the application to manage special
892 * actions relating to MHD responses that "upgrade" 903 * actions relating to MHD responses that "upgrade"
893 * the HTTP protocol (i.e. to WebSockets). 904 * the HTTP protocol (i.e. to WebSockets).
@@ -913,6 +924,40 @@ struct MHD_UpgradeResponseHandle
913 struct MHD_UpgradeResponseHandle *prev; 924 struct MHD_UpgradeResponseHandle *prev;
914 925
915 /** 926 /**
927 * The buffer for receiving data from TLS to
928 * be passed to the application. Contains @e in_buffer_size
929 * bytes. Do not free!
930 */
931 char *in_buffer;
932
933 /**
934 * The buffer for receiving data from the application to
935 * be passed to TLS. Contains @e out_buffer_size
936 * bytes. Do not free!
937 */
938 char *out_buffer;
939
940 /**
941 * Size of the @e in_buffer
942 */
943 size_t in_buffer_size;
944
945 /**
946 * Size of the @e out_buffer
947 */
948 size_t out_buffer_size;
949
950 /**
951 * Number of bytes actually in use in the @e in_buffer
952 */
953 size_t in_buffer_off;
954
955 /**
956 * Number of bytes actually in use in the @e out_buffer
957 */
958 size_t out_buffer_off;
959
960 /**
916 * The socket we gave to the application (r/w). 961 * The socket we gave to the application (r/w).
917 */ 962 */
918 MHD_socket app_socket; 963 MHD_socket app_socket;
@@ -932,6 +977,12 @@ struct MHD_UpgradeResponseHandle
932 * IO-state of the @e connection's socket. 977 * IO-state of the @e connection's socket.
933 */ 978 */
934 enum MHD_EpollState celi_client; 979 enum MHD_EpollState celi_client;
980
981 /**
982 * Emergency IO buffer we use in case the memory pool has literally
983 * nothing left.
984 */
985 char e_buf[RESERVE_EBUF_SIZE];
935#endif 986#endif
936 987
937}; 988};
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c
index 037cbf57..7cc4f286 100644
--- a/src/microhttpd/memorypool.c
+++ b/src/microhttpd/memorypool.c
@@ -151,6 +151,19 @@ MHD_pool_destroy (struct MemoryPool *pool)
151 151
152 152
153/** 153/**
154 * Check how much memory is left in the @a pool
155 *
156 * @param pool pool to check
157 * @return number of bytes still available in @a pool
158 */
159size_t
160MHD_pool_get_free (struct MemoryPool *pool)
161{
162 return (pool->end - pool->pos);
163}
164
165
166/**
154 * Allocate size bytes from the pool. 167 * Allocate size bytes from the pool.
155 * 168 *
156 * @param pool memory pool to use for the operation 169 * @param pool memory pool to use for the operation
@@ -163,7 +176,8 @@ MHD_pool_destroy (struct MemoryPool *pool)
163 */ 176 */
164void * 177void *
165MHD_pool_allocate (struct MemoryPool *pool, 178MHD_pool_allocate (struct MemoryPool *pool,
166 size_t size, int from_end) 179 size_t size,
180 int from_end)
167{ 181{
168 void *ret; 182 void *ret;
169 size_t asize; 183 size_t asize;
@@ -171,7 +185,8 @@ MHD_pool_allocate (struct MemoryPool *pool,
171 asize = ROUND_TO_ALIGN (size); 185 asize = ROUND_TO_ALIGN (size);
172 if ( (0 == asize) && (0 != size) ) 186 if ( (0 == asize) && (0 != size) )
173 return NULL; /* size too close to SIZE_MAX */ 187 return NULL; /* size too close to SIZE_MAX */
174 if ((pool->pos + asize > pool->end) || (pool->pos + asize < pool->pos)) 188 if ( (pool->pos + asize > pool->end) ||
189 (pool->pos + asize < pool->pos))
175 return NULL; 190 return NULL;
176 if (from_end == MHD_YES) 191 if (from_end == MHD_YES)
177 { 192 {
diff --git a/src/microhttpd/memorypool.h b/src/microhttpd/memorypool.h
index 84135c37..36136af8 100644
--- a/src/microhttpd/memorypool.h
+++ b/src/microhttpd/memorypool.h
@@ -70,7 +70,8 @@ MHD_pool_destroy (struct MemoryPool *pool);
70 */ 70 */
71void * 71void *
72MHD_pool_allocate (struct MemoryPool *pool, 72MHD_pool_allocate (struct MemoryPool *pool,
73 size_t size, int from_end); 73 size_t size,
74 int from_end);
74 75
75 76
76/** 77/**
@@ -98,6 +99,16 @@ MHD_pool_reallocate (struct MemoryPool *pool,
98 99
99 100
100/** 101/**
102 * Check how much memory is left in the @a pool
103 *
104 * @param pool pool to check
105 * @return number of bytes still available in @a pool
106 */
107size_t
108MHD_pool_get_free (struct MemoryPool *pool);
109
110
111/**
101 * Clear all entries from the memory pool except 112 * Clear all entries from the memory pool except
102 * for @a keep of the given @a copy_bytes. The pointer 113 * for @a keep of the given @a copy_bytes. The pointer
103 * returned should be a buffer of @a new_size where 114 * returned should be a buffer of @a new_size where
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 5b67b983..e778ed7f 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -32,6 +32,8 @@
32#include "mhd_sockets.h" 32#include "mhd_sockets.h"
33#include "mhd_itc.h" 33#include "mhd_itc.h"
34#include "connection.h" 34#include "connection.h"
35#include "memorypool.h"
36
35 37
36#if defined(_WIN32) && defined(MHD_W32_MUTEX_) 38#if defined(_WIN32) && defined(MHD_W32_MUTEX_)
37#ifndef WIN32_LEAN_AND_MEAN 39#ifndef WIN32_LEAN_AND_MEAN
@@ -667,12 +669,19 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
667 urh = malloc (sizeof (struct MHD_UpgradeResponseHandle)); 669 urh = malloc (sizeof (struct MHD_UpgradeResponseHandle));
668 if (NULL == urh) 670 if (NULL == urh)
669 return MHD_NO; 671 return MHD_NO;
672 memset (urh,
673 0,
674 sizeof (struct MHD_UpgradeResponseHandle));
670 urh->connection = connection; 675 urh->connection = connection;
671 rbo = connection->read_buffer_offset; 676 rbo = connection->read_buffer_offset;
672 connection->read_buffer_offset = 0; 677 connection->read_buffer_offset = 0;
673#if HTTPS_SUPPORT 678#if HTTPS_SUPPORT
674 if (0 != (daemon->options & MHD_USE_SSL) ) 679 if (0 != (daemon->options & MHD_USE_SSL) )
675 { 680 {
681 struct MemoryPool *pool;
682 size_t avail;
683 char *buf;
684
676 /* FIXME: this is non-portable for now; W32 port pending... */ 685 /* FIXME: this is non-portable for now; W32 port pending... */
677 if (0 != socketpair (AF_UNIX, 686 if (0 != socketpair (AF_UNIX,
678 SOCK_STREAM, 687 SOCK_STREAM,
@@ -698,9 +707,34 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
698 free (urh); 707 free (urh);
699 return MHD_NO; 708 return MHD_NO;
700 } 709 }
701
702 urh->app_socket = sv[0]; 710 urh->app_socket = sv[0];
703 urh->mhd_socket = sv[1]; 711 urh->mhd_socket = sv[1];
712 pool = connection->pool;
713 avail = MHD_pool_get_free (pool);
714 if (avail < 8)
715 {
716 /* connection's pool is totally at the limit,
717 use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
718 avail = RESERVE_EBUF_SIZE;
719 buf = urh->e_buf;
720 }
721 else
722 {
723 /* Normal case: grab all remaining memory from the
724 connection's pool for the IO buffers; the connection
725 certainly won't need it anymore as we've upgraded
726 to another protocol. */
727 buf = MHD_pool_allocate (pool,
728 avail,
729 MHD_NO);
730 }
731 /* use half the buffer for inbound, half for outbound */
732 avail /= 2;
733 urh->in_buffer_size = avail;
734 urh->out_buffer_size = avail;
735 urh->in_buffer = buf;
736 urh->out_buffer = &buf[avail];
737 /* hand over internal socket to application */
704 response->upgrade_handler (response->upgrade_handler_cls, 738 response->upgrade_handler (response->upgrade_handler_cls,
705 connection, 739 connection,
706 connection->client_context, 740 connection->client_context,
@@ -717,6 +751,8 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
717 /* FIXME: is it possible we did not fully drain the client 751 /* FIXME: is it possible we did not fully drain the client
718 socket yet and are thus read-ready already? This may 752 socket yet and are thus read-ready already? This may
719 matter if we are in epoll() edge triggered mode... */ 753 matter if we are in epoll() edge triggered mode... */
754 /* Launch IO processing by the event loop */
755 /* FIXME: this will not work (yet) for thread-per-connection processing */
720 DLL_insert (connection->daemon->urh_head, 756 DLL_insert (connection->daemon->urh_head,
721 connection->daemon->urh_tail, 757 connection->daemon->urh_tail,
722 urh); 758 urh);