libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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!