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