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