libtest_convenience.c (14737B)
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 Christian Grothoff 5 Copyright (C) 2025 Evgeny Grin (Karlson2k) 6 7 GNU libmicrohttpd is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 GNU libmicrohttpd is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 Alternatively, you can redistribute GNU libmicrohttpd and/or 18 modify it under the terms of the GNU General Public License as 19 published by the Free Software Foundation; either version 2 of 20 the License, or (at your option) any later version, together 21 with the eCos exception, as follows: 22 23 As a special exception, if other files instantiate templates or 24 use macros or inline functions from this file, or you compile this 25 file and link it with other works to produce a work based on this 26 file, this file does not by itself cause the resulting work to be 27 covered by the GNU General Public License. However the source code 28 for this file must still be made available in accordance with 29 section (3) of the GNU General Public License v2. 30 31 This exception does not invalidate any other reasons why a work 32 based on this file might be covered by the GNU General Public 33 License. 34 35 You should have received copies of the GNU Lesser General Public 36 License and the GNU General Public License along with this library; 37 if not, see <https://www.gnu.org/licenses/>. 38 */ 39 40 /** 41 * @file libtest_convenience.c 42 * @brief convenience functions for libtest users 43 * @author Christian Grothoff 44 */ 45 #include "libtest.h" 46 #include <pthread.h> 47 #include <fcntl.h> 48 #include <unistd.h> 49 #include <errno.h> 50 #ifdef MHD_SUPPORT_EPOLL 51 # include <sys/epoll.h> 52 #endif 53 #include <curl/curl.h> 54 55 56 const char * 57 MHDT_server_setup_minimal (const void *cls, 58 struct MHD_Daemon *d) 59 { 60 const struct MHD_DaemonOptionAndValue *options = cls; 61 62 if (MHD_SC_OK != 63 MHD_daemon_set_options ( 64 d, 65 options, 66 MHD_OPTIONS_ARRAY_MAX_SIZE)) 67 return "Failed to configure threading mode!"; 68 if (MHD_SC_OK != 69 MHD_DAEMON_SET_OPTIONS ( 70 d, 71 MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO, 72 0))) 73 return "Failed to bind to port 0!"; 74 return NULL; 75 } 76 77 78 /** 79 * Setup TLS at @a d for the given backend @a be. 80 * 81 * @return NULL on success, otherwise error message 82 */ 83 static const char * 84 server_setup_tls (struct MHD_Daemon *d, 85 enum MHD_TlsBackend be) 86 { 87 static const char *mem_cert = 88 "-----BEGIN CERTIFICATE-----\n\ 89 MIIDjTCCAnWgAwIBAgIUKkxAx2lVnvYcaNqBpJmTgXh1/VgwDQYJKoZIhvcNAQEL\n\ 90 BQAwVjELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxDzANBgNV\n\ 91 BAcMBkJvc3RvbjENMAsGA1UECgwEUm9vdDEPMA0GA1UEAwwGY2EuZ251MB4XDTI0\n\ 92 MTEyOTEyNDUyOFoXDTM0MTEyNzEyNDUyOFowVjELMAkGA1UEBhMCVVMxFjAUBgNV\n\ 93 BAgMDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcMBkJvc3RvbjENMAsGA1UECgwEUm9v\n\ 94 dDEPMA0GA1UEAwwGY2EuZ251MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n\ 95 AQEA23YSrcGIBgZf9bbzTnmYFy+4tM82kUhsVFKxWCNEMdKmhaeVvXogyd6Evq4P\n\ 96 NvBGdUABDtHp4pSEijrxWbn8sxddTznoT/8IOuHI0/PtwXYP/sHQ/HzekEUVKN2Z\n\ 97 NMbMUzQfaJyiIV5TrZlaBwHjQ+sRs8E56C3cQjkwuyjll2zDsEfmEnPimZRAL3kb\n\ 98 wW8VFfBcR2Id+a9xKjwlnB4eXQFAgYINoRgCtUOUxSeFgNnwkOUSqDknO6Xi47YZ\n\ 99 EdLlHyUnv5eX547xUkrYhfQuQwaqpGrjHf3GFoysN8P9kd2f1qsJKtQcUbF9DDeZ\n\ 100 6ya47X/LBO8QflMsVjb1V3oz9QIDAQABo1MwUTAdBgNVHQ4EFgQUsvdZoX3RxdN6\n\ 101 wrONr31SOA9Qbc4wHwYDVR0jBBgwFoAUsvdZoX3RxdN6wrONr31SOA9Qbc4wDwYD\n\ 102 VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAS3PyV7crGk9brqU90aML\n\ 103 2TWkjgzFb3/nASnpvVYiqyiV4neGiEjtDy7eVlqP6GlD2pYcVodY+ly9wNlo85/h\n\ 104 YfgCFFl37tMG7PpRac2qBqaSn1DpwsCb08LjRrOvoaRffWUikSoZmsYDlaCgl9nT\n\ 105 pGtIrz0BSoyu5mHalIZTVQOrbkNBNK6ZgnYy2iWuiLa5Z1xzKpsRBRaKJc1pcQE/\n\ 106 QVbPdCiyGQMPEVn/KHxitlycFoee/fA+izXVdstVwfig2DoMvrlGZvEkN1ER3Yz4\n\ 107 QPJ6HzOsBQL1F+YhnMCQfc2rpcwxAWf8JMy6jsCq42KGq53tkWqHyQ6Zu2SiLRYk\n\ 108 CA==\n\ 109 -----END CERTIFICATE-----"; 110 static const char *mem_key = 111 "-----BEGIN ENCRYPTED PRIVATE KEY-----\n\ 112 MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQJ1VSHi+akaaVYO3O\n\ 113 H7I0EAICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIZlNzQR1bh4IEggTI\n\ 114 8U86bfGmyAXXSi/R/l3G8ziZFyHrRE5Q/Q3uUW/jyUpe+S0gMRPqwW3V542ForbH\n\ 115 IH/Aa+KVxlwmsq0jlheCQewj9qZMQGuqa3iTl/OfCcuGMfsuQs2HsutoDMdEYuBI\n\ 116 6yOqNIrRvSHunZILLDpKz/AmCO6JnRiAwiSqPBixE5M+cm1qc7dy024REiW9l9K6\n\ 117 Hth9A0iYc94CUyUfHFj4CEkCNqk533Z2Ktkk3RQJnx5ORQG0iBJvoFiVODFKnoAk\n\ 118 Ge2HNrJH3bVvhQ+p8A/L4VmnWUCfcTyqgzo887WXRxORya6gcWWtrcEJGUbLh8sL\n\ 119 /mXFYj/0kEllIY+fHOmSx94I3GwBkQKER/CeOCIp+C392Pujgzrz23pdq20uIt3d\n\ 120 FCgbnIB+5IwOwQcqCkTYa1+Y5qCa6eFLgd8PXGTDyFwP4BHfG6WT/ctHQFi8vnXV\n\ 121 D1S726do1mA6CFE3DYmi45sf+Te2Xb346xk1GTSWtxGh9y4FblFDAWva4oTuvxPR\n\ 122 IDseBhXBsIqnOy1gb/5cGj0SIOQzqR1qlg4igv3UZFC8cVl+fNnngDBiX+nTYQVm\n\ 123 rDyxTzcX9txPSNpLyYRdNHwLGpzZAMoN46bUFnxt0cvRWN6MA7j1r0TYWBZKJ7b7\n\ 124 Yt/SuYsqSE0UJQEJz4QcQnlxu3qu4HJl7dOlto3fa42MWTkOcNr9XinHmKCZ9oYZ\n\ 125 PYNTggRGMXlqm66KmHWDqXqw9CeufprHq15SIJJR8v4SlvEZr+YlYQeHRI4E+FDA\n\ 126 mEFZy/U3ZL7ZHSDsEvpeBzIJkWxHobt57BIxYHE8KN0ZIz/mJZTxljacblFWnJRb\n\ 127 AUXTfrRZn3lGX+4WA6Biilwyxb71slCKaiz28C55Hnj1UwoUF8vNA3G2FGAX5Wk0\n\ 128 m3J2SoCHtJQYc/3lEC7zR9i3/F/7vgRxZMUWt/y6KRYq8ZnoQl3Eo2yvJYX/z7I6\n\ 129 JyqexAx3OvA+frN3rbO/o/k6w9333Smi0QxZzDM9tHn1BAgAtmyC1lizzKn7hDYK\n\ 130 o/eaPeatILbS0a/bHJBbP/R53keVr0hJ3MWK2nb/DV5Dl9j4Z6sHpo3P9L+Kq06y\n\ 131 G9q7NhBd7cxGq4AkCp+eSjqTvwgOX1PtAry00TUmzisLz8gIYutwJqbfZGL8WpR/\n\ 132 /wnLQXuM/tPLdQNy+PZeTQnPFwWQeZz4VgkMRhHV2xDw0mpzE+cdD204+YjHVdMH\n\ 133 D4MNrDlUmKM0OVoYgXd9YyLKzYVgW95GvY1X0SxTlIUuDiRv/SqRsurPFkSG457d\n\ 134 zmTUny1NRsnbv9bTXqt1Xewqsylyu02N1dZvjIzBnYMVYXl0r4aej1VNEXozQtWO\n\ 135 YRfWaZ29dXwZqUzd83ETQvhI4mZbwAlHbqm/CoyY6Vw4Am8hGa7II134lz2b3tkr\n\ 136 F1zBkvzzl6+HXewGOEjm+YorDMtfADiU/hkkykWq01NG3QSwk7jaKieb5Rlou53d\n\ 137 IXJQBw0KW5UrgbIFqMjpSZz1jdALBKsV+dw0wvCQ8BVXZm3zZpsV+0E4Z0sdj3TI\n\ 138 UbkFqQ6GpoxB25UUUlLZhBbtKy7dheuPBk0HowitYlo1kLVA/JiFB4qbdf5X/9Tm\n\ 139 XRkN+T0orEgy7rBQa7dJN9bdLj+dS5q8\n\ 140 -----END ENCRYPTED PRIVATE KEY-----"; 141 142 if (MHD_SC_OK != 143 MHD_DAEMON_SET_OPTIONS ( 144 d, 145 MHD_D_OPTION_TLS (be))) 146 return "Failed to enable TLS!"; 147 if (MHD_SC_OK != 148 MHD_DAEMON_SET_OPTIONS ( 149 d, 150 MHD_D_OPTION_TLS_CERT_KEY (mem_cert, 151 mem_key, 152 "masterword"))) 153 return "Failed to enable TLS!"; 154 return NULL; 155 } 156 157 158 const char * 159 MHDT_server_setup_tls (const void *cls, 160 struct MHD_Daemon *d) 161 { 162 const struct MHD_DaemonOptionAndValue *options = cls; 163 const char *err; 164 165 err = MHDT_server_setup_minimal (options, 166 d); 167 if (NULL != err) 168 return err; 169 err = server_setup_tls (d, 170 MHD_TLS_BACKEND_ANY); 171 if (NULL != err) 172 return err; 173 return NULL; 174 } 175 176 177 const char * 178 MHDT_server_setup_gnutls (const void *cls, 179 struct MHD_Daemon *d) 180 { 181 const struct MHD_DaemonOptionAndValue *options = cls; 182 const char *err; 183 184 err = MHDT_server_setup_minimal (options, 185 d); 186 if (NULL != err) 187 return err; 188 err = server_setup_tls (d, 189 MHD_TLS_BACKEND_GNUTLS); 190 if (NULL != err) 191 return err; 192 return NULL; 193 } 194 195 196 const char * 197 MHDT_server_setup_openssl (const void *cls, 198 struct MHD_Daemon *d) 199 { 200 const struct MHD_DaemonOptionAndValue *options = cls; 201 const char *err; 202 203 err = MHDT_server_setup_minimal (options, 204 d); 205 if (NULL != err) 206 return err; 207 err = server_setup_tls (d, 208 MHD_TLS_BACKEND_OPENSSL); 209 if (NULL != err) 210 return err; 211 return NULL; 212 } 213 214 215 void 216 MHDT_server_run_minimal (void *cls, 217 int finsig, 218 struct MHD_Daemon *d) 219 { 220 fd_set r; 221 char c; 222 223 (void) cls; /* Unused */ 224 (void) d; /* Unused */ 225 226 FD_ZERO (&r); 227 FD_SET (finsig, &r); 228 while (1) 229 { 230 if ( (-1 == 231 select (finsig + 1, 232 &r, 233 NULL, 234 NULL, 235 NULL)) && 236 (EAGAIN != errno) ) 237 { 238 fprintf (stderr, 239 "Failure waiting on termination signal: %s\n", 240 strerror (errno)); 241 break; 242 } 243 if (FD_ISSET (finsig, 244 &r)) 245 break; 246 } 247 if ( (FD_ISSET (finsig, 248 &r)) && 249 (1 != read (finsig, 250 &c, 251 1)) ) 252 { 253 fprintf (stderr, 254 "Failed to drain termination signal\n"); 255 } 256 } 257 258 259 void 260 MHDT_server_run_blocking (void *cls, 261 int finsig, 262 struct MHD_Daemon *d) 263 { 264 fd_set r; 265 char c; 266 267 (void) cls; /* Unused */ 268 (void) d; /* Unused */ 269 270 FD_ZERO (&r); 271 FD_SET (finsig, &r); 272 while (1) 273 { 274 struct timeval timeout = { 275 .tv_usec = 1000 /* 1000 microseconds */ 276 }; 277 278 if ( (-1 == 279 select (finsig + 1, 280 &r, 281 NULL, 282 NULL, 283 &timeout)) && 284 (EAGAIN != errno) ) 285 { 286 fprintf (stderr, 287 "Failure waiting on termination signal: %s\n", 288 strerror (errno)); 289 break; 290 } 291 #ifdef FIXME 292 if (MHD_SC_OK != 293 MHD_daemon_process_blocking (d, 294 1000)) 295 { 296 fprintf (stderr, 297 "Failure running MHD_daemon_process_blocking()\n"); 298 break; 299 } 300 #else 301 abort (); 302 #endif 303 } 304 if ( (FD_ISSET (finsig, 305 &r)) && 306 (1 != read (finsig, 307 &c, 308 1)) ) 309 { 310 fprintf (stderr, 311 "Failed to drain termination signal\n"); 312 } 313 } 314 315 316 #ifdef MHD_SUPPORT_EPOLL 317 static int my_epoll_fd = -1; 318 319 320 /** 321 * The callback for registration/de-registration of the sockets to watch. 322 * 323 * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(), 324 * #MHD_daemon_add_connection(). 325 * 326 * @param cls the closure 327 * @param fd the socket to watch 328 * @param watch_for the states of the @a fd to watch, if set to 329 * #MHD_FD_STATE_NONE the socket must be de-registred 330 * @param app_cntx_old the old application defined context for the socket, 331 * NULL if @a fd socket was not registered before 332 * @param ecb_cntx the context handle to be used 333 * with #MHD_daemon_event_update() 334 * @return NULL if error (to connection will be aborted), 335 * or the new socket context 336 * @ingroup event 337 */ 338 static void * 339 update_fd ( 340 void *cls, 341 MHD_Socket fd, 342 enum MHD_FdState watch_for, 343 MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old, 344 struct MHD_EventUpdateContext *ecb_cntx) 345 { 346 struct epoll_event ev; 347 348 if (watch_for == MHD_FD_STATE_NONE) 349 { 350 epoll_ctl (my_epoll_fd, 351 EPOLL_CTL_DEL, 352 fd, 353 &ev /* for Linux 2.6.9-compatibility */); 354 return NULL; 355 } 356 ev.data.ptr = ecb_cntx; 357 ev.events = 0; 358 if (0 != (watch_for & MHD_FD_STATE_RECV)) 359 ev.events |= EPOLLIN; 360 if (0 != (watch_for & MHD_FD_STATE_SEND)) 361 ev.events |= EPOLLOUT; 362 if (0 != (watch_for & MHD_FD_STATE_EXCEPT)) 363 ev.events |= EPOLLHUP; 364 if (0 != 365 epoll_ctl (my_epoll_fd, 366 NULL == app_cntx_old 367 ? EPOLL_CTL_ADD 368 : EPOLL_CTL_MOD, 369 fd, 370 &ev)) 371 { 372 fprintf (stderr, 373 "epoll_ctl failed: %s\n", 374 strerror (errno)); 375 return NULL; 376 } 377 return ecb_cntx; 378 } 379 380 381 const char * 382 MHDT_server_setup_external (const void *cls, 383 struct MHD_Daemon *d) 384 { 385 (void) cls; 386 if (MHD_SC_OK != 387 MHD_DAEMON_SET_OPTIONS ( 388 d, 389 MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL (&update_fd, 390 NULL))) 391 return "Failed to configure external mode!"; 392 if (MHD_SC_OK != 393 MHD_DAEMON_SET_OPTIONS ( 394 d, 395 MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO, 396 0))) 397 return "Failed to bind to port 0!"; 398 my_epoll_fd = epoll_create1 (0); 399 400 return NULL; 401 } 402 403 404 void 405 MHDT_server_run_external (void *cls, 406 int finsig, 407 struct MHD_Daemon *d) 408 { 409 fd_set r; 410 411 (void) cls; /* Unused */ 412 if (-1 == my_epoll_fd) 413 abort (); 414 while (1) 415 { 416 uint_fast64_t next_wait; 417 struct timeval timeout; 418 419 if (MHD_SC_OK != 420 MHD_daemon_process_reg_events (d, 421 &next_wait)) 422 { 423 fprintf (stderr, 424 "MHD_daemon_process_reg_events() failed\n"); 425 break; 426 } 427 timeout.tv_sec = next_wait / 1000000; 428 timeout.tv_usec = next_wait % 1000000; 429 430 FD_ZERO (&r); 431 FD_SET (finsig, 432 &r); 433 FD_SET (my_epoll_fd, 434 &r); 435 if ( (-1 == 436 select ((my_epoll_fd > finsig ? my_epoll_fd : finsig) + 1, 437 &r, 438 NULL, 439 NULL, 440 &timeout)) && 441 (EAGAIN != errno) ) 442 { 443 fprintf (stderr, 444 "Failure in select(): %s\n", 445 strerror (errno)); 446 break; 447 } 448 if (FD_ISSET (finsig, 449 &r)) 450 break; 451 if (FD_ISSET (my_epoll_fd, 452 &r)) 453 { 454 int maxevents = 40; 455 struct epoll_event events[maxevents]; 456 int n; 457 int i; 458 459 n = epoll_wait (my_epoll_fd, 460 events, 461 maxevents, 462 0); 463 if (-1 == n) 464 { 465 fprintf (stderr, 466 "epoll_wait() failed: %s\n", 467 strerror (errno)); 468 break; 469 } 470 for (i = 0; i < n; i++) 471 { 472 enum MHD_FdState state = MHD_FD_STATE_NONE; 473 474 if (0 != (events[i].events & EPOLLIN)) 475 MHD_FD_STATE_SET_RECV (state); 476 if (0 != (events[i].events & EPOLLOUT)) 477 MHD_FD_STATE_SET_SEND (state); 478 if (0 != (events[i].events & (EPOLLERR | EPOLLHUP)) ) 479 MHD_FD_STATE_SET_EXCEPT (state); 480 MHD_daemon_event_update (d, 481 events[i].data.ptr, 482 state); 483 } 484 } 485 } 486 487 { 488 char c; 489 490 if ( (FD_ISSET (finsig, 491 &r)) && 492 (1 != read (finsig, 493 &c, 494 1)) ) 495 { 496 fprintf (stderr, 497 "Failed to drain termination signal\n"); 498 } 499 } 500 501 close (my_epoll_fd); 502 my_epoll_fd = -1; 503 } 504 505 506 #endif /* MHD_SUPPORT_EPOLL */