libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

daemon_add_conn.c (41801B)


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