libmicrohttpd2

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

daemon_add_conn.c (42529B)


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