Line data Source code
1 : #ifndef HEADER_fd_src_waltz_http_fd_http_server_h
2 : #define HEADER_fd_src_waltz_http_fd_http_server_h
3 :
4 : /* An fd_http_server is a WebSocket capable HTTP server designed to
5 : stream output messages quickly to many connected clients, where each
6 : output message can go to many (and in some cases all) clients.
7 :
8 : The primary use case is for serving ongoing RPC data to RPC
9 : subscribers, but it also serves a WebSocket stream for browser
10 : clients to show the GUI.
11 :
12 : The server does not allocate and has a built in allocation strategy
13 : and memory region for outgoing messages which the caller should use.
14 : HTTP response bodies and WebSocket frames are placed into an outgoing
15 : ring buffer, wrapping around when reaching the end, and the server
16 : will automatically evict slow clients that do not read their messages
17 : in time and would be overwritten when the buffer has wrapped fully
18 : around.
19 :
20 : Using the outgoing ring has two steps,
21 :
22 : (1) Stage data into the ring with fd_http_server_printf and
23 : fd_http_server_memcpy functions.
24 : (2) Send the staged data to clients with fd_http_server_send and
25 : fd_http_server_oring_broadcast.
26 :
27 : The server is designed to be used in a single threaded event loop
28 : and run within a tile. Server fds live in the epoll set provided
29 : at listen time; the caller calls fd_http_server_epoll_poll when the
30 : set is ready to service connections and make forward progress. */
31 :
32 : #include "../../util/fd_util_base.h"
33 : #include "../../util/net/fd_ip6.h"
34 :
35 342 : #define FD_HTTP_SERVER_ALIGN (128UL)
36 :
37 1179 : #define FD_HTTP_SERVER_METHOD_GET (0)
38 18 : #define FD_HTTP_SERVER_METHOD_POST (1)
39 0 : #define FD_HTTP_SERVER_METHOD_OPTIONS (2)
40 3 : #define FD_HTTP_SERVER_METHOD_PUT (3)
41 :
42 45 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_OK ( -1)
43 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_EVICTED ( -2)
44 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_TOO_SLOW ( -3)
45 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_EXPECTED_EOF ( -4)
46 21 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_PEER_RESET ( -5)
47 3 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_LARGE_REQUEST ( -6)
48 21 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_BAD_REQUEST ( -7)
49 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_MISSING_CONTENT_LENGTH_HEADER ( -8)
50 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_UNKNOWN_METHOD ( -9)
51 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_PATH_TOO_LONG (-10)
52 6 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_BAD_KEY (-11)
53 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_UNEXPECTED_VERSION (-12)
54 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_MISSING_KEY_HEADER (-13)
55 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_MISSING_VERSION_HEADER (-14)
56 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_BAD_MASK (-15)
57 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_UNKNOWN_OPCODE (-16)
58 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_OVERSIZE_FRAME (-17)
59 3 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_CLIENT_TOO_SLOW (-18)
60 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_MISSING_UPGRADE (-19)
61 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_EXPECTED_CONT_OPCODE (-20)
62 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_EXPECTED_TEXT_OPCODE (-21)
63 0 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_WS_CONTROL_FRAME_TOO_LARGE (-22)
64 6 : #define FD_HTTP_SERVER_CONNECTION_CLOSE_UNSUPPORTED_TRANSFER_ENCODING (-23)
65 :
66 : /* Given a FD_HTTP_SERVER_CONNECTION_CLOSE_* reason code, a reason that
67 : a HTTP connection a client was closed, produce a human readable
68 : string describing the reason. */
69 :
70 : FD_FN_CONST char const *
71 : fd_http_server_connection_close_reason_str( int reason );
72 :
73 : /* Given a FD_HTTP_SERVER_METHOD_* code, produce the string for that
74 : method. */
75 :
76 : FD_FN_CONST char const *
77 : fd_http_server_method_str( uchar method );
78 :
79 : /* Parameters needed for constructing an HTTP server. */
80 :
81 : struct fd_http_server_params {
82 : ulong treap_seed; /* Seed used to randomize connection treap priorities */
83 : ulong max_connection_cnt; /* Maximum number of concurrent HTTP/1.1 connections open. Connections are persistent and serve requests until the client closes or is evicted */
84 : ulong max_ws_connection_cnt; /* Maximum number of concurrent websocket connections open */
85 : ulong max_request_len; /* Maximum total length of an HTTP request, including the terminating \r\n\r\n and any body in the case of a POST */
86 : ulong max_ws_recv_frame_len; /* Maximum size of an incoming websocket frame from the client. Must be >= max_request_len */
87 : ulong max_ws_send_frame_cnt; /* Maximum number of outgoing websocket frames that can be queued before the client is disconnected */
88 : ulong outgoing_buffer_sz; /* Size of the outgoing data ring, which is used to stage outgoing HTTP response bodies and WebSocket frames */
89 : ulong send_buffer_sz; /* SO_SNDBUF for the listen socket, inherited by accepted sockets. Zero leaves the kernel default */
90 : int compress_websocket; /* True if large websocket messages are compressed and sent as binary websocket frames */
91 : };
92 :
93 : typedef struct fd_http_server_params fd_http_server_params_t;
94 :
95 : struct fd_http_server_request {
96 : ulong connection_id; /* Unique identifier for the connection. In [0, max_connection_cnt). The connection ID is a unique identifier for the lifetime of the connection, and will be
97 : provided to close to indicate that the connection is closed. After a connection is closed the ID may be recycled */
98 :
99 : uchar method; /* One of FD_HTTP_SERVER_METHOD_* indicating what the method of the request is */
100 : char const * path; /* The NUL termoinated path component of the request. Not sanitized and may contain arbitrary content. Path is the full HTTP path of the request, for example
101 : "/img/monkeys/gorilla.jpg" */
102 : char const * path_raw; /* The non-NUL-terminated path component backed by the connection request buffer. Valid until the response has been sent */
103 : ulong path_len; /* The length of path_raw */
104 :
105 : void * ctx; /* The user provided context pointer passed when constructing the HTTP server */
106 :
107 : struct {
108 : char const * content_type; /* The NUL terminated value of the Content-Type header of the request. Not sanitized and may contain arbitrary content. May be NULL if the header was not present */
109 : char const * accept_encoding; /* The NUL terminated value of the Accept-Encoding header of the request. Not sanitized and may contain arbitrary content. May be NULL if the header was not present */
110 : char const * if_none_match; /* The NUL terminated value of the If-None-Match header of the request. Not sanitized and may contain arbitrary content. Empty if the header was not present */
111 : int compress_websocket; /* True if the client has provided an `Sec-WebSocket-Protocol: compress-zstd` header indicating that the responder can choose to compress WebSocket frames with ZStandard. Only large (>200 bytes) Server -> Client messages are compressed */
112 : int upgrade_websocket; /* True if the client has provided an `Upgrade: websocket` header, valid `Sec-WebSocket-Key` and supported `Sec-Websocket-Version`, indicating that the
113 : responder should upgrade the connection to a WebSocket by setting `upgrade_websocket` to 1 in the response */
114 : } headers;
115 :
116 : union {
117 : struct {
118 : uchar const * body; /* The body of the HTTP request. The body is byte data, might have internal NUL characters, and may not be NUL terminated */
119 : ulong body_len; /* The length of the body of the HTTP request */
120 : } post;
121 : };
122 : };
123 :
124 : typedef struct fd_http_server_request fd_http_server_request_t;
125 :
126 : /* A response issued by the server handler function to an HTTP request.
127 :
128 : The handler should typically create response bodies via. the HTTP
129 : server functions like fd_http_server_printf. This allows the server
130 : to manage buffer lifetimes and ensure high performance. If using
131 : the server buffers, the handler should not set a static_body or
132 : static_body_len, and should instead use fd_http_server_stage_body
133 : to snap off the staging buffer contents into the body.
134 :
135 : In certain cases, it is desirable to send static content where the
136 : lifetime of the buffer is known to outlive the HTTP server. In
137 : that case, you can set body_static to non-NULL and body_len_static
138 : to the length of the body payload, and the server will send this
139 : data instead of the staged data instead.
140 :
141 : status is an HTTP status code. If status is not 200, the response
142 : body is ignored and the server will send an empty response.
143 :
144 : If upgrade_websocket is true, the connection will be upgraded to a
145 : websocket, after which the handler will begin receiving websocket
146 : frames. */
147 :
148 : struct fd_http_server_response {
149 : ulong status; /* Status code of the HTTP response */
150 : int upgrade_websocket; /* 1 if we should send a websocket upgrade response */
151 : int compress_websocket; /* 1 if we should add a `Sec-WebSocket-Protocol: compress-zstd` header to the response */
152 :
153 : char const * content_type; /* Content-Type to set in the HTTP response */
154 : char const * cache_control; /* Cache-Control to set in the HTTP response */
155 : char const * link; /* Link to set in the HTTP response */
156 : char const * content_encoding; /* Content-Encoding to set in the HTTP response */
157 : char const * vary; /* Vary to set in the HTTP response */
158 : char const * etag; /* ETag to set in the HTTP response */
159 : char const * location[2]; /* Location to set in the HTTP response (concatenated) */
160 : ulong location_len[2]; /* Lengths of the two location fragments */
161 :
162 : char const * access_control_allow_origin;
163 : char const * access_control_allow_methods;
164 : char const * access_control_allow_headers;
165 : ulong access_control_max_age;
166 :
167 : uchar const * static_body; /* Response body to send. Lifetime of response data must outlive the entire HTTP server. */
168 : ulong static_body_len; /* Length of the response body */
169 :
170 : ulong _body_off; /* Internal use only. Offset into the outgoing buffer where the body starts */
171 : ulong _body_len; /* Internal use only. Length of the body in the outgoing buffer */
172 : };
173 :
174 : typedef struct fd_http_server_response fd_http_server_response_t;
175 :
176 : struct fd_http_server_callbacks {
177 : /* Handle an incoming HTTP request. The callback must be provided
178 : and is assumed to be non-NULL. request is a representation of
179 : the incoming HTTP request. The callback should return a response
180 : which will be sent to the client. */
181 :
182 : fd_http_server_response_t ( * request )( fd_http_server_request_t const * request );
183 :
184 : /* Called when a regular HTTP connection is established. Called
185 : immediately after the connection is accepted. sockfd is the file
186 : descriptor of the socket. ctx is the user provided context pointer
187 : provided when constructing the HTTP server. The open callback can
188 : be NULL in which case the callback will not be invoked. */
189 :
190 : void ( * open )( ulong conn_id, int sockfd, void * ctx );
191 :
192 : /* Close an HTTP connection. Connections are persistent and may
193 : serve many requests, so this is not a per-request completion
194 : notification: it is called back when the connection closes, which
195 : happens after a response completes for HTTP/1.0 clients, explicit
196 : Connection: close, or pipelined requests, and otherwise when an
197 : error condition occurs, the connection is evicted, the client
198 : disconnects, or the caller force closes it by calling close. If a
199 : connection is upgraded to a WebSocket connection, a close event is
200 : first sent once the HTTP upgrade response is sent, before a ws_open
201 : event is sent. Close is not called when a WebSocket connection is
202 : closed, instead ws_close is called. reason is one of
203 : FD_HTTP_SERVER_CONNECTION_CLOSE_* indicating why the connection is
204 : being closed. ctx is the user provided context pointer provided
205 : when constructing the HTTP server. The close callback can be NULL
206 : in which case the callback will not be invoked. */
207 :
208 : void ( * close )( ulong conn_id, int reason, void * ctx );
209 :
210 : /* Called when a WebSocket is opened. ws_conn_id in [0,
211 : max_ws_connection_cnt). Connection IDs are recycled as WebSocket
212 : connections are closed. Connection IDs overlap with regular
213 : (non-WebSocket) connection IDs, but are in a distinct namespace,
214 : and WebSocket connection 0 is different from regular connection 0.
215 : ctx is the user provided context pointer provided when constructing
216 : the HTTP server. */
217 :
218 : void ( * ws_open )( ulong ws_conn_id, void * ctx );
219 :
220 : /* Called when a WebSocket message is received on the connection.
221 : data is the message data, and data_len is the length of the message
222 : data. ctx is the user provided context pointer provided when
223 : constructing the HTTP server. The data provided is valid only
224 : until the callback returns, and the buffer will be recycled again
225 : immediately. data_len is in [0, max_ws_recv_frame_len). */
226 :
227 : void ( * ws_message )( ulong ws_conn_id, uchar const * data, ulong data_len, void * ctx );
228 :
229 : /* Called when a WebSocket connection is closed. reason is one of
230 : FD_HTTP_SERVER_CONNECTION_CLOSE_* indicating why the connection was
231 : closed. ctx is the user provided context pointer provided when
232 : constructing the HTTP server. Typical reasons for closing the
233 : WebSocket include the peer disconnecting or timing out, or being
234 : evicted to make space for a new incoming connection. Also called
235 : back when the user of the API forcibly closes a connection by
236 : calling ws_close. */
237 :
238 : void ( * ws_close )( ulong ws_conn_id, int reason, void * ctx );
239 : };
240 :
241 : typedef struct fd_http_server_callbacks fd_http_server_callbacks_t;
242 :
243 : struct fd_http_server_private;
244 : typedef struct fd_http_server_private fd_http_server_t;
245 :
246 : FD_PROTOTYPES_BEGIN
247 :
248 : /* fd_http_server_{align,footprint} give the needed alignment and
249 : footprint of a memory region suitable to hold an http server.
250 :
251 : fd_http_server_new formats memory region with suitable alignment and
252 : footprint suitable for holding a http server state. Assumes shmem
253 : points on the caller to the first byte of the memory region owned by
254 : the caller to use. Returns shmem on success and NULL on failure
255 : (logs details). The memory region will be owned by the state on
256 : successful return. The caller is not joined on return.
257 :
258 : fd_http_server_join joins the caller to a http server state. Assumes
259 : shhttp points to the first byte of the memory region holding the
260 : state. Returns a local handle to the join on success (this is
261 : not necessarily a simple cast of the address) and NULL on failure
262 : (logs details).
263 :
264 : fd_http_server_leave leaves the caller's current local join to a http
265 : server state. Returns a pointer to the memory region holding the
266 : state on success (this is not necessarily a simple cast of the
267 : address) and NULL on failure (logs details). The caller is not
268 : joined on successful return.
269 :
270 : fd_http_server_delete unformats a memory region that holds a http
271 : server state. Assumes shhttp points on the caller to the first
272 : byte of the memory region holding the state and that nobody is
273 : joined. Returns a pointer to the memory region on success and NULL
274 : on failure (logs details). The caller has ownership of the memory
275 : region on successful return. */
276 :
277 : FD_FN_CONST ulong
278 : fd_http_server_align( void );
279 :
280 : FD_FN_CONST ulong
281 : fd_http_server_footprint( fd_http_server_params_t params );
282 :
283 : void *
284 : fd_http_server_new( void * shmem,
285 : fd_http_server_params_t params,
286 : fd_http_server_callbacks_t callbacks,
287 : void * callback_ctx );
288 :
289 : fd_http_server_t *
290 : fd_http_server_join( void * shhttp );
291 :
292 : void *
293 : fd_http_server_leave( fd_http_server_t * http );
294 :
295 : void *
296 : fd_http_server_delete( void * shhttp );
297 :
298 : /* fd_http_server_fd returns the file descriptor of the server. The
299 : file descriptor is used to poll for incoming connections and data
300 : on the server. */
301 :
302 : int
303 : fd_http_server_fd( fd_http_server_t * http );
304 :
305 : /* fd_http_server_listen binds and listens on the given IPv4 address
306 : and port. All server fds (listen socket and connections, present
307 : and future) are registered in the provided epoll set,
308 : level-triggered, with EPOLLOUT armed only while a connection has
309 : pending output. The server does not take ownership of epoll_fd.
310 : Logs an error and exits the process on failure. */
311 :
312 : fd_http_server_t *
313 : fd_http_server_listen( fd_http_server_t * http,
314 : int epoll_fd,
315 : uint address,
316 : ushort port );
317 :
318 : /* fd_http_server_listen6 binds and listens on the given IPv6 address
319 : and port. Logs an error and exits the process on failure.
320 :
321 : An IPv4-mapped address without a zone ID creates an AF_INET socket,
322 : any other address creates a dual stack AF_INET6 socket, which also
323 : accepts IPv4 clients if bound to the wildcard address (::). */
324 :
325 : fd_http_server_t *
326 : fd_http_server_listen6( fd_http_server_t * http,
327 : int epoll_fd,
328 : fd_ip6_addr_t const * address,
329 : ushort port );
330 :
331 : /* Close an active connection. The connection ID must be an open
332 : open connection in [0, max_connection_cnt). The connection will
333 : be forcibly (ungracefully) terminated. The connection ID is released
334 : and should not be used again, as it may be recycled for a future
335 : connection. If a close callback has been provided to the http
336 : server, it will be invoked with the reason provided. */
337 :
338 : void
339 : fd_http_server_close( fd_http_server_t * http,
340 : ulong conn_id,
341 : int reason );
342 :
343 : /* Returns 1 if the If-None-Match field value matches etag, else 0.
344 : etag is the quoted strong validator the server would serve. */
345 :
346 : int
347 : fd_http_server_etag_matches( char const * if_none_match,
348 : char const * etag );
349 :
350 : /* fd_http_server_accept_encoding_q returns the qvalue, in thousandths
351 : (0..1000), that the NUL terminated Accept-Encoding header value gives
352 : content coding `coding` (whole token, case-insensitive, RFC 9110
353 : s12.5.3); 0 if the coding is absent or has q=0. "*" is not honored;
354 : a request that accepts nothing on offer is served identity. */
355 :
356 : int
357 : fd_http_server_accept_encoding_q( char const * accept_encoding,
358 : char const * coding );
359 :
360 : /* Close an active WebSocket connection. The connection ID must be an
361 : open WebSocket connection ID in [0, max_ws_connection_cnt). The
362 : connection will be forcibly (ungracefully) terminated. The
363 : connection ID is released and should not be used again, as it may be
364 : recycled for a future WebSocket connection. If a ws_close callback
365 : has been provided to the http server, it will be invoked with the
366 : reason provided. */
367 :
368 : void
369 : fd_http_server_ws_close( fd_http_server_t * http,
370 : ulong ws_conn_id,
371 : int reason );
372 :
373 : /* fd_http_server_buffer_trunc truncates the pending message to the given length. */
374 :
375 : void
376 : fd_http_server_stage_trunc( fd_http_server_t * http,
377 : ulong len );
378 :
379 : /* fd_http_server_buffer_len returns the length of the pending message. */
380 :
381 : ulong
382 : fd_http_server_stage_len( fd_http_server_t * http );
383 :
384 : /* fd_http_server_printf appends the rendered format string fmt into the
385 : staging area of the outgoing ring buffer. Assumes http is a current
386 : local join.
387 :
388 : If appending to the ring buffer causes it to wrap around and
389 : overwrite existing data from a prior message, any connections which
390 : are still using data from the prior message will be evicted, as they
391 : cannot keep up.
392 :
393 : Once the full message has been appended into the outgoing ring buffer,
394 : the staged contents can be sent to all connected WebSocket clients of
395 : the HTTP server using fd_http_server_broadcast. This will end the
396 : current staged message so future prints go into a new message.
397 :
398 : Printing is not error-free, it is assumed that the format string is
399 : valid but the entire outgoing buffer may not be large enough to hold
400 : the printed string. In that case, the staging buffer is marked as
401 : being in an error state internally. The next call to send or
402 : broadcast will fail, returning the error, and the error state will be
403 : cleared. */
404 :
405 : void
406 : fd_http_server_printf( fd_http_server_t * http,
407 : char const * fmt,
408 : ... ) __attribute__((format (printf, 2, 3)));
409 :
410 : /* fd_http_server_memcpy appends the data provided to the end of the
411 : staging area of the outgoing ring buffer. Assumes http is a current
412 : local join.
413 :
414 : If appending to the ring buffer causes it to wrap around and
415 : overwrite existing data from a prior message, any connections which
416 : are still using data from the prior message will be evicted, as they
417 : cannot keep up.
418 :
419 : Once the full message has been appended into the outgoing ring buffer,
420 : the staged contents can be sent to all connected WebSocket clients of
421 : the HTTP server using fd_http_server_broadcast. This will end the
422 : current staged message so future prints go into a new message.
423 :
424 : Appending is not error-free, it is assumed that the data provided is
425 : valid but the entire outgoing buffer may not be large enough to hold
426 : data_len bytes. In that case, the staging buffer is marked as
427 : being in an error state internally. The next call to send or
428 : broadcast will fail, returning the error, and the error state will be
429 : cleared. */
430 :
431 : void
432 : fd_http_server_memcpy( fd_http_server_t * http,
433 : uchar const * data,
434 : ulong data_len );
435 :
436 : /* fd_http_server_append_start starts an in-place append operation.
437 : len is the amount of buffer space to reserve. Returns a pointer to
438 : len bytes to which the user should write the message to, on success.
439 : On failure (insufficient buffer space), returns NULL. */
440 :
441 : uchar *
442 : fd_http_server_append_start( fd_http_server_t * http,
443 : ulong len );
444 :
445 : /* fd_http_server_append_end finishes an earlier started in-place
446 : append. len is the number of bytes that were actually written. */
447 :
448 : void
449 : fd_http_server_append_end( fd_http_server_t * http,
450 : ulong len );
451 :
452 : /* fd_http_server_unstage unstages any data written into the staging
453 : buffer, clearing its contents. It does not advance the ring buffer
454 : usage, and no clients will be evicted. */
455 :
456 : void
457 : fd_http_server_unstage( fd_http_server_t * http );
458 :
459 : /* fd_http_server_stage_body marks the current contents of the staging
460 : buffer as the body of the response. The response is then ready to be
461 : sent to the client. Returns 0 on success and -1 on failure if the
462 : ring buffer is in an error state, and then clears the error state. */
463 :
464 : int
465 : fd_http_server_stage_body( fd_http_server_t * http,
466 : fd_http_server_response_t * response );
467 :
468 : /* Send the contents of the staging buffer as a a WebSocket message to a
469 : single client. The staging buffer is then cleared. Returns -1 on
470 : failure if the ring buffer is an error state, and then clears the
471 : error state.
472 :
473 : The contents are marked as needing to be sent to the client, but this
474 : does not block or wait for them to send, which happens async as the
475 : client is able to read. If the client reads too slow, and the
476 : staging buffer wraps around and is eventually overwritten by another
477 : printer, this client will be force disconnected as being too slow. */
478 :
479 : int
480 : fd_http_server_ws_send( fd_http_server_t * http,
481 : ulong ws_conn_id ); /* An existing, open connection. In [0, max_ws_connection_cnt) */
482 :
483 : /* Broadcast the contents of the staging buffer as a WebSocket message
484 : to all connected clients. The staging buffer is then cleared.
485 : Returns -1 on failure if the ring buffer is an error state, and then
486 : clears the error state.
487 :
488 : The contents are marked as needing to be sent to the client, but this
489 : does not block or wait for them to send, which happens async as the
490 : client is able to read. If the client reads too slow, and the
491 : staging buffer wraps around and is eventually overwritten by another
492 : printer, this client will be force disconnected as being too slow. */
493 :
494 : int
495 : fd_http_server_ws_broadcast( fd_http_server_t * http );
496 :
497 : /* fd_http_server_epoll_poll drives the server forward: a non-blocking
498 : epoll_wait on the registered set, servicing only ready connections.
499 : conn_max limits the number of fds serviced per call (clamped to
500 : [1,64]); leftover readiness stays pending in the kernel and is
501 : picked up by the next call. Returns 1 if there was any work to do
502 : on the HTTP server, or 0 otherwise. Call repeatedly until it
503 : returns 0 to drain the set. */
504 :
505 : int
506 : fd_http_server_epoll_poll( fd_http_server_t * http,
507 : ulong conn_max );
508 :
509 : FD_PROTOTYPES_END
510 :
511 : #endif /* HEADER_fd_src_waltz_http_fd_http_server_h */
|