libmicrohttpd2

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

daemon_add_conn.c (42513B)


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