diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-08-28 20:51:54 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-08-28 20:51:54 +0000 |
commit | af90b3cd5169fbc49d376f4b96df1f231a577fdc (patch) | |
tree | a29ce09b6676ba7c7175178a99780397b3d4d090 | |
parent | 404538a7cf03d11bbb433e381744a6055bfb72ea (diff) | |
download | libmicrohttpd-af90b3cd5169fbc49d376f4b96df1f231a577fdc.tar.gz libmicrohttpd-af90b3cd5169fbc49d376f4b96df1f231a577fdc.zip |
-setup IO buffers for upgraded connections from memory pool - if possible
-rw-r--r-- | src/microhttpd/daemon.c | 66 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 51 | ||||
-rw-r--r-- | src/microhttpd/memorypool.c | 19 | ||||
-rw-r--r-- | src/microhttpd/memorypool.h | 13 | ||||
-rw-r--r-- | src/microhttpd/response.c | 38 |
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, | |||
2174 | static void | 2174 | static void |
2175 | process_urh (struct MHD_UpgradeResponseHandle *urh) | 2175 | process_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 | */ | ||
159 | size_t | ||
160 | MHD_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 | */ |
164 | void * | 177 | void * |
165 | MHD_pool_allocate (struct MemoryPool *pool, | 178 | MHD_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 | */ |
71 | void * | 71 | void * |
72 | MHD_pool_allocate (struct MemoryPool *pool, | 72 | MHD_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 | */ | ||
107 | size_t | ||
108 | MHD_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); |