daemon_add_conn.c (41817B)
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_NONNULL_IF_NONZERO_ (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_NONNULL_IF_NONZERO_ (4, 3) 587 enum MHD_StatusCode 588 internal_add_connection (struct MHD_Daemon *daemon, 589 MHD_Socket client_socket, 590 size_t addrlen, 591 struct sockaddr_storage *addr, 592 bool external_add, 593 bool non_blck, 594 bool sk_spipe_supprs, 595 enum mhd_Tristate sk_is_nonip) 596 { 597 struct MHD_Connection *connection; 598 enum MHD_StatusCode res; 599 600 /* Direct add to master daemon could never happen. */ 601 mhd_assert (!mhd_D_HAS_WORKERS (daemon)); 602 mhd_assert (mhd_FD_FITS_DAEMON (daemon, client_socket)); 603 604 res = MHD_SC_OK; 605 606 if ((!non_blck) 607 && (mhd_POLL_TYPE_INT_IS_EPOLL (daemon->events.poll_type) 608 || (mhd_WM_INT_EXTERNAL_EVENTS_EDGE == daemon->wmode_int))) 609 { 610 mhd_LOG_MSG (daemon, MHD_SC_NONBLOCKING_REQUIRED, \ 611 "The daemon configuration requires non-blocking sockets, " 612 "the new socket has not been added."); 613 res = MHD_SC_NONBLOCKING_REQUIRED; 614 } 615 616 if (MHD_SC_OK == res) 617 { 618 if (daemon->conns.block_new) 619 { /* Connections limit */ 620 mhd_LOG_MSG (daemon, MHD_SC_LIMIT_CONNECTIONS_REACHED, \ 621 "Server reached connection limit. " \ 622 "Closing inbound connection."); 623 res = MHD_SC_LIMIT_CONNECTIONS_REACHED; 624 } 625 626 if (MHD_SC_OK == res) 627 { 628 res = new_connection_prepare_ (daemon, 629 client_socket, 630 addrlen, addr, 631 external_add, 632 non_blck, 633 sk_spipe_supprs, 634 sk_is_nonip, 635 &connection); 636 addr = NULL; /* Cleaned up with 'connection' if needed */ 637 638 if (MHD_SC_OK == res) 639 { 640 mhd_ASSUME (NULL != connection); 641 642 if (external_add) 643 res = MHD_SC_FEATURE_DISABLED; 644 else 645 return new_connection_process_ (daemon, connection); 646 } 647 } 648 } 649 650 if ((NULL != addr) && external_add) 651 free (addr); 652 mhd_socket_close (client_socket); 653 654 mhd_assert (MHD_SC_OK != res); 655 656 return res; 657 } 658 659 660 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_ (4) MHD_EXTERN_ enum MHD_StatusCode 661 MHD_daemon_add_connection (struct MHD_Daemon *MHD_RESTRICT daemon, 662 MHD_Socket new_socket, 663 size_t addr_size, 664 const struct sockaddr *MHD_RESTRICT addr, 665 void *connection_cntx) 666 { 667 enum MHD_StatusCode ret; 668 bool sk_nonbl; 669 bool sk_spipe_supprs; 670 671 sk_nonbl = false; 672 673 // TODO: global daemon lock for external events 674 (void)connection_cntx; // TODO: add support for connection's context 675 676 ret = MHD_SC_OK; 677 678 if (!mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type) 679 && daemon->conns.block_new) 680 ret = MHD_SC_LIMIT_CONNECTIONS_REACHED; 681 682 if (NULL != addr) 683 { 684 bool log_bad_addlen; 685 686 log_bad_addlen = false; 687 if (0u == addr_size) 688 log_bad_addlen = true; 689 else if (addr_size < (sizeof(addr->sa_family) 690 + offsetof (struct sockaddr, sa_family))) 691 log_bad_addlen = true; 692 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 693 else if (addr_size < (sizeof(addr->sa_len) 694 + offsetof (struct sockaddr, sa_len))) 695 log_bad_addlen = true; 696 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 697 #ifdef SOCK_MAXADDRLEN 698 else if (SOCK_MAXADDRLEN < addr_size) 699 log_bad_addlen = true; 700 #endif 701 else if (AF_INET == addr->sa_family) 702 { 703 if (sizeof(struct sockaddr_in) > addr_size) 704 log_bad_addlen = true; 705 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 706 else if ((0 != addr->sa_len) 707 && (sizeof(struct sockaddr_in) > (size_t)addr->sa_len)) 708 { 709 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 710 "MHD_add_connection() has been called with " \ 711 "non-zero value of 'sa_len' member of " \ 712 "'struct sockaddr' which does not match 'sa_family'."); 713 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 714 } 715 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 716 } 717 #ifdef HAVE_INET6 718 else if (AF_INET6 == addr->sa_family) 719 { 720 if (sizeof(struct sockaddr_in6) != addr_size) 721 log_bad_addlen = true; 722 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 723 else if ((0 != addr->sa_len) 724 && (sizeof(struct sockaddr_in6) > (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 #endif /* HAVE_INET6 */ 735 mhd_ASSUME ((log_bad_addlen && (MHD_SC_OK == ret)) 736 || ((MHD_SC_OK != ret) && !log_bad_addlen) 737 || (MHD_SC_OK == ret)); 738 if (log_bad_addlen) 739 { 740 mhd_LOG_MSG (daemon, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \ 741 "MHD_add_connection() has been called with " \ 742 "incorrect 'addr_size' value."); 743 ret = MHD_SC_CONFIGURATION_WRONG_SA_SIZE; 744 } 745 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 746 if ((0 != addr->sa_len) 747 && (addr_size > (size_t)addr->sa_len)) 748 addr_size = (size_t)addr->sa_len; /* Use safest value */ 749 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 750 } 751 else 752 addr_size = 0u; 753 754 if (MHD_SC_OK == ret) 755 { 756 if (!mhd_FD_FITS_DAEMON (daemon, 757 new_socket)) 758 { 759 mhd_LOG_MSG (daemon, MHD_SC_NEW_CONN_FD_OUTSIDE_OF_SET_RANGE, \ 760 "The new connection FD value is higher than allowed"); 761 ret = MHD_SC_NEW_CONN_FD_OUTSIDE_OF_SET_RANGE; 762 } 763 } 764 765 if (MHD_SC_OK == ret) 766 { 767 sk_nonbl = mhd_socket_nonblocking (new_socket); 768 if (!sk_nonbl) 769 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, \ 770 "Failed to set nonblocking mode on the new client socket."); 771 772 if (1) // TODO: implement turbo 773 { 774 if (!mhd_socket_noninheritable (new_socket)) 775 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, \ 776 "Failed to set noninheritable mode on new client socket."); 777 } 778 } 779 780 #ifndef MHD_SOCKETS_KIND_WINSOCK 781 sk_spipe_supprs = false; 782 #else /* MHD_SOCKETS_KIND_WINSOCK */ 783 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 784 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 785 #if defined(mhd_socket_nosignal) 786 if (MHD_SC_OK == ret) 787 { 788 if (!sk_spipe_supprs) 789 sk_spipe_supprs = mhd_socket_nosignal (new_socket); 790 if (!sk_spipe_supprs) 791 { 792 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED, \ 793 "Failed to suppress SIGPIPE on the new client socket."); 794 # ifndef HAVE_DCLR_MSG_NOSIGNAL 795 /* Application expects that SIGPIPE will be suppressed, 796 * but suppression failed and SIGPIPE cannot be suppressed with send(). */ 797 if (!daemon->sigpipe_blocked) 798 ret = MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED; 799 # endif /* HAVE_DCLR_MSG_NOSIGNAL */ 800 } 801 } 802 #endif /* mhd_socket_nosignal */ 803 804 if (MHD_SC_OK == ret) 805 { 806 struct mhd_DaemonExtAddedConn *new_conn; 807 808 new_conn = 809 (struct mhd_DaemonExtAddedConn *) 810 malloc (sizeof(struct mhd_DaemonExtAddedConn)); 811 812 if (NULL == new_conn) 813 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 814 else 815 { 816 mhd_DLINKEDL_INIT_LINKS (new_conn, queue); 817 new_conn->skt = new_socket; 818 new_conn->is_nonblock = sk_nonbl; 819 new_conn->has_spipe_suppr = sk_spipe_supprs; 820 new_conn->addr_size = addr_size; 821 822 if (0 != addr_size) 823 { 824 new_conn->addr = (struct sockaddr_storage *)malloc (addr_size); 825 if (NULL == new_conn->addr) 826 ret = MHD_SC_CONNECTION_MEM_ALLOC_FAILURE; 827 else 828 memcpy (new_conn->addr, 829 addr, 830 addr_size); 831 } 832 else 833 new_conn->addr = NULL; 834 835 if (MHD_SC_OK == ret) 836 { 837 struct MHD_Daemon *d_to_add; 838 if (!mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type)) 839 d_to_add = daemon; 840 else 841 { 842 #if defined(MHD_SUPPORT_THREADS) 843 size_t d_offset; 844 845 d_offset = 846 mhd_atomic_counter_get_inc_wrap ( 847 &(daemon->events.act_req.ext_added.master.next_d_idx)); 848 849 d_to_add = (daemon->threading.hier.pool.workers 850 + (d_offset % daemon->threading.hier.pool.num)); 851 mhd_ASSUME (NULL != d_to_add); 852 853 if (d_to_add->conns.block_new) 854 { 855 /* Try to find daemon with available connection slots */ 856 size_t i; 857 858 /* Start from the other side of the workers pool to avoid 859 conflict with the next called "add external connection". */ 860 d_offset += daemon->threading.hier.pool.num / 2; 861 862 for (i = 0u; i < daemon->threading.hier.pool.num; ++i) 863 { 864 d_to_add = (daemon->threading.hier.pool.workers 865 + ((d_offset + i) % daemon->threading.hier.pool.num)); 866 867 if (d_to_add->conns.block_new) 868 d_to_add = NULL; 869 else 870 break; 871 } 872 } 873 #else /* ! MHD_SUPPORT_THREADS */ 874 mhd_UNREACHABLE (); 875 d_to_add = NULL; 876 #endif /* ! MHD_SUPPORT_THREADS */ 877 } 878 879 if (NULL == d_to_add) 880 ret = MHD_SC_LIMIT_CONNECTIONS_REACHED; 881 else 882 { 883 mhd_mutex_lock_chk ( 884 &(d_to_add->events.act_req.ext_added.worker.q_lock)); 885 mhd_DLINKEDL_INS_LAST (&(d_to_add->events.act_req.ext_added.worker), 886 new_conn, 887 queue); 888 mhd_mutex_unlock_chk ( 889 &(d_to_add->events.act_req.ext_added.worker.q_lock)); 890 891 (void)mhd_daemon_trigger_itc (d_to_add); 892 893 return MHD_SC_OK; /* Success exit point */ 894 } 895 896 /* Below is a clean-up path */ 897 898 if (NULL != new_conn->addr) 899 free (new_conn->addr); 900 } 901 free (new_conn); 902 } 903 } 904 905 (void)mhd_socket_close (new_socket); 906 907 mhd_assert (MHD_SC_OK != ret); 908 909 return ret; 910 } 911 912 913 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_DaemonAcceptResult 914 mhd_daemon_accept_connection (struct MHD_Daemon *restrict daemon) 915 { 916 struct sockaddr_storage addrstorage[2]; /* Support non-standard extensions */ 917 socklen_t addrlen; 918 MHD_Socket s; 919 MHD_Socket fd; 920 bool sk_nonbl; 921 bool sk_spipe_supprs; 922 bool sk_cloexec; 923 enum mhd_Tristate sk_non_ip; 924 #if !defined(NDEBUG) && defined(mhd_USE_ACCEPT4) 925 const bool use_accept4 = !daemon->dbg.avoid_accept4; 926 #elif defined(mhd_USE_ACCEPT4) 927 static const bool use_accept4 = true; 928 #else /* ! USE_ACCEPT4 && ! _DEBUG */ 929 static const bool use_accept4 = false; 930 #endif /* ! USE_ACCEPT4 && ! _DEBUG */ 931 932 #ifdef MHD_SUPPORT_THREADS 933 mhd_assert ((!mhd_D_HAS_THREADS (daemon)) \ 934 || mhd_thread_handle_ID_is_current_thread ( 935 daemon->threading.tid)); 936 mhd_assert (!mhd_D_TYPE_HAS_WORKERS (daemon->threading.d_type)); 937 #endif /* MHD_SUPPORT_THREADS */ 938 939 fd = daemon->net.listen.fd; 940 mhd_assert (MHD_INVALID_SOCKET != fd); 941 mhd_assert (!daemon->net.listen.is_broken); 942 943 addrlen = (socklen_t)sizeof (addrstorage); 944 memset (addrstorage, 945 0, 946 (size_t)addrlen); 947 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 948 addrstorage->ss_len = (uint8_t)addrlen; 949 #endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ 950 951 /* Initialise with default values to avoid compiler warnings */ 952 sk_nonbl = false; 953 sk_spipe_supprs = false; 954 sk_cloexec = false; 955 s = MHD_INVALID_SOCKET; 956 957 #ifdef mhd_USE_ACCEPT4 958 if (use_accept4) 959 { 960 s = accept4 (fd, 961 (struct sockaddr *)addrstorage, 962 &addrlen, 963 mhd_SOCK_CLOEXEC | mhd_SOCK_NONBLOCK | mhd_SOCK_NOSIGPIPE); 964 if (MHD_INVALID_SOCKET != s) 965 { 966 sk_nonbl = (mhd_SOCK_NONBLOCK != 0); 967 # ifndef MHD_SOCKETS_KIND_WINSOCK 968 sk_spipe_supprs = (mhd_SOCK_NOSIGPIPE != 0); 969 # else /* MHD_SOCKETS_KIND_WINSOCK */ 970 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 971 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 972 sk_cloexec = (mhd_SOCK_CLOEXEC != 0); 973 } 974 } 975 #endif /* mhd_USE_ACCEPT4 */ 976 #if !defined(mhd_USE_ACCEPT4) || !defined(NDEBUG) 977 if (!use_accept4) 978 { 979 s = accept (fd, 980 (struct sockaddr *)addrstorage, 981 &addrlen); 982 if (MHD_INVALID_SOCKET != s) 983 { 984 # ifdef MHD_ACCEPTED_INHERITS_NONBLOCK 985 sk_nonbl = daemon->net.listen.non_block; 986 # else /* ! MHD_ACCEPTED_INHERITS_NONBLOCK */ 987 sk_nonbl = false; 988 # endif /* ! MHD_ACCEPTED_INHERITS_NONBLOCK */ 989 # ifndef MHD_SOCKETS_KIND_WINSOCK 990 sk_spipe_supprs = false; 991 # else /* MHD_SOCKETS_KIND_WINSOCK */ 992 sk_spipe_supprs = true; /* Nothing to suppress on W32 */ 993 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 994 sk_cloexec = false; 995 } 996 } 997 #endif /* !mhd_USE_ACCEPT4 || _DEBUG */ 998 999 if (MHD_INVALID_SOCKET == s) 1000 { /* This could be a common occurrence with multiple worker threads */ 1001 const int err = mhd_SCKT_GET_LERR (); 1002 1003 if (mhd_SCKT_ERR_IS_EINVAL (err)) 1004 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; /* can happen during shutdown */ // FIXME: remove? 1005 if (mhd_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT (err)) 1006 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; /* do not print error if client just disconnects early */ 1007 if (mhd_SCKT_ERR_IS_EINTR (err)) 1008 return mhd_DAEMON_ACCEPT_SKIPPED; 1009 if (mhd_SCKT_ERR_IS_EAGAIN (err)) 1010 return mhd_DAEMON_ACCEPT_NO_MORE_PENDING; 1011 if (mhd_SCKT_ERR_IS_LOW_RESOURCES (err)) 1012 { 1013 /* system/process out of resources */ 1014 if (0 == daemon->conns.count) 1015 { 1016 /* Not setting 'block_new' flag, as there is no way it 1017 would ever be cleared. Instead trying to produce 1018 bit fat ugly warning. */ 1019 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED_INSTANTLY, \ 1020 "Hit process or system resource limit at FIRST " \ 1021 "connection. This is really bad as there is no sane " \ 1022 "way to proceed. Will try busy waiting for system " \ 1023 "resources to become magically available."); 1024 } 1025 else 1026 { 1027 daemon->conns.block_new = true; 1028 mhd_LOG_PRINT (daemon, MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED, \ 1029 mhd_LOG_FMT ("Hit process or system resource limit " \ 1030 "at %u connections, temporarily " \ 1031 "suspending accept(). Consider setting " \ 1032 "a lower MHD_OPTION_CONNECTION_LIMIT."), \ 1033 daemon->conns.count); 1034 } 1035 return mhd_DAEMON_ACCEPT_FAILED; 1036 } 1037 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_FAILED_UNEXPECTEDLY, 1038 "Error accepting connection."); 1039 return mhd_DAEMON_ACCEPT_FAILED; 1040 } 1041 1042 if (!mhd_FD_FITS_DAEMON (daemon, s)) 1043 { 1044 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_OUTSIDE_OF_SET_RANGE, \ 1045 "The accepted socket has value outside of allowed range."); 1046 (void)mhd_socket_close (s); 1047 return mhd_DAEMON_ACCEPT_FAILED; 1048 } 1049 if (mhd_SOCKET_TYPE_IP == daemon->net.listen.type) 1050 sk_non_ip = mhd_T_NO; 1051 else if (mhd_SOCKET_TYPE_UNKNOWN == daemon->net.listen.type) 1052 sk_non_ip = mhd_T_MAYBE; 1053 else 1054 sk_non_ip = mhd_T_YES; 1055 if (0 >= addrlen) 1056 { 1057 if (mhd_SOCKET_TYPE_IP == daemon->net.listen.type) 1058 mhd_LOG_MSG (daemon, MHD_SC_ACCEPTED_UNKNOWN_TYPE, \ 1059 "Accepted socket has non-positive length of the address. " \ 1060 "Processing the new socket as a socket with " \ 1061 "unknown type."); 1062 addrlen = 0; 1063 sk_non_ip = mhd_T_MAYBE; 1064 } 1065 else if (((socklen_t)sizeof (addrstorage)) < addrlen) 1066 { 1067 /* Should not happen as 'sockaddr_storage' must be large enough to 1068 * store any address supported by the system. */ 1069 mhd_LOG_MSG (daemon, MHD_SC_ACCEPTED_SOCKADDR_TOO_LARGE, \ 1070 "Accepted socket address is larger than expected by " \ 1071 "system headers. Processing the new socket as a socket with " \ 1072 "unknown type."); 1073 addrlen = 0; 1074 sk_non_ip = mhd_T_MAYBE; /* IP-type addresses must fit */ 1075 } 1076 else if (mhd_T_MAYBE == sk_non_ip) 1077 { 1078 if (AF_INET == ((struct sockaddr *)addrstorage)->sa_family) 1079 sk_non_ip = mhd_T_NO; 1080 #ifdef HAVE_INET6 1081 else if (AF_INET6 == ((struct sockaddr *)addrstorage)->sa_family) 1082 sk_non_ip = mhd_T_NO; 1083 #endif /* HAVE_INET6 */ 1084 } 1085 1086 if (!sk_nonbl) 1087 { /* Was not set automatically */ 1088 sk_nonbl = mhd_socket_nonblocking (s); 1089 if (!sk_nonbl) 1090 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NONBLOCKING_FAILED, \ 1091 "Failed to set nonblocking mode on " 1092 "new connection socket."); 1093 } 1094 1095 if (!sk_cloexec) 1096 { /* Was not set automatically */ 1097 sk_cloexec = mhd_socket_noninheritable (s); 1098 if (!sk_cloexec) 1099 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOINHERIT_FAILED, \ 1100 "Failed to set non-inheritable mode on " 1101 "new connection socket."); 1102 } 1103 1104 #if defined(mhd_socket_nosignal) 1105 if (!sk_spipe_supprs && !mhd_socket_nosignal (s)) 1106 { 1107 mhd_LOG_MSG (daemon, MHD_SC_ACCEPT_CONFIGURE_NOSIGPIPE_FAILED, 1108 "Failed to suppress SIGPIPE on incoming connection " \ 1109 "socket."); 1110 # ifndef HAVE_DCLR_MSG_NOSIGNAL 1111 /* Application expects that SIGPIPE will be suppressed, 1112 * but suppression failed and SIGPIPE cannot be suppressed with send(). */ 1113 if (!daemon->sigpipe_blocked) 1114 { 1115 (void)MHD_socket_close_ (s); 1116 return mhd_DAEMON_ACCEPT_FAILED; 1117 } 1118 # endif /* HAVE_DCLR_MSG_NOSIGNAL */ 1119 } 1120 else 1121 sk_spipe_supprs = true; 1122 #endif /* mhd_socket_nosignal */ 1123 return (MHD_SC_OK == internal_add_connection (daemon, 1124 s, 1125 (size_t)addrlen, 1126 addrstorage, 1127 false, 1128 sk_nonbl, 1129 sk_spipe_supprs, 1130 sk_non_ip)) ? 1131 mhd_DAEMON_ACCEPT_SUCCESS : mhd_DAEMON_ACCEPT_FAILED; 1132 } 1133 1134 1135 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1136 mhd_conn_remove_from_daemon (struct MHD_Connection *restrict c) 1137 { 1138 mhd_assert (c->dbg.closing_started); 1139 mhd_assert (c->dbg.pre_cleaned); 1140 mhd_assert (!c->dbg.removed_from_daemon); 1141 mhd_assert (NULL == c->rp.response); 1142 mhd_assert (!c->rq.app_aware); 1143 mhd_assert (!c->in_proc_ready); 1144 mhd_assert (NULL == c->rq.cntn.lbuf.data); 1145 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, proc_ready)); 1146 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, proc_ready)); 1147 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->events), proc_ready)); 1148 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->events), proc_ready)); 1149 1150 if (mhd_D_HAS_THR_PER_CONN (c->daemon)) 1151 { 1152 mhd_assert (0 && "Not implemented yet"); 1153 // TODO: Support "thread per connection" 1154 } 1155 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (&(c->timeout), tmout_list)); 1156 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list)); 1157 mhd_assert (NULL == c->pool); 1158 1159 mhd_DLINKEDL_DEL (&(c->daemon->conns), c, all_conn); 1160 1161 // TODO: update per-IP limits 1162 1163 c->daemon->conns.count--; 1164 c->daemon->conns.block_new = false; 1165 1166 #ifndef NDEBUG 1167 c->dbg.removed_from_daemon = true; 1168 #endif /* NDEBUG */ 1169 } 1170 1171 1172 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1173 mhd_conn_close_final (struct MHD_Connection *restrict c) 1174 { 1175 mhd_assert (c->dbg.closing_started); 1176 mhd_assert (c->dbg.pre_cleaned); 1177 mhd_assert (c->dbg.removed_from_daemon); 1178 mhd_assert (NULL == c->rp.response); 1179 mhd_assert (!c->rq.app_aware); 1180 mhd_assert (!c->in_proc_ready); 1181 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, proc_ready)); 1182 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, proc_ready)); 1183 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->events), proc_ready)); 1184 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->events), proc_ready)); 1185 1186 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (&(c->timeout), tmout_list)); 1187 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list)); 1188 mhd_assert (NULL == c->pool); 1189 1190 mhd_assert (NULL == mhd_DLINKEDL_GET_NEXT (c, all_conn)); 1191 mhd_assert (NULL == mhd_DLINKEDL_GET_PREV (c, all_conn)); 1192 mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->conns), all_conn)); 1193 mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->conns), all_conn)); 1194 1195 #ifdef MHD_SUPPORT_HTTPS 1196 if (mhd_C_HAS_TLS (c)) 1197 { 1198 mhd_assert (mhd_D_HAS_TLS (c->daemon)); 1199 mhd_assert (c->dbg.tls_inited); 1200 mhd_tls_conn_deinit (c->tls); 1201 } 1202 # ifndef NDEBUG 1203 else 1204 { 1205 mhd_assert (!mhd_D_HAS_TLS (c->daemon)); 1206 mhd_assert (!c->dbg.tls_inited); 1207 } 1208 # endif 1209 #endif 1210 1211 if (NULL != c->sk.addr.data) 1212 free (c->sk.addr.data); 1213 mhd_socket_close (c->sk.fd); 1214 #ifdef MHD_USE_TRACE_CONN_ADD_CLOSE 1215 fprintf (stderr, 1216 "&&& Closed connection, FD: %2llu\n", 1217 (unsigned long long)c->sk.fd); 1218 #endif /* MHD_USE_TRACE_CONN_ADD_CLOSE */ 1219 1220 free (c); 1221 } 1222 1223 1224 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1225 mhd_daemon_process_ext_added_conns (struct MHD_Daemon *restrict d) 1226 { 1227 struct mhd_DaemonExtAddedConn *ext_added; 1228 mhd_DLNKDL_LIST (mhd_DaemonExtAddedConn, detached_q); 1229 1230 mhd_assert (!mhd_D_HAS_WORKERS (d)); 1231 1232 if (NULL == 1233 mhd_DLINKEDL_GET_FIRST (&(d->events.act_req.ext_added.worker), 1234 queue)) 1235 return; /* Shortcut: the queue is empty */ 1236 1237 /* Detach the queue to quickly manipulate the lock one time only */ 1238 mhd_mutex_lock_chk (&(d->events.act_req.ext_added.worker.q_lock)); 1239 detached_q = d->events.act_req.ext_added.worker.queue; 1240 mhd_DLINKEDL_INIT_LIST (&(d->events.act_req.ext_added.worker), 1241 queue); 1242 mhd_mutex_unlock_chk (&(d->events.act_req.ext_added.worker.q_lock)); 1243 1244 /* Process without lock the detached queue in FIFO order */ 1245 for (ext_added = mhd_DLINKEDL_GET_FIRST_D (&detached_q); 1246 NULL != ext_added; 1247 ext_added = mhd_DLINKEDL_GET_FIRST_D (&detached_q)) 1248 { 1249 mhd_ASSUME (NULL == mhd_DLINKEDL_GET_PREV (ext_added, 1250 queue)); 1251 mhd_DLINKEDL_DEL_D (&detached_q, ext_added, 1252 queue); 1253 1254 if (!d->conns.block_new) 1255 { 1256 (void)internal_add_connection (d, 1257 ext_added->skt, 1258 ext_added->addr_size, 1259 ext_added->addr, 1260 true, 1261 ext_added->is_nonblock, 1262 ext_added->has_spipe_suppr, 1263 mhd_T_MAYBE); 1264 } 1265 else 1266 { 1267 if (NULL != ext_added->addr) 1268 free (ext_added->addr); 1269 } 1270 free (ext_added); 1271 } 1272 }