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