libmicrohttpd2

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

daemon_add_conn.c (41817B)


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