libmicrohttpd2

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

daemon_add_conn.c (41939B)


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