daemon_get_info.c (11177B)
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_MILSEC: 195 if (sizeof(output_buf->v_default_timeout_milsec_uint32) > output_buf_size) 196 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 197 output_buf->v_default_timeout_milsec_uint32 = 198 daemon->conns.cfg.timeout_milsec; 199 return MHD_SC_OK; 200 case MHD_DAEMON_INFO_FIXED_GLOBAL_CONNECTION_LIMIT: 201 if (sizeof(output_buf->v_global_connection_limit_uint) > output_buf_size) 202 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 203 output_buf->v_global_connection_limit_uint = 204 daemon->conns.cfg.count_limit; 205 return MHD_SC_OK; 206 case MHD_DAEMON_INFO_FIXED_PER_IP_LIMIT: 207 if (sizeof(output_buf->v_per_ip_limit_uint) > output_buf_size) 208 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 209 output_buf->v_per_ip_limit_uint = daemon->conns.cfg.per_ip_limit; 210 return MHD_SC_OK; 211 case MHD_DAEMON_INFO_FIXED_SUPPRESS_DATE_HEADER: 212 if (sizeof(output_buf->v_suppress_date_header_bool) > output_buf_size) 213 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 214 output_buf->v_suppress_date_header_bool = 215 daemon->req_cfg.suppress_date ? MHD_YES : MHD_NO; 216 return MHD_SC_OK; 217 case MHD_DAEMON_INFO_FIXED_CONN_MEMORY_LIMIT: 218 if (sizeof(output_buf->v_conn_memory_limit_sizet) > output_buf_size) 219 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 220 output_buf->v_conn_memory_limit_sizet = daemon->conns.cfg.mem_pool_size; 221 return MHD_SC_OK; 222 case MHD_DAEMON_INFO_FIXED_FD_NUMBER_LIMIT: 223 #ifdef MHD_SOCKETS_KIND_POSIX 224 if (sizeof(output_buf->v_fd_number_limit_socket) > output_buf_size) 225 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 226 output_buf->v_fd_number_limit_socket = daemon->net.cfg.max_fd_num; 227 return MHD_SC_OK; 228 #else /* ! MHD_SOCKETS_KIND_POSIX */ 229 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 230 #endif /* ! MHD_SOCKETS_KIND_POSIX */ 231 232 case MHD_DAEMON_INFO_FIXED_SENTINEL: 233 default: 234 break; 235 } 236 return MHD_SC_INFO_GET_TYPE_UNKNOWN; 237 } 238 239 240 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_ 241 MHD_FN_PAR_NONNULL_ (1) 242 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode 243 MHD_daemon_get_info_dynamic_sz ( 244 struct MHD_Daemon *MHD_RESTRICT daemon, 245 enum MHD_DaemonInfoDynamicType info_type, 246 union MHD_DaemonInfoDynamicData *MHD_RESTRICT output_buf, 247 size_t output_buf_size) 248 { 249 mhd_assert (! mhd_D_HAS_MASTER (daemon)); 250 if (mhd_DAEMON_STATE_STARTED > daemon->state) 251 return MHD_SC_TOO_EARLY; 252 if (mhd_DAEMON_STATE_STARTED < daemon->state) 253 return MHD_SC_TOO_LATE; 254 255 switch (info_type) 256 { 257 case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT: 258 if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) 259 return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; 260 if (sizeof(output_buf->v_max_time_to_wait_uint64) > output_buf_size) 261 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 262 output_buf->v_max_time_to_wait_uint64 = mhd_daemon_get_wait_max (daemon); 263 return MHD_SC_OK; 264 case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS: 265 if (sizeof(output_buf->v_has_connections_bool) <= output_buf_size) 266 { 267 enum MHD_Bool res; 268 /* 269 Reading number of connection from the daemon member could be non-atomic 270 and may give wrong result (if it is modified in other thread), however 271 test against zero/non-zero value is valid even if reading is 272 non-atomic. 273 */ 274 if (! mhd_D_HAS_WORKERS (daemon)) 275 res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO; 276 else 277 { 278 #ifdef MHD_SUPPORT_THREADS 279 unsigned int i; 280 res = MHD_NO; 281 mhd_assert (NULL != daemon->threading.hier.pool.workers); 282 for (i = 0; i < daemon->threading.hier.pool.num; ++i) 283 { 284 if (0 != daemon->threading.hier.pool.workers[i].conns.count) 285 { 286 res = MHD_YES; 287 break; 288 } 289 } 290 #else /* ! MHD_SUPPORT_THREADS */ 291 res = MHD_NO; /* No used, mute compiler waring */ 292 #endif /* ! MHD_SUPPORT_THREADS */ 293 } 294 output_buf->v_has_connections_bool = res; 295 return MHD_SC_OK; 296 } 297 return MHD_SC_INFO_GET_BUFF_TOO_SMALL; 298 case MHD_DAEMON_INFO_DYNAMIC_SENTINEL: 299 default: 300 break; 301 } 302 return MHD_SC_INFO_GET_TYPE_UNKNOWN; 303 }