external.inc (11650B)
1 A modern HTTP server should handle multiple concurrent connections 2 and an application embedding an HTTP server into its process may 3 possibly need do other work not directly related to handling HTTP 4 requests. 5 6 There are several approches for how an HTTP server can handle 7 concurrent requests: 8 9 @itemize 10 @item start a new process per request, or use a pool of processes 11 @item run a (new) thread per request, or use a pool of threads 12 @item use an event loop to learn when data can be received from or 13 sent to the client (based on system calls like @code{select()} 14 or @code{epoll()}) 15 @end itemize 16 17 Finally, these different approaches are not mutually exclusive, 18 it is possible to use multiple processes with multiple threads 19 each using an event loop. The good news is that MHD supports 20 all of these. 21 22 The @emph{initially} simplest approach is usually to simply tell MHD 23 to start one or more new threads to handle connections, allowing the 24 main application to continue doing its work in its own separate 25 threats. The disadvantage of this approach is that concurrent 26 accesses between the main application's threads and MHD's threads 27 require the use of synchronization primitives (such as mutexes) to 28 avoid data races. Furthermore, threads are not available on all 29 platforms and require additional stack space for each thread. 30 31 An alternative to using threads is to integrate MHD's request 32 processing into the main (event) loop of the application. This is 33 particularly suitable for applications that already have an event loop 34 and that avoid using threads for performance, portability, 35 maintainability or security reasons. We call this approach the 36 use of MHD with an @emph{external} event loop, in contrast to 37 MHD creating its own threads with an @emph{internal} event loop. 38 39 This chapter describes MHD's API for integrating a daemon with 40 an external event loop. Any external event loop needs to ask 41 MHD for three pieces of information: 42 43 @itemize 44 @item The set of sockets to wait on for status changes; 45 @item for each socket the types of status changes to 46 wait for (ready-to-read, ready-to-write, failed); 47 @item a timeout for when to wake up MHD again even if nothing 48 else happened. 49 @end itemize 50 51 Depending on the operating system and the event loop style, the 52 representation of these bits of information may differ; in particular, 53 with @code{epoll()} MHD might even give the application a single 54 handle that represents the entire set. Finally, we need to 55 distinguish between event loops that support edge triggers (only 56 notifying when the status changed to ready) and level triggers 57 (notifying about the socket being ready, even if it simply remained 58 ready). 59 60 61 @anchor{external-registration} 62 @node libmicrohttpd-external-registration 63 @section The @code{MHD_SocketRegistrationUpdateCallback} 64 65 External event loops are enabled using either 66 @ref{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL} or 67 @ref{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE} depending 68 on whether edge or level triggers should be used. In both 69 cases, the application must provide a function of type 70 @code{MHD_SocketRegistrationUpdateCallback} when enabling 71 the option. 72 73 @anchor{MHD_SocketRegistrationUpdateCallback} 74 @deftypefn {Function Pointer} {MHD_APP_SOCKET_CNTX_TYPE *} (*MHD_SocketRegistrationUpdateCallback) (void *cls, MHD_Socket fd, enum MHD_FdState watch_for, MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old, struct MHD_EventUpdateContext *ecb_cntx) 75 76 Type of a function for registration or de-registration of the sockets to 77 watch in the external event loop. 78 79 Implementations of this callback must not call 80 @ref{MHD_daemon_destroy,,@code{MHD_daemon_destroy()}}, 81 @ref{MHD_daemon_quiesce,,@code{MHD_daemon_quiesce()}} or 82 @ref{MHD_daemon_add_connection,,@code{MHD_daemon_add_connection()}}. 83 84 @table @var 85 @item cls 86 custom value provided by the application at callback registration time; 87 88 @item fd 89 the socket to watch; 90 91 @item watch_for 92 the states of the @var{fd} to watch, if set to 93 @code{MHD_FD_STATE_NONE} the socket must be de-registred 94 and the resources from the application state in the @var{app_cntx_old} should 95 be released; 96 97 @item app_cntx_old 98 the old application-defined context for the socket, 99 @code{NULL} if the @var{fd} socket was not registered before; 100 101 @item ecb_cntx 102 the context handle to be used 103 with @code{MHD_daemon_event_update()}; 104 @end table 105 106 Implementations must return the new socket context to be used with 107 this @var{fd}. Implementations must return @code{NULL} on de-registration 108 and on error (in which case the connection to the client will be 109 closed). 110 111 @end deftypefn 112 113 The registration update callback is provided with @var{fd} which 114 is the socket for which the external event loop should become 115 active. The use of @ref{MHD_Socket,,@code{MHD_Socket}} is for 116 portability. The @var{watch_for} determines the types of 117 triggers the external event loop should use as triggers. 118 119 120 @deftp {Enumeration} MHD_FdState 121 122 The network status of the socket or the type of trigger to wait for. 123 When set by MHD (for @code{MHD_SocketRegistrationUpdateCallback} and 124 similar APIs) it indicates a request by MHD to watch for specific 125 socket state: readiness for receiving the data, readiness for 126 sending the data and/or an exception state of the socket. 127 When set by application (and provided to 128 @code{MHD_daemon_event_update()} and similar APIs) 129 it must indicate the actual status of the socket. 130 131 In both cases, the actual value may be a bitwise OR 132 combination of @code{MHD_FD_STATE_RECV}, 133 @code{MHD_FD_STATE_SEND} and @code{MHD_FD_STATE_EXCEPT}. 134 135 @table @code 136 @item MHD_FD_STATE_NONE 137 The socket is not ready for receiving or sending and 138 does not have any exceptional state. 139 The state is used for de-registration of sockets in 140 a @code{MHD_SocketRegistrationUpdateCallback}. 141 142 @item MHD_FD_STATE_RECV 143 Indicates that socket should be watched for incoming data 144 (when set for @code{MHD_SocketRegistrationUpdateCallback}) 145 or that a socket has incoming data ready to read (when used for 146 @code{MHD_daemon_event_update()}); 147 148 @item MHD_FD_STATE_SEND 149 Indicates that socket should be watched for availability for sending 150 (when set for @code{MHD_SocketRegistrationUpdateCallback}) 151 or that a socket is ready for transmission of data (when used 152 for @code{MHD_daemon_event_update()}); 153 154 @item MHD_FD_STATE_EXCEPT 155 Indicates that socket should be watched for disconnect, out-of-band 156 data available or high priority data available (when set by 157 @code{MHD_SocketRegistrationUpdateCallback}) 158 or that a socket has been disconnected, has out-of-band data available or 159 has high priority data available (when used for 160 @code{MHD_daemon_event_update()}). This status must not include 161 signalling the ``remote peer shut down writing'' (FIN) status. 162 163 @item MHD_FD_STATE_RECV_SEND 164 Combination of @code{MHD_FD_STATE_RECV} and @code{MHD_FD_STATE_SEND}; 165 166 @item MHD_FD_STATE_RECV_EXCEPT 167 Combination of @code{MHD_FD_STATE_RECV} and @code{MHD_FD_STATE_EXCEPT}; 168 169 @item MHD_FD_STATE_SEND_EXCEPT 170 Combination of @code{MHD_FD_STATE_SEND} and @code{MHD_FD_STATE_EXCEPT}; 171 172 @item MHD_FD_STATE_RECV_SEND_EXCEPT 173 Combination of @code{MHD_FD_STATE_RECV}, @code{MHD_FD_STATE_SEND} 174 and @code{MHD_FD_STATE_EXCEPT}. 175 176 @end table 177 @end deftp 178 179 @anchor{MHD_APP_SOCKET_CNTX_TYPE} 180 The @var{app_cntx_old} argument is a bit unusual: 181 @code{MHD_APP_SOCKET_CNTX_TYPE} is actually a macro that @emph{should} 182 be defined by the application @emph{before} including 183 ``microhttpd2.h''. If the application does not define this type, it 184 will be defined as @code{void}. The use of this argument is to give 185 the application the opportunity to associate its own data structure 186 with the external event loop trigger responsibility given to it by 187 MHD. When called to register a @var{fd} for the first time, MHD will 188 always pass @code{NULL}. Subsequently, MHD will pass whatever value 189 was returned by the @code{MHD_SocketRegistrationUpdateCallback}. By 190 giving MHD a pointer to whatever data structure the event loop of the 191 application wants to use, applications can avoid iterating over their 192 internal data structures to find an entry for @var{fd}. The use of 193 an application-defined macro for this type improves type-safety. 194 When MHD calls the callback to de-register a socket, the application 195 must free any of its resources associated with @var{app_cntx_old}. 196 The application must at least store the @var{ecb_cntx}. A typical 197 application will furthemore store the @var{fd} and the @var{watch_for} 198 value in the application context. 199 200 Finally, @var{ecb_cntx} is provided because after registration, the 201 application is expected to call 202 @ref{MHD_daemon_event_update,,@code{MHD_daemon_event_update()}} 203 whenever the specified type of event is triggered, and 204 @code{MHD_daemon_event_update()} requires the @var{ecb_cntx} to allow 205 MHD to understand which socket changed state. 206 207 208 @anchor{external-trigger} 209 @node libmicrohttpd-external-trigger 210 @section Notifying MHD that a socket is ready 211 212 When the application's external event loop learns that a socket 213 is ready for an event MHD registered for, it must call 214 @code{MHD_daemon_event_update()}. 215 216 217 @anchor{MHD_daemon_event_update} 218 @deftypefun void MHD_daemon_event_update (struct MHD_Daemon *daemon, struct MHD_EventUpdateContext *ecb_cntx, enum MHD_FdState fd_current_state) 219 220 Update the socket's state for MHD. 221 Must be called for every socket for which the status changed. 222 In @code{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL()} mode 223 should be called for each registered socket. 224 In @code{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE()} mode 225 should be called only when a socket becomes ready for the specified 226 event. 227 228 Available only for daemons stated in 229 @code{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL} or 230 @code{MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE} mode. 231 232 @table @var 233 @item ecb_cntx 234 context handle provided during the call 235 to the @code{MHD_SocketRegistrationUpdateCallback} 236 237 @item fd_current_state 238 the current state of the socket 239 240 @end table 241 @end deftypefun 242 243 Note that calling @code{MHD_daemon_event_update()} does not 244 cause MHD to actually work on the events: MHD will merely 245 update its internal state. To actually do work, applications 246 must still call @code{MHD_daemon_process_reg_events()}. 247 248 249 @anchor{external-runner} 250 @node libmicrohttpd-external-runner 251 @section Processing externally triggered events 252 253 @anchor{MHD_daemon_process_reg_events} 254 @deftypefun {enum MHD_StatusCode} MHD_daemon_process_reg_events (struct MHD_Daemon *daemon, uint_fast64_t *next_max_wait) 255 256 Process registered network events and updates sockets registration. 257 This function first processes @emph{all} 258 previously registered (via @code{MHD_daemon_event_update()}) 259 network events (if any) and then calls the 260 @code{MHD_SocketRegistrationUpdateCallback} 261 callback for every socket that needs to be added/updated/removed 262 from the external event loop. 263 264 This function is only available only for daemons stated in 265 @code{MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL} or 266 @code{MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE} mode. 267 268 @table @var 269 @item daemon 270 daemon to process connections of 271 272 @item next_max_wait 273 address where MHD will store the next maximum wait time in 274 microseconds to be used for the external event loop as an upper limit; 275 can be @code{NULL} (but that is uncommon as usually the external event 276 loop needs to learn the timeout). 277 278 @end table 279 280 Returns @code{MHD_SC_OK} on success, otherwise an 281 error code. 282 @end deftypefun 283 284 285 @node libmicrohttpd-external-example 286 @section External event loop example: select 287 288 The following is a simple example for how to implement 289 an external event loop using @code{select()} using 290 a level trigger. 291 292 @example c 293 @verbatiminclude examples/external-select.c 294 @end example 295 296 @c FIXME: add one for epoll() with edge trigger!