/src/mhd2/src/mhd2/daemon_get_info.c
Line | Count | Source |
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 | 1.99k | { |
74 | 1.99k | mhd_assert (!mhd_D_HAS_MASTER (daemon)); |
75 | 1.99k | if (mhd_DAEMON_STATE_STARTED > daemon->state) |
76 | 1.99k | return MHD_SC_TOO_EARLY; |
77 | 0 | if (mhd_DAEMON_STATE_STARTED < daemon->state) |
78 | 0 | return MHD_SC_TOO_LATE; |
79 | | |
80 | 0 | switch (info_type) |
81 | 0 | { |
82 | 0 | case MHD_DAEMON_INFO_FIXED_POLL_SYSCALL: |
83 | 0 | if (mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int)) |
84 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
85 | 0 | if (sizeof(output_buf->v_poll_syscall) > output_buf_size) |
86 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
87 | 0 | output_buf->v_poll_syscall = |
88 | 0 | (enum MHD_SockPollSyscall)daemon->events.poll_type; |
89 | 0 | return MHD_SC_OK; |
90 | 0 | case MHD_DAEMON_INFO_FIXED_NUM_WORK_THREADS: |
91 | 0 | #ifdef MHD_SUPPORT_THREADS |
92 | 0 | if (!mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) |
93 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
94 | 0 | if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION == daemon->wmode_int) |
95 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
96 | 0 | if (sizeof(output_buf->v_num_work_threads_uint) > output_buf_size) |
97 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
98 | 0 | if (mhd_DAEMON_TYPE_SINGLE == daemon->threading.d_type) |
99 | 0 | output_buf->v_num_work_threads_uint = 1; |
100 | 0 | else |
101 | 0 | { |
102 | 0 | mhd_assert (mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY == \ |
103 | 0 | daemon->threading.d_type); |
104 | 0 | output_buf->v_num_work_threads_uint = daemon->threading.hier.pool.num; |
105 | 0 | } |
106 | 0 | return MHD_SC_OK; |
107 | | #else /* ! MHD_SUPPORT_THREADS */ |
108 | | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
109 | | #endif /* ! MHD_SUPPORT_THREADS */ |
110 | 0 | case MHD_DAEMON_INFO_FIXED_BIND_PORT: |
111 | 0 | if ((MHD_INVALID_SOCKET == daemon->net.listen.fd) |
112 | 0 | && !daemon->net.listen.is_broken) |
113 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
114 | 0 | if (mhd_SOCKET_TYPE_UNKNOWN > daemon->net.listen.type) |
115 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
116 | 0 | if (0 == daemon->net.listen.port) |
117 | 0 | { |
118 | 0 | if (mhd_SOCKET_TYPE_IP != daemon->net.listen.type) |
119 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
120 | 0 | return MHD_SC_INFO_GET_TYPE_UNOBTAINABLE; |
121 | 0 | } |
122 | 0 | if (sizeof(output_buf->v_bind_port_uint16) > output_buf_size) |
123 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
124 | 0 | output_buf->v_bind_port_uint16 = daemon->net.listen.port; |
125 | 0 | return MHD_SC_OK; |
126 | 0 | case MHD_DAEMON_INFO_FIXED_LISTEN_SOCKET: |
127 | 0 | if (1) |
128 | 0 | { |
129 | 0 | MHD_Socket listen_fd = daemon->net.listen.fd; |
130 | 0 | if (MHD_INVALID_SOCKET == listen_fd) |
131 | 0 | return daemon->net.listen.is_broken ? |
132 | 0 | MHD_SC_INFO_GET_TYPE_UNOBTAINABLE : |
133 | 0 | MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
134 | 0 | if (sizeof(output_buf->v_listen_socket) > output_buf_size) |
135 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
136 | 0 | output_buf->v_listen_socket = listen_fd; |
137 | 0 | } |
138 | 0 | return MHD_SC_OK; |
139 | 0 | case MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD: |
140 | 0 | #ifdef MHD_SUPPORT_EPOLL |
141 | 0 | if (!mhd_D_IS_USING_EPOLL (daemon)) |
142 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
143 | 0 | if (sizeof(output_buf->v_aggreagate_fd) > output_buf_size) |
144 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
145 | 0 | output_buf->v_aggreagate_fd = daemon->events.data.epoll.e_fd; |
146 | 0 | return MHD_SC_OK; |
147 | | #else |
148 | | return MHD_SC_INFO_GET_TYPE_NOT_SUPP_BY_BUILD; |
149 | | #endif |
150 | 0 | break; |
151 | 0 | case MHD_DAEMON_INFO_FIXED_TLS_BACKEND: |
152 | 0 | if (sizeof(output_buf->v_tls_backend) > output_buf_size) |
153 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
154 | 0 | if (!mhd_D_HAS_TLS (daemon)) |
155 | 0 | output_buf->v_tls_backend = MHD_TLS_BACKEND_NONE; |
156 | 0 | else |
157 | 0 | { |
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 | 0 | } |
193 | 0 | return MHD_SC_OK; |
194 | 0 | case MHD_DAEMON_INFO_FIXED_DEFAULT_TIMEOUT_MILSEC: |
195 | 0 | if (sizeof(output_buf->v_default_timeout_milsec_uint32) > output_buf_size) |
196 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
197 | 0 | output_buf->v_default_timeout_milsec_uint32 = |
198 | 0 | daemon->conns.cfg.timeout_milsec; |
199 | 0 | return MHD_SC_OK; |
200 | 0 | case MHD_DAEMON_INFO_FIXED_GLOBAL_CONNECTION_LIMIT: |
201 | 0 | if (sizeof(output_buf->v_global_connection_limit_uint) > output_buf_size) |
202 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
203 | 0 | output_buf->v_global_connection_limit_uint = |
204 | 0 | daemon->conns.cfg.count_limit; |
205 | 0 | return MHD_SC_OK; |
206 | 0 | case MHD_DAEMON_INFO_FIXED_PER_IP_LIMIT: |
207 | 0 | if (sizeof(output_buf->v_per_ip_limit_uint) > output_buf_size) |
208 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
209 | 0 | output_buf->v_per_ip_limit_uint = daemon->conns.cfg.per_ip_limit; |
210 | 0 | return MHD_SC_OK; |
211 | 0 | case MHD_DAEMON_INFO_FIXED_SUPPRESS_DATE_HEADER: |
212 | 0 | if (sizeof(output_buf->v_suppress_date_header_bool) > output_buf_size) |
213 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
214 | 0 | output_buf->v_suppress_date_header_bool = |
215 | 0 | daemon->req_cfg.suppress_date ? MHD_YES : MHD_NO; |
216 | 0 | return MHD_SC_OK; |
217 | 0 | case MHD_DAEMON_INFO_FIXED_CONN_MEMORY_LIMIT: |
218 | 0 | if (sizeof(output_buf->v_conn_memory_limit_sizet) > output_buf_size) |
219 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
220 | 0 | output_buf->v_conn_memory_limit_sizet = daemon->conns.cfg.mem_pool_size; |
221 | 0 | return MHD_SC_OK; |
222 | 0 | case MHD_DAEMON_INFO_FIXED_FD_NUMBER_LIMIT: |
223 | 0 | #ifdef MHD_SOCKETS_KIND_POSIX |
224 | 0 | if (sizeof(output_buf->v_fd_number_limit_socket) > output_buf_size) |
225 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
226 | 0 | output_buf->v_fd_number_limit_socket = daemon->net.cfg.max_fd_num; |
227 | 0 | 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 | 0 | case MHD_DAEMON_INFO_FIXED_SENTINEL: |
233 | 0 | default: |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | return MHD_SC_INFO_GET_TYPE_UNKNOWN; |
237 | 0 | } |
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 | 2.01k | { |
249 | 2.01k | mhd_assert (!mhd_D_HAS_MASTER (daemon)); |
250 | 2.01k | if (mhd_DAEMON_STATE_STARTED > daemon->state) |
251 | 2.01k | return MHD_SC_TOO_EARLY; |
252 | 0 | if (mhd_DAEMON_STATE_STARTED < daemon->state) |
253 | 0 | return MHD_SC_TOO_LATE; |
254 | | |
255 | 0 | switch (info_type) |
256 | 0 | { |
257 | 0 | case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT: |
258 | 0 | if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int)) |
259 | 0 | return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE; |
260 | 0 | if (sizeof(output_buf->v_max_time_to_wait_uint64) > output_buf_size) |
261 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
262 | 0 | output_buf->v_max_time_to_wait_uint64 = mhd_daemon_get_wait_max (daemon); |
263 | 0 | return MHD_SC_OK; |
264 | 0 | case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS: |
265 | 0 | if (sizeof(output_buf->v_has_connections_bool) <= output_buf_size) |
266 | 0 | { |
267 | 0 | 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 | 0 | if (!mhd_D_HAS_WORKERS (daemon)) |
275 | 0 | res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO; |
276 | 0 | else |
277 | 0 | { |
278 | 0 | #ifdef MHD_SUPPORT_THREADS |
279 | 0 | unsigned int i; |
280 | 0 | res = MHD_NO; |
281 | 0 | mhd_assert (NULL != daemon->threading.hier.pool.workers); |
282 | 0 | for (i = 0; i < daemon->threading.hier.pool.num; ++i) |
283 | 0 | { |
284 | 0 | if (0 != daemon->threading.hier.pool.workers[i].conns.count) |
285 | 0 | { |
286 | 0 | res = MHD_YES; |
287 | 0 | break; |
288 | 0 | } |
289 | 0 | } |
290 | | #else /* ! MHD_SUPPORT_THREADS */ |
291 | | res = MHD_NO; /* No used, mute compiler waring */ |
292 | | #endif /* ! MHD_SUPPORT_THREADS */ |
293 | 0 | } |
294 | 0 | output_buf->v_has_connections_bool = res; |
295 | 0 | return MHD_SC_OK; |
296 | 0 | } |
297 | 0 | return MHD_SC_INFO_GET_BUFF_TOO_SMALL; |
298 | 0 | case MHD_DAEMON_INFO_DYNAMIC_SENTINEL: |
299 | 0 | default: |
300 | 0 | break; |
301 | 0 | } |
302 | 0 | return MHD_SC_INFO_GET_TYPE_UNKNOWN; |
303 | 0 | } |