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