daemon_get_info.c (11284B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2024-2025 Evgeny Grin (Karlson2k) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/daemon_get_info.c 41 * @brief The implementation of MHD_daemon_get_info_*() functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "mhd_assert.h" 48 #include "mhd_unreachable.h" 49 50 #include "sys_base_types.h" 51 #include "sys_sockets_types.h" 52 53 #include "mhd_socket_type.h" 54 #include "mhd_daemon.h" 55 #include "events_process.h" 56 #ifdef MHD_SUPPORT_HTTPS 57 # include "mhd_tls_choice.h" 58 # ifdef MHD_USE_MULTITLS 59 # include "tls_multi_daemon_data.h" 60 # endif 61 #endif 62 63 #include "mhd_public_api.h" 64 65 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_ 66 MHD_FN_PAR_NONNULL_ (1) 67 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode 68 MHD_daemon_get_info_fixed_sz ( 69 struct MHD_Daemon *MHD_RESTRICT daemon, 70 enum MHD_DaemonInfoFixedType info_type, 71 union MHD_DaemonInfoFixedData *MHD_RESTRICT output_buf, 72 size_t output_buf_size) 73 { 74 mhd_assert (! mhd_D_HAS_MASTER (daemon)); 75 if (mhd_DAEMON_STATE_STARTED > daemon->state) 76 return MHD_SC_TOO_EARLY; 77 if (mhd_DAEMON_STATE_STARTED < daemon->state) 78 return MHD_SC_TOO_LATE; 79 80 switch (info_type) 81 { 82 case MHD_DAEMON_INFO_FIXED_POLL_SYSCALL: 83 if (mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int)) 84 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 85 if (sizeof(output_buf->v_poll_syscall) > output_buf_size) 86 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 87 output_buf->v_poll_syscall = 88 (enum MHD_SockPollSyscall) daemon->events.poll_type; 89 return MHD_SC_OK; 90 case MHD_DAEMON_INFO_FIXED_NUM_WORK_THREADS: 91 #ifdef MHD_SUPPORT_THREADS 92 if (! mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) 93 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 94 if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION == daemon->wmode_int) 95 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 96 if (sizeof(output_buf->v_num_work_threads_uint) > output_buf_size) 97 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 98 if (mhd_DAEMON_TYPE_SINGLE == daemon->threading.d_type) 99 output_buf->v_num_work_threads_uint = 1; 100 else 101 { 102 mhd_assert (mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY == \ 103 daemon->threading.d_type); 104 output_buf->v_num_work_threads_uint = daemon->threading.hier.pool.num; 105 } 106 return MHD_SC_OK; 107 #else /* ! MHD_SUPPORT_THREADS */ 108 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 109 #endif /* ! MHD_SUPPORT_THREADS */ 110 case MHD_DAEMON_INFO_FIXED_BIND_PORT: 111 if ((MHD_INVALID_SOCKET == daemon->net.listen.fd) 112 && ! daemon->net.listen.is_broken) 113 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 114 if (mhd_SOCKET_TYPE_UNKNOWN > daemon->net.listen.type) 115 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 116 if (0 == daemon->net.listen.port) 117 { 118 if (mhd_SOCKET_TYPE_IP != daemon->net.listen.type) 119 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 120 return MHD_SC_INFO_GET_TYPE_UNOBTAINABLE; 121 } 122 if (sizeof(output_buf->v_bind_port_uint16) > output_buf_size) 123 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 124 output_buf->v_bind_port_uint16 = daemon->net.listen.port; 125 return MHD_SC_OK; 126 case MHD_DAEMON_INFO_FIXED_LISTEN_SOCKET: 127 if (1) 128 { 129 MHD_Socket listen_fd = daemon->net.listen.fd; 130 if (MHD_INVALID_SOCKET == listen_fd) 131 return daemon->net.listen.is_broken ? 132 MHD_SC_INFO_GET_TYPE_UNOBTAINABLE : 133 MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 134 if (sizeof(output_buf->v_listen_socket) > output_buf_size) 135 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 136 output_buf->v_listen_socket = listen_fd; 137 } 138 return MHD_SC_OK; 139 case MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD: 140 #ifdef MHD_SUPPORT_EPOLL 141 if (! mhd_D_IS_USING_EPOLL (daemon)) 142 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 143 if (sizeof(output_buf->v_aggreagate_fd) > output_buf_size) 144 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 145 output_buf->v_aggreagate_fd = daemon->events.data.epoll.e_fd; 146 return MHD_SC_OK; 147 #else 148 return MHD_SC_INFO_GET_TYPE_NOT_SUPP_BY_BUILD; 149 #endif 150 break; 151 case MHD_DAEMON_INFO_FIXED_TLS_BACKEND: 152 if (sizeof(output_buf->v_tls_backend) > output_buf_size) 153 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 154 if (! mhd_D_HAS_TLS (daemon)) 155 output_buf->v_tls_backend = MHD_TLS_BACKEND_NONE; 156 else 157 { 158 #if ! defined(MHD_SUPPORT_HTTPS) 159 mhd_UNREACHABLE (); 160 #elif defined(MHD_USE_MULTITLS) 161 switch (daemon->tls->choice) 162 { 163 # ifdef MHD_SUPPORT_GNUTLS 164 case mhd_TLS_MULTI_ROUTE_GNU: 165 output_buf->v_tls_backend = MHD_TLS_BACKEND_GNUTLS; 166 break; 167 # endif 168 # ifdef MHD_SUPPORT_OPENSSL 169 case mhd_TLS_MULTI_ROUTE_OPEN: 170 output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL; 171 break; 172 # endif 173 # ifdef MHD_SUPPORT_MBEDTLS 174 case mhd_TLS_MULTI_ROUTE_MBED: 175 output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS; 176 break; 177 # endif 178 case mhd_TLS_MULTI_ROUTE_NONE: 179 default: 180 mhd_UNREACHABLE (); 181 break; 182 } 183 #elif defined(MHD_SUPPORT_GNUTLS) 184 output_buf->v_tls_backend = MHD_TLS_BACKEND_GNUTLS; 185 #elif defined(MHD_SUPPORT_OPENSSL) 186 output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL; 187 #elif defined(MHD_SUPPORT_MBEDTLS) 188 output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS; 189 #else 190 #error No TLS backends enabled, while TLS support is enabled 191 #endif 192 } 193 return MHD_SC_OK; 194 case MHD_DAEMON_INFO_FIXED_DEFAULT_TIMEOUT: 195 if (sizeof(output_buf->v_default_timeout_uint) > output_buf_size) 196 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 197 output_buf->v_default_timeout_uint = 198 (unsigned int) (daemon->conns.cfg.timeout_ms / 1000u); 199 mhd_assert (output_buf->v_default_timeout_uint * 1000u == \ 200 daemon->conns.cfg.timeout_ms); 201 return MHD_SC_OK; 202 case MHD_DAEMON_INFO_FIXED_GLOBAL_CONNECTION_LIMIT: 203 if (sizeof(output_buf->v_global_connection_limit_uint) > output_buf_size) 204 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 205 output_buf->v_global_connection_limit_uint = 206 daemon->conns.cfg.count_limit; 207 return MHD_SC_OK; 208 case MHD_DAEMON_INFO_FIXED_PER_IP_LIMIT: 209 if (sizeof(output_buf->v_per_ip_limit_uint) > output_buf_size) 210 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 211 output_buf->v_per_ip_limit_uint = daemon->conns.cfg.per_ip_limit; 212 return MHD_SC_OK; 213 case MHD_DAEMON_INFO_FIXED_SUPPRESS_DATE_HEADER: 214 if (sizeof(output_buf->v_suppress_date_header_bool) > output_buf_size) 215 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 216 output_buf->v_suppress_date_header_bool = 217 daemon->req_cfg.suppress_date ? MHD_YES : MHD_NO; 218 return MHD_SC_OK; 219 case MHD_DAEMON_INFO_FIXED_CONN_MEMORY_LIMIT: 220 if (sizeof(output_buf->v_conn_memory_limit_sizet) > output_buf_size) 221 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 222 output_buf->v_conn_memory_limit_sizet = daemon->conns.cfg.mem_pool_size; 223 return MHD_SC_OK; 224 case MHD_DAEMON_INFO_FIXED_FD_NUMBER_LIMIT: 225 #ifdef MHD_SOCKETS_KIND_POSIX 226 if (sizeof(output_buf->v_fd_number_limit_socket) > output_buf_size) 227 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 228 output_buf->v_fd_number_limit_socket = daemon->net.cfg.max_fd_num; 229 return MHD_SC_OK; 230 #else /* ! MHD_SOCKETS_KIND_POSIX */ 231 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 232 #endif /* ! MHD_SOCKETS_KIND_POSIX */ 233 234 case MHD_DAEMON_INFO_FIXED_SENTINEL: 235 default: 236 break; 237 } 238 return MHD_SC_INFO_GET_TYPE_UNKNOWN; 239 } 240 241 242 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_ 243 MHD_FN_PAR_NONNULL_ (1) 244 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode 245 MHD_daemon_get_info_dynamic_sz ( 246 struct MHD_Daemon *MHD_RESTRICT daemon, 247 enum MHD_DaemonInfoDynamicType info_type, 248 union MHD_DaemonInfoDynamicData *MHD_RESTRICT output_buf, 249 size_t output_buf_size) 250 { 251 mhd_assert (! mhd_D_HAS_MASTER (daemon)); 252 if (mhd_DAEMON_STATE_STARTED > daemon->state) 253 return MHD_SC_TOO_EARLY; 254 if (mhd_DAEMON_STATE_STARTED < daemon->state) 255 return MHD_SC_TOO_LATE; 256 257 switch (info_type) 258 { 259 case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT: 260 if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) 261 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 262 if (sizeof(output_buf->v_max_time_to_wait_uint64) > output_buf_size) 263 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 264 output_buf->v_max_time_to_wait_uint64 = mhd_daemon_get_wait_max (daemon); 265 return MHD_SC_OK; 266 case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS: 267 if (sizeof(output_buf->v_has_connections_bool) <= output_buf_size) 268 { 269 enum MHD_Bool res; 270 /* 271 Reading number of connection from the daemon member could be non-atomic 272 and may give wrong result (if it is modified in other thread), however 273 test against zero/non-zero value is valid even if reading is 274 non-atomic. 275 */ 276 if (! mhd_D_HAS_WORKERS (daemon)) 277 res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO; 278 else 279 { 280 #ifdef MHD_SUPPORT_THREADS 281 unsigned int i; 282 res = MHD_NO; 283 mhd_assert (NULL != daemon->threading.hier.pool.workers); 284 for (i = 0; i < daemon->threading.hier.pool.num; ++i) 285 { 286 if (0 != daemon->threading.hier.pool.workers[i].conns.count) 287 { 288 res = MHD_YES; 289 break; 290 } 291 } 292 #else /* ! MHD_SUPPORT_THREADS */ 293 res = MHD_NO; /* No used, mute compiler waring */ 294 #endif /* ! MHD_SUPPORT_THREADS */ 295 } 296 output_buf->v_has_connections_bool = res; 297 return MHD_SC_OK; 298 } 299 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 300 case MHD_DAEMON_INFO_DYNAMIC_SENTINEL: 301 default: 302 break; 303 } 304 return MHD_SC_INFO_GET_TYPE_UNKNOWN; 305 }