From 83beaa825f6ebee718ea6a35e7db8d28c9c57ce2 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Sat, 6 Apr 2024 19:12:10 +0200 Subject: [PATCH] microhttpd2.h: preparation --- src/include/microhttpd2.h | 1017 +++++++++++++++++++++++++------------ 1 file changed, 690 insertions(+), 327 deletions(-) diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h index 258eb5c2..9f78fe48 100644 --- a/src/include/microhttpd2.h +++ b/src/include/microhttpd2.h @@ -2614,9 +2614,617 @@ MHD_EXTERN_ void MHD_daemon_destroy (struct MHD_Daemon *daemon) MHD_FN_PAR_NONNULL_ALL_; +/* ******************* External event loop ************************ */ + +/** + * The network status of the socket. + * When set by MHD (by #MHD_get_watched_fds(), #MHD_get_watched_fds_update() and + * similar) it indicates a request to watch for specific socket state: + * readiness for receiving the data, readiness for sending the data and/or + * exception state of the socket. + * When set by application (and provided for #MHD_process_watched_fds() and + * similar) it must indicate the actual status of the socket. + * + * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV, + * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT. + * @ingroup event + */ +enum MHD_FIXED_ENUM_ MHD_FdState +{ + /** + * The socket is not ready for receiving or sending and + * does not have any exceptional state. + * The state never set by MHD, except de-registration of the sockets + * for #MHD_SocketRegistrationUpdateCallback(). + */ + MHD_FD_STATE_NONE = 0 + , + /* ** Three bit-flags ** */ + + /** + * Indicates that socket should be watched for incoming data + * (when set by #MHD_get_watched_fds()) + * / socket has incoming data ready to read (when used for + * #MHD_process_watched_fds()) + */ + MHD_FD_STATE_RECV = 1 << 0, + /** + * Indicates that socket should be watched for availability for sending + * (when set by #MHD_get_watched_fds()) + * / socket has ability to send data (when used for + * #MHD_process_watched_fds()) + */ + MHD_FD_STATE_SEND = 1 << 1, + /** + * Indicates that socket should be watched for disconnect, out-of-band + * data available or high priority data available (when set by + * #MHD_get_watched_fds()) + * / socket has been disconnected, has out-of-band data available or + * has high priority data available (when used for + * #MHD_process_watched_fds()). This status must not include "remote + * peer shut down writing" status. + * Note: #MHD_get_watched_fds() always set it as exceptions must be + * always watched. + */ + MHD_FD_STATE_EXCEPT = 1 << 2, + + /* The rest of the list is a bit-wise combination of three main + * states. Application may use three main states directly as + * a bit-mask instead of using of following values + */ + + /** + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states. + */ + MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND, + /** + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. + */ + MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, + /** + * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. + */ + MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, + /** + * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and + * #MHD_FD_STATE_EXCEPT states. + */ + MHD_FD_STATE_RECV_SEND_EXCEPT = \ + MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT +}; + +/** + * Checks whether specific @a state is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET(var,state) \ + (MHD_FD_STATE_NONE != \ + (((enum MHD_FdState) (var)) & ((enum MHD_FdState) (state)))) + +/** + * Checks whether RECV is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_RECV(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV) +/** + * Checks whether SEND is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_SEND(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND) +/** + * Checks whether EXCEPT is enabled in @a var + */ +#define MHD_FD_STATE_IS_SET_EXCEPT(var) \ + MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT) + + +/** + * Enable specific @a state in @a var + */ +#define MHD_FD_STATE_SET(var,state) \ + (var) = (enum MHD_FdState) ((var) | (state)) +/** + * Enable RECV state in @a var + */ +#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV) +/** + * Enable SEND state in @a var + */ +#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND) +/** + * Enable EXCEPT state in @a var + */ +#define MHD_FD_STATE_SET_EXCEPT(var) \ + MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT) + +/** + * Clear/disable specific @a state in @a var + */ +#define MHD_FD_STATE_CLEAR(var,state) \ + (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state))) +/** + * Clear/disable RECV state in @a var + */ +#define MHD_FD_STATE_CLEAR_RECV(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV) +/** + * Clear/disable SEND state in @a var + */ +#define MHD_FD_STATE_CLEAR_SEND(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND) +/** + * Clear/disable EXCEPT state in @a var + */ +#define MHD_FD_STATE_CLEAR_EXCEPT(var) \ + MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT) + + +/* Changes: + * + status update callback replaced with function + * + status update accepts array of updates + */ + +/** + * The context data to be used for updates of the socket state + */ +struct MHD_EventUpdateContext; + + +/* Define MHD_APP_SOCKET_CNTX_TYPE to the socket context type before + * including this header. + * This is optional, but improves the types safety. + * For example: + * #define MHD_APP_SOCKET_CNTX_TYPE struct my_structure + */ +#ifndef MHD_APP_SOCKET_CNTX_TYPE +# define MHD_APP_SOCKET_CNTX_TYPE void +#endif + +/** + * The callback for registration/de-registration of the sockets to watch. + * + * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(), + * #MHD_daemon_add_connection(). + * + * @param cls the closure + * @param fd the socket to watch + * @param watch_for the states of the @a fd to watch, if set to + * #MHD_FD_STATE_NONE the socket must be de-registred + * @param app_cntx_old the old application defined context for the socket, + * NULL if @a fd socket was not registered before + * @param ecb_cntx the context handle to be used + * with #MHD_daemon_event_update() + * @return NULL if error (to connection will be closed), + * or the new socket context + * @ingroup event + */ +typedef MHD_APP_SOCKET_CNTX_TYPE * +(MHD_FN_PAR_NONNULL_(5) + *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); + + +/** + * Update the sockets state. + * Must be called for every socket that got state updated. + * For #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL mode should be called for each + * socket. + * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or + * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. + * @param daemon the daemon handle + * @param ecb_cntx the context handle provided + * for #MHD_SocketRegistrationUpdateCallback + * @param fd_current_state the current state of the socket + */ +MHD_EXTERN_ void +MHD_daemon_event_update ( + struct MHD_Daemon *daemon, + struct MHD_EventUpdateContext *ecb_cntx, + enum MHD_FdState fd_current_state) +MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(2); + + +/** + * Perform sockets registration, process registered network events. + * + * This function first processes all registered (by MHD_daemon_event_update()) + * network events (if any) and then calls #MHD_SocketRegistrationUpdateCallback + * callback for every socket that needs to be added/updated/removed. + * + * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or + * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. + * + * @param daemon the daemon handle + * @param[out] next_max_wait the optional pointer to receive the next maximum + * wait time in microseconds to be used for sockets + * polling function, can be NULL + * @return MHD_SC_OK on success, + * error code otherwise + */ +MHD_EXTERN_ enum MHD_StatusCode +MHD_deamon_process_reg_events(struct MHD_Daemon *daemon, + uint_fast64_t *next_max_wait) +MHD_FN_PAR_NONNULL_(1); /* ********************* daemon options ************** */ + +/** + * Which threading and polling mode should be used by MHD? + */ +enum MHD_FIXED_ENUM_APP_SET_ MHD_WorkMode +{ + /** + * Work mode with no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + */ + MHD_WM_EXTERNAL_PERIODIC = 0 + , + /** + * Work mode with an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). + */ + MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 8 + , + /** + * Work mode with an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + */ + MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE = 9 + , + /** + * Work mode with no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + */ + MHD_WM_EXTERNAL_SINGLE_FD_WATCH = 16 + , + /** + * Work mode with one or more worker threads. + * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified + * then daemon starts with single worker thread that process + * all connections. + * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more + * than one, then that number of worker threads and distributed + * processing of requests among the workers. + */ + MHD_WM_WORKER_THREADS = 24 + , + /** + * Work mode with one internal thread for listening and additional threads + * per every connection. Use this if handling requests is CPU-intensive or + * blocking, your application is thread-safe and you have plenty of + * memory (per connection). + */ + MHD_WM_THREAD_PER_CONNECTION = 32 +}; + +/** + * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and + * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes + */ +struct MHD_WorkModeExternalEventLoopCBParam +{ + /** + * Socket registration callback + */ + MHD_SocketRegistrationUpdateCallback reg_cb; + /** + * Closure for the @a reg_cb + */ + void *reg_cb_cls; +} + +/** + * MHD work mode parameters + */ +union MHD_WorkModeParam +{ + /** + * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and + * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes + */ + MHD_SocketRegistrationUpdateCallback v_external_event_loop_cb; + /** + * Number of worker threads for #MHD_WM_WORKER_THREADS. + * If set to one, then daemon starts with single worker thread that process + * all connections. + * If set to value larger than one, then that number of worker threads + * and distributed handling of requests among the workers. + * Zero is treated as one. + */ + unsigned int num_worker_threads; +}; + +/** + * Parameter for #MHD_DAEMON_OPTION_WORK_MODE(). + * Not recommended to be used directly, better use macro/functions to create it: + * #MHD_WM_OPTION_EXTERNAL_PERIODIC(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(), + * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(), + * #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(), + * #MHD_WM_OPTION_WORKER_THREADS(), + * #MHD_WM_OPTION_THREAD_PER_CONNECTION() + */ +struct MHD_WorkModeWithParam +{ + /** + * The work mode for MHD + */ + enum MHD_WorkMode mode; + /** + * The parameters used for specified work mode + */ + union MHD_WorkModeParam params; +}; + + + +#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT) +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_PERIODIC() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_PERIODIC) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL), \ + .params.v_external_event_loop_cb.reg_cb = (cb_val), \ + .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE), \ + .params.v_external_event_loop_cb.reg_cb = (cb_val), \ + .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_EXTERNAL_SINGLE_FD_WATCH) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_WORKER_THREADS(num_workers) \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_WORKER_THREADS), \ + .params.num_worker_threads = (num_workers) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +# define MHD_WM_OPTION_THREAD_PER_CONNECTION() \ + MHD_NOWARN_COMPOUND_LITERALS_ \ + (const struct MHD_WorkModeWithParam) \ + { \ + .mode = (MHD_WM_THREAD_PER_CONNECTION) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ + +#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ +MHD_NOWARN_UNUSED_FUNC_ + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_PERIODIC(void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_PERIODIC; + + return wm_val; +} + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with level triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered + * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL( + MHD_SocketRegistrationUpdateCallback cb_val, + void *cb_cls_val) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL; + wm_val.params.v_external_event_loop_cb.reg_cb = cb_val; + wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val; + + return wm_val; +} + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE( + MHD_SocketRegistrationUpdateCallback cb_val, + void *cb_cls_val) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE; + wm_val.params.v_external_event_loop_cb.reg_cb = cb_val; + wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val; + + return wm_val; +} + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_SINGLE_FD_WATCH; + + return wm_val; +} + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_WORKER_THREADS(unsigned int num_workers) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE; + wm_val.params.num_worker_threads = num_workers; + + return wm_val; +} + +/** + * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_WorkModeWithParam with requested values + */ +static MHD_INLINE struct MHD_WorkModeWithParam +MHD_WM_OPTION_THREAD_PER_CONNECTION(void) +{ + struct MHD_WorkModeWithParam wm_val; + + wm_val.mode = MHD_WM_THREAD_PER_CONNECTION; + + return wm_val; +} + +MHD_RESTORE_WARN_UNUSED_FUNC_ +#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */ + + +/** + * Specify threading mode to use. + * + * @param[in,out] daemon daemon to configure + * @param tm mode to use + */ +MHD_EXTERN_ enum MHD_StatusCode +MHD_daemon_set_threading_mode (struct MHD_Daemon *daemon, + enum MHD_ThreadingMode tm) +MHD_FN_PAR_NONNULL_ (1); + /** * Type of a callback function used for logging by MHD. * @@ -2959,9 +3567,9 @@ MHD_daemon_listen_socket (struct MHD_Daemon *daemon, MHD_FN_PAR_NONNULL_ (1); /** - * Event loop internal syscalls supported by MHD. + * Sockets polling internal syscalls used by MHD. */ -enum MHD_FIXED_ENUM_APP_SET_ MHD_EventLoopSyscall +enum MHD_FIXED_ENUM_APP_SET_ MHD_SockPollSyscall { /** * Automatic selection of best-available method. This is also the @@ -3067,7 +3675,7 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_ProtocolStrictLevel , /** * More relaxed protocol interpretation, violating RFCs' - * "SHOULD" type of requirements for HTTP servers. + * "SHOULD" type of restrictions for HTTP servers. * For cookies parsing this (and more permissive) level * allows whitespaces in cookie values. * This level can be used in isolated environments. @@ -3076,7 +3684,7 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_ProtocolStrictLevel /** * The most flexible protocol interpretation, beyond - * RFCs' "MUST" type of requirements for HTTP server. + * RFCs' "MUST" type of restrictions for HTTP server. * The level allow HTTP/1.1 requests without "Host:" header. * For cookies parsing this level adds allowance of * whitespaces before and after '=' character. @@ -3098,6 +3706,7 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel * Use requested level if available or the nearest stricter * level. * Fail if only more permissive levels available. + * Recommended value. */ MHD_USL_THIS_OR_STRICTER = 0 , @@ -3908,332 +4517,86 @@ MHD_RESTORE_WARN_VARIADIC_MACROS_ #endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */ +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * no internal threads. + * The application periodically calls #MHD_daemon_process_blocking(), where + * MHD internally checks all sockets automatically. + * This is the default mode. + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC() \ + MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_PERIODIC()) + +/** +* Create parameter for #MHD_daemon_options_set() for work mode with +* an external event loop with level triggers. +* Application uses #MHD_SocketRegistrationUpdateCallback, level triggered +* sockets polling (like select() or poll()) and #MHD_daemon_event_update(). +* @param cb_val the callback for sockets registration +* @param cb_cls_val the closure for the @a cv_val callback +* @return the object of struct MHD_DaemonOptionAndValue with requested values +*/ +#define MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \ + MHD_DAEMON_OPTION_WORK_MODE( \ + MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL((cb_val),(cb_cls_val))) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * an external event loop with edge triggers. + * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered + * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). + * @param cb_val the callback for sockets registration + * @param cb_cls_val the closure for the @a cv_val callback + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val) \ + MHD_DAEMON_OPTION_WORK_MODE( \ + MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE((cb_val),(cb_cls_val))) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * no internal threads and aggregate watch FD. + * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD + * that gets triggered by any MHD event. + * This FD can be watched as an aggregate indicator for all MHD events. + * This mode is available only on selected platforms (currently + * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. + * When the FD is triggered, #MHD_daemon_process_nonblocking() should + * be called. + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH() \ + MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH()) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * one or more worker threads. + * If number of threads is one, then daemon starts with single worker thread + * that handles all connections. + * If number of threads is larger than one, then that number of worker threads, + * and handling of connection is distributed among the workers. + * @param num_workers the number of worker threads, zero is treated as one + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_DAEMON_OPTION_WORKER_THREADS(num_workers) \ + MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_WORKER_THREADS(num_workers)) + +/** + * Create parameter for #MHD_daemon_options_set() for work mode with + * one internal thread for listening and additional threads per every + * connection. Use this if handling requests is CPU-intensive or blocking, + * your application is thread-safe and you have plenty of memory (per + * connection). + * @return the object of struct MHD_DaemonOptionAndValue with requested values + */ +#define MHD_DAEMON_OPTION_THREAD_PER_CONNECTION() \ + MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_THREAD_PER_CONNECTION()) + + /* ******************* Event loop ************************ */ -/** - * Which threading and polling mode should be used by MHD? - */ -enum MHD_FIXED_ENUM_APP_SET_ MHD_WorkMode -{ - /** - * The daemon has no internal threads. - * The application periodically calls #MHD_daemon_process_blocking(), where - * MHD internally checks all sockets automatically. - * This is the default. - */ - MHD_WM_EXTERNAL_PERIODIC = 0 - , - /** - * Use an external event loop with level triggers. - * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered - * sockets polling (like select() or poll()) and #MHD_daemon_event_update(). - */ - MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 8 - , - /** - * Use an external event loop with edge triggers. - * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered - * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update(). - */ - MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE = 9 - , - /** - * The daemon has no internal threads. - * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD - * that triggered when any MHD event happens. - * This FD can be watched as an aggregate indicator for all MHD events. - * This mode is available only on selected platforms (currently - * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD. - * When the FD is triggered, #MHD_daemon_process_nonblocking() should - * be called. - */ - MHD_WM_EXTERNAL_SINGLE_FD_WATCH = 16 - , - /** - * Run with one or more worker threads. - * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified - * then daemon starts with single worker thread that process - * all connections. - * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more - * than one, then that number of worker threads and distributed - * processing of requests among the workers. - */ - MHD_WM_WORKER_THREADS = 24 - , - - /** - * MHD should create its own thread for listening and furthermore create - * additional threads per every connection. Use this if handling requests - * is CPU-intensive or blocking, your application is thread-safe and you - * have plenty of memory (per connection). - */ - MHD_WM_THREAD_PER_CONNECTION = 32 -}; - -union MHD_WorkModeParam -{ - -}; - -struct MHD_WorkModeWithParam -{ - /** - * The work mode for MHD - */ - enum MHD_WorkMode mode; - /** - * The parameters used for specified work mode - */ - union MHD_WorkModeParam val; -}; - -/** - * Specify threading mode to use. - * - * @param[in,out] daemon daemon to configure - * @param tm mode to use - */ -MHD_EXTERN_ enum MHD_StatusCode -MHD_daemon_set_threading_mode (struct MHD_Daemon *daemon, - enum MHD_ThreadingMode tm) -MHD_FN_PAR_NONNULL_ (1); - - -/** - * The network status of the socket. - * When set by MHD (by #MHD_get_watched_fds(), #MHD_get_watched_fds_update() and - * similar) it indicates a request to watch for specific socket state: - * readiness for receiving the data, readiness for sending the data and/or - * exception state of the socket. - * When set by application (and provided for #MHD_process_watched_fds() and - * similar) it must indicate the actual status of the socket. - * - * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV, - * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT. - * @ingroup event - */ -enum MHD_FIXED_ENUM_ MHD_FdState -{ - /** - * The socket is not ready for receiving or sending and - * does not have any exceptional state. - * The state never set by MHD, except de-registration of the sockets - * for #MHD_SocketRegistrationUpdateCallback(). - */ - MHD_FD_STATE_NONE = 0 - , - /* ** Three bit-flags ** */ - - /** - * Indicates that socket should be watched for incoming data - * (when set by #MHD_get_watched_fds()) - * / socket has incoming data ready to read (when used for - * #MHD_process_watched_fds()) - */ - MHD_FD_STATE_RECV = 1 << 0, - /** - * Indicates that socket should be watched for availability for sending - * (when set by #MHD_get_watched_fds()) - * / socket has ability to send data (when used for - * #MHD_process_watched_fds()) - */ - MHD_FD_STATE_SEND = 1 << 1, - /** - * Indicates that socket should be watched for disconnect, out-of-band - * data available or high priority data available (when set by - * #MHD_get_watched_fds()) - * / socket has been disconnected, has out-of-band data available or - * has high priority data available (when used for - * #MHD_process_watched_fds()). This status must not include "remote - * peer shut down writing" status. - * Note: #MHD_get_watched_fds() always set it as exceptions must be - * always watched. - */ - MHD_FD_STATE_EXCEPT = 1 << 2, - - /* The rest of the list is a bit-wise combination of three main - * states. Application may use three main states directly as - * a bit-mask instead of using of following values - */ - - /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states. - */ - MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND, - /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. - */ - MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, - /** - * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states. - */ - MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT, - /** - * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and - * #MHD_FD_STATE_EXCEPT states. - */ - MHD_FD_STATE_RECV_SEND_EXCEPT = \ - MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT -}; - -/** - * Checks whether specific @a state is enabled in @a var - */ -#define MHD_FD_STATE_IS_SET(var,state) \ - (MHD_FD_STATE_NONE != \ - (((enum MHD_FdState) (var)) & ((enum MHD_FdState) (state)))) - -/** - * Checks whether RECV is enabled in @a var - */ -#define MHD_FD_STATE_IS_SET_RECV(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV) -/** - * Checks whether SEND is enabled in @a var - */ -#define MHD_FD_STATE_IS_SET_SEND(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND) -/** - * Checks whether EXCEPT is enabled in @a var - */ -#define MHD_FD_STATE_IS_SET_EXCEPT(var) \ - MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT) - - -/** - * Enable specific @a state in @a var - */ -#define MHD_FD_STATE_SET(var,state) \ - (var) = (enum MHD_FdState) ((var) | (state)) -/** - * Enable RECV state in @a var - */ -#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV) -/** - * Enable SEND state in @a var - */ -#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND) -/** - * Enable EXCEPT state in @a var - */ -#define MHD_FD_STATE_SET_EXCEPT(var) \ - MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT) - -/** - * Clear/disable specific @a state in @a var - */ -#define MHD_FD_STATE_CLEAR(var,state) \ - (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state))) -/** - * Clear/disable RECV state in @a var - */ -#define MHD_FD_STATE_CLEAR_RECV(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV) -/** - * Clear/disable SEND state in @a var - */ -#define MHD_FD_STATE_CLEAR_SEND(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND) -/** - * Clear/disable EXCEPT state in @a var - */ -#define MHD_FD_STATE_CLEAR_EXCEPT(var) \ - MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT) - - -/* Changes: - * + status update callback replaced with function - * + status update accepts array of updates - */ - -/** - * The context data to be used for updates of the socket state - */ -struct MHD_EventUpdateContext; - - -/* Define MHD_APP_SOCKET_CNTX_TYPE to the socket context type before - * including this header. - * This is optional, but improves the types safety. - * For example: - * #define MHD_APP_SOCKET_CNTX_TYPE struct my_structure - */ -#ifndef MHD_APP_SOCKET_CNTX_TYPE -# define MHD_APP_SOCKET_CNTX_TYPE void -#endif - -/** - * The callback for registration/de-registration of the sockets to watch. - * - * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(), - * #MHD_daemon_add_connection(). - * - * @param cls the closure - * @param fd the socket to watch - * @param watch_for the states of the @a fd to watch, if set to - * #MHD_FD_STATE_NONE the socket must be de-registred - * @param app_cntx_old the old application defined context for the socket, - * NULL if @a fd socket was not registered before - * @param ecb_cntx the context handle to be used - * with #MHD_daemon_event_update() - * @return NULL if error (to connection will be closed), - * or the new socket context - * @ingroup event - */ -typedef MHD_APP_SOCKET_CNTX_TYPE * -(MHD_FN_PAR_NONNULL_(5) - *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); - - -/** - * Update the sockets state. - * Must be called for every socket that got state updated. - * For #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL mode should be called for each - * socket. - * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or - * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. - * @param daemon the daemon handle - * @param ecb_cntx the context handle provided - * for #MHD_SocketRegistrationUpdateCallback - * @param fd_current_state the current state of the socket - */ -MHD_EXTERN_ void -MHD_daemon_event_update ( - struct MHD_Daemon *daemon, - struct MHD_EventUpdateContext *ecb_cntx, - enum MHD_FdState fd_current_state) -MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(2); - - -/** - * Perform sockets registration, process registered network events. - * - * This function first processes all registered (by MHD_daemon_event_update()) - * network events (if any) and then calls #MHD_SocketRegistrationUpdateCallback - * callback for every socket that needs to be added/updated/removed. - * - * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or - * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes. - * - * @param daemon the daemon handle - * @param[out] next_max_wait the optional pointer to receive the next maximum - * wait time in microseconds to be used for sockets - * polling function, can be NULL - * @return MHD_SC_OK on success, - * error code otherwise - */ -MHD_EXTERN_ enum MHD_StatusCode -MHD_deamon_process_reg_events(struct MHD_Daemon *daemon, - uint_fast64_t *next_max_wait) -MHD_FN_PAR_NONNULL_(1); - - /** * Run websever operation with possible blocking. *