libmicrohttpd2

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

daemon_add_conn.c (42663B)


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