daemon_add_conn.c (42663B)
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) 2014-2024 Evgeny Grin (Karlson2k) 5 Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff 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 src/mhd2/daemon_add_conn.c 42 * @brief The implementations of MHD functions for adding new connections 43 * @author Karlson2k (Evgeny Grin) 44 * @author Daniel Pittman 45 * @author Christian Grothoff 46 * 47 * @warning Imported from MHD1 with minimal changes 48 * TODO: 49 * + Rewrite, 50 * + add per IP limit, 51 * + add app policy for new conn, 52 */ 53 54 #include "mhd_sys_options.h" 55 56 #include "sys_bool_type.h" 57 #include "sys_base_types.h" 58 59 #include "mhd_assert.h" 60 #include "mhd_unreachable.h" 61 #include "mhd_assume.h" 62 63 #include "sys_offsetof.h" 64 65 #include "mhd_locks.h" 66 #include "mhd_atomic_counter.h" 67 68 #include "sys_sockets_types.h" 69 #include "sys_sockets_headers.h" 70 #include "sys_ip_headers.h" 71 72 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 73 # include <stdio.h> 74 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 75 #include <string.h> 76 #ifdef MHD_SUPPORT_EPOLL 77 # include <sys/epoll.h> 78 #endif 79 80 #include "compat_calloc.h" 81 82 #include "mhd_sockets_macros.h" 83 #include "mhd_sockets_funcs.h" 84 85 #include "mhd_panic.h" 86 #include "mhd_dbg_print.h" 87 88 #include "mhd_daemon.h" 89 #include "mhd_connection.h" 90 91 #include "daemon_logger.h" 92 #include "mhd_mono_clock.h" 93 #include "mempool_funcs.h" 94 #include "events_process.h" 95 96 #include "daemon_funcs.h" 97 #include "response_from.h" 98 #include "response_destroy.h" 99 #include "conn_timeout.h" 100 #include "conn_mark_ready.h" 101 102 #ifdef MHD_SUPPORT_HTTP2 103 # include "h2/h2_comm.h" 104 #endif /* MHD_SUPPORT_HTTP2 */ 105 #ifdef MHD_SUPPORT_HTTPS 106 # include "mhd_tls_funcs.h" 107 #endif 108 109 #include "mhd_public_api.h" 110 111 #include "daemon_add_conn.h" 112 113 #ifdef MHD_SUPPORT_HTTP2 114 static void 115 connection_set_http_layer_init_state (struct MHD_Connection *restrict c) 116 { 117 c->h_layer.state = mhd_HTTP_LAYER_PREFACE; 118 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_SET; 119 } 120 121 122 #else /* ! MHD_SUPPORT_HTTP2 */ 123 # define connection_set_http_layer_init_state(c) ((void) 0) 124 #endif /* ! MHD_SUPPORT_HTTP2 */ 125 126 /** 127 * Set initial internal states for the connection to start reading and 128 * processing incoming data. 129 * This sets: 130 * + data processing stage 131 * + stream request and reply initial data 132 * + connection read and write buffers 133 * 134 * @param c the connection to process 135 */ 136 static void 137 connection_set_initial_state (struct MHD_Connection *restrict c) 138 { 139 size_t read_buf_size; 140 141 mhd_assert (mhd_HTTP_STAGE_INIT == c->stage); 142 143 c->conn_reuse = mhd_CONN_KEEPALIVE_POSSIBLE; 144 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 145 146 // TODO: move request reset to special function 147 memset (&(c->rq), 0, sizeof(c->rq)); 148 // TODO: move reply reset to special function 149 memset (&(c->rp), 0, sizeof(c->rp)); 150 151 #ifndef HAVE_NULL_PTR_ALL_ZEROS 152 // TODO: move request reset to special function 153 mhd_DLINKEDL_INIT_LIST (&(c->rq), fields); 154 #ifdef MHD_SUPPORT_POST_PARSER 155 mhd_DLINKEDL_INIT_LIST (&(c->rq), post_fields); 156 #endif /* MHD_SUPPORT_POST_PARSER */ 157 c->rq.version = NULL; 158 c->rq.url = NULL; 159 c->rq.field_lines.start = NULL; 160 c->rq.app_context = NULL; 161 c->rq.hdrs.rq_line.rq_tgt = NULL; 162 c->rq.hdrs.rq_line.rq_tgt_qmark = NULL; 163 164 // TODO: move reply reset to special function 165 c->rp.app_act_ctx.connection = NULL; 166 c->rp.response = NULL; 167 c->rp.resp_iov.iov = NULL; 168 #endif /* ! HAVE_NULL_PTR_ALL_ZEROS */ 169 170 c->write_buffer = NULL; 171 c->write_buffer_size = 0; 172 c->write_buffer_send_offset = 0; 173 c->write_buffer_append_offset = 0; 174 175 c->continue_message_write_offset = 0; 176 177 c->read_buffer_offset = 0; 178 read_buf_size = c->daemon->conns.cfg.mem_pool_size / 2; 179 c->read_buffer 180 = (char *) mhd_pool_allocate (c->pool, 181 read_buf_size, 182 false); 183 c->read_buffer_size = read_buf_size; 184 } 185 186 187 static void 188 notify_app_conn (struct MHD_Daemon *restrict daemon, 189 struct MHD_Connection *restrict connection, 190 bool closed) 191 { 192 (void) daemon, (void) connection, (void) closed; 193 // TODO: implement 194 } 195 196 197 /** 198 * Do basic preparation work on the new incoming connection. 199 * 200 * This function do all preparation that is possible outside main daemon 201 * thread. 202 * @remark Could be called from any thread. 203 * 204 * @param daemon daemon that manages the connection 205 * @param client_socket socket to manage (MHD will expect 206 * to receive an HTTP request from this socket next). 207 * @param addrlen number of bytes in @a addr 208 * @param addr IP address of the client, 209 * will be deallocated by free() if @a external_add is 'true' 210 * @param external_add indicate that socket has been added externally 211 * @param non_blck indicate that socket in non-blocking mode 212 * @param sk_spipe_supprs indicate that the @a client_socket has 213 * set SIGPIPE suppression 214 * @param sk_is_nonip _MHD_YES if this is not a TCP/IP socket 215 * @param[out] conn_out the pointer to variable to be set to the address 216 * of newly allocated connection structure 217 * @return #MHD_SC_OK on success, 218 * error on failure (the @a client_socket is closed) 219 */ 220 static MHD_FN_MUST_CHECK_RESULT_ 221 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_INOUT_SIZE_ (4,3) 222 MHD_FN_PAR_NONNULL_ (9) MHD_FN_PAR_OUT_ (9) enum MHD_StatusCode 223 new_connection_prepare_ (struct MHD_Daemon *restrict daemon, 224 MHD_Socket client_socket, 225 size_t addrlen, 226 struct sockaddr_storage *restrict addr, 227 bool external_add, 228 bool non_blck, 229 bool sk_spipe_supprs, 230 enum mhd_Tristate sk_is_nonip, 231 struct MHD_Connection **restrict conn_out) 232 { 233 struct MHD_Connection *c; 234 enum MHD_StatusCode ret; 235 size_t tls_data_size; 236 237 mhd_assert ((0 == addrlen) || (NULL != addr)); 238 239 ret = MHD_SC_OK; 240 *conn_out = NULL; 241 242 tls_data_size = 0; 243 #ifdef MHD_SUPPORT_HTTPS 244 if (mhd_D_HAS_TLS (daemon)) 245 tls_data_size = mhd_tls_conn_get_tls_size (daemon->tls); 246 #endif 247 248 c = (struct MHD_Connection *) 249 mhd_calloc (1, 250 sizeof (struct MHD_Connection) + tls_data_size); 251 if (NULL == c) 252 { 253 mhd_LOG_MSG (daemon, \ 254 MHD_SC_CONNECTION_MEM_ALLOC_FAILURE, \ 255 "Failed to allocate memory for the new connection"); 256 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 257 } 258 else 259 { 260 #ifndef HAVE_NULL_PTR_ALL_ZEROS 261 mhd_DLINKEDL_INIT_LINKS (c, all_conn); 262 c->extr_event.app_cntx = NULL; 263 mhd_DLINKEDL_INIT_LINKS (c, proc_ready); 264 mhd_DLINKEDL_INIT_LINKS (c, by_timeout); 265 # ifdef MHD_SUPPORT_UPGRADE 266 c->upgr.c = NULL; 267 mhd_DLINKEDL_INIT_LINKS (c, upgr_cleanup); 268 # endif /* MHD_SUPPORT_UPGRADE */ 269 c->socket_context = NULL; 270 #endif /* ! HAVE_NULL_PTR_ALL_ZEROS */ 271 #ifdef MHD_SUPPORT_HTTPS 272 if (0 != tls_data_size) 273 c->tls = (struct mhd_TlsConnData *) (c + 1); 274 # ifndef HAVE_NULL_PTR_ALL_ZEROS 275 else 276 c->tls = NULL; 277 # endif 278 #endif 279 280 #ifdef MHD_SUPPORT_HTTP2 281 mhd_h2_blank_init (c); 282 #endif /* MHD_SUPPORT_HTTP2 */ 283 284 if (! external_add) 285 { 286 c->sk.state.corked = mhd_T_NO; 287 c->sk.state.nodelay = mhd_T_NO; 288 } 289 else 290 { 291 c->sk.state.corked = mhd_T_MAYBE; 292 c->sk.state.nodelay = mhd_T_MAYBE; 293 } 294 295 if ((0 < addrlen)) 296 { 297 if (! external_add) 298 { 299 c->sk.addr.data = (struct sockaddr_storage *) malloc (addrlen); 300 if (NULL == c->sk.addr.data) 301 { 302 mhd_LOG_MSG (daemon, \ 303 MHD_SC_CONNECTION_MEM_ALLOC_FAILURE, \ 304 "Failed to allocate memory for the new connection"); 305 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 306 } 307 else 308 { 309 memcpy (c->sk.addr.data, 310 addr, 311 addrlen); 312 c->sk.addr.size = addrlen; 313 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 314 c->sk.addr.data->ss_len = addrlen; 315 #endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ 316 } 317 } 318 else 319 { 320 c->sk.addr.data = addr; 321 c->sk.addr.size = addrlen; 322 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 323 c->sk.addr.data->ss_len = addrlen; 324 #endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ 325 addr = NULL; 326 } 327 } 328 else 329 { 330 c->sk.addr.data = NULL; 331 c->sk.addr.size = 0u; 332 } 333 334 if (MHD_SC_OK == ret) 335 { 336 c->sk.fd = client_socket; 337 c->sk.props.is_nonblck = non_blck; 338 c->sk.props.is_nonip = sk_is_nonip; 339 c->sk.props.has_spipe_supp = sk_spipe_supprs; 340 #ifdef MHD_SUPPORT_THREADS 341 mhd_thread_handle_ID_set_invalid (&c->tid); 342 #endif /* MHD_SUPPORT_THREADS */ 343 c->daemon = daemon; 344 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 345 346 #ifdef MHD_SUPPORT_HTTPS 347 if (0 != tls_data_size) 348 { 349 if (! mhd_tls_conn_init (daemon->tls, 350 &(c->sk), 351 c->tls)) 352 { 353 mhd_LOG_MSG (daemon, \ 354 MHD_SC_TLS_CONNECTION_INIT_FAILED, \ 355 "Failed to initialise TLS context for " \ 356 "the new connection"); 357 ret = MHD_SC_TLS_CONNECTION_INIT_FAILED; 358 } 359 else 360 { 361 c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_RECV; 362 #ifndef NDEBUG 363 c->dbg.tls_inited = true; 364 #endif 365 } 366 } 367 #endif /* MHD_SUPPORT_HTTPS */ 368 369 if (MHD_SC_OK == ret) 370 { 371 *conn_out = c; 372 373 return MHD_SC_OK; /* Success exit point */ 374 } 375 376 /* Below is a cleanup path */ 377 if (NULL != c->sk.addr.data) 378 free (c->sk.addr.data); 379 } 380 free (c); 381 } 382 383 if ((NULL != addr) && external_add) 384 free (addr); 385 386 mhd_assert (MHD_SC_OK != ret); 387 return ret; /* Failure exit point */ 388 } 389 390 391 /** 392 * Internal (inner) function. 393 * Finally insert the new connection to the list of connections 394 * served by the daemon and start processing. 395 * @remark To be called only from thread that process 396 * daemon's select()/poll()/etc. 397 * 398 * @param daemon daemon that manages the connection 399 * @param connection the newly created connection 400 * @return #MHD_SC_OK on success, 401 * error code otherwise 402 */ 403 static enum MHD_StatusCode 404 new_connection_process_inner (struct MHD_Daemon *restrict daemon, 405 struct MHD_Connection *restrict connection) 406 { 407 enum MHD_StatusCode res; 408 mhd_assert (connection->daemon == daemon); 409 410 res = MHD_SC_OK; /* Mute compiler warning */ 411 mhd_assert (MHD_SC_OK == res); /* Mute analyser warning */ 412 /* Allocate memory pool in the processing thread so 413 * intensively used memory area is allocated in "good" 414 * (for the thread) memory region. It is important with 415 * NUMA and/or complex cache hierarchy. */ 416 connection->pool = mhd_pool_create (daemon->conns.cfg.mem_pool_size, 417 daemon->conns.cfg.mem_pool_zeroing); 418 if (NULL == connection->pool) 419 { /* 'pool' creation failed */ 420 mhd_LOG_MSG (daemon, MHD_SC_POOL_MEM_ALLOC_FAILURE, \ 421 "Failed to allocate memory for the connection memory pool."); 422 res = MHD_SC_POOL_MEM_ALLOC_FAILURE; 423 } 424 else 425 { 426 /* 'pool' creation succeed */ 427 428 mhd_assert (! daemon->conns.block_new); 429 mhd_assert (daemon->conns.count < daemon->conns.cfg.count_limit); 430 431 daemon->conns.count++; 432 daemon->conns.block_new = 433 (daemon->conns.count >= daemon->conns.cfg.count_limit); 434 mhd_DLINKEDL_INS_LAST (&(daemon->conns), connection, all_conn); 435 436 mhd_conn_init_activity_timeout (connection, 437 daemon->conns.cfg.timeout_milsec); 438 439 connection_set_http_layer_init_state (connection); 440 connection_set_initial_state (connection); 441 442 notify_app_conn (daemon, connection, false); 443 444 #ifdef MHD_SUPPORT_THREADS 445 if (mhd_DAEMON_TYPE_LISTEN_ONLY == daemon->threading.d_type) 446 { 447 mhd_assert ((mhd_POLL_TYPE_SELECT == daemon->events.poll_type) || \ 448 (mhd_POLL_TYPE_POLL == daemon->events.poll_type)); 449 if (! mhd_create_named_thread (&connection->tid, 450 "MHD-connection", 451 daemon->threading.cfg.stack_size, 452 &mhd_worker_connection, 453 connection)) 454 { 455 #ifdef EAGAIN 456 if (EAGAIN == errno) 457 { 458 mhd_LOG_MSG (daemon, MHD_SC_CONNECTION_THREAD_SYS_LIMITS_REACHED, 459 "Failed to create a new thread because it would " 460 "have exceeded the system limit on the number of " 461 "threads or no system resources available."); 462 res = MHD_SC_CONNECTION_THREAD_SYS_LIMITS_REACHED; 463 } 464 else 465 #endif /* EAGAIN */ 466 if (1) 467 { 468 mhd_LOG_MSG (daemon, MHD_SC_CONNECTION_THREAD_LAUNCH_FAILURE, 469 "Failed to create a thread."); 470 res = MHD_SC_CONNECTION_THREAD_LAUNCH_FAILURE; 471 } 472 } 473 else /* New thread has been created successfully */ 474 return MHD_SC_OK; /* *** Function success exit point *** */ 475 } 476 else 477 #else /* ! MHD_SUPPORT_THREADS */ 478 if (1) 479 #endif /* ! MHD_SUPPORT_THREADS */ 480 { /* No 'thread-per-connection' */ 481 #ifdef MHD_SUPPORT_THREADS 482 connection->tid = daemon->threading.tid; 483 #endif /* MHD_SUPPORT_THREADS */ 484 #ifdef MHD_SUPPORT_EPOLL 485 if (mhd_POLL_TYPE_EPOLL == daemon->events.poll_type) 486 { 487 struct epoll_event event; 488 489 event.events = EPOLLIN | EPOLLOUT | EPOLLET; 490 event.data.ptr = connection; 491 if (0 != epoll_ctl (daemon->events.data.epoll.e_fd, 492 EPOLL_CTL_ADD, 493 connection->sk.fd, 494 &event)) 495 { 496 mhd_LOG_MSG (daemon, MHD_SC_EPOLL_CTL_ADD_FAILED, 497 "Failed to add connection socket to epoll."); 498 res = MHD_SC_EPOLL_CTL_ADD_FAILED; 499 } 500 else 501 { 502 mhd_dbg_print_fd_mon_req ("conn", \ 503 connection->sk.fd, \ 504 true, \ 505 true, \ 506 false); 507 if (0) // TODO: implement turbo 508 { 509 connection->sk.ready = 510 (enum mhd_SocketNetState) (mhd_SOCKET_NET_STATE_RECV_READY 511 | mhd_SOCKET_NET_STATE_SEND_READY); 512 mhd_conn_mark_ready (connection, daemon); 513 } 514 return MHD_SC_OK; /* *** Function success exit point *** */ 515 } 516 } 517 else /* No 'epoll' */ 518 #endif /* MHD_SUPPORT_EPOLL */ 519 return MHD_SC_OK; /* *** Function success exit point *** */ 520 } 521 522 /* ** Below is a cleanup path ** */ 523 mhd_assert (MHD_SC_OK != res); 524 notify_app_conn (daemon, connection, true); 525 526 mhd_conn_deinit_activity_timeout (connection); 527 528 mhd_DLINKEDL_DEL (&(daemon->conns), connection, all_conn); 529 daemon->conns.count--; 530 daemon->conns.block_new = false; 531 532 mhd_pool_destroy (connection->pool); 533 } 534 /* Free resources allocated before the call of this functions */ 535 536 #ifdef MHD_SUPPORT_HTTPS 537 if (mhd_C_HAS_TLS (connection)) 538 mhd_tls_conn_deinit (connection->tls); 539 #endif 540 541 // TODO: per IP limit 542 543 if (NULL != connection->sk.addr.data) 544 free (connection->sk.addr.data); 545 (void) mhd_socket_close (connection->sk.fd); 546 free (connection); 547 mhd_assert (MHD_SC_OK != res); 548 return res; /* *** Function failure exit point *** */ 549 } 550 551 552 /** 553 * Finally insert the new connection to the list of connections 554 * served by the daemon and start processing. 555 * @remark To be called only from thread that process 556 * daemon's select()/poll()/etc. 557 * 558 * @param daemon daemon that manages the connection 559 * @param connection the newly created connection 560 * @return #MHD_SC_OK on success, 561 * error code otherwise 562 */ 563 static enum MHD_StatusCode 564 new_connection_process_ (struct MHD_Daemon *restrict daemon, 565 struct MHD_Connection *restrict connection) 566 { 567 enum MHD_StatusCode res; 568 569 res = new_connection_process_inner (daemon, 570 connection); 571 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 572 if (MHD_SC_OK == res) 573 fprintf (stderr, 574 "&&& Added new connection, FD: %2llu\n", 575 (unsigned long long) connection->sk.fd); 576 else 577 fprintf (stderr, 578 "&&& Failed add connection, FD: %2llu -> %u\n", 579 (unsigned long long) connection->sk.fd, 580 (unsigned int) res); 581 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 582 583 return res; 584 } 585 586 587 /** 588 * The given client socket will be managed (and closed!) by MHD after 589 * this call and must no longer be used directly by the application 590 * afterwards. 591 * 592 * @param daemon daemon that manages the connection 593 * @param client_socket socket to manage (MHD will expect 594 * to receive an HTTP request from this socket next). 595 * @param addrlen number of bytes in @a addr 596 * @param addr IP address of the client, 597 * will be deallocated by free() if @a external_add is 'true' 598 * @param external_add perform additional operations needed due 599 * to the application calling us directly 600 * @param non_blck indicate that socket in non-blocking mode 601 * @param sk_spipe_supprs indicate that the @a client_socket has 602 * set SIGPIPE suppression 603 * @param sk_is_nonip _MHD_YES if this is not a TCP/IP socket 604 * @return #MHD_SC_OK on success, 605 * error on failure (the @a client_socket is closed) 606 */ 607 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_INOUT_SIZE_ (4,3) enum MHD_StatusCode 608 internal_add_connection (struct MHD_Daemon *daemon, 609 MHD_Socket client_socket, 610 size_t addrlen, 611 struct sockaddr_storage *addr, 612 bool external_add, 613 bool non_blck, 614 bool sk_spipe_supprs, 615 enum mhd_Tristate sk_is_nonip) 616 { 617 struct MHD_Connection *connection; 618 enum MHD_StatusCode res; 619 620 /* Direct add to master daemon could never happen. */ 621 mhd_assert (! mhd_D_HAS_WORKERS (daemon)); 622 mhd_assert (mhd_FD_FITS_DAEMON (daemon, client_socket)); 623 624 res = MHD_SC_OK; 625 626 if ((! non_blck) && 627 (mhd_POLL_TYPE_INT_IS_EPOLL (daemon->events.poll_type) || 628 (mhd_WM_INT_EXTERNAL_EVENTS_EDGE == daemon->wmode_int))) 629 { 630 mhd_LOG_MSG (daemon, MHD_SC_NONBLOCKING_REQUIRED, \ 631 "The daemon configuration requires non-blocking sockets, " 632 "the new socket has not been added."); 633 res = MHD_SC_NONBLOCKING_REQUIRED; 634 } 635 636 if (MHD_SC_OK == res) 637 { 638 if (daemon->conns.block_new) 639 { /* Connections limit */ 640 mhd_LOG_MSG (daemon, MHD_SC_LIMIT_CONNECTIONS_REACHED, \ 641 "Server reached connection limit. " \ 642 "Closing inbound connection."); 643 res = MHD_SC_LIMIT_CONNECTIONS_REACHED; 644 } 645 646 if (MHD_SC_OK == res) 647 { 648 res = new_connection_prepare_ (daemon, 649 client_socket, 650 addrlen, addr, 651 external_add, 652 non_blck, 653 sk_spipe_supprs, 654 sk_is_nonip, 655 &connection); 656 addr = NULL; /* Cleaned up with 'connection' if needed */ 657 658 if (MHD_SC_OK == res) 659 { 660 mhd_ASSUME (NULL != connection); 661 662 if (external_add) 663 res = MHD_SC_FEATURE_DISABLED; 664 else 665 return new_connection_process_ (daemon, connection); 666 } 667 } 668 } 669 670 if ((NULL != addr) && external_add) 671 free (addr); 672 mhd_socket_close (client_socket); 673 674 mhd_assert (MHD_SC_OK != res); 675 676 return res; 677 } 678 679 680 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_ (4) MHD_EXTERN_ enum MHD_StatusCode 681 MHD_daemon_add_connection (struct MHD_Daemon *MHD_RESTRICT daemon, 682 MHD_Socket new_socket, 683 size_t addr_size, 684 const struct sockaddr *MHD_RESTRICT addr, 685 void *connection_cntx) 686 { 687 enum MHD_StatusCode ret; 688 bool sk_nonbl; 689 bool sk_spipe_supprs; 690 691 sk_nonbl = false; 692 693 // TODO: global daemon lock for external events 694 (void) connection_cntx; // TODO: add support for connection's context 695 696 ret = MHD_SC_OK; 697 698 if (! mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type) 699 && daemon->conns.block_new) 700 ret = MHD_SC_LIMIT_CONNECTIONS_REACHED; 701 702 if ((MHD_SC_OK == ret) && 703 (0 != addr_size)) 704 { 705 if (addr_size < (sizeof(addr->sa_family) 706 + offsetof (struct sockaddr, sa_family))) 707 { 708 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 709 "MHD_add_connection() has been called with " \ 710 "incorrect 'addr_size' value."); 711 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 712 } 713 else if (AF_INET == addr->sa_family) 714 { 715 if (sizeof(struct sockaddr_in) > addr_size) 716 { 717 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 718 "MHD_add_connection() has been called with " \ 719 "incorrect 'addr_size' value."); 720 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 721 } 722 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 723 else if ((0 != addr->sa_len) && 724 (sizeof(struct sockaddr_in) > (size_t) addr->sa_len) ) 725 { 726 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 727 "MHD_add_connection() has been called with " \ 728 "non-zero value of 'sa_len' member of " \ 729 "'struct sockaddr' which does not match 'sa_family'."); 730 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 731 } 732 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 733 } 734 #ifdef HAVE_INET6 735 else if (AF_INET6 == addr->sa_family) 736 { 737 if (sizeof(struct sockaddr_in6) > addr_size) 738 { 739 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 740 "MHD_add_connection() has been called with " \ 741 "incorrect 'addr_size' value."); 742 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 743 } 744 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 745 else if ((0 != addr->sa_len) && 746 (sizeof(struct sockaddr_in6) > (size_t) addr->sa_len) ) 747 { 748 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 749 "MHD_add_connection() has been called with " \ 750 "non-zero value of 'sa_len' member of " \ 751 "'struct sockaddr' which does not match 'sa_family'."); 752 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 753 } 754 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 755 } 756 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 757 else if (addr_size < (sizeof(addr->sa_len) 758 + offsetof (struct sockaddr, sa_len))) 759 { 760 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 761 "MHD_add_connection() has been called with " \ 762 "incorrect 'addr_size' value."); 763 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 764 } 765 if ((0 != addr->sa_len) && 766 (addr_size > (size_t) addr->sa_len)) 767 addr_size = (size_t) addr->sa_len; /* Use safest value */ 768 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 769 #endif /* HAVE_INET6 */ 770 } 771 772 if (MHD_SC_OK == ret) 773 { 774 if (! mhd_FD_FITS_DAEMON (daemon, 775 new_socket)) 776 { 777 mhd_LOG_MSG (daemon, MHD_SC_NEW_CONN_FD_OUTSIDE_OF_SET_RANGE, \ 778 "The new connection FD value is higher than allowed"); 779 ret = MHD_SC_NEW_CONN_FD_OUTSIDE_OF_SET_RANGE; 780 } 781 } 782 783 if (MHD_SC_OK == ret) 784 { 785 sk_nonbl = mhd_socket_nonblocking (new_socket); 786 if (! sk_nonbl) 787 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, \ 788 "Failed to set nonblocking mode on the new client socket."); 789 790 if (1) // TODO: implement turbo 791 { 792 if (! mhd_socket_noninheritable (new_socket)) 793 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, \ 794 "Failed to set noninheritable mode on new client socket."); 795 } 796 } 797 798 #ifndef MHD_SOCKETS_KIND_WINSOCK 799 sk_spipe_supprs = false; 800 #else /* MHD_SOCKETS_KIND_WINSOCK */ 801 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 802 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 803 #if defined(mhd_socket_nosignal) 804 if (MHD_SC_OK == ret) 805 { 806 if (! sk_spipe_supprs) 807 sk_spipe_supprs = mhd_socket_nosignal (new_socket); 808 if (! sk_spipe_supprs) 809 { 810 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED, \ 811 "Failed to suppress SIGPIPE on the new client socket."); 812 # ifndef HAVE_DCLR_MSG_NOSIGNAL 813 /* Application expects that SIGPIPE will be suppressed, 814 * but suppression failed and SIGPIPE cannot be suppressed with send(). */ 815 if (! daemon->sigpipe_blocked) 816 ret = MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED; 817 # endif /* HAVE_DCLR_MSG_NOSIGNAL */ 818 } 819 } 820 #endif /* mhd_socket_nosignal */ 821 822 if (MHD_SC_OK == ret) 823 { 824 struct mhd_DaemonExtAddedConn *new_conn; 825 826 new_conn = 827 (struct mhd_DaemonExtAddedConn*) 828 malloc (sizeof(struct mhd_DaemonExtAddedConn)); 829 830 if (NULL == new_conn) 831 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 832 else 833 { 834 mhd_DLINKEDL_INIT_LINKS (new_conn, queue); 835 new_conn->skt = new_socket; 836 new_conn->is_nonblock = sk_nonbl; 837 new_conn->has_spipe_suppr = sk_spipe_supprs; 838 new_conn->addr_size = addr_size; 839 840 if (0 != addr_size) 841 { 842 new_conn->addr = (struct sockaddr_storage *) malloc (addr_size); 843 if (NULL == new_conn->addr) 844 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 845 else 846 memcpy (new_conn->addr, 847 addr, 848 addr_size); 849 } 850 else 851 new_conn->addr = NULL; 852 853 if (MHD_SC_OK == ret) 854 { 855 struct MHD_Daemon *d_to_add; 856 if (! mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type)) 857 d_to_add = daemon; 858 else 859 { 860 #if defined(MHD_SUPPORT_THREADS) 861 size_t d_offset; 862 863 d_offset = 864 mhd_atomic_counter_get_inc_wrap ( 865 &(daemon->events.act_req.ext_added.master.next_d_idx)); 866 867 d_to_add = (daemon->threading.hier.pool.workers 868 + (d_offset % daemon->threading.hier.pool.num)); 869 mhd_ASSUME (NULL != d_to_add); 870 871 if (d_to_add->conns.block_new) 872 { 873 /* Try to find daemon with available connection slots */ 874 size_t i; 875 876 /* Start from the other side of the workers pool to avoid 877 conflict with the next called "add external connection". */ 878 d_offset += daemon->threading.hier.pool.num / 2; 879 880 for (i = 0u; i < daemon->threading.hier.pool.num; ++i) 881 { 882 d_to_add = (daemon->threading.hier.pool.workers 883 + ((d_offset + i) % daemon->threading.hier.pool.num)); 884 885 if (d_to_add->conns.block_new) 886 d_to_add = NULL; 887 else 888 break; 889 } 890 } 891 #else /* ! MHD_SUPPORT_THREADS */ 892 mhd_UNREACHABLE (); 893 d_to_add = NULL; 894 #endif /* ! MHD_SUPPORT_THREADS */ 895 } 896 897 if (NULL == d_to_add) 898 ret = MHD_SC_LIMIT_CONNECTIONS_REACHED; 899 else 900 { 901 mhd_mutex_lock_chk ( 902 &(d_to_add->events.act_req.ext_added.worker.q_lock)); 903 mhd_DLINKEDL_INS_LAST (&(d_to_add->events.act_req.ext_added.worker), 904 new_conn, 905 queue); 906 mhd_mutex_unlock_chk ( 907 &(d_to_add->events.act_req.ext_added.worker.q_lock)); 908 909 mhd_daemon_trigger_itc (d_to_add); 910 911 return MHD_SC_OK; /* Success exit point */ 912 } 913 914 /* Below is a clean-up path */ 915 916 if (NULL != new_conn->addr) 917 free (new_conn->addr); 918 } 919 free (new_conn); 920 } 921 } 922 923 (void) mhd_socket_close (new_socket); 924 925 mhd_assert (MHD_SC_OK != ret); 926 927 return ret; 928 } 929 930 931 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_DaemonAcceptResult 932 mhd_daemon_accept_connection (struct MHD_Daemon *restrict daemon) 933 { 934 struct sockaddr_storage addrstorage[2]; /* Support non-standard extensions */ 935 socklen_t addrlen; 936 MHD_Socket s; 937 MHD_Socket fd; 938 bool sk_nonbl; 939 bool sk_spipe_supprs; 940 bool sk_cloexec; 941 enum mhd_Tristate sk_non_ip; 942 #if ! defined(NDEBUG) && defined (mhd_USE_ACCEPT4) 943 const bool use_accept4 = ! daemon->dbg.avoid_accept4; 944 #elif defined (mhd_USE_ACCEPT4) 945 static const bool use_accept4 = true; 946 #else /* ! USE_ACCEPT4 && ! _DEBUG */ 947 static const bool use_accept4 = false; 948 #endif /* ! USE_ACCEPT4 && ! _DEBUG */ 949 950 #ifdef MHD_SUPPORT_THREADS 951 mhd_assert ((! mhd_D_HAS_THREADS (daemon)) || \ 952 mhd_thread_handle_ID_is_current_thread (daemon->threading.tid)); 953 mhd_assert (! mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type)); 954 #endif /* MHD_SUPPORT_THREADS */ 955 956 fd = daemon->net.listen.fd; 957 mhd_assert (MHD_INVALID_SOCKET != fd); 958 mhd_assert (! daemon->net.listen.is_broken); 959 960 addrlen = (socklen_t) sizeof (addrstorage); 961 memset (addrstorage, 962 0, 963 (size_t) addrlen); 964 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 965 addrstorage->ss_len = addrlen; 966 #endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ 967 968 /* Initialise with default values to avoid compiler warnings */ 969 sk_nonbl = false; 970 sk_spipe_supprs = false; 971 sk_cloexec = false; 972 s = MHD_INVALID_SOCKET; 973 974 #ifdef mhd_USE_ACCEPT4 975 if (use_accept4) 976 { 977 s = accept4 (fd, 978 (struct sockaddr *) addrstorage, 979 &addrlen, 980 mhd_SOCK_CLOEXEC | mhd_SOCK_NONBLOCK | mhd_SOCK_NOSIGPIPE); 981 if (MHD_INVALID_SOCKET != s) 982 { 983 sk_nonbl = (mhd_SOCK_NONBLOCK != 0); 984 #ifndef MHD_SOCKETS_KIND_WINSOCK 985 sk_spipe_supprs = (mhd_SOCK_NOSIGPIPE != 0); 986 #else /* MHD_SOCKETS_KIND_WINSOCK */ 987 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 988 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 989 sk_cloexec = (mhd_SOCK_CLOEXEC != 0); 990 } 991 } 992 #endif /* mhd_USE_ACCEPT4 */ 993 #if ! defined(mhd_USE_ACCEPT4) || ! defined(NDEBUG) 994 if (! use_accept4) 995 { 996 s = accept (fd, 997 (struct sockaddr *) addrstorage, 998 &addrlen); 999 if (MHD_INVALID_SOCKET != s) 1000 { 1001 #ifdef MHD_ACCEPTED_INHERITS_NONBLOCK 1002 sk_nonbl = daemon->net.listen.non_block; 1003 #else /* ! MHD_ACCEPTED_INHERITS_NONBLOCK */ 1004 sk_nonbl = false; 1005 #endif /* ! MHD_ACCEPTED_INHERITS_NONBLOCK */ 1006 #ifndef MHD_SOCKETS_KIND_WINSOCK 1007 sk_spipe_supprs = false; 1008 #else /* MHD_SOCKETS_KIND_WINSOCK */ 1009 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 1010 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 1011 sk_cloexec = false; 1012 } 1013 } 1014 #endif /* !mhd_USE_ACCEPT4 || _DEBUG */ 1015 1016 if (MHD_INVALID_SOCKET == s) 1017 { /* This could be a common occurrence with multiple worker threads */ 1018 const int err = mhd_SCKT_GET_LERR (); 1019 1020 if (mhd_SCKT_ERR_IS_EINVAL (err)) 1021 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; /* can happen during shutdown */ // FIXME: remove? 1022 if (mhd_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT (err)) 1023 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; /* do not print error if client just disconnects early */ 1024 if (mhd_SCKT_ERR_IS_EINTR (err)) 1025 return mhd_DAEMON_ACCEPT_SKIPPED; 1026 if (mhd_SCKT_ERR_IS_EAGAIN (err)) 1027 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; 1028 if (mhd_SCKT_ERR_IS_LOW_RESOURCES (err) ) 1029 { 1030 /* system/process out of resources */ 1031 if (0 == daemon->conns.count) 1032 { 1033 /* Not setting 'block_new' flag, as there is no way it 1034 would ever be cleared. Instead trying to produce 1035 bit fat ugly warning. */ 1036 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY, \ 1037 "Hit process or system resource limit at FIRST " \ 1038 "connection. This is really bad as there is no sane " \ 1039 "way to proceed. Will try busy waiting for system " \ 1040 "resources to become magically available."); 1041 } 1042 else 1043 { 1044 daemon->conns.block_new = true; 1045 mhd_LOG_PRINT (daemon, MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED, \ 1046 mhd_LOG_FMT ("Hit process or system resource limit " \ 1047 "at %u connections, temporarily " \ 1048 "suspending accept(). Consider setting " \ 1049 "a lower MHD_OPTION_CONNECTION_LIMIT."), \ 1050 daemon->conns.count); 1051 } 1052 return mhd_DAEMON_ACCEPT_FAILED; 1053 } 1054 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY, 1055 "Error accepting connection."); 1056 return mhd_DAEMON_ACCEPT_FAILED; 1057 } 1058 1059 if (! mhd_FD_FITS_DAEMON (daemon, s)) 1060 { 1061 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_OUTSIDE_OF_SET_RANGE, \ 1062 "The accepted socket has value outside of allowed range."); 1063 (void) mhd_socket_close (s); 1064 return mhd_DAEMON_ACCEPT_FAILED; 1065 } 1066 if (mhd_SOCKET_TYPE_IP == daemon->net.listen.type) 1067 sk_non_ip = mhd_T_NO; 1068 else if (mhd_SOCKET_TYPE_UNKNOWN == daemon->net.listen.type) 1069 sk_non_ip = mhd_T_MAYBE; 1070 else 1071 sk_non_ip = mhd_T_YES; 1072 if (0 >= addrlen) 1073 { 1074 if (mhd_SOCKET_TYPE_IP == daemon->net.listen.type) 1075 mhd_LOG_MSG (daemon, MHD_SC_ACCEPTED_UNKNOWN_TYPE, \ 1076 "Accepted socket has non-positive length of the address. " \ 1077 "Processing the new socket as a socket with " \ 1078 "unknown type."); 1079 addrlen = 0; 1080 sk_non_ip = mhd_T_MAYBE; 1081 } 1082 else if (((socklen_t) sizeof (addrstorage)) < addrlen) 1083 { 1084 /* Should not happen as 'sockaddr_storage' must be large enough to 1085 * store any address supported by the system. */ 1086 mhd_LOG_MSG (daemon, MHD_SC_ACCEPTED_SOCKADDR_TOO_LARGE, \ 1087 "Accepted socket address is larger than expected by " \ 1088 "system headers. Processing the new socket as a socket with " \ 1089 "unknown type."); 1090 addrlen = 0; 1091 sk_non_ip = mhd_T_MAYBE; /* IP-type addresses must fit */ 1092 } 1093 else if (mhd_T_MAYBE == sk_non_ip) 1094 { 1095 if (AF_INET == ((struct sockaddr *) addrstorage)->sa_family) 1096 sk_non_ip = mhd_T_NO; 1097 #ifdef HAVE_INET6 1098 else if (AF_INET6 == ((struct sockaddr *) addrstorage)->sa_family) 1099 sk_non_ip = mhd_T_NO; 1100 #endif /* HAVE_INET6 */ 1101 } 1102 1103 if (! sk_nonbl) 1104 { /* Was not set automatically */ 1105 sk_nonbl = mhd_socket_nonblocking (s); 1106 if (! sk_nonbl) 1107 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, \ 1108 "Failed to set nonblocking mode on " 1109 "new connection socket."); 1110 } 1111 1112 if (! sk_cloexec) 1113 { /* Was not set automatically */ 1114 sk_cloexec = mhd_socket_noninheritable (s); 1115 if (! sk_cloexec) 1116 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, \ 1117 "Failed to set non-inheritable mode on " 1118 "new connection socket."); 1119 } 1120 1121 #if defined(mhd_socket_nosignal) 1122 if (! sk_spipe_supprs && ! mhd_socket_nosignal (s)) 1123 { 1124 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED, 1125 "Failed to suppress SIGPIPE on incoming connection " \ 1126 "socket."); 1127 #ifndef HAVE_DCLR_MSG_NOSIGNAL 1128 /* Application expects that SIGPIPE will be suppressed, 1129 * but suppression failed and SIGPIPE cannot be suppressed with send(). */ 1130 if (! daemon->sigpipe_blocked) 1131 { 1132 (void) MHD_socket_close_ (s); 1133 return mhd_DAEMON_ACCEPT_FAILED; 1134 } 1135 #endif /* HAVE_DCLR_MSG_NOSIGNAL */ 1136 } 1137 else 1138 sk_spipe_supprs = true; 1139 #endif /* mhd_socket_nosignal */ 1140 return (MHD_SC_OK == internal_add_connection (daemon, 1141 s, 1142 (size_t) addrlen, 1143 addrstorage, 1144 false, 1145 sk_nonbl, 1146 sk_spipe_supprs, 1147 sk_non_ip)) ? 1148 mhd_DAEMON_ACCEPT_SUCCESS : mhd_DAEMON_ACCEPT_FAILED; 1149 } 1150 1151 1152 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1153 mhd_conn_remove_from_daemon (struct MHD_Connection *restrict c) 1154 { 1155 mhd_assert (c->dbg.closing_started); 1156 mhd_assert (c->dbg.pre_cleaned); 1157 mhd_assert (! c->dbg.removed_from_daemon); 1158 mhd_assert (NULL == c->rp.response); 1159 mhd_assert (! c->rq.app_aware); 1160 mhd_assert (! c->in_proc_ready); 1161 mhd_assert (NULL == c->rq.cntn.lbuf.data); 1162 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, proc_ready)); 1163 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, proc_ready)); 1164 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->events), proc_ready)); 1165 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->events), proc_ready)); 1166 1167 if (mhd_D_HAS_THR_PER_CONN (c->daemon)) 1168 { 1169 mhd_assert (0 && "Not implemented yet"); 1170 // TODO: Support "thread per connection" 1171 } 1172 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (&(c->timeout), tmout_list)); 1173 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list)); 1174 mhd_assert (NULL == c->pool); 1175 1176 mhd_DLINKEDL_DEL (&(c->daemon->conns), c, all_conn); 1177 1178 // TODO: update per-IP limits 1179 1180 c->daemon->conns.count--; 1181 c->daemon->conns.block_new = false; 1182 1183 #ifndef NDEBUG 1184 c->dbg.removed_from_daemon = true; 1185 #endif /* NDEBUG */ 1186 } 1187 1188 1189 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1190 mhd_conn_close_final (struct MHD_Connection *restrict c) 1191 { 1192 mhd_assert (c->dbg.closing_started); 1193 mhd_assert (c->dbg.pre_cleaned); 1194 mhd_assert (c->dbg.removed_from_daemon); 1195 mhd_assert (NULL == c->rp.response); 1196 mhd_assert (! c->rq.app_aware); 1197 mhd_assert (! c->in_proc_ready); 1198 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, proc_ready)); 1199 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, proc_ready)); 1200 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->events), proc_ready)); 1201 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->events), proc_ready)); 1202 1203 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (&(c->timeout), tmout_list)); 1204 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list)); 1205 mhd_assert (NULL == c->pool); 1206 1207 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, all_conn)); 1208 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, all_conn)); 1209 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->conns), all_conn)); 1210 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->conns), all_conn)); 1211 1212 #ifdef MHD_SUPPORT_HTTPS 1213 if (mhd_C_HAS_TLS (c)) 1214 { 1215 mhd_assert (mhd_D_HAS_TLS (c->daemon)); 1216 mhd_assert (c->dbg.tls_inited); 1217 mhd_tls_conn_deinit (c->tls); 1218 } 1219 # ifndef NDEBUG 1220 else 1221 { 1222 mhd_assert (! mhd_D_HAS_TLS (c->daemon)); 1223 mhd_assert (! c->dbg.tls_inited); 1224 } 1225 # endif 1226 #endif 1227 1228 if (NULL != c->sk.addr.data) 1229 free (c->sk.addr.data); 1230 mhd_socket_close (c->sk.fd); 1231 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 1232 fprintf (stderr, 1233 "&&& Closed connection, FD: %2llu\n", 1234 (unsigned long long) c->sk.fd); 1235 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 1236 1237 free (c); 1238 } 1239 1240 1241 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1242 mhd_daemon_process_ext_added_conns (struct MHD_Daemon *restrict d) 1243 { 1244 struct mhd_DaemonExtAddedConn *ext_added; 1245 mhd_DLNKDL_LIST (mhd_DaemonExtAddedConn, detached_q); 1246 1247 mhd_assert (! mhd_D_HAS_WORKERS (d)); 1248 1249 if (NULL == 1250 mhd_DLINKEDL_GET_FIRST (&(d->events.act_req.ext_added.worker), 1251 queue)) 1252 return; /* Shortcut: the queue is empty */ 1253 1254 /* Detach the queue to quickly manipulate the lock one time only */ 1255 mhd_mutex_lock_chk (&(d->events.act_req.ext_added.worker.q_lock)); 1256 detached_q = d->events.act_req.ext_added.worker.queue; 1257 mhd_DLINKEDL_INIT_LIST (&(d->events.act_req.ext_added.worker), 1258 queue); 1259 mhd_mutex_unlock_chk (&(d->events.act_req.ext_added.worker.q_lock)); 1260 1261 /* Process without lock the detached queue in FIFO order */ 1262 for (ext_added = mhd_DLINKEDL_GET_FIRST_D (&detached_q); 1263 NULL != ext_added; 1264 ext_added = mhd_DLINKEDL_GET_FIRST_D (&detached_q)) 1265 { 1266 mhd_ASSUME (NULL == mhd_DLINKEDL_GET_PREV (ext_added, 1267 queue)); 1268 mhd_DLINKEDL_DEL_D (&detached_q, ext_added, 1269 queue); 1270 1271 if (! d->conns.block_new) 1272 { 1273 (void) internal_add_connection (d, 1274 ext_added->skt, 1275 ext_added->addr_size, 1276 ext_added->addr, 1277 true, 1278 ext_added->is_nonblock, 1279 ext_added->has_spipe_suppr, 1280 mhd_T_MAYBE); 1281 } 1282 else 1283 { 1284 if (NULL != ext_added->addr) 1285 free (ext_added->addr); 1286 } 1287 free (ext_added); 1288 } 1289 }