events_process.c (87242B)
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-2026 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/events_process.c 41 * @brief The implementation of events processing functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 #include "events_process.h" 47 48 #include "mhd_assert.h" 49 #include "mhd_unreachable.h" 50 51 #include "mhd_predict.h" 52 53 #if defined(MHD_USE_TRACE_SUSPEND_RESUME) || defined(MHD_USE_TRACE_POLLING_FDS) 54 # include <stdio.h> 55 # include <string.h> 56 #endif /* MHD_USE_TRACE_SUSPEND_RESUME || MHD_USE_TRACE_POLLING_FDS */ 57 58 #include "mhd_locks.h" 59 60 #include "mhd_socket_type.h" 61 #include "sys_poll.h" 62 #include "sys_select.h" 63 #ifdef MHD_SUPPORT_EPOLL 64 # include <sys/epoll.h> 65 #endif 66 #include "sys_kqueue.h" 67 #ifdef MHD_SOCKETS_KIND_POSIX 68 # include "sys_errno.h" 69 #endif 70 71 #include "mhd_itc.h" 72 73 #include "mhd_panic.h" 74 #include "mhd_dbg_print.h" 75 76 #include "mhd_sockets_macros.h" 77 #include "mhd_socket_error_funcs.h" 78 79 #include "mhd_daemon.h" 80 #include "mhd_connection.h" 81 82 #include "mhd_mono_clock.h" 83 84 #include "conn_timeout.h" 85 #include "conn_mark_ready.h" 86 #include "daemon_logger.h" 87 #include "daemon_add_conn.h" 88 #include "daemon_funcs.h" 89 #include "conn_data_process.h" 90 #include "stream_funcs.h" 91 #include "extr_events_funcs.h" 92 93 #ifdef MHD_SUPPORT_UPGRADE 94 # include "upgrade_proc.h" 95 #endif /* MHD_SUPPORT_UPGRADE */ 96 97 #ifdef MHD_SUPPORT_HTTPS 98 # include "mhd_tls_funcs.h" 99 #endif 100 101 #ifdef MHD_SUPPORT_HTTP2 102 # include "h2/h2_comm.h" 103 #endif 104 105 #include "mhd_public_api.h" 106 107 #ifdef MHD_USE_TRACE_POLLING_FDS 108 /** 109 * Debug-printf request of FD polling/monitoring 110 * @param fd_name the name of FD ("ITC", "lstn" or "conn") 111 * @param fd the FD value 112 * @param r_ready the request for read (or receive) readiness 113 * @param w_ready the request for write (or send) readiness 114 * @param e_ready the request for exception (or error) readiness 115 */ 116 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 117 mhd_dbg_print_fd_mon_req (const char *fd_name, 118 MHD_Socket fd, 119 bool r_ready, 120 bool w_ready, 121 bool e_ready) 122 { 123 char state_str[] = "x:x:x"; 124 state_str[0] = r_ready ? 'R' : '-'; 125 state_str[2] = w_ready ? 'W' : '-'; 126 state_str[4] = e_ready ? 'E' : '-'; 127 128 fprintf (stderr, 129 "### Set FD watching: %4s [%2llu] for %s\n", 130 fd_name, 131 (unsigned long long)fd, 132 state_str); 133 } 134 135 136 /** 137 * Debug-printf reported (by polling) status of FD 138 * @param fd_name the name of FD ("ITC", "lstn" or "conn") 139 * @param fd the FD value 140 * @param r_ready the read (or receive) readiness 141 * @param w_ready the write (or send) readiness 142 * @param e_ready the exception (or error) readiness 143 */ 144 static MHD_FN_PAR_NONNULL_ALL_ void 145 dbg_print_fd_state_update (const char *fd_name, 146 MHD_Socket fd, 147 bool r_ready, 148 bool w_ready, 149 bool e_ready) 150 { 151 char state_str[] = "x:x:x"; 152 state_str[0] = r_ready ? 'R' : '-'; 153 state_str[2] = w_ready ? 'W' : '-'; 154 state_str[4] = e_ready ? 'E' : '-'; 155 156 fprintf (stderr, 157 "### FD state update: %4s [%2llu] -> %s\n", 158 fd_name, 159 (unsigned long long)fd, 160 state_str); 161 } 162 163 164 # ifdef MHD_SUPPORT_KQUEUE 165 166 static const char * 167 mhd_dbg_kefilter_to_name (const struct kevent *ke) 168 { 169 switch (ke->filter) 170 { 171 case EVFILT_READ: 172 return "READ "; 173 case EVFILT_WRITE: 174 return "WRITE"; 175 default: 176 break; 177 } 178 return "OTHER"; 179 } 180 181 182 # define mhd_DBG_KEFLAGS_BUF_SIZE 512 183 184 static void 185 mdd_dbg_keflags_to_text (const struct kevent *ke, 186 char buf[mhd_DBG_KEFLAGS_BUF_SIZE]) 187 { 188 static const size_t buf_size = mhd_DBG_KEFLAGS_BUF_SIZE; 189 size_t len = 0u; 190 const unsigned int keflags = ke->flags; 191 unsigned int extra_flags; 192 buf[0] = '\0'; 193 194 if (0 != (EV_ADD & keflags)) 195 strcat (buf, "ADD|"); 196 if (0 != (EV_ENABLE & keflags)) 197 strcat (buf, "ENABLE|"); 198 if (0 != (EV_DISABLE & keflags)) 199 strcat (buf, "DISABLE|"); 200 if (0 != (EV_DISPATCH & keflags)) 201 strcat (buf, "DISPATCH|"); 202 if (0 != (EV_DELETE & keflags)) 203 strcat (buf, "DELETE|"); 204 if (0 != (EV_RECEIPT & keflags)) 205 strcat (buf, "RECEIPT|"); 206 if (0 != (EV_ONESHOT & keflags)) 207 strcat (buf, "ONESHOT|"); 208 if (0 != (EV_CLEAR & keflags)) 209 strcat (buf, "CLEAR|"); 210 if (0 != (EV_EOF & keflags)) 211 strcat (buf, "EOF|"); 212 if (0 != (EV_ERROR & keflags)) 213 strcat (buf, "ERROR|"); 214 # ifdef EV_KEEPUDATA 215 if (0 != (EV_KEEPUDATA & keflags)) 216 strcat (buf, "KEEPUDATA|"); 217 # endif /* EV_KEEPUDATA */ 218 219 len = strlen (buf); 220 mhd_assert (buf_size > len); 221 222 extra_flags = 223 (~((unsigned int)(EV_ADD | EV_ENABLE | EV_DISABLE | EV_DISPATCH | EV_DELETE 224 | EV_RECEIPT | EV_ONESHOT | EV_CLEAR | EV_EOF | EV_ERROR 225 | mhd_EV_KEEPUDATA_OR_ZERO))) & keflags; 226 227 if (0u != extra_flags) 228 { 229 (void)snprintf (buf + len, 230 buf_size - len, 231 "0x%02X|", 232 extra_flags); 233 len = strlen (buf); 234 mhd_assert (buf_size > len); 235 } 236 237 if (0u == len) 238 strcpy (buf, "0"); 239 else 240 buf[len - 1u] = '\0'; /* Erase last '|' */ 241 } 242 243 244 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 245 mhd_dbg_print_kevent (const char *fd_name, 246 const struct kevent *ke, 247 bool update_req) 248 { 249 char flags_txt[mhd_DBG_KEFLAGS_BUF_SIZE]; 250 const char *action_name = 251 update_req ? "Update FD watching" : "FD state update"; 252 253 mdd_dbg_keflags_to_text (ke, 254 flags_txt); 255 256 fprintf (stderr, 257 "### %s: %4s [%2llu]; filter: %s; flags: %s;\t" 258 "fflags: %u;\tdata %lld\n", 259 action_name, 260 fd_name, 261 (unsigned long long)ke->ident, 262 mhd_dbg_kefilter_to_name (ke), 263 flags_txt, 264 (unsigned int)ke->fflags, 265 (long long)ke->data); 266 } 267 268 269 # endif /* MHD_SUPPORT_KQUEUE */ 270 271 #else /* ! MHD_USE_TRACE_POLLING_FDS */ 272 # define dbg_print_fd_state_update(fd_n, fd, r_ready, w_ready, e_ready) \ 273 ((void) 0) 274 # ifdef MHD_SUPPORT_KQUEUE 275 # define mhd_dbg_print_kq_fd_mon_req(fd_name, ke) 276 # endif /* MHD_SUPPORT_KQUEUE */ 277 #endif /* ! MHD_USE_TRACE_POLLING_FDS */ 278 279 #ifdef MHD_SUPPORT_THREADS 280 /** 281 * Log error message about broken ITC 282 * @param d the daemon to use 283 */ 284 static MHD_FN_PAR_NONNULL_ALL_ void 285 log_itc_broken (struct MHD_Daemon *restrict d) 286 { 287 mhd_LOG_MSG (d, \ 288 MHD_SC_ITC_STATUS_ERROR, \ 289 "System reported that ITC has an error status or broken."); 290 } 291 292 293 #endif /* MHD_SUPPORT_THREADS */ 294 295 /** 296 * Log error message about broken listen socket 297 * @param d the daemon to use 298 */ 299 static MHD_FN_PAR_NONNULL_ALL_ void 300 log_listen_broken (struct MHD_Daemon *restrict d) 301 { 302 mhd_LOG_MSG (d, MHD_SC_LISTEN_STATUS_ERROR, \ 303 "System reported that the listening socket has an error " \ 304 "status or broken. The daemon will not listen any more."); 305 } 306 307 308 static MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t 309 mhd_daemon_get_wait_erliest_timeout (const struct MHD_Daemon *restrict d) 310 { 311 uint_fast64_t ret; 312 uint_fast64_t cur_milsec; 313 const struct MHD_Connection *c; 314 315 c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout)); 316 if ((NULL == c) 317 && (NULL == mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)))) 318 return MHD_WAIT_INDEFINITELY; 319 320 /* Do not use mhd_daemon_get_milsec_counter() as actual time is required 321 here */ 322 cur_milsec = mhd_monotonic_msec_counter (); 323 324 /* Check just the first connection in the ordered "default timeout" list */ 325 if (NULL != c) 326 ret = mhd_conn_get_timeout_left (c, 327 cur_milsec); 328 else 329 ret = MHD_WAIT_INDEFINITELY; 330 331 for (c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)); 332 (NULL != c) && (0u != ret); 333 c = mhd_DLINKEDL_GET_PREV (&(c->timeout), 334 tmout_list)) 335 { 336 uint_fast64_t conn_tmout_left; 337 conn_tmout_left = mhd_conn_get_timeout_left (c, 338 cur_milsec); 339 if (ret > conn_tmout_left) 340 ret = conn_tmout_left; 341 } 342 343 return ret; 344 } 345 346 347 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t 348 mhd_daemon_get_wait_max (const struct MHD_Daemon *restrict d) 349 { 350 uint_fast64_t ret; 351 352 mhd_assert (!mhd_D_HAS_WORKERS (d)); 353 354 if (d->events.accept_pending && !d->conns.block_new) 355 { 356 #ifdef MHD_USE_TRACE_POLLING_FDS 357 fprintf (stderr, 358 "### mhd_daemon_get_wait_max(daemon) -> zero " 359 "(accept new conn pending)\n"); 360 #endif 361 return 0; 362 } 363 if (d->events.act_req.resume) 364 { 365 #ifdef MHD_USE_TRACE_POLLING_FDS 366 fprintf (stderr, 367 "### mhd_daemon_get_wait_max(daemon) -> zero " 368 "(resume connection pending)\n"); 369 #endif 370 return 0; 371 } 372 if (NULL != mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready)) 373 { 374 #ifdef MHD_USE_TRACE_POLLING_FDS 375 fprintf (stderr, 376 "### mhd_daemon_get_wait_max(daemon) -> zero " 377 "(connection(s) is already ready)\n"); 378 #endif 379 return 0; 380 } 381 if (NULL != mhd_DLINKEDL_GET_FIRST (&(d->events.act_req.ext_added.worker), 382 queue)) 383 { 384 #ifdef MHD_USE_TRACE_POLLING_FDS 385 fprintf (stderr, 386 "### mhd_daemon_get_wait_max(daemon) -> zero " 387 "(externally added connection(s) pending)\n"); 388 #endif 389 return 0; 390 } 391 #ifdef MHD_SUPPORT_KQUEUE 392 if (mhd_D_IS_USING_KQUEUE (d)) 393 { 394 if ((NULL != mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn)) 395 && !mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn)->events.kq.monitored) 396 { 397 # ifdef MHD_USE_TRACE_POLLING_FDS 398 fprintf (stderr, 399 "### mhd_daemon_get_wait_max(daemon) -> zero " 400 "(kqueue unmonitored connection(s) pending)\n"); 401 # endif 402 return 0; 403 } 404 } 405 #endif /* MHD_SUPPORT_KQUEUE */ 406 407 ret = mhd_daemon_get_wait_erliest_timeout (d); 408 409 #ifdef MHD_USE_TRACE_POLLING_FDS 410 if (MHD_WAIT_INDEFINITELY == ret) 411 fprintf (stderr, 412 "### mhd_daemon_get_wait_max(daemon) -> MHD_WAIT_INDEFINITELY\n"); 413 else 414 fprintf (stderr, 415 "### mhd_daemon_get_wait_max(daemon) -> %lu\n", 416 (unsigned long)ret); 417 #endif 418 419 return ret; 420 } 421 422 423 static MHD_FN_PAR_NONNULL_ALL_ void 424 start_resuming_connection (struct MHD_Connection *restrict c, 425 struct MHD_Daemon *restrict d) 426 { 427 mhd_assert (c->suspended); 428 #ifdef MHD_USE_TRACE_SUSPEND_RESUME 429 fprintf (stderr, 430 "%%%%%% Resuming connection, FD: %2llu\n", 431 (unsigned long long)c->sk.fd); 432 #endif /* MHD_USE_TRACE_SUSPEND_RESUME */ 433 c->suspended = false; 434 mhd_conn_init_activity_timeout (c, 435 c->timeout.milsec); 436 mhd_conn_mark_ready (c, d); /* Force processing connection in this round */ 437 } 438 439 440 /** 441 * Check whether any resuming connections are pending and resume them 442 * @param d the daemon to use 443 */ 444 static MHD_FN_PAR_NONNULL_ALL_ void 445 daemon_resume_conns_if_needed (struct MHD_Daemon *restrict d) 446 { 447 struct MHD_Connection *c; 448 449 if (!d->events.act_req.resume) 450 return; 451 452 d->events.act_req.resume = false; /* Reset flag before processing data */ 453 454 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 455 NULL != c; 456 c = mhd_DLINKEDL_GET_NEXT (c, all_conn)) 457 { 458 if (c->resuming) 459 start_resuming_connection (c, d); 460 } 461 } 462 463 464 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_EPOLL) 465 466 mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE 467 468 static MHD_FN_PAR_NONNULL_ALL_ int 469 get_max_wait (const struct MHD_Daemon *restrict d) 470 { 471 const uint_fast64_t ui64_wait = mhd_daemon_get_wait_max (d); 472 int i_wait = (int)ui64_wait; 473 474 if (MHD_WAIT_INDEFINITELY <= ui64_wait) 475 return -1; 476 477 if (mhd_COND_ALMOST_NEVER ((0 > i_wait) 478 || (ui64_wait != (uint_fast64_t)i_wait))) 479 return INT_MAX; 480 481 return i_wait; 482 } 483 484 485 mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE 486 /* End of warning-less data truncation */ 487 488 #endif 489 /* MHD_SUPPORT_POLL || MHD_SUPPORT_EPOLL */ 490 491 492 MHD_FN_PAR_NONNULL_ (1) static void 493 update_conn_net_status (struct MHD_Daemon *restrict d, 494 struct MHD_Connection *restrict c, 495 bool recv_ready, 496 bool send_ready, 497 bool err_state) 498 { 499 enum mhd_SocketNetState sk_state; 500 501 mhd_assert (d == c->daemon); 502 /* "resuming" must be not processed yet */ 503 mhd_assert (!c->resuming || c->suspended); 504 505 dbg_print_fd_state_update ("conn", \ 506 c->sk.fd, \ 507 recv_ready, \ 508 send_ready, \ 509 err_state); 510 511 sk_state = mhd_SOCKET_NET_STATE_NOTHING; 512 if (recv_ready) 513 sk_state = (enum mhd_SocketNetState) 514 (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_RECV_READY); 515 if (send_ready) 516 sk_state = (enum mhd_SocketNetState) 517 (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_SEND_READY); 518 if (err_state) 519 sk_state = (enum mhd_SocketNetState) 520 (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_ERROR_READY); 521 c->sk.ready = sk_state; 522 523 if (!c->suspended) 524 mhd_conn_mark_ready_update3 (c, err_state, d); 525 else 526 mhd_assert (!c->in_proc_ready); 527 } 528 529 530 /** 531 * Accept new connections on the daemon 532 * @param d the daemon to use 533 * @return true if all incoming connections has been accepted, 534 * false if some connection may still wait to be accepted 535 */ 536 MHD_FN_PAR_NONNULL_ (1) static bool 537 daemon_accept_new_conns (struct MHD_Daemon *restrict d) 538 { 539 unsigned int num_to_accept; 540 mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd); 541 mhd_assert (!d->net.listen.is_broken); 542 mhd_assert (!d->conns.block_new); 543 mhd_assert (d->conns.count < d->conns.cfg.count_limit); 544 mhd_assert (!mhd_D_HAS_WORKERS (d)); 545 546 if (!d->net.listen.non_block) 547 num_to_accept = 1; /* listen socket is blocking, only one connection can be processed */ 548 else 549 { 550 const unsigned int slots_left = d->conns.cfg.count_limit - d->conns.count; 551 if (!mhd_D_HAS_MASTER (d)) 552 { 553 /* Fill up to one quarter of allowed limit in one turn */ 554 num_to_accept = d->conns.cfg.count_limit / 4; 555 /* Limit to a reasonable number */ 556 if (((sizeof(void *) > 4) ? 4096 : 1024) < num_to_accept) 557 num_to_accept = ((sizeof(void *) > 4) ? 4096 : 1024); 558 if (slots_left < num_to_accept) 559 num_to_accept = slots_left; 560 } 561 #ifdef MHD_SUPPORT_THREADS 562 else 563 { 564 /* Has workers thread pool. Care must be taken to evenly distribute 565 new connections in the workers pool. 566 At the same time, the burst of new connections should be handled as 567 quick as possible. */ 568 const unsigned int num_conn = d->conns.count; 569 const unsigned int limit = d->conns.cfg.count_limit; 570 const unsigned int num_workers = 571 d->threading.hier.master->threading.hier.pool.num; 572 if (num_conn < limit / 16) 573 { 574 num_to_accept = num_conn / num_workers; 575 if (8 > num_to_accept) 576 { 577 if (8 > slots_left / 16) 578 num_to_accept = slots_left / 16; 579 else 580 num_to_accept = 8; 581 } 582 if (64 < num_to_accept) 583 num_to_accept = 64; 584 } 585 else if (num_conn < limit / 8) 586 { 587 num_to_accept = num_conn * 2 / num_workers; 588 if (8 > num_to_accept) 589 { 590 if (8 > slots_left / 8) 591 num_to_accept = slots_left / 8; 592 else 593 num_to_accept = 8; 594 } 595 if (128 < num_to_accept) 596 num_to_accept = 128; 597 } 598 else if (num_conn < limit / 4) 599 { 600 num_to_accept = num_conn * 4 / num_workers; 601 if (8 > num_to_accept) 602 num_to_accept = 8; 603 if (slots_left / 4 < num_to_accept) 604 num_to_accept = slots_left / 4; 605 if (256 < num_to_accept) 606 num_to_accept = 256; 607 } 608 else if (num_conn < limit / 2) 609 { 610 num_to_accept = num_conn * 8 / num_workers; 611 if (16 > num_to_accept) 612 num_to_accept = 16; 613 if (slots_left / 4 < num_to_accept) 614 num_to_accept = slots_left / 4; 615 if (256 < num_to_accept) 616 num_to_accept = 256; 617 } 618 else if (slots_left > limit / 4) 619 { 620 num_to_accept = slots_left * 4 / num_workers; 621 if (slots_left / 8 < num_to_accept) 622 num_to_accept = slots_left / 8; 623 if (128 < num_to_accept) 624 num_to_accept = 128; 625 } 626 else if (slots_left > limit / 8) 627 { 628 num_to_accept = slots_left * 2 / num_workers; 629 if (slots_left / 16 < num_to_accept) 630 num_to_accept = slots_left / 16; 631 if (64 < num_to_accept) 632 num_to_accept = 64; 633 } 634 else /* (slots_left <= limit / 8) */ 635 num_to_accept = slots_left / 16; 636 637 if (0 == num_to_accept) 638 num_to_accept = 1; 639 else if (slots_left > num_to_accept) 640 num_to_accept = slots_left; 641 } 642 #endif /* MHD_SUPPORT_THREADS */ 643 } 644 645 while (0 != --num_to_accept) 646 { 647 enum mhd_DaemonAcceptResult res; 648 res = mhd_daemon_accept_connection (d); 649 if (mhd_DAEMON_ACCEPT_NO_MORE_PENDING == res) 650 return true; 651 if (mhd_DAEMON_ACCEPT_FAILED == res) 652 return false; /* This is probably "no system resources" error. 653 To do try to accept more connections now. */ 654 } 655 return false; /* More connections may need to be accepted */ 656 } 657 658 659 /** 660 * Check whether particular connection should be excluded from standard HTTP 661 * communication. 662 * @param c the connection the check 663 * @return 'true' if connection should not be used for HTTP communication 664 * 'false' if connection should be processed as HTTP 665 */ 666 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ bool 667 is_conn_excluded_from_http_comm (struct MHD_Connection *restrict c) 668 { 669 #ifdef MHD_SUPPORT_UPGRADE 670 if (NULL != c->upgr.c) 671 { 672 mhd_assert ((mhd_HTTP_STAGE_UPGRADED == c->stage) \ 673 || (mhd_HTTP_STAGE_UPGRADED_CLEANING == c->stage)); 674 return true; 675 } 676 #endif /* MHD_SUPPORT_UPGRADE */ 677 678 return c->suspended; 679 } 680 681 682 static bool 683 daemon_process_all_active_conns (struct MHD_Daemon *restrict d) 684 { 685 struct MHD_Connection *c; 686 mhd_assert (!mhd_D_HAS_WORKERS (d)); 687 688 c = mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready); 689 while (NULL != c) 690 { 691 struct MHD_Connection *next; 692 /* The current connection can be closed or removed from 693 "ready" list */ 694 next = mhd_DLINKEDL_GET_NEXT (c, proc_ready); 695 if (!mhd_conn_process_recv_send_data (c)) 696 { 697 mhd_conn_pre_clean (c); 698 mhd_conn_remove_from_daemon (c); 699 mhd_conn_close_final (c); 700 } 701 else 702 { 703 mhd_assert (!c->resuming || c->suspended); 704 } 705 706 c = next; 707 } 708 return true; 709 } 710 711 712 #ifdef MHD_SUPPORT_UPGRADE 713 /** 714 * Clean-up all HTTP-Upgraded connections scheduled for clean-up 715 * @param d the daemon to process 716 */ 717 static MHD_FN_PAR_NONNULL_ALL_ void 718 daemon_cleanup_upgraded_conns (struct MHD_Daemon *d) 719 { 720 volatile struct MHD_Daemon *voltl_d = d; 721 mhd_assert (!mhd_D_HAS_WORKERS (d)); 722 723 if (NULL == mhd_DLINKEDL_GET_FIRST (&(voltl_d->conns.upgr), upgr_cleanup)) 724 return; 725 726 while (true) 727 { 728 struct MHD_Connection *c; 729 730 mhd_mutex_lock_chk (&(d->conns.upgr.ucu_lock)); 731 c = mhd_DLINKEDL_GET_FIRST (&(d->conns.upgr), upgr_cleanup); 732 if (NULL != c) 733 mhd_DLINKEDL_DEL (&(d->conns.upgr), c, upgr_cleanup); 734 mhd_mutex_unlock_chk (&(d->conns.upgr.ucu_lock)); 735 736 if (NULL == c) 737 break; 738 739 mhd_assert (mhd_HTTP_STAGE_UPGRADED_CLEANING == c->stage); 740 mhd_upgraded_deinit (c); 741 mhd_conn_pre_clean (c); 742 mhd_conn_remove_from_daemon (c); 743 mhd_conn_close_final (c); 744 } 745 } 746 747 748 #else /* ! MHD_SUPPORT_UPGRADE */ 749 # define daemon_cleanup_upgraded_conns(d) ((void) d) 750 #endif /* ! MHD_SUPPORT_UPGRADE */ 751 752 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 753 mhd_daemon_close_all_conns (struct MHD_Daemon *d) 754 { 755 struct MHD_Connection *c; 756 bool has_upgraded_unclosed; 757 758 has_upgraded_unclosed = false; 759 if (!mhd_D_HAS_THR_PER_CONN (d)) 760 { 761 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 762 NULL != c; 763 c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn)) 764 { 765 #ifdef MHD_SUPPORT_UPGRADE 766 mhd_assert (mhd_HTTP_STAGE_UPGRADING != c->stage); 767 mhd_assert (mhd_HTTP_STAGE_UPGRADED_CLEANING != c->stage); 768 if (NULL != c->upgr.c) 769 { 770 mhd_assert (c == c->upgr.c); 771 has_upgraded_unclosed = true; 772 mhd_upgraded_deinit (c); 773 } 774 else /* Combined with the next 'if' */ 775 #endif 776 if (1) 777 { 778 #ifdef MHD_SUPPORT_HTTP2 779 if (mhd_C_IS_HTTP2 (c)) 780 mhd_h2_conn_h2_deinit_start_closing (c); 781 else 782 #endif /* MHD_SUPPORT_HTTP2 */ 783 mhd_conn_start_closing_d_shutdown (c); 784 } 785 mhd_conn_pre_clean (c); 786 mhd_conn_remove_from_daemon (c); 787 mhd_conn_close_final (c); 788 } 789 } 790 else 791 mhd_assert (0 && "Not implemented yet"); 792 793 if (has_upgraded_unclosed) 794 mhd_LOG_MSG (d, MHD_SC_DAEMON_DESTROYED_WITH_UNCLOSED_UPGRADED, \ 795 "The daemon is being destroyed, but at least one " \ 796 "HTTP-Upgraded connection is unclosed. Any use (including " \ 797 "closing) of such connections is undefined behaviour."); 798 } 799 800 801 /** 802 * Process all external events updated of existing connections, information 803 * about new connections pending to be accept()'ed, presence of the events on 804 * the daemon's ITC; resume connections. 805 * @return 'true' if processed successfully, 806 * 'false' is unrecoverable error occurs and the daemon must be 807 * closed 808 */ 809 static MHD_FN_PAR_NONNULL_ (1) bool 810 ext_events_process_net_updates_and_resume_conn (struct MHD_Daemon *restrict d) 811 { 812 struct MHD_Connection *restrict c; 813 814 mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int)); 815 mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type); 816 817 d->events.act_req.resume = false; /* Reset flag before processing data */ 818 819 #ifdef MHD_SUPPORT_THREADS 820 if (d->events.data.extr.itc_data.is_active) 821 { 822 d->events.data.extr.itc_data.is_active = false; 823 /* Clear ITC here, before other data processing. 824 * Any external events will activate ITC again if additional data to 825 * process is added externally. Clearing ITC early ensures that new data 826 * (with additional ITC activation) will not be missed. */ 827 mhd_itc_clear (d->threading.itc); 828 } 829 #endif /* MHD_SUPPORT_THREADS */ 830 831 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 832 NULL != c; 833 c = mhd_DLINKEDL_GET_NEXT (c, all_conn)) 834 { 835 bool has_err_state; 836 837 if (c->resuming) 838 start_resuming_connection (c, d); 839 else 840 { 841 if (is_conn_excluded_from_http_comm (c)) 842 { 843 mhd_assert (!c->in_proc_ready); 844 continue; 845 } 846 847 has_err_state = (0 != (((unsigned int)c->sk.ready) 848 & mhd_SOCKET_NET_STATE_ERROR_READY)); 849 850 mhd_conn_mark_ready_update3 (c, 851 has_err_state, 852 d); 853 } 854 } 855 856 return true; 857 } 858 859 860 /** 861 * Update all registrations of FDs for external monitoring. 862 * @return #MHD_SC_OK on success, 863 * error code otherwise 864 */ 865 static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode 866 ext_events_update_registrations (struct MHD_Daemon *restrict d) 867 { 868 const bool rereg_all = d->events.data.extr.reg_all; 869 const bool edge_trigg = (mhd_WM_INT_EXTERNAL_EVENTS_EDGE == d->wmode_int); 870 bool daemon_fds_succeed; 871 struct MHD_Connection *c; 872 struct MHD_Connection *c_next; 873 874 mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int)); 875 mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type); 876 877 /* (Re-)register daemon's FDs */ 878 879 #ifdef MHD_SUPPORT_THREADS 880 if (rereg_all 881 || (NULL == d->events.data.extr.itc_data.app_cntx)) 882 { 883 /* (Re-)register ITC FD */ 884 d->events.data.extr.itc_data.app_cntx = 885 mhd_daemon_extr_event_reg (d, 886 mhd_itc_r_fd (d->threading.itc), 887 MHD_FD_STATE_RECV_EXCEPT, 888 d->events.data.extr.itc_data.app_cntx, 889 (struct MHD_EventUpdateContext *) 890 mhd_SOCKET_REL_MARKER_ITC); 891 } 892 daemon_fds_succeed = (NULL != d->events.data.extr.itc_data.app_cntx); 893 #else /* ! MHD_SUPPORT_THREADS */ 894 daemon_fds_succeed = true; 895 #endif /* ! MHD_SUPPORT_THREADS */ 896 897 if (daemon_fds_succeed) 898 { 899 if ((MHD_INVALID_SOCKET == d->net.listen.fd) 900 && (NULL != d->events.data.extr.listen_data.app_cntx)) 901 { 902 /* De-register the listen FD */ 903 d->events.data.extr.listen_data.app_cntx = 904 mhd_daemon_extr_event_reg (d, 905 d->net.listen.fd, 906 MHD_FD_STATE_NONE, 907 d->events.data.extr.listen_data.app_cntx, 908 (struct MHD_EventUpdateContext *) 909 mhd_SOCKET_REL_MARKER_LISTEN); 910 if (NULL != d->events.data.extr.listen_data.app_cntx) 911 mhd_log_extr_event_dereg_failed (d); 912 } 913 else if ((MHD_INVALID_SOCKET != d->net.listen.fd) 914 && (rereg_all 915 || (NULL == d->events.data.extr.listen_data.app_cntx))) 916 { 917 /* (Re-)register listen FD */ 918 d->events.data.extr.listen_data.app_cntx = 919 mhd_daemon_extr_event_reg (d, 920 d->net.listen.fd, 921 MHD_FD_STATE_RECV_EXCEPT, 922 d->events.data.extr.listen_data.app_cntx, 923 (struct MHD_EventUpdateContext *) 924 mhd_SOCKET_REL_MARKER_LISTEN); 925 926 daemon_fds_succeed = (NULL != d->events.data.extr.listen_data.app_cntx); 927 } 928 } 929 930 if (!daemon_fds_succeed) 931 { 932 mhd_LOG_MSG (d, MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE, \ 933 "Failed to register daemon FDs in the application " 934 "(external events) monitoring."); 935 return MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE; 936 } 937 938 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 939 NULL != c; 940 c = c_next) 941 { 942 enum MHD_FdState watch_for; 943 944 /* Get the next connection now, as the current connection could be removed 945 from the daemon. */ 946 c_next = mhd_DLINKEDL_GET_NEXT (c, all_conn); 947 948 mhd_assert (!c->resuming || c->suspended); 949 950 if (is_conn_excluded_from_http_comm (c)) 951 { 952 if (NULL != c->events.extrn.app_cntx) 953 { 954 /* De-register the connection socket FD */ 955 c->events.extrn.app_cntx = 956 mhd_daemon_extr_event_reg (d, 957 c->sk.fd, 958 MHD_FD_STATE_NONE, 959 c->events.extrn.app_cntx, 960 (struct MHD_EventUpdateContext *)c); 961 if (NULL != c->events.extrn.app_cntx) 962 mhd_log_extr_event_dereg_failed (d); 963 } 964 continue; 965 } 966 967 watch_for = 968 edge_trigg ? 969 MHD_FD_STATE_RECV_SEND_EXCEPT : 970 (enum MHD_FdState)(MHD_FD_STATE_EXCEPT 971 | (((unsigned int)c->event_loop_info) 972 & (MHD_EVENT_LOOP_INFO_RECV 973 | MHD_EVENT_LOOP_INFO_SEND))); 974 975 mhd_assert ((!edge_trigg) \ 976 || (MHD_FD_STATE_RECV_SEND_EXCEPT == c->events.extrn.reg_for) \ 977 || (NULL == c->events.extrn.app_cntx)); 978 979 if ((NULL == c->events.extrn.app_cntx) 980 || rereg_all 981 || (!edge_trigg && (watch_for != c->events.extrn.reg_for))) 982 { 983 /* (Re-)register the connection socket FD */ 984 c->events.extrn.app_cntx = 985 mhd_daemon_extr_event_reg (d, 986 c->sk.fd, 987 watch_for, 988 c->events.extrn.app_cntx, 989 (struct MHD_EventUpdateContext *)c); 990 if (NULL == c->events.extrn.app_cntx) 991 { 992 mhd_conn_start_closing_ext_event_failed (c); 993 mhd_conn_pre_clean (c); 994 mhd_conn_remove_from_daemon (c); 995 mhd_conn_close_final (c); 996 } 997 c->events.extrn.reg_for = watch_for; 998 } 999 } 1000 1001 return MHD_SC_OK; 1002 } 1003 1004 1005 #ifdef MHD_SUPPORT_SELECT 1006 1007 /** 1008 * Add socket to the fd_set 1009 * @param fd the socket to add 1010 * @param fs the pointer to fd_set 1011 * @param max the pointer to variable to be updated with maximum FD value (or 1012 * set to non-zero in case of WinSock) 1013 * @param d the daemon object 1014 */ 1015 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ 1016 MHD_FN_PAR_INOUT_ (2) 1017 MHD_FN_PAR_INOUT_ (3) void 1018 fd_set_wrap (MHD_Socket fd, 1019 fd_set *restrict fs, 1020 int *restrict max, 1021 struct MHD_Daemon *restrict d) 1022 { 1023 mhd_assert (mhd_FD_FITS_DAEMON (d, fd)); /* Must be checked for every FD before 1024 it is added */ 1025 mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type); 1026 (void)d; /* Unused with non-debug builds */ 1027 # if defined(MHD_SOCKETS_KIND_POSIX) 1028 FD_SET (fd, fs); 1029 if (*max < fd) 1030 *max = fd; 1031 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 1032 /* Use custom set function to take advantage of know uniqueness of 1033 * used sockets (to skip useless (for this function) check for duplicated 1034 * sockets implemented in system's macro). */ 1035 mhd_assert (fs->fd_count < FD_SETSIZE - 1); /* Daemon limits set to always fit FD_SETSIZE */ 1036 mhd_assert (!FD_ISSET (fd, fs)); /* All sockets must be unique */ 1037 fs->fd_array[fs->fd_count++] = fd; 1038 *max = 1; 1039 # else 1040 # error Unknown sockets type 1041 # endif 1042 } 1043 1044 1045 /** 1046 * Set daemon's FD_SETs to monitor all daemon's sockets 1047 * @param d the daemon to use 1048 * @param listen_only set to 'true' if connections's sockets should NOT 1049 * be monitored 1050 * @return with POSIX sockets: the maximum number of the socket used in 1051 * the FD_SETs; 1052 * with winsock: non-zero if at least one socket has been added to 1053 * the FD_SETs, 1054 * zero if no sockets in the FD_SETs 1055 */ 1056 static MHD_FN_PAR_NONNULL_ (1) int 1057 select_update_fdsets (struct MHD_Daemon *restrict d, 1058 bool listen_only) 1059 { 1060 struct MHD_Connection *c; 1061 fd_set *const restrict rfds = d->events.data.select.rfds; 1062 fd_set *const restrict wfds = d->events.data.select.wfds; 1063 fd_set *const restrict efds = d->events.data.select.efds; 1064 int ret; 1065 1066 mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type); 1067 mhd_assert (NULL != rfds); 1068 mhd_assert (NULL != wfds); 1069 mhd_assert (NULL != efds); 1070 FD_ZERO (rfds); 1071 FD_ZERO (wfds); 1072 FD_ZERO (efds); 1073 1074 ret = 0; 1075 # ifdef MHD_SUPPORT_THREADS 1076 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 1077 fd_set_wrap (mhd_itc_r_fd (d->threading.itc), 1078 rfds, 1079 &ret, 1080 d); 1081 fd_set_wrap (mhd_itc_r_fd (d->threading.itc), 1082 efds, 1083 &ret, 1084 d); 1085 mhd_dbg_print_fd_mon_req ("ITC", \ 1086 mhd_itc_r_fd (d->threading.itc), \ 1087 true, \ 1088 false, \ 1089 true); 1090 # endif 1091 if ((MHD_INVALID_SOCKET != d->net.listen.fd) 1092 && !d->conns.block_new) 1093 { 1094 mhd_assert (!d->net.listen.is_broken); 1095 1096 fd_set_wrap (d->net.listen.fd, 1097 rfds, 1098 &ret, 1099 d); 1100 fd_set_wrap (d->net.listen.fd, 1101 efds, 1102 &ret, 1103 d); 1104 mhd_dbg_print_fd_mon_req ("lstn", \ 1105 d->net.listen.fd, \ 1106 true, \ 1107 false, \ 1108 true); 1109 } 1110 if (listen_only) 1111 return ret; 1112 1113 for (c = mhd_DLINKEDL_GET_LAST (&(d->conns), all_conn); NULL != c; 1114 c = mhd_DLINKEDL_GET_PREV (c, all_conn)) 1115 { 1116 mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage); 1117 if (is_conn_excluded_from_http_comm (c)) 1118 continue; 1119 1120 if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) 1121 fd_set_wrap (c->sk.fd, 1122 rfds, 1123 &ret, 1124 d); 1125 if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND)) 1126 fd_set_wrap (c->sk.fd, 1127 wfds, 1128 &ret, 1129 d); 1130 fd_set_wrap (c->sk.fd, 1131 efds, 1132 &ret, 1133 d); 1134 mhd_dbg_print_fd_mon_req ("conn", \ 1135 c->sk.fd, \ 1136 FD_ISSET (c->sk.fd, rfds), \ 1137 FD_ISSET (c->sk.fd, wfds), \ 1138 true); 1139 } 1140 1141 return ret; 1142 } 1143 1144 1145 static MHD_FN_PAR_NONNULL_ (1) bool 1146 select_update_statuses_from_fdsets_and_resume_conn (struct MHD_Daemon *d, 1147 int num_events) 1148 { 1149 struct MHD_Connection *c; 1150 fd_set *const restrict rfds = d->events.data.select.rfds; 1151 fd_set *const restrict wfds = d->events.data.select.wfds; 1152 fd_set *const restrict efds = d->events.data.select.efds; 1153 bool resuming_conn; 1154 1155 mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type); 1156 mhd_assert (0 <= num_events); 1157 mhd_assert (((unsigned int)num_events) <= d->dbg.num_events_elements); 1158 1159 resuming_conn = d->events.act_req.resume; 1160 if (resuming_conn) 1161 { 1162 mhd_assert (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type)); 1163 mhd_assert (!mhd_D_HAS_THR_PER_CONN (d)); 1164 num_events = (int)-1; /* Force process all connections */ 1165 d->events.act_req.resume = false; 1166 } 1167 1168 # ifndef MHD_FAVOR_SMALL_CODE 1169 if (0 == num_events) 1170 return true; 1171 # endif /* MHD_FAVOR_SMALL_CODE */ 1172 1173 # ifdef MHD_SUPPORT_THREADS 1174 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 1175 dbg_print_fd_state_update ("ITC", \ 1176 mhd_itc_r_fd (d->threading.itc), \ 1177 FD_ISSET (mhd_itc_r_fd (d->threading.itc), rfds), \ 1178 FD_ISSET (mhd_itc_r_fd (d->threading.itc), wfds), \ 1179 FD_ISSET (mhd_itc_r_fd (d->threading.itc), efds)); 1180 if (FD_ISSET (mhd_itc_r_fd (d->threading.itc), efds)) 1181 { 1182 log_itc_broken (d); 1183 /* ITC is broken, need to stop the daemon thread now as otherwise 1184 application will not be able to stop the thread. */ 1185 return false; 1186 } 1187 if (FD_ISSET (mhd_itc_r_fd (d->threading.itc), rfds)) 1188 { 1189 --num_events; 1190 /* Clear ITC here, before other data processing. 1191 * Any external events will activate ITC again if additional data to 1192 * process is added externally. Clearing ITC early ensures that new data 1193 * (with additional ITC activation) will not be missed. */ 1194 mhd_itc_clear (d->threading.itc); 1195 } 1196 1197 # ifndef MHD_FAVOR_SMALL_CODE 1198 if (0 == num_events) 1199 return true; 1200 # endif /* MHD_FAVOR_SMALL_CODE */ 1201 # endif /* MHD_SUPPORT_THREADS */ 1202 1203 if (MHD_INVALID_SOCKET != d->net.listen.fd) 1204 { 1205 mhd_assert (!d->net.listen.is_broken); 1206 dbg_print_fd_state_update ("lstn", \ 1207 d->net.listen.fd, \ 1208 FD_ISSET (d->net.listen.fd, rfds), \ 1209 FD_ISSET (d->net.listen.fd, wfds), \ 1210 FD_ISSET (d->net.listen.fd, efds)); 1211 if (FD_ISSET (d->net.listen.fd, efds)) 1212 { 1213 --num_events; 1214 log_listen_broken (d); 1215 /* Close the listening socket unless the master daemon should close it */ 1216 if (!mhd_D_HAS_MASTER (d)) 1217 mhd_socket_close (d->net.listen.fd); 1218 1219 d->events.accept_pending = false; 1220 d->net.listen.is_broken = true; 1221 /* Stop monitoring socket to avoid spinning with busy-waiting */ 1222 d->net.listen.fd = MHD_INVALID_SOCKET; 1223 # ifndef MHD_FAVOR_SMALL_CODE 1224 if (FD_ISSET (d->net.listen.fd, rfds)) 1225 --num_events; 1226 # endif /* MHD_FAVOR_SMALL_CODE */ 1227 } 1228 else 1229 { 1230 d->events.accept_pending = FD_ISSET (d->net.listen.fd, rfds); 1231 if (d->events.accept_pending) 1232 --num_events; 1233 } 1234 } 1235 1236 mhd_assert ((0 == num_events) \ 1237 || (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type))); 1238 1239 # ifdef MHD_FAVOR_SMALL_CODE 1240 (void)num_events; 1241 num_events = 1; /* Use static value to minimise the binary size of the next loop */ 1242 # endif /* ! MHD_FAVOR_SMALL_CODE */ 1243 1244 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 1245 (NULL != c) && (0 != num_events); 1246 c = mhd_DLINKEDL_GET_NEXT (c, all_conn)) 1247 { 1248 if (c->resuming) 1249 start_resuming_connection (c, d); 1250 else 1251 { 1252 MHD_Socket sk; 1253 bool recv_ready; 1254 bool send_ready; 1255 bool err_state; 1256 1257 if (is_conn_excluded_from_http_comm (c)) 1258 continue; 1259 1260 sk = c->sk.fd; 1261 recv_ready = FD_ISSET (sk, rfds); 1262 send_ready = FD_ISSET (sk, wfds); 1263 err_state = FD_ISSET (sk, efds); 1264 1265 update_conn_net_status (d, 1266 c, 1267 recv_ready, 1268 send_ready, 1269 err_state); 1270 # ifndef MHD_FAVOR_SMALL_CODE 1271 num_events -= 1272 (recv_ready ? 1 : 0) + (send_ready ? 1 : 0) + (err_state ? 1 : 0); 1273 # endif /* MHD_FAVOR_SMALL_CODE */ 1274 } 1275 } 1276 1277 # ifndef MHD_FAVOR_SMALL_CODE 1278 mhd_assert ((0 == num_events) || resuming_conn); 1279 # endif /* MHD_FAVOR_SMALL_CODE */ 1280 return true; 1281 } 1282 1283 1284 /** 1285 * Get pointer to struct timeval for select() for polling daemon's sockets 1286 * @param d the daemon to use 1287 * @param[out] tmvl to pointer to the allocated struct timeval 1288 * @return the @a tmvl pointer (with maximum wait value set) 1289 * or NULL if select may wait indefinitely 1290 */ 1291 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ 1292 MHD_FN_PAR_OUT_ (2) struct timeval * 1293 get_timeval_for_select (const struct MHD_Daemon *restrict d, 1294 struct timeval *tmvl) 1295 { 1296 const uint_fast64_t max_wait = mhd_daemon_get_wait_max (d); 1297 # ifdef HAVE_TIME_T 1298 time_t max_wait_secs = (time_t)(max_wait / 1000u); 1299 # else /* ! HAVE_TIME_T */ 1300 long max_wait_secs = (long)(max_wait / 1000u); 1301 # endif /* ! HAVE_TIME_T */ 1302 # ifdef HAVE_SUSECONDS_T 1303 suseconds_t max_wait_usecs = (suseconds_t)((max_wait % 1000u) * 1000u); 1304 # else /* ! HAVE_SUSECONDS_T */ 1305 long max_wait_usecs = (long)((max_wait % 1000u) * 1000u); 1306 # endif /* ! HAVE_SUSECONDS_T */ 1307 1308 if (MHD_WAIT_INDEFINITELY <= max_wait) 1309 return NULL; 1310 1311 if (0u == max_wait) 1312 { 1313 tmvl->tv_sec = 0; 1314 tmvl->tv_usec = 0; 1315 1316 return tmvl; 1317 } 1318 1319 if (mhd_COND_ALMOST_NEVER ((max_wait / 1000u != 1320 (uint_fast64_t)max_wait_secs) 1321 || (max_wait_secs <= 0))) 1322 { 1323 /* Do not bother figuring out the real maximum 'time_t' value. 1324 '0x7FFFFFFF' is large enough to be already unrealistic and should 1325 fit most of signed or unsigned time_t types. */ 1326 tmvl->tv_sec = 0x7FFFFFFF; 1327 tmvl->tv_usec = 0; 1328 1329 return tmvl; 1330 } 1331 1332 tmvl->tv_sec = max_wait_secs; 1333 tmvl->tv_usec = max_wait_usecs; 1334 1335 return tmvl; 1336 } 1337 1338 1339 /** 1340 * Update states of all connections, check for connection pending 1341 * to be accept()'ed, check for the events on ITC; resume connections 1342 * @param listen_only set to 'true' if connections's sockets should NOT 1343 * be monitored 1344 * @return 'true' if processed successfully, 1345 * 'false' is unrecoverable error occurs and the daemon must be 1346 * closed 1347 */ 1348 static MHD_FN_PAR_NONNULL_ (1) bool 1349 get_all_net_updates_by_select_and_resume_conn (struct MHD_Daemon *restrict d, 1350 bool listen_only) 1351 { 1352 int max_socket; 1353 struct timeval tmvl_value; 1354 struct timeval *tmvl_ptr; 1355 int num_events; 1356 mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type); 1357 1358 max_socket = select_update_fdsets (d, 1359 listen_only); 1360 1361 tmvl_ptr = get_timeval_for_select (d, 1362 &tmvl_value); 1363 1364 # ifdef MHD_SOCKETS_KIND_WINSOCK 1365 if (0 == max_socket) 1366 { 1367 Sleep (tmvl_ptr ? tmvl_ptr->tv_sec : 600); 1368 return true; 1369 } 1370 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 1371 1372 # ifdef MHD_USE_TRACE_POLLING_FDS 1373 if (NULL != tmvl_ptr) 1374 fprintf (stderr, 1375 "### (Starting) select(%d, rfds, wfds, efds, [%llu, %llu])...\n", 1376 max_socket + 1, 1377 (unsigned long long)tmvl_ptr->tv_sec, 1378 (unsigned long long)tmvl_ptr->tv_usec); 1379 else 1380 fprintf (stderr, 1381 "### (Starting) select(%d, rfds, wfds, efds, [NULL])...\n", 1382 max_socket + 1); 1383 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1384 num_events = select (max_socket + 1, 1385 d->events.data.select.rfds, 1386 d->events.data.select.wfds, 1387 d->events.data.select.efds, 1388 tmvl_ptr); 1389 # ifdef MHD_USE_TRACE_POLLING_FDS 1390 if (NULL != tmvl_ptr) 1391 fprintf (stderr, 1392 "### (Finished) select(%d, rfds, wfds, efds, ->[%llu, %llu]) -> " 1393 "%d\n", 1394 max_socket + 1, 1395 (unsigned long long)tmvl_ptr->tv_sec, 1396 (unsigned long long)tmvl_ptr->tv_usec, 1397 num_events); 1398 else 1399 fprintf (stderr, 1400 "### (Finished) select(%d, rfds, wfds, efds, [NULL]) -> " 1401 "%d\n", 1402 max_socket + 1, 1403 num_events); 1404 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1405 1406 if (0 > num_events) 1407 { 1408 int err; 1409 bool is_hard_error; 1410 bool is_ignored_error; 1411 is_hard_error = false; 1412 is_ignored_error = false; 1413 # if defined(MHD_SOCKETS_KIND_POSIX) 1414 err = errno; 1415 if (0 != err) 1416 { 1417 is_hard_error = 1418 ((mhd_EBADF_OR_ZERO == err) || (mhd_EINVAL_OR_ZERO == err)); 1419 is_ignored_error = (mhd_EINTR_OR_ZERO == err); 1420 } 1421 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 1422 err = WSAGetLastError (); 1423 is_hard_error = 1424 ((WSAENETDOWN == err) || (WSAEFAULT == err) || (WSAEINVAL == err) 1425 || (WSANOTINITIALISED == err)); 1426 # endif 1427 if (!is_ignored_error) 1428 { 1429 if (is_hard_error) 1430 { 1431 mhd_LOG_MSG (d, MHD_SC_SELECT_HARD_ERROR, \ 1432 "The select() encountered unrecoverable error."); 1433 return false; 1434 } 1435 mhd_LOG_MSG (d, MHD_SC_SELECT_SOFT_ERROR, \ 1436 "The select() encountered error."); 1437 return true; 1438 } 1439 } 1440 1441 return select_update_statuses_from_fdsets_and_resume_conn (d, num_events); 1442 } 1443 1444 1445 #endif /* MHD_SUPPORT_SELECT */ 1446 1447 1448 #ifdef MHD_SUPPORT_POLL 1449 1450 static MHD_FN_PAR_NONNULL_ (1) unsigned int 1451 poll_update_fds (struct MHD_Daemon *restrict d, 1452 bool listen_only) 1453 { 1454 unsigned int i_s; 1455 unsigned int i_c; 1456 struct MHD_Connection *restrict c; 1457 # ifndef NDEBUG 1458 unsigned int num_skipped = 0; 1459 # endif /* ! NDEBUG */ 1460 1461 mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type); 1462 1463 i_s = 0; 1464 # ifdef MHD_SUPPORT_THREADS 1465 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 1466 mhd_assert (d->events.data.poll.fds[i_s].fd == \ 1467 mhd_itc_r_fd (d->threading.itc)); 1468 mhd_assert (mhd_SOCKET_REL_MARKER_ITC == \ 1469 d->events.data.poll.rel[i_s].fd_id); 1470 # ifndef HAVE_POLL_CLOBBERS_EVENTS 1471 mhd_assert (POLLIN == d->events.data.poll.fds[i_s].events); 1472 # else /* HAVE_POLL_CLOBBERS_EVENTS */ 1473 d->events.data.poll.fds[i_s].events = POLLIN; 1474 # endif /* HAVE_POLL_CLOBBERS_EVENTS */ 1475 mhd_dbg_print_fd_mon_req ("ITC", \ 1476 mhd_itc_r_fd (d->threading.itc), \ 1477 true, \ 1478 false, \ 1479 false); 1480 ++i_s; 1481 # endif 1482 if (MHD_INVALID_SOCKET != d->net.listen.fd) 1483 { 1484 mhd_assert (!d->net.listen.is_broken); 1485 mhd_assert (d->events.data.poll.fds[i_s].fd == d->net.listen.fd); 1486 mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN == \ 1487 d->events.data.poll.rel[i_s].fd_id); 1488 # ifndef HAVE_POLL_CLOBBERS_EVENTS 1489 mhd_assert ((POLLIN == d->events.data.poll.fds[i_s].events) 1490 || (0 == d->events.data.poll.fds[i_s].events)); 1491 # endif /* ! HAVE_POLL_CLOBBERS_EVENTS */ 1492 d->events.data.poll.fds[i_s].events = d->conns.block_new ? 0 : POLLIN; 1493 mhd_dbg_print_fd_mon_req ("lstn", \ 1494 d->net.listen.fd, \ 1495 POLLIN == d->events.data.poll.fds[i_s].events, \ 1496 false, \ 1497 false); 1498 ++i_s; 1499 } 1500 if (listen_only) 1501 return i_s; 1502 1503 i_c = i_s; 1504 for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); NULL != c; 1505 c = mhd_DLINKEDL_GET_NEXT (c, all_conn)) 1506 { 1507 unsigned short events; /* 'unsigned' for correct bits manipulations */ 1508 1509 if (is_conn_excluded_from_http_comm (c)) 1510 { 1511 # ifndef NDEBUG 1512 ++num_skipped; 1513 # endif /* ! NDEBUG */ 1514 continue; 1515 } 1516 1517 mhd_assert ((i_c - i_s) < d->conns.cfg.count_limit); 1518 mhd_assert (i_c < d->dbg.num_events_elements); 1519 mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage); 1520 1521 d->events.data.poll.fds[i_c].fd = c->sk.fd; 1522 d->events.data.poll.rel[i_c].connection = c; 1523 events = 0; 1524 if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) 1525 events |= MHD_POLL_IN; 1526 if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND)) 1527 events |= MHD_POLL_OUT; 1528 1529 d->events.data.poll.fds[i_c].events = (short)events; 1530 mhd_dbg_print_fd_mon_req ("conn", \ 1531 c->sk.fd, \ 1532 MHD_POLL_IN == (MHD_POLL_IN & events), \ 1533 MHD_POLL_OUT == (MHD_POLL_OUT & events), \ 1534 false); 1535 ++i_c; 1536 } 1537 mhd_assert ((d->conns.count - num_skipped) == (i_c - i_s)); 1538 mhd_assert (i_c <= d->dbg.num_events_elements); 1539 return i_c; 1540 } 1541 1542 1543 static MHD_FN_PAR_NONNULL_ (1) bool 1544 poll_update_statuses_from_fds (struct MHD_Daemon *restrict d, 1545 int num_events) 1546 { 1547 unsigned int i_s; 1548 unsigned int i_c; 1549 mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type); 1550 mhd_assert (0 <= num_events); 1551 mhd_assert (((unsigned int)num_events) <= d->dbg.num_events_elements); 1552 1553 if (0 == num_events) 1554 return true; 1555 1556 i_s = 0; 1557 # ifdef MHD_SUPPORT_THREADS 1558 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 1559 mhd_assert (d->events.data.poll.fds[i_s].fd == \ 1560 mhd_itc_r_fd (d->threading.itc)); 1561 mhd_assert (mhd_SOCKET_REL_MARKER_ITC == \ 1562 d->events.data.poll.rel[i_s].fd_id); 1563 # ifndef HAVE_POLL_CLOBBERS_EVENTS 1564 mhd_assert (POLLIN == d->events.data.poll.fds[i_s].events); 1565 # endif /* ! HAVE_POLL_CLOBBERS_EVENTS */ 1566 dbg_print_fd_state_update ( \ 1567 "ITC", \ 1568 d->events.data.poll.fds[i_s].fd, \ 1569 0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_IN | POLLIN)), \ 1570 0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_OUT | POLLOUT)), \ 1571 0 != (d->events.data.poll.fds[i_s].revents & (POLLERR | POLLNVAL))); 1572 1573 if (0 != (d->events.data.poll.fds[i_s].revents & (POLLERR | POLLNVAL))) 1574 { 1575 log_itc_broken (d); 1576 /* ITC is broken, need to stop the daemon thread now as otherwise 1577 application will not be able to stop the thread. */ 1578 return false; 1579 } 1580 if (0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_IN | POLLIN))) 1581 { 1582 --num_events; 1583 /* Clear ITC here, before other data processing. 1584 * Any external events will activate ITC again if additional data to 1585 * process is added externally. Clearing ITC early ensures that new data 1586 * (with additional ITC activation) will not be missed. */ 1587 mhd_itc_clear (d->threading.itc); 1588 } 1589 ++i_s; 1590 1591 if (0 == num_events) 1592 return true; 1593 # endif /* MHD_SUPPORT_THREADS */ 1594 1595 if (MHD_INVALID_SOCKET != d->net.listen.fd) 1596 { 1597 const short revents = d->events.data.poll.fds[i_s].revents; 1598 1599 mhd_assert (!d->net.listen.is_broken); 1600 mhd_assert (d->events.data.poll.fds[i_s].fd == d->net.listen.fd); 1601 mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN == \ 1602 d->events.data.poll.rel[i_s].fd_id); 1603 # ifndef HAVE_POLL_CLOBBERS_EVENTS 1604 mhd_assert ((POLLIN == d->events.data.poll.fds[i_s].events) 1605 || (0 == d->events.data.poll.fds[i_s].events)); 1606 # endif /* ! HAVE_POLL_CLOBBERS_EVENTS */ 1607 dbg_print_fd_state_update ("lstn", \ 1608 d->events.data.poll.fds[i_s].fd, \ 1609 0 != (revents & (MHD_POLL_IN | POLLIN)), \ 1610 0 != (revents & (MHD_POLL_OUT | POLLOUT)), \ 1611 0 != (revents & (POLLERR | POLLNVAL | POLLHUP))); 1612 if (0 != (revents & (POLLERR | POLLNVAL | POLLHUP))) 1613 { 1614 --num_events; 1615 log_listen_broken (d); 1616 /* Close the listening socket unless the master daemon should close it */ 1617 if (!mhd_D_HAS_MASTER (d)) 1618 mhd_socket_close (d->net.listen.fd); 1619 1620 d->events.accept_pending = false; 1621 d->net.listen.is_broken = true; 1622 /* Stop monitoring socket to avoid spinning with busy-waiting */ 1623 d->net.listen.fd = MHD_INVALID_SOCKET; 1624 } 1625 else 1626 { 1627 const bool has_new_conns = (0 != (revents & (MHD_POLL_IN | POLLIN))); 1628 if (has_new_conns) 1629 { 1630 --num_events; 1631 d->events.accept_pending = true; 1632 } 1633 else 1634 { 1635 /* Check whether the listen socket was monitored for incoming 1636 connections */ 1637 if (0 != (d->events.data.poll.fds[i_s].events & POLLIN)) 1638 d->events.accept_pending = false; 1639 } 1640 } 1641 ++i_s; 1642 } 1643 1644 mhd_assert ((0 == num_events) \ 1645 || (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type))); 1646 1647 for (i_c = i_s; (i_c < i_s + d->conns.count) && (0 < num_events); ++i_c) 1648 { 1649 struct MHD_Connection *restrict c; 1650 bool recv_ready; 1651 bool send_ready; 1652 bool err_state; 1653 short revents; 1654 mhd_assert (i_c < d->dbg.num_events_elements); 1655 mhd_assert (mhd_SOCKET_REL_MARKER_EMPTY != \ 1656 d->events.data.poll.rel[i_c].fd_id); 1657 mhd_assert (mhd_SOCKET_REL_MARKER_ITC != \ 1658 d->events.data.poll.rel[i_c].fd_id); 1659 mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN != \ 1660 d->events.data.poll.rel[i_c].fd_id); 1661 1662 c = d->events.data.poll.rel[i_c].connection; 1663 mhd_assert (!is_conn_excluded_from_http_comm (c)); 1664 mhd_assert (c->sk.fd == d->events.data.poll.fds[i_c].fd); 1665 revents = d->events.data.poll.fds[i_c].revents; 1666 recv_ready = (0 != (revents & (MHD_POLL_IN | POLLIN))); 1667 send_ready = (0 != (revents & (MHD_POLL_OUT | POLLOUT))); 1668 # ifndef MHD_POLLHUP_ON_REM_SHUT_WR 1669 err_state = (0 != (revents & (POLLHUP | POLLERR | POLLNVAL))); 1670 # else 1671 err_state = (0 != (revents & (POLLERR | POLLNVAL))); 1672 if (0 != (revents & POLLHUP)) 1673 { /* This can be a disconnect OR remote side set SHUT_WR */ 1674 recv_ready = true; /* Check the socket by reading */ 1675 if (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)) 1676 err_state = true; /* The socket will not be checked by reading, the only way to avoid spinning */ 1677 } 1678 # endif 1679 if (0 != (revents & (MHD_POLLPRI | MHD_POLLRDBAND))) 1680 { /* Statuses were not requested, but returned */ 1681 if (!recv_ready 1682 || (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV))) 1683 err_state = true; /* The socket will not be read, the only way to avoid spinning */ 1684 } 1685 if (0 != (revents & MHD_POLLWRBAND)) 1686 { /* Status was not requested, but returned */ 1687 if (!send_ready 1688 || (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND))) 1689 err_state = true; /* The socket will not be written, the only way to avoid spinning */ 1690 } 1691 1692 update_conn_net_status (d, c, recv_ready, send_ready, err_state); 1693 } 1694 mhd_assert (d->conns.count >= (i_c - i_s)); 1695 mhd_assert (i_c <= d->dbg.num_events_elements); 1696 return true; 1697 } 1698 1699 1700 static MHD_FN_PAR_NONNULL_ (1) bool 1701 get_all_net_updates_by_poll (struct MHD_Daemon *restrict d, 1702 bool listen_only) 1703 { 1704 # ifdef MHD_USE_TRACE_POLLING_FDS 1705 # ifdef MHD_SOCKETS_KIND_POSIX 1706 static const char poll_fn_name[] = "poll"; 1707 # else /* MHD_SOCKETS_KIND_WINSOCK */ 1708 static const char poll_fn_name[] = "WSAPoll"; 1709 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 1710 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1711 unsigned int num_fds; 1712 int max_wait; 1713 int num_events; 1714 1715 mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type); 1716 1717 num_fds = poll_update_fds (d, listen_only); 1718 1719 // TODO: handle empty list situation 1720 max_wait = get_max_wait (d); 1721 1722 # ifdef MHD_USE_TRACE_POLLING_FDS 1723 fprintf (stderr, 1724 "### (Starting) %s(fds, %u, %d)...\n", 1725 poll_fn_name, 1726 num_fds, 1727 max_wait); 1728 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1729 num_events = mhd_poll (d->events.data.poll.fds, 1730 num_fds, 1731 max_wait); // TODO: use correct timeout value 1732 # ifdef MHD_USE_TRACE_POLLING_FDS 1733 fprintf (stderr, 1734 "### (Finished) %s(fds, %u, %d) -> %d\n", 1735 poll_fn_name, 1736 num_fds, 1737 max_wait, 1738 num_events); 1739 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1740 if (0 > num_events) 1741 { 1742 int err; 1743 bool is_hard_error; 1744 bool is_ignored_error; 1745 is_hard_error = false; 1746 is_ignored_error = false; 1747 # if defined(MHD_SOCKETS_KIND_POSIX) 1748 err = errno; 1749 if (0 != err) 1750 { 1751 is_hard_error = 1752 ((mhd_EFAULT_OR_ZERO == err) || (mhd_EINVAL_OR_ZERO == err)); 1753 is_ignored_error = (mhd_EINTR_OR_ZERO == err); 1754 } 1755 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 1756 err = WSAGetLastError (); 1757 is_hard_error = 1758 ((WSAENETDOWN == err) || (WSAEFAULT == err) || (WSAEINVAL == err)); 1759 # endif 1760 if (!is_ignored_error) 1761 { 1762 if (is_hard_error) 1763 { 1764 mhd_LOG_MSG (d, MHD_SC_POLL_HARD_ERROR, \ 1765 "The poll() encountered unrecoverable error."); 1766 return false; 1767 } 1768 mhd_LOG_MSG (d, MHD_SC_POLL_SOFT_ERROR, \ 1769 "The poll() encountered error."); 1770 } 1771 return true; 1772 } 1773 1774 return poll_update_statuses_from_fds (d, num_events); 1775 } 1776 1777 1778 #endif /* MHD_SUPPORT_POLL */ 1779 1780 #ifdef MHD_SUPPORT_EPOLL 1781 1782 /** 1783 * Map events provided by epoll to connection states, ITC and 1784 * listen socket states 1785 */ 1786 static MHD_FN_PAR_NONNULL_ (1) bool 1787 update_statuses_from_eevents (struct MHD_Daemon *restrict d, 1788 unsigned int num_events) 1789 { 1790 unsigned int i; 1791 struct epoll_event *const restrict events = 1792 d->events.data.epoll.events; 1793 for (i = 0; num_events > i; ++i) 1794 { 1795 struct epoll_event *const e = events + i; 1796 # ifdef MHD_SUPPORT_THREADS 1797 if (((uint64_t)mhd_SOCKET_REL_MARKER_ITC) == e->data.u64) /* uint64_t is in the system header */ 1798 { 1799 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 1800 dbg_print_fd_state_update ( \ 1801 "ITC", \ 1802 mhd_itc_r_fd (d->threading.itc), \ 1803 0 != (e->events & EPOLLIN), \ 1804 0 != (e->events & EPOLLOUT), \ 1805 0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP))); 1806 1807 if (0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP))) 1808 { 1809 log_itc_broken (d); 1810 /* ITC is broken, need to stop the daemon thread now as otherwise 1811 application will not be able to stop the thread. */ 1812 return false; 1813 } 1814 if (0 != (e->events & EPOLLIN)) 1815 { 1816 /* Clear ITC here, before other data processing. 1817 * Any external events will activate ITC again if additional data to 1818 * process is added externally. Clearing ITC early ensures that new data 1819 * (with additional ITC activation) will not be missed. */ 1820 mhd_itc_clear (d->threading.itc); 1821 } 1822 } 1823 else 1824 # endif /* MHD_SUPPORT_THREADS */ 1825 if (((uint64_t)mhd_SOCKET_REL_MARKER_LISTEN) == e->data.u64) /* uint64_t is in the system header */ 1826 { 1827 mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd); 1828 dbg_print_fd_state_update ( \ 1829 "lstn", \ 1830 d->net.listen.fd, \ 1831 0 != (e->events & EPOLLIN), \ 1832 0 != (e->events & EPOLLOUT), \ 1833 0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP))); 1834 if (0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP))) 1835 { 1836 log_listen_broken (d); 1837 1838 /* Close the listening socket unless the master daemon should close it */ 1839 if (!mhd_D_HAS_MASTER (d)) 1840 mhd_socket_close (d->net.listen.fd); 1841 else 1842 { 1843 /* Ignore possible error as the socket could be already removed 1844 from the epoll monitoring by closing the socket */ 1845 (void)epoll_ctl (d->events.data.epoll.e_fd, 1846 EPOLL_CTL_DEL, 1847 d->net.listen.fd, 1848 NULL); 1849 } 1850 1851 d->events.accept_pending = false; 1852 d->net.listen.is_broken = true; 1853 d->net.listen.fd = MHD_INVALID_SOCKET; 1854 } 1855 else 1856 d->events.accept_pending = (0 != (e->events & EPOLLIN)); 1857 } 1858 else 1859 { 1860 bool recv_ready; 1861 bool send_ready; 1862 bool err_state; 1863 struct MHD_Connection *const restrict c = 1864 (struct MHD_Connection *)e->data.ptr; 1865 mhd_assert (!is_conn_excluded_from_http_comm (c)); 1866 recv_ready = (0 != (e->events & (EPOLLIN | EPOLLERR | EPOLLHUP))); 1867 send_ready = (0 != (e->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))); 1868 err_state = (0 != (e->events & (EPOLLERR | EPOLLHUP))); 1869 1870 update_conn_net_status (d, c, recv_ready, send_ready, err_state); 1871 } 1872 } 1873 return true; 1874 } 1875 1876 1877 /** 1878 * Update states of all connections, check for connection pending 1879 * to be accept()'ed, check for the events on ITC. 1880 */ 1881 static MHD_FN_PAR_NONNULL_ (1) bool 1882 get_all_net_updates_by_epoll (struct MHD_Daemon *restrict d) 1883 { 1884 int max_events; 1885 int num_events; 1886 unsigned int events_processed; 1887 int max_wait; 1888 mhd_assert (mhd_POLL_TYPE_EPOLL == d->events.poll_type); 1889 mhd_assert (0 < ((int)d->events.data.epoll.num_elements)); 1890 mhd_assert (0 <= ((int)d->conns.count)); 1891 mhd_assert (d->events.data.epoll.num_elements == \ 1892 (size_t)((int)d->events.data.epoll.num_elements)); 1893 mhd_assert (0 != d->events.data.epoll.num_elements); 1894 mhd_assert (0 != d->conns.cfg.count_limit); 1895 mhd_assert (d->events.data.epoll.num_elements == d->dbg.num_events_elements); 1896 1897 // TODO: add listen socket enable/disable 1898 1899 /* Minimise amount of data passed from userspace to kernel and back */ 1900 max_events = (int)d->conns.count; 1901 # ifdef MHD_SUPPORT_THREADS 1902 ++max_events; 1903 # endif /* MHD_SUPPORT_THREADS */ 1904 if (MHD_INVALID_SOCKET != d->net.listen.fd) 1905 ++max_events; 1906 /* Make sure that one extra slot used to clearly detect that all events 1907 * were gotten. */ 1908 ++max_events; 1909 if ((0 > max_events) 1910 || (max_events > (int)d->events.data.epoll.num_elements)) 1911 max_events = (int)d->events.data.epoll.num_elements; 1912 1913 events_processed = 0; 1914 max_wait = get_max_wait (d); 1915 do 1916 { 1917 # ifdef MHD_USE_TRACE_POLLING_FDS 1918 fprintf (stderr, 1919 "### (Starting) epoll_wait(%d, events, %d, %d)...\n", 1920 d->events.data.epoll.e_fd, 1921 (int)d->events.data.epoll.num_elements, 1922 max_wait); 1923 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1924 num_events = epoll_wait (d->events.data.epoll.e_fd, 1925 d->events.data.epoll.events, 1926 max_events, 1927 max_wait); 1928 # ifdef MHD_USE_TRACE_POLLING_FDS 1929 fprintf (stderr, 1930 "### (Finished) epoll_wait(%d, events, %d, %d) -> %d\n", 1931 d->events.data.epoll.e_fd, 1932 max_events, 1933 max_wait, 1934 num_events); 1935 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1936 max_wait = 0; 1937 if (0 > num_events) 1938 { 1939 const int err = errno; 1940 if (EINTR != err) 1941 { 1942 mhd_LOG_MSG (d, MHD_SC_EPOLL_HARD_ERROR, \ 1943 "The epoll_wait() encountered unrecoverable error."); 1944 return false; 1945 } 1946 return true; /* EINTR, try next time */ 1947 } 1948 if (!update_statuses_from_eevents (d, (unsigned int)num_events)) 1949 return false; 1950 if (max_events > num_events) 1951 return true; /* All events have been read */ 1952 1953 /* Use all buffer for the next getting events round(s) */ 1954 max_events = (int)d->events.data.epoll.num_elements; 1955 mhd_assert (0 < max_events); 1956 mhd_assert (d->events.data.epoll.num_elements == (size_t)max_events); 1957 max_wait = 0; /* Do not block on the next getting events rounds */ 1958 1959 events_processed += (unsigned int)num_events; /* Avoid reading too many events */ 1960 } while ((events_processed < d->conns.cfg.count_limit) 1961 || (events_processed < d->conns.cfg.count_limit + 2)); 1962 1963 return true; 1964 } 1965 1966 1967 #endif /* MHD_SUPPORT_EPOLL */ 1968 1969 #ifdef MHD_SUPPORT_KQUEUE 1970 1971 static MHD_FN_PAR_NONNULL_ALL_ 1972 MHD_FN_PAR_IN_ (2) void 1973 kqueue_handle_missed_change (struct MHD_Daemon *restrict d, 1974 const struct kevent *restrict upd_event) 1975 { 1976 mhd_assert (mhd_D_IS_USING_KQUEUE (d)); 1977 mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_EMPTY != mhd_KE_GET_UDATA (upd_event)); 1978 mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_ITC != mhd_KE_GET_UDATA (upd_event)); 1979 1980 if (mhd_SOCKET_REL_PTRMARKER_LISTEN == mhd_KE_GET_UDATA (upd_event)) 1981 { 1982 return; 1983 } 1984 else 1985 { 1986 struct MHD_Connection *const restrict c = 1987 (struct MHD_Connection *)mhd_KE_GET_UDATA (upd_event); 1988 1989 mhd_ASSUME (d == c->daemon); 1990 1991 mhd_conn_start_closing_no_sys_res (c); 1992 mhd_conn_pre_clean (c); 1993 mhd_conn_remove_from_daemon (c); 1994 mhd_conn_close_final (c); 1995 } 1996 } 1997 1998 1999 static MHD_FN_PAR_NONNULL_ALL_ 2000 MHD_FN_PAR_IN_SIZE_ (2, 3) void 2001 kqueue_handle_missed_changes (struct MHD_Daemon *restrict d, 2002 struct kevent *restrict kes, 2003 int num_elements) 2004 { 2005 int i; 2006 2007 mhd_ASSUME (0 < num_elements); 2008 2009 for (i = 0; i < num_elements; ++i) 2010 kqueue_handle_missed_change (d, 2011 kes + i); 2012 } 2013 2014 2015 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ int 2016 update_kqueue_monitoring (struct MHD_Daemon *restrict d) 2017 { 2018 struct MHD_Connection *c; 2019 struct kevent *restrict kes = d->events.data.kq.kes; 2020 int num_updates; 2021 const int max_changes = (int)d->events.data.kq.num_elements; 2022 2023 mhd_assert (mhd_D_IS_USING_KQUEUE (d)); 2024 mhd_assert (NULL != kes); 2025 mhd_assert (2 <= max_changes); 2026 2027 num_updates = 0; 2028 2029 if (MHD_INVALID_SOCKET != d->net.listen.fd) 2030 { 2031 mhd_assert (!d->net.listen.is_broken); 2032 2033 mhd_KE_SET (kes + num_updates, 2034 d->net.listen.fd, 2035 EVFILT_READ, 2036 (d->conns.block_new ? EV_DISABLE : EV_ENABLE) 2037 | mhd_EV_KEEPUDATA_OR_ZERO, 2038 mhd_SOCKET_REL_PTRMARKER_LISTEN); 2039 2040 mhd_dbg_print_kevent_change ("lstn", 2041 kes + num_updates); 2042 ++num_updates; 2043 } 2044 2045 /* Process unmonitored connections starting from the earliest added 2046 unmonitored connection */ 2047 2048 c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); 2049 2050 if ((NULL == c) || (c->events.kq.monitored)) 2051 return num_updates; 2052 2053 while (1) 2054 { 2055 struct MHD_Connection *const next_c = mhd_DLINKEDL_GET_NEXT (c, all_conn); 2056 if (NULL == next_c) 2057 break; /* Found the end of the list */ 2058 if (next_c->events.kq.monitored) 2059 break; /* Found the earliest added unmonitored connection */ 2060 c = next_c; 2061 } 2062 2063 mhd_ASSUME (NULL != c); 2064 mhd_ASSUME (!c->events.kq.monitored); 2065 2066 for ((void)c; NULL != c; c = mhd_DLINKEDL_GET_PREV (c, all_conn)) 2067 { 2068 mhd_ASSUME (!c->events.kq.monitored); 2069 2070 mhd_assert (!is_conn_excluded_from_http_comm (c)); 2071 mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage); 2072 2073 /* Check for the space for two filters */ 2074 if ((max_changes - 1) <= num_updates) 2075 { 2076 /* Too many updates for a single kevent() call */ 2077 static const struct timespec zero_timeout = {0, 0}; 2078 int res; 2079 2080 # ifdef MHD_USE_TRACE_POLLING_FDS 2081 fprintf (stderr, 2082 "### (Starting) kevent(%d, changes, %d, [NULL], " 2083 "0, [0, 0])...\n", 2084 d->events.data.kq.kq_fd, 2085 num_updates); 2086 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2087 res = mhd_kevent (d->events.data.kq.kq_fd, 2088 kes, 2089 num_updates, 2090 NULL, 2091 0, 2092 &zero_timeout); 2093 # ifdef MHD_USE_TRACE_POLLING_FDS 2094 fprintf (stderr, 2095 "### (Finished) kevent(%d, changes, %d, [NULL], " 2096 "0, [0, 0]) -> %d\n", 2097 d->events.data.kq.kq_fd, 2098 num_updates, 2099 res); 2100 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2101 if (0 > res) 2102 { 2103 if (EINTR != errno) 2104 kqueue_handle_missed_changes (d, 2105 kes, 2106 num_updates); 2107 2108 } 2109 num_updates = 0; 2110 } 2111 2112 /* Add recv() filter */ 2113 mhd_KE_SET (kes + num_updates, 2114 c->sk.fd, 2115 EVFILT_READ, 2116 EV_ADD | EV_CLEAR, /* 'EV_CLEAR' means edge trigger */ 2117 c); 2118 mhd_dbg_print_kevent_change ("conn", 2119 kes + num_updates); 2120 2121 ++num_updates; 2122 2123 /* Add send() filter */ 2124 mhd_KE_SET (kes + num_updates, 2125 c->sk.fd, 2126 EVFILT_WRITE, 2127 EV_ADD | EV_CLEAR, /* 'EV_CLEAR' means edge trigger */ 2128 c); 2129 mhd_dbg_print_kevent_change ("conn", 2130 kes + num_updates); 2131 2132 ++num_updates; 2133 2134 c->events.kq.monitored = true; 2135 2136 mhd_assert (0 < num_updates); 2137 } 2138 2139 mhd_assert (0 <= num_updates); 2140 mhd_assert (num_updates <= (int)d->events.data.kq.num_elements); 2141 2142 return num_updates; 2143 } 2144 2145 2146 /** 2147 * Map events provided by kqueue to connection states, ITC and 2148 * listen socket states 2149 */ 2150 static MHD_FN_PAR_NONNULL_ (1) bool 2151 update_statuses_from_kevents (struct MHD_Daemon *restrict d, 2152 unsigned int num_events) 2153 { 2154 unsigned int i; 2155 struct kevent *restrict kes = d->events.data.kq.kes; 2156 2157 mhd_assert (mhd_D_IS_USING_KQUEUE (d)); 2158 2159 for (i = 0u; num_events > i; ++i) 2160 { 2161 struct kevent *const e = kes + i; 2162 bool eof_ready; 2163 # ifdef MHD_SUPPORT_THREADS 2164 if (mhd_SOCKET_REL_PTRMARKER_ITC == mhd_KE_GET_UDATA (e)) 2165 { 2166 mhd_assert (mhd_ITC_IS_VALID (d->threading.itc)); 2167 mhd_assert (mhd_itc_r_fd (d->threading.itc) == (int)e->ident); 2168 mhd_assert (EVFILT_READ == e->filter); 2169 mhd_assert (0 == (e->flags & EV_ERROR)); 2170 2171 eof_ready = (0 != (e->flags & EV_EOF)); 2172 2173 mhd_dbg_print_kevent_report ("ITC", 2174 e); 2175 2176 if (eof_ready) 2177 { 2178 log_itc_broken (d); 2179 /* ITC is broken, need to stop the daemon thread now as otherwise 2180 application will not be able to stop the thread. */ 2181 return false; 2182 } 2183 /* Clear ITC here, before other data processing. 2184 Any external events will activate ITC again if additional data to 2185 process is added externally. Clearing ITC early ensures that new data 2186 (which followed by ITC activation) will not be missed. */ 2187 mhd_itc_clear (d->threading.itc); 2188 } 2189 else 2190 # endif /* MHD_SUPPORT_THREADS */ 2191 if (mhd_SOCKET_REL_PTRMARKER_LISTEN == mhd_KE_GET_UDATA (e)) 2192 { 2193 bool listen_broken; 2194 mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd); 2195 mhd_assert (d->net.listen.fd == (int)e->ident); 2196 mhd_assert (EVFILT_READ == e->filter); 2197 2198 eof_ready = (0 != (e->flags & EV_EOF)); 2199 2200 mhd_dbg_print_kevent_report ("lstn", 2201 e); 2202 2203 listen_broken = false; 2204 if (eof_ready) 2205 listen_broken = true; 2206 else if ((0 != (e->flags & EV_ERROR))) 2207 listen_broken = true; 2208 2209 if (listen_broken) 2210 { 2211 log_listen_broken (d); 2212 2213 /* Close the listening socket unless the master daemon should close it */ 2214 if (!mhd_D_HAS_MASTER (d)) 2215 mhd_socket_close (d->net.listen.fd); 2216 else 2217 { 2218 static const struct timespec zero_timeout = {0, 0}; 2219 struct kevent remove_listen; 2220 int res; 2221 2222 mhd_KE_SET (&remove_listen, 2223 d->net.listen.fd, 2224 EVFILT_READ, 2225 EV_DELETE, 2226 mhd_SOCKET_REL_PTRMARKER_LISTEN); 2227 2228 # ifdef MHD_USE_TRACE_POLLING_FDS 2229 fprintf (stderr, 2230 "### (Starting) kevent(%d, changes, 1, [NULL], " 2231 "0, [0, 0])...\n", 2232 d->events.data.kq.kq_fd); 2233 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2234 res = mhd_kevent (d->events.data.kq.kq_fd, 2235 &remove_listen, 2236 1, 2237 NULL, 2238 0, 2239 &zero_timeout); 2240 # ifdef MHD_USE_TRACE_POLLING_FDS 2241 fprintf (stderr, 2242 "### (Finished) kevent(%d, changes, 1, [NULL], " 2243 "0, [0, 0]) -> %d\n", 2244 d->events.data.kq.kq_fd, 2245 res); 2246 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2247 /* Ignore possible error as the socket could be already removed 2248 from the kqueue monitoring by closing the socket */ 2249 (void)res; 2250 } 2251 2252 d->events.accept_pending = false; 2253 d->net.listen.is_broken = true; 2254 d->net.listen.fd = MHD_INVALID_SOCKET; 2255 } 2256 else 2257 d->events.accept_pending = true; 2258 } 2259 else 2260 { 2261 bool err_ready; 2262 bool recv_ready; 2263 bool send_ready; 2264 struct MHD_Connection *const restrict c = 2265 (struct MHD_Connection *)mhd_KE_GET_UDATA (e); 2266 2267 mhd_ASSUME (d == c->daemon); 2268 mhd_assert (c->events.kq.monitored); 2269 mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_EMPTY != mhd_KE_GET_UDATA (e)); 2270 2271 mhd_dbg_print_kevent_report ("conn", 2272 e); 2273 2274 if ((0 != (e->flags & EV_ERROR))) 2275 { 2276 /* Error adding connection to monitoring */ 2277 kqueue_handle_missed_change (d, 2278 e); 2279 2280 continue; 2281 } 2282 2283 eof_ready = (0 != (e->flags & EV_EOF)); 2284 err_ready = (eof_ready && (0 != e->fflags)); 2285 2286 if (err_ready) 2287 { 2288 c->sk.state.discnt_err = 2289 mhd_socket_error_get_from_sys_err ((int)e->fflags); 2290 mhd_assert (mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 2291 } 2292 /* This is a tricky processing as each "filter" updates only its own 2293 side of the monitoring, not giving a picture of a complete socket 2294 readiness. */ 2295 2296 if (EVFILT_READ == e->filter) 2297 { 2298 recv_ready = true; 2299 send_ready = mhd_SCKT_NET_ST_HAS_FLAG_SEND (c->sk.ready); 2300 } 2301 else 2302 { 2303 mhd_assert (EVFILT_WRITE == e->filter); 2304 recv_ready = mhd_SCKT_NET_ST_HAS_FLAG_RECV (c->sk.ready); 2305 send_ready = true; 2306 } 2307 2308 update_conn_net_status (d, 2309 c, 2310 recv_ready, 2311 send_ready, 2312 err_ready 2313 || mhd_SCKT_NET_ST_HAS_FLAG_ERROR (c->sk.ready)); 2314 } 2315 } 2316 return true; 2317 } 2318 2319 2320 /** 2321 * Update states of all connections, check for connection pending 2322 * to be accept()'ed, check for the events on ITC. 2323 */ 2324 static MHD_FN_PAR_NONNULL_ (1) bool 2325 get_all_net_updates_by_kqueue (struct MHD_Daemon *restrict d) 2326 { 2327 int max_events; 2328 int num_events; 2329 int num_updates; 2330 size_t events_processed; 2331 uint_fast64_t max_wait; 2332 struct timespec ke_timeout; 2333 2334 mhd_assert (mhd_D_IS_USING_KQUEUE (d)); 2335 mhd_assert (0 < d->events.data.kq.kq_fd); 2336 mhd_assert (0 < (int)(d->events.data.kq.num_elements)); 2337 mhd_assert (0 != d->events.data.kq.num_elements); 2338 mhd_assert (0 != d->conns.cfg.count_limit); 2339 mhd_assert (d->events.data.kq.num_elements == d->dbg.num_events_elements); 2340 2341 num_updates = update_kqueue_monitoring (d); 2342 mhd_ASSUME (0 <= num_updates); 2343 2344 /* Minimise amount of data passed from userspace to kernel and back */ 2345 max_events = (int)(d->conns.count * 2); 2346 # ifdef MHD_SUPPORT_THREADS 2347 ++max_events; 2348 # endif /* MHD_SUPPORT_THREADS */ 2349 if (MHD_INVALID_SOCKET != d->net.listen.fd) 2350 ++max_events; 2351 /* Make sure that one extra slot used to clearly detect that all events 2352 were gotten (if all provided slots are used then extra event could be 2353 pending still). */ 2354 ++max_events; 2355 if ((0 >= max_events) 2356 || (max_events > (int)d->events.data.kq.num_elements)) 2357 max_events = (int)d->events.data.kq.num_elements; 2358 2359 max_wait = mhd_daemon_get_wait_max (d); 2360 ke_timeout.tv_sec = (time_t)(max_wait / 1000); 2361 ke_timeout.tv_nsec = (long)((max_wait % 1000) * 1000000L); 2362 events_processed = 0; 2363 do 2364 { 2365 # ifdef MHD_USE_TRACE_POLLING_FDS 2366 if (max_wait == MHD_WAIT_INDEFINITELY) 2367 fprintf (stderr, 2368 "### (Starting) kevent(%d, changes, %d, events, " 2369 "%d, [NULL])...\n", 2370 d->events.data.kq.kq_fd, 2371 num_updates, 2372 max_events); 2373 else 2374 fprintf (stderr, 2375 "### (Starting) kevent(%d, changes, %d, events, " 2376 "%d, [%llu, %llu])...\n", 2377 d->events.data.kq.kq_fd, 2378 num_updates, 2379 max_events, 2380 (unsigned long long)ke_timeout.tv_sec, 2381 (unsigned long long)ke_timeout.tv_nsec); 2382 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2383 num_events = 2384 kevent (d->events.data.kq.kq_fd, 2385 d->events.data.kq.kes, 2386 num_updates, 2387 d->events.data.kq.kes, 2388 max_events, 2389 (max_wait == MHD_WAIT_INDEFINITELY) ? NULL : &ke_timeout); 2390 # ifdef MHD_USE_TRACE_POLLING_FDS 2391 if (max_wait == MHD_WAIT_INDEFINITELY) 2392 fprintf (stderr, 2393 "### (Finished) kevent(%d, changes, %d, events, " 2394 "%d, [NULL]) -> %d\n", 2395 d->events.data.kq.kq_fd, 2396 num_updates, 2397 max_events, 2398 num_events); 2399 else 2400 fprintf (stderr, 2401 "### (Finished) kevent(%d, changes, %d, events, " 2402 "%d, [%llu, %llu]) -> %d\n", 2403 d->events.data.kq.kq_fd, 2404 num_updates, 2405 max_events, 2406 (unsigned long long)ke_timeout.tv_sec, 2407 (unsigned long long)ke_timeout.tv_nsec, 2408 num_events); 2409 # endif /* MHD_USE_TRACE_POLLING_FDS */ 2410 2411 if (0 > num_events) 2412 { 2413 const int err = errno; 2414 if (EINTR == err) 2415 return true; /* EINTR, try next time */ 2416 2417 mhd_LOG_MSG (d, MHD_SC_KQUEUE_HARD_ERROR, \ 2418 "The kevent() encountered unrecoverable error."); 2419 return false; 2420 } 2421 if (!update_statuses_from_kevents (d, 2422 (unsigned int)num_events)) 2423 return false; 2424 if (max_events > num_events) 2425 return true; /* All events have been read */ 2426 2427 /* Use all slots for the next round(s) of getting events */ 2428 max_events = (int)d->events.data.kq.num_elements; 2429 max_wait = 0; /* Do not block on the next getting events rounds */ 2430 ke_timeout.tv_sec = 0; 2431 ke_timeout.tv_nsec = 0; 2432 2433 mhd_assert (0 < max_events); 2434 2435 /* If too many events are coming - process events that have been read already */ 2436 events_processed += (size_t)num_events; 2437 } while ((events_processed < (d->conns.cfg.count_limit * 2)) 2438 || (events_processed < (d->conns.cfg.count_limit * 2) + 2)); 2439 2440 return true; 2441 } 2442 2443 2444 #endif /* MHD_SUPPORT_KQUEUE */ 2445 2446 2447 /** 2448 * Close timed-out connections (if any) 2449 * @param d the daemon to use 2450 */ 2451 static MHD_FN_PAR_NONNULL_ALL_ void 2452 daemon_close_timedout_conns (struct MHD_Daemon *restrict d) 2453 { 2454 struct MHD_Connection *c; 2455 struct MHD_Connection *prev_c; 2456 2457 #if defined(MHD_SUPPORT_THREADS) 2458 mhd_assert (!mhd_D_HAS_WORKERS (d)); 2459 mhd_assert (!mhd_D_HAS_THR_PER_CONN (d)); 2460 #endif /* MHD_SUPPORT_THREADS */ 2461 2462 /* Check "normal" timeouts list */ 2463 c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout)); 2464 2465 while (NULL != c) 2466 { 2467 mhd_assert (!c->timeout.in_cstm_tmout_list); 2468 mhd_assert (0u != d->conns.cfg.timeout_milsec); 2469 2470 if (mhd_conn_is_timeout_expired (c)) 2471 { 2472 prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout), 2473 tmout_list); 2474 mhd_conn_start_closing_timedout (c); 2475 mhd_conn_pre_clean (c); 2476 mhd_conn_remove_from_daemon (c); 2477 mhd_conn_close_final (c); 2478 2479 c = prev_c; 2480 } 2481 else 2482 break; /* DL-list is sorted, no need to check the rest of the list */ 2483 } 2484 2485 /* Check "custom" timeouts list */ 2486 c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)); 2487 2488 while (NULL != c) 2489 { 2490 mhd_assert (c->timeout.in_cstm_tmout_list); 2491 2492 prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout), 2493 tmout_list); 2494 2495 if (mhd_conn_is_timeout_expired (c)) 2496 { 2497 mhd_conn_start_closing_timedout (c); 2498 mhd_conn_pre_clean (c); 2499 mhd_conn_remove_from_daemon (c); 2500 mhd_conn_close_final (c); 2501 } 2502 2503 /* "Custom" timeouts list is not sorted, check all members */ 2504 c = prev_c; 2505 } 2506 } 2507 2508 2509 /** 2510 * Prepare daemon's data for the new round of connections processing 2511 * @param d the daemon to use 2512 */ 2513 static MHD_FN_PAR_NONNULL_ALL_ void 2514 daemon_reset_per_round_data (struct MHD_Daemon *restrict d) 2515 { 2516 d->events.time.is_set = false; 2517 } 2518 2519 2520 /** 2521 * Perform one round of daemon connection and data processing. 2522 * 2523 * This function do the following: 2524 * + poll all connections and daemon FDs (if internal polling is used); 2525 * + resume connections pending to be resumed; 2526 * + update connection statuses based on socket states (recv/send ready or 2527 * disconnect detection); 2528 * + receive, send and/or parse connections data as needed, including call of 2529 * callbacks for processing requests and response generation; 2530 * + close broken connections; 2531 * + accept new connection (if needed); 2532 * + cleanup closed "upgraded" connections. 2533 * @param d the daemon to use 2534 * @return 'true' on success, 2535 * 'false' if daemon is broken 2536 */ 2537 static MHD_FN_PAR_NONNULL_ (1) bool 2538 process_all_events_and_data (struct MHD_Daemon *restrict d) 2539 { 2540 daemon_reset_per_round_data (d); 2541 2542 switch (d->events.poll_type) 2543 { 2544 case mhd_POLL_TYPE_EXT: 2545 mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int)); 2546 if (!ext_events_process_net_updates_and_resume_conn (d)) 2547 return false; 2548 break; 2549 #ifdef MHD_SUPPORT_SELECT 2550 case mhd_POLL_TYPE_SELECT: 2551 if (!get_all_net_updates_by_select_and_resume_conn (d, false)) 2552 return false; 2553 break; 2554 #endif /* MHD_SUPPORT_SELECT */ 2555 #ifdef MHD_SUPPORT_POLL 2556 case mhd_POLL_TYPE_POLL: 2557 if (!get_all_net_updates_by_poll (d, false)) 2558 return false; 2559 daemon_resume_conns_if_needed (d); 2560 break; 2561 #endif /* MHD_SUPPORT_POLL */ 2562 #ifdef MHD_SUPPORT_EPOLL 2563 case mhd_POLL_TYPE_EPOLL: 2564 if (!get_all_net_updates_by_epoll (d)) 2565 return false; 2566 daemon_resume_conns_if_needed (d); 2567 break; 2568 #endif /* MHD_SUPPORT_EPOLL */ 2569 #ifdef MHD_SUPPORT_KQUEUE 2570 case mhd_POLL_TYPE_KQUEUE: 2571 if (!get_all_net_updates_by_kqueue (d)) 2572 return false; 2573 daemon_resume_conns_if_needed (d); 2574 break; 2575 #endif /* MHD_SUPPORT_KQUEUE */ 2576 #ifndef MHD_SUPPORT_SELECT 2577 case mhd_POLL_TYPE_SELECT: 2578 #endif /* ! MHD_SUPPORT_SELECT */ 2579 #ifndef MHD_SUPPORT_POLL 2580 case mhd_POLL_TYPE_POLL: 2581 #endif /* ! MHD_SUPPORT_POLL */ 2582 case mhd_POLL_TYPE_NOT_SET_YET: 2583 default: 2584 mhd_UNREACHABLE (); 2585 MHD_PANIC ("Daemon data integrity broken"); 2586 break; 2587 } 2588 2589 mhd_daemon_process_ext_added_conns (d); 2590 2591 if (d->events.accept_pending && !d->conns.block_new) 2592 d->events.accept_pending = !daemon_accept_new_conns (d); 2593 2594 daemon_process_all_active_conns (d); 2595 daemon_close_timedout_conns (d); 2596 daemon_cleanup_upgraded_conns (d); 2597 return !mhd_D_HAS_STOP_REQ (d); 2598 } 2599 2600 2601 static 2602 MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode 2603 process_reg_events_int (struct MHD_Daemon *MHD_RESTRICT daemon, 2604 uint_fast64_t *MHD_RESTRICT next_max_wait) 2605 { 2606 enum MHD_StatusCode res; 2607 2608 if (mhd_DAEMON_STATE_STARTED > daemon->state) 2609 return MHD_SC_TOO_EARLY; 2610 if (!mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int)) 2611 return MHD_SC_EXTERNAL_EVENT_ONLY; 2612 if (mhd_DAEMON_STATE_STARTED < daemon->state) 2613 return MHD_SC_TOO_LATE; 2614 2615 #ifdef MHD_SUPPORT_THREADS 2616 if (daemon->events.data.extr.itc_data.is_broken) 2617 return MHD_SC_DAEMON_SYS_DATA_BROKEN; 2618 #endif /* MHD_SUPPORT_THREADS */ 2619 2620 if (daemon->net.listen.is_broken) 2621 return MHD_SC_DAEMON_SYS_DATA_BROKEN; 2622 2623 /* Ignore returned value */ 2624 (void)process_all_events_and_data (daemon); 2625 2626 if (NULL != next_max_wait) 2627 *next_max_wait = MHD_WAIT_INDEFINITELY; 2628 2629 res = ext_events_update_registrations (daemon); 2630 if (MHD_SC_OK != res) 2631 return res; 2632 2633 #ifdef MHD_SUPPORT_THREADS 2634 if (daemon->events.data.extr.itc_data.is_broken) 2635 { 2636 log_itc_broken (daemon); 2637 return MHD_SC_DAEMON_SYS_DATA_BROKEN; 2638 } 2639 #endif /* MHD_SUPPORT_THREADS */ 2640 2641 if (daemon->net.listen.is_broken) 2642 { 2643 log_listen_broken (daemon); 2644 return MHD_SC_DAEMON_SYS_DATA_BROKEN; 2645 } 2646 2647 if (NULL != next_max_wait) 2648 *next_max_wait = mhd_daemon_get_wait_max (daemon); 2649 2650 return MHD_SC_OK; 2651 } 2652 2653 2654 MHD_EXTERN_ 2655 MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode 2656 MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon, 2657 uint_fast64_t *MHD_RESTRICT next_max_wait) 2658 { 2659 enum MHD_StatusCode res; 2660 #ifdef MHD_USE_TRACE_POLLING_FDS 2661 fprintf (stderr, 2662 "### (Starting) MHD_daemon_process_reg_events(daemon, [%s])...\n", 2663 (NULL != next_max_wait) ? "non-NULL" : "NULL"); 2664 #endif 2665 res = process_reg_events_int (daemon, 2666 next_max_wait); 2667 #ifdef MHD_USE_TRACE_POLLING_FDS 2668 if (NULL == next_max_wait) 2669 fprintf (stderr, 2670 "### (Finished) MHD_daemon_process_reg_events(daemon, [NULL]) ->" 2671 "%u\n", 2672 (unsigned int)res); 2673 else if (MHD_WAIT_INDEFINITELY == *next_max_wait) 2674 fprintf (stderr, 2675 "### (Finished) MHD_daemon_process_reg_events(daemon, " 2676 "->MHD_WAIT_INDEFINITELY) ->%u\n", 2677 (unsigned int)res); 2678 else 2679 fprintf (stderr, 2680 "### (Finished) MHD_daemon_process_reg_events(daemon, ->%llu) " 2681 "->%u\n", 2682 (unsigned long long)*next_max_wait, 2683 (unsigned int)res); 2684 #endif 2685 return res; 2686 } 2687 2688 2689 #ifdef MHD_SUPPORT_THREADS 2690 2691 /** 2692 * The entry point for the daemon worker thread 2693 * @param cls the closure 2694 */ 2695 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC 2696 mhd_worker_all_events (void *cls) 2697 { 2698 struct MHD_Daemon *const restrict d = (struct MHD_Daemon *)cls; 2699 mhd_thread_handle_ID_set_current_thread_ID (&(d->threading.tid)); 2700 mhd_assert (d->dbg.net_inited); 2701 mhd_assert (!d->dbg.net_deinited); 2702 mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type)); 2703 mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type)); 2704 mhd_assert (mhd_DAEMON_TYPE_LISTEN_ONLY != d->threading.d_type); 2705 mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type)); 2706 mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION != d->wmode_int); 2707 mhd_assert (d->dbg.events_fully_inited); 2708 mhd_assert (d->dbg.connections_inited); 2709 2710 # ifdef mhd_HAVE_MHD_THREAD_BLOCK_SIGPIPE 2711 // TODO: store and use the result 2712 (void)mhd_thread_block_sigpipe (); 2713 # endif 2714 2715 while (!d->threading.stop_requested) 2716 { 2717 if (!process_all_events_and_data (d)) 2718 break; 2719 } 2720 if (!d->threading.stop_requested) 2721 { 2722 mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED, \ 2723 "The daemon thread is stopping, but termination has not " \ 2724 "been requested for the daemon."); 2725 } 2726 mhd_daemon_close_all_conns (d); 2727 2728 # ifdef MHD_SUPPORT_HTTPS 2729 if (mhd_D_HAS_TLS (d)) 2730 mhd_tls_thread_cleanup (d->tls); 2731 # endif /* MHD_SUPPORT_HTTPS */ 2732 2733 return (mhd_THRD_RTRN_TYPE)0; 2734 } 2735 2736 2737 static MHD_FN_PAR_NONNULL_ (1) bool 2738 process_listening_and_itc_only (struct MHD_Daemon *restrict d) 2739 { 2740 if (false) 2741 (void)0; 2742 # ifdef MHD_SUPPORT_SELECT 2743 else if (mhd_POLL_TYPE_SELECT == d->events.poll_type) 2744 { 2745 return false; // TODO: implement 2746 } 2747 # endif /* MHD_SUPPORT_SELECT */ 2748 # ifdef MHD_SUPPORT_POLL 2749 else if (mhd_POLL_TYPE_POLL == d->events.poll_type) 2750 { 2751 if (!get_all_net_updates_by_poll (d, true)) 2752 return false; 2753 } 2754 # endif /* MHD_SUPPORT_POLL */ 2755 else 2756 { 2757 (void)d; /* Mute compiler warning */ 2758 mhd_assert (0 && "Impossible value"); 2759 mhd_UNREACHABLE (); 2760 MHD_PANIC ("Daemon data integrity broken"); 2761 } 2762 // TODO: Accept connections 2763 return false; 2764 } 2765 2766 2767 /** 2768 * The entry point for the daemon listening thread 2769 * @param cls the closure 2770 */ 2771 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC 2772 mhd_worker_listening_only (void *cls) 2773 { 2774 struct MHD_Daemon *const restrict d = (struct MHD_Daemon *)cls; 2775 mhd_thread_handle_ID_set_current_thread_ID (&(d->threading.tid)); 2776 2777 mhd_assert (d->dbg.net_inited); 2778 mhd_assert (!d->dbg.net_deinited); 2779 mhd_assert (mhd_DAEMON_TYPE_LISTEN_ONLY == d->threading.d_type); 2780 mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION == d->wmode_int); 2781 mhd_assert (d->dbg.events_fully_inited); 2782 mhd_assert (d->dbg.connections_inited); 2783 2784 # ifdef mhd_HAVE_MHD_THREAD_BLOCK_SIGPIPE 2785 // TODO: store and use the result 2786 (void)mhd_thread_block_sigpipe (); 2787 # endif 2788 2789 while (!d->threading.stop_requested) 2790 { 2791 if (!process_listening_and_itc_only (d)) 2792 break; 2793 } 2794 if (!d->threading.stop_requested) 2795 { 2796 mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED, \ 2797 "The daemon thread is stopping, but termination has " \ 2798 "not been requested by the daemon."); 2799 } 2800 2801 # ifdef MHD_SUPPORT_HTTPS 2802 if (mhd_D_HAS_TLS (d)) 2803 mhd_tls_thread_cleanup (d->tls); 2804 # endif /* MHD_SUPPORT_HTTPS */ 2805 2806 return (mhd_THRD_RTRN_TYPE)0; 2807 } 2808 2809 2810 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC 2811 mhd_worker_connection (void *cls) 2812 { 2813 if (cls) // TODO: Implement 2814 MHD_PANIC ("Not yet implemented"); 2815 2816 # if 0 // def MHD_SUPPORT_HTTPS 2817 if (mhd_D_HAS_TLS (d)) 2818 mhd_tls_thread_cleanup (d->tls); 2819 # endif /* MHD_SUPPORT_HTTPS */ 2820 2821 return (mhd_THRD_RTRN_TYPE)0; 2822 } 2823 2824 2825 #endif /* MHD_SUPPORT_THREADS */