From de741e6926f082cc2fdc98e70cfa482e232768d2 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Wed, 15 Jan 2025 19:11:13 +0100 Subject: [PATCH] MHD_daemon_get_info_dynamic_sz(): implemented --- src/include/microhttpd2.h | 70 +++++++++++++++++++------------ src/include/microhttpd2_main.h.in | 70 +++++++++++++++++++------------ src/mhd2/daemon_get_info.c | 56 +++++++++++++++++++++++++ src/mhd2/events_process.c | 33 +++++++++++++-- src/mhd2/events_process.h | 14 +++++++ 5 files changed, 187 insertions(+), 56 deletions(-) diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h index d9084c11..dbc42971 100644 --- a/src/include/microhttpd2.h +++ b/src/include/microhttpd2.h @@ -9315,7 +9315,7 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); enum MHD_DaemonInfoDynamicType { /** - * The the maximum number of microseconds from the current moment until + * The the maximum number of millisecond from the current moment until * the mandatory call of the daemon data processing function (like * #MHD_deamon_process_reg_events(), #MHD_daemon_process_blocking()). * If resulting value is zero then daemon data processing function should be @@ -9324,19 +9324,17 @@ enum MHD_DaemonInfoDynamicType * Available only for daemons stated in #MHD_WM_EXTERNAL_PERIODIC, * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL, #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE * or #MHD_WM_EXTERNAL_SINGLE_FD_WATCH modes. + * The function return #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if daemon has + * internal handling of events (internal threads). * The result is placed in @a v_uint64 member. */ MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT = 1 , /** - * Request the number of current connections handled by the daemon. - * No extra arguments should be passed. - * Note: when using MHD without internal threads, this type of request - * could be used only when MHD is is not processing the connection data - * in other thread at the same time. - * The result is placed in @a v_uint member. + * Check whether the daemon has any connected network clients. + * The result is placed in @a v_bool member. */ - MHD_DAEMON_INFO_DYNAMIC_CURRENT_CONNECTIONS = 20 + MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS = 20 , /* * Sentinel * */ /** @@ -9353,16 +9351,16 @@ enum MHD_DaemonInfoDynamicType */ union MHD_DaemonInfoDynamicData { + /** + * The boolean value + */ + enum MHD_Bool v_bool; + /** * Unsigned 64 bits integer value. */ uint_fast64_t v_uint64; - /** - * Unsigned integer value. - */ - unsigned int v_uint; - /** * Unused member. * Help enforcing future-proof alignment of the union. @@ -9379,19 +9377,30 @@ union MHD_DaemonInfoDynamicData * * @param daemon the daemon to get information about * @param info_type the type of information requested - * @param[out] return_value pointer to union where requested information will - * be stored - * @param return_value_size the size of the memory area pointed - * by @a return_data, in bytes + * @param[out] output_buf the pointer to union to be set to the requested + * information + * @param output_buf_size the size of the memory area pointed by @a output_buf + * (provided by the caller for storing the requested + * information), in bytes * @return #MHD_SC_OK if succeed, - * error code otherwise + * #MHD_SC_INFO_GET_BUFF_TOO_SMALL if @a output_buf_size is too small, + * #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if the requested information + * is not available for this + * daemon due to the daemon + * configuration/mode, + * #MHD_SC_INFO_GET_TYPE_UNOBTAINABLE if the requested information + * should be available for + * the daemon, but cannot be provided + * due to some error or other + * reasons, + * other error code in case of other errors * @ingroup specialized */ MHD_EXTERN_ enum MHD_StatusCode MHD_daemon_get_info_dynamic_sz (struct MHD_Daemon *daemon, enum MHD_DaemonInfoDynamicType info_type, - union MHD_DaemonInfoDynamicData *return_value, - size_t return_value_size) + union MHD_DaemonInfoDynamicData *output_buf, + size_t output_buf_size) MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); @@ -9401,15 +9410,24 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); * * @param daemon the daemon to get information about * @param info_type the type of information requested - * @param[out] return_value pointer to union where requested information will - * be stored + * @param[out] output_buf the pointer to union to be set to the requested + * information * @return #MHD_SC_OK if succeed, - * error code otherwise + * #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if the requested information + * is not available for this + * daemon due to the daemon + * configuration/mode, + * #MHD_SC_INFO_GET_TYPE_UNOBTAINABLE if the requested information + * should be available for + * the daemon, but cannot be provided + * due to some error or other + * reasons, + * other error code in case of other errors * @ingroup specialized */ -#define MHD_daemon_get_info_dynamic(daemon,info_type,return_value) \ - MHD_daemon_get_info_dynamic_sz ((daemon), (info_type), (return_value), \ - sizeof(*(return_value))) +#define MHD_daemon_get_info_dynamic(daemon,info_type,output_buf) \ + MHD_daemon_get_info_dynamic_sz ((daemon), (info_type), (output_buf), \ + sizeof(*(output_buf))) /** diff --git a/src/include/microhttpd2_main.h.in b/src/include/microhttpd2_main.h.in index cff1686b..43fa865c 100644 --- a/src/include/microhttpd2_main.h.in +++ b/src/include/microhttpd2_main.h.in @@ -4693,7 +4693,7 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); enum MHD_DaemonInfoDynamicType { /** - * The the maximum number of microseconds from the current moment until + * The the maximum number of millisecond from the current moment until * the mandatory call of the daemon data processing function (like * #MHD_deamon_process_reg_events(), #MHD_daemon_process_blocking()). * If resulting value is zero then daemon data processing function should be @@ -4702,19 +4702,17 @@ enum MHD_DaemonInfoDynamicType * Available only for daemons stated in #MHD_WM_EXTERNAL_PERIODIC, * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL, #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE * or #MHD_WM_EXTERNAL_SINGLE_FD_WATCH modes. + * The function return #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if daemon has + * internal handling of events (internal threads). * The result is placed in @a v_uint64 member. */ MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT = 1 , /** - * Request the number of current connections handled by the daemon. - * No extra arguments should be passed. - * Note: when using MHD without internal threads, this type of request - * could be used only when MHD is is not processing the connection data - * in other thread at the same time. - * The result is placed in @a v_uint member. + * Check whether the daemon has any connected network clients. + * The result is placed in @a v_bool member. */ - MHD_DAEMON_INFO_DYNAMIC_CURRENT_CONNECTIONS = 20 + MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS = 20 , /* * Sentinel * */ /** @@ -4731,16 +4729,16 @@ enum MHD_DaemonInfoDynamicType */ union MHD_DaemonInfoDynamicData { + /** + * The boolean value + */ + enum MHD_Bool v_bool; + /** * Unsigned 64 bits integer value. */ uint_fast64_t v_uint64; - /** - * Unsigned integer value. - */ - unsigned int v_uint; - /** * Unused member. * Help enforcing future-proof alignment of the union. @@ -4757,19 +4755,30 @@ union MHD_DaemonInfoDynamicData * * @param daemon the daemon to get information about * @param info_type the type of information requested - * @param[out] return_value pointer to union where requested information will - * be stored - * @param return_value_size the size of the memory area pointed - * by @a return_data, in bytes + * @param[out] output_buf the pointer to union to be set to the requested + * information + * @param output_buf_size the size of the memory area pointed by @a output_buf + * (provided by the caller for storing the requested + * information), in bytes * @return #MHD_SC_OK if succeed, - * error code otherwise + * #MHD_SC_INFO_GET_BUFF_TOO_SMALL if @a output_buf_size is too small, + * #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if the requested information + * is not available for this + * daemon due to the daemon + * configuration/mode, + * #MHD_SC_INFO_GET_TYPE_UNOBTAINABLE if the requested information + * should be available for + * the daemon, but cannot be provided + * due to some error or other + * reasons, + * other error code in case of other errors * @ingroup specialized */ MHD_EXTERN_ enum MHD_StatusCode MHD_daemon_get_info_dynamic_sz (struct MHD_Daemon *daemon, enum MHD_DaemonInfoDynamicType info_type, - union MHD_DaemonInfoDynamicData *return_value, - size_t return_value_size) + union MHD_DaemonInfoDynamicData *output_buf, + size_t output_buf_size) MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); @@ -4779,15 +4788,24 @@ MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3); * * @param daemon the daemon to get information about * @param info_type the type of information requested - * @param[out] return_value pointer to union where requested information will - * be stored + * @param[out] output_buf the pointer to union to be set to the requested + * information * @return #MHD_SC_OK if succeed, - * error code otherwise + * #MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE if the requested information + * is not available for this + * daemon due to the daemon + * configuration/mode, + * #MHD_SC_INFO_GET_TYPE_UNOBTAINABLE if the requested information + * should be available for + * the daemon, but cannot be provided + * due to some error or other + * reasons, + * other error code in case of other errors * @ingroup specialized */ -#define MHD_daemon_get_info_dynamic(daemon,info_type,return_value) \ - MHD_daemon_get_info_dynamic_sz ((daemon), (info_type), (return_value), \ - sizeof(*(return_value))) +#define MHD_daemon_get_info_dynamic(daemon,info_type,output_buf) \ + MHD_daemon_get_info_dynamic_sz ((daemon), (info_type), (output_buf), \ + sizeof(*(output_buf))) /** diff --git a/src/mhd2/daemon_get_info.c b/src/mhd2/daemon_get_info.c index 86d7bc78..3af4c62f 100644 --- a/src/mhd2/daemon_get_info.c +++ b/src/mhd2/daemon_get_info.c @@ -31,6 +31,7 @@ #include "mhd_socket_type.h" #include "mhd_daemon.h" +#include "events_process.h" #include "mhd_public_api.h" @@ -84,3 +85,58 @@ MHD_daemon_get_info_fixed_sz (struct MHD_Daemon *daemon, } return MHD_SC_INFO_GET_TYPE_UNKNOWN; } + + +MHD_EXTERN_ +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode +MHD_daemon_get_info_dynamic_sz (struct MHD_Daemon *daemon, + enum MHD_DaemonInfoDynamicType info_type, + union MHD_DaemonInfoDynamicData *output_buf, + size_t output_buf_size) +{ + switch (info_type) + { + case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT: + if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) + return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; + if (sizeof(output_buf->v_uint64) > output_buf_size) + return MHD_SC_INFO_GET_BUFF_TOO_SMALL; + output_buf->v_uint64 = mhd_daemon_get_wait_max (daemon); + return MHD_SC_OK; + case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS: + if (sizeof(output_buf->v_bool) <= output_buf_size) + { + enum MHD_Bool res; + /* + Reading number of connection from the daemon member could be non-atomic + and may give wrong result (if it is modified in other thread), however + test against zero/non-zero value is valid even if reading is + non-atomic. + */ + if (! mhd_D_HAS_WORKERS (daemon)) + res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO; + else + { + unsigned int i; + res = MHD_NO; + mhd_assert (NULL != daemon->threading.hier.pool.workers); + for (i = 0; i < daemon->threading.hier.pool.num; ++i) + { + if (0 != daemon->threading.hier.pool.workers[i].conns.count) + { + res = MHD_YES; + break; + } + } + } + output_buf->v_bool = res; + return MHD_SC_OK; + } + return MHD_SC_INFO_GET_BUFF_TOO_SMALL; + case MHD_DAEMON_INFO_DYNAMIC_SENTINEL: + default: + break; + } + return MHD_SC_INFO_GET_TYPE_UNKNOWN; +} diff --git a/src/mhd2/events_process.c b/src/mhd2/events_process.c index fe07301b..1e2423b6 100644 --- a/src/mhd2/events_process.c +++ b/src/mhd2/events_process.c @@ -64,14 +64,16 @@ #include "mhd_public_api.h" -static int -get_max_wait (struct MHD_Daemon *restrict d) +MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t +mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d) { bool zero_wait = d->events.zero_wait; + + mhd_assert (! mhd_D_HAS_WORKERS (d)); + if (d->events.act_req.accept && d->conns.block_new) d->events.act_req.accept = false; - d->events.zero_wait = false; /* Reset as this pending data will be processed */ if (d->events.act_req.accept) return 0; if (zero_wait) @@ -79,10 +81,33 @@ get_max_wait (struct MHD_Daemon *restrict d) if (NULL != mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready)) return 0; - return INT_MAX; // TODO: calculate correct timeout value + return MHD_WAIT_INDEFINITELY; // TODO: calculate correct timeout value } +mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE + +static MHD_FN_PAR_NONNULL_ALL_ int +get_max_wait (struct MHD_Daemon *restrict d) +{ + uint_fast64_t ui64_wait = mhd_daemon_get_wait_max (d); + int i_wait = (int) ui64_wait; + + // TODO: move reset to the processing loop + d->events.zero_wait = false; /* Reset as this pending data will be processed */ + + if ((0 > i_wait) || + (ui64_wait != (uint_fast64_t) i_wait)) + return INT_MAX; + + return i_wait; +} + + +mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE +/* End of warning-less data truncation */ + + MHD_FN_PAR_NONNULL_ (1) static void update_conn_net_status (struct MHD_Daemon *restrict d, struct MHD_Connection *restrict c, diff --git a/src/mhd2/events_process.h b/src/mhd2/events_process.h index 8807d389..8a0205ab 100644 --- a/src/mhd2/events_process.h +++ b/src/mhd2/events_process.h @@ -29,8 +29,12 @@ #include "mhd_sys_options.h" +#include "sys_base_types.h" + #include "sys_thread_entry_type.h" +struct MHD_Daemon; /* forward declaration */ + /** * The entry point for the daemon worker thread * @param cls the closure @@ -52,4 +56,14 @@ mhd_worker_listening_only (void *cls); mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC mhd_worker_connection (void *cls); +/** + * Get maximum wait time for the daemon + * @param d the daemon to check + * @return the maximum wait time, + * #MHD_WAIT_INDEFINITELY if wait time is not limited + */ +MHD_INTERNAL uint_fast64_t +mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d) +MHD_FN_PAR_NONNULL_ALL_; + #endif /* ! MHD_EVENTS_PROCESS_H */