libmicrohttpd2

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

daemon_start.c (137985B)


      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) 2024-2026 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/daemon_start.c
     41  * @brief  The implementation of the MHD_daemon_start()
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "mhd_assert.h"
     48 #include "mhd_static_assert.h"
     49 #include "mhd_unreachable.h"
     50 #include "mhd_assume.h"
     51 
     52 #include "mhd_constexpr.h"
     53 
     54 #include "sys_bool_type.h"
     55 #include "sys_base_types.h"
     56 #include "sys_malloc.h"
     57 #include "compat_calloc.h"
     58 
     59 #include <string.h>
     60 #include "sys_sockets_types.h"
     61 #include "sys_sockets_headers.h"
     62 #include "mhd_sockets_macros.h"
     63 #include "sys_ip_headers.h"
     64 
     65 #include "mhd_atomic_counter.h"
     66 
     67 #ifdef MHD_SOCKETS_KIND_POSIX
     68 #  include "sys_errno.h"
     69 #endif
     70 #include "sys_select.h"
     71 #include "sys_poll.h"
     72 #ifdef MHD_SUPPORT_EPOLL
     73 #  include <sys/epoll.h>
     74 #endif
     75 #include "sys_kqueue.h"
     76 
     77 #ifdef MHD_SOCKETS_KIND_POSIX
     78 #  include <fcntl.h>
     79 #endif
     80 
     81 #include "extr_events_funcs.h"
     82 
     83 #include "mhd_dbg_print.h"
     84 
     85 #include "mhd_limits.h"
     86 
     87 #include "mhd_daemon.h"
     88 #include "daemon_options.h"
     89 
     90 #include "mhd_sockets_funcs.h"
     91 
     92 #include "mhd_lib_init.h"
     93 #include "daemon_logger.h"
     94 
     95 #ifdef MHD_SUPPORT_HTTPS
     96 #  include "mhd_tls_common.h"
     97 #  include "mhd_tls_funcs.h"
     98 #  ifdef MHD_SUPPORT_ACME
     99 #    include "mhd_tls_acme_func.h"
    100 #  endif
    101 #endif
    102 
    103 #include "events_process.h"
    104 
    105 #ifdef MHD_SUPPORT_THREADS
    106 #  include "mhd_itc.h"
    107 #  include "mhd_threads.h"
    108 #  include "daemon_funcs.h"
    109 #endif
    110 
    111 
    112 #include "mhd_public_api.h"
    113 
    114 
    115 /**
    116  * The default value for fastopen queue length (currently GNU/Linux only)
    117  */
    118 #define MHD_TCP_FASTOPEN_DEF_QUEUE_LEN 64
    119 
    120 /**
    121  * Release any internally allocated pointers, then deallocate the settings.
    122  * @param s the pointer to the settings to release
    123  */
    124 static void
    125 dsettings_release (struct DaemonOptions *s)
    126 {
    127   /* Release starting from the last member */
    128   if (NULL != s->random_entropy.v_buf)
    129     free (s->random_entropy.v_buf);
    130   if (NULL != s->tls_openssl_def_file.v_pathname)
    131     free (s->tls_openssl_def_file.v_pathname);
    132   if (NULL != s->tls_app_name.v_app_name)
    133     free (s->tls_app_name.v_app_name);
    134   if (NULL != s->tls_cert_key.v_mem_cert)
    135     free (s->tls_cert_key.v_mem_cert);
    136   if (MHD_INVALID_SOCKET != s->listen_socket)
    137     mhd_socket_close (s->listen_socket);
    138   if (NULL != s->bind_sa.v_sa)
    139     free (s->bind_sa.v_sa);
    140   free (s);
    141 }
    142 
    143 
    144 /**
    145  * Set basic daemon parameters that not require additional initialisation.
    146  * Mostly copy such parameters from the settings object to the daemon object.
    147  * @param d the daemon object
    148  * @param s the user settings
    149  * @return MHD_SC_OK on success,
    150  *         the error code otherwise
    151  */
    152 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    153 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    154 daemon_set_basic_settings (struct MHD_Daemon *restrict d,
    155                            struct DaemonOptions *restrict s)
    156 {
    157   mhd_constexpr uint_fast64_t max_timeout_ms_value = 1209600000u;
    158 
    159 #ifdef MHD_SUPPORT_HTTP2
    160   // TODO: make it configurable
    161   d->http_cfg.http1x = true;
    162   d->http_cfg.http2 = true;
    163 #endif /* MHD_SUPPORT_HTTP2 */
    164 
    165   d->req_cfg.strictness = s->protocol_strict_level.v_sl;
    166 
    167 #ifdef MHD_SUPPORT_COOKIES
    168   d->req_cfg.disable_cookies = (MHD_NO != s->disable_cookies);
    169 #endif
    170 
    171   d->req_cfg.suppress_date = (MHD_NO != s->suppress_date_header);
    172 
    173   d->conns.cfg.timeout_milsec = s->default_timeout_milsec;
    174   if (max_timeout_ms_value < d->conns.cfg.timeout_milsec)
    175     d->conns.cfg.timeout_milsec = max_timeout_ms_value;
    176 
    177   d->conns.cfg.per_ip_limit = s->per_ip_limit;
    178 
    179   return MHD_SC_OK;
    180 }
    181 
    182 
    183 /**
    184  * Set the daemon work mode.
    185  * This function also checks whether requested work mode is supported by
    186  * current build and whether work mode is compatible with requested events
    187  * polling technique.
    188  * @param d the daemon object
    189  * @param s the user settings
    190  * @return MHD_SC_OK on success,
    191  *         the error code otherwise
    192  */
    193 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    194 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    195 daemon_set_work_mode (struct MHD_Daemon *restrict d,
    196                       struct DaemonOptions *restrict s)
    197 {
    198   switch (s->work_mode.mode)
    199   {
    200   case MHD_WM_EXTERNAL_PERIODIC:
    201     d->wmode_int = mhd_WM_INT_INTERNAL_EVENTS_NO_THREADS;
    202     break;
    203   case MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL:
    204   case MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE:
    205     if (MHD_SPS_AUTO != s->poll_syscall)
    206     {
    207       mhd_LOG_MSG ( \
    208         d, MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID, \
    209         "The requested work mode is not compatible with setting " \
    210         "socket polling syscall.");
    211       return MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID;
    212     }
    213     if (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL == s->work_mode.mode)
    214       d->wmode_int = mhd_WM_INT_EXTERNAL_EVENTS_LEVEL;
    215     else
    216       d->wmode_int = mhd_WM_INT_EXTERNAL_EVENTS_EDGE;
    217     break;
    218   case MHD_WM_EXTERNAL_SINGLE_FD_WATCH:
    219     if ((MHD_SPS_AUTO != s->poll_syscall)
    220         && (MHD_SPS_EPOLL != s->poll_syscall)
    221         && (MHD_SPS_KQUEUE != s->poll_syscall))
    222     {
    223       mhd_LOG_MSG ( \
    224         d, MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID, \
    225         "The requested work mode MHD_WM_EXTERNAL_SINGLE_FD_WATCH " \
    226         "is not compatible with requested socket polling syscall.");
    227       return MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID;
    228     }
    229 #if !defined(MHD_SUPPORT_EPOLL) && !defined(MHD_SUPPORT_KQUEUE)
    230     mhd_LOG_MSG ( \
    231       d, MHD_SC_FEATURE_DISABLED, \
    232       "The epoll or kqueue is required for the requested work mode " \
    233       "MHD_WM_EXTERNAL_SINGLE_FD_WATCH, but none is available on this " \
    234       "platform or MHD build.");
    235     return MHD_SC_FEATURE_DISABLED;
    236 #else
    237     d->wmode_int = mhd_WM_INT_INTERNAL_EVENTS_NO_THREADS;
    238 #endif
    239     break;
    240   case MHD_WM_THREAD_PER_CONNECTION:
    241     if (MHD_SPS_EPOLL == s->poll_syscall)
    242     {
    243       mhd_LOG_MSG ( \
    244         d, MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID, \
    245         "The requested work mode MHD_WM_THREAD_PER_CONNECTION " \
    246         "is not compatible with 'epoll' sockets polling.");
    247       return MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID;
    248     }
    249     if (MHD_SPS_KQUEUE == s->poll_syscall)
    250     {
    251       mhd_LOG_MSG ( \
    252         d, MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID, \
    253         "The requested work mode MHD_WM_THREAD_PER_CONNECTION " \
    254         "is not compatible with 'kqueue' sockets polling.");
    255       return MHD_SC_SYSCALL_WORK_MODE_COMBINATION_INVALID;
    256     }
    257     mhd_FALLTHROUGH;
    258   /* Intentional fallthrough */
    259   case MHD_WM_WORKER_THREADS:
    260 #ifndef MHD_SUPPORT_THREADS
    261     mhd_LOG_MSG (d, MHD_SC_FEATURE_DISABLED, \
    262                  "The internal threads modes are not supported by this " \
    263                  "build of MHD.");
    264     return MHD_SC_FEATURE_DISABLED;
    265 #else  /* MHD_SUPPORT_THREADS */
    266     if (MHD_WM_THREAD_PER_CONNECTION == s->work_mode.mode)
    267       d->wmode_int = mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION;
    268     else if (1 >= s->work_mode.params.num_worker_threads)   /* && (MHD_WM_WORKER_THREADS == s->work_mode.mode) */
    269       d->wmode_int = mhd_WM_INT_INTERNAL_EVENTS_ONE_THREAD;
    270     else
    271       d->wmode_int = mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL;
    272 #endif /* MHD_SUPPORT_THREADS */
    273     break;
    274   default:
    275     mhd_LOG_MSG (d, MHD_SC_CONFIGURATION_UNEXPECTED_WM, \
    276                  "Wrong requested work mode.");
    277     return MHD_SC_CONFIGURATION_UNEXPECTED_WM;
    278   }
    279 
    280   if ((mhd_WM_INT_EXTERNAL_EVENTS_LEVEL != d->wmode_int)
    281       && (mhd_WM_INT_EXTERNAL_EVENTS_EDGE != d->wmode_int)
    282       && (MHD_NO != s->reregister_all))
    283   {
    284     mhd_LOG_MSG ( \
    285       d, \
    286       MHD_SC_EXTERNAL_EVENT_ONLY, \
    287       "The MHD_D_O_REREGISTER_ALL option can be used only with external " \
    288       "events work modes.");
    289     return MHD_SC_EXTERNAL_EVENT_ONLY;
    290   }
    291 
    292   return MHD_SC_OK;
    293 }
    294 
    295 
    296 union mhd_SockaddrAny
    297 {
    298   struct sockaddr sa;
    299   struct sockaddr_in sa_i4;
    300 #ifdef HAVE_INET6
    301   struct sockaddr_in6 sa_i6;
    302 #endif /* HAVE_INET6 */
    303   struct sockaddr_storage sa_stor;
    304 };
    305 
    306 
    307 /**
    308  * The type of the socket to create
    309  */
    310 enum mhd_CreateSktType
    311 {
    312   /**
    313    * Unknown address family (could be IP or not IP)
    314    */
    315   mhd_SKT_UNKNOWN = -4
    316   ,
    317   /**
    318    * The socket is not IP.
    319    */
    320   mhd_SKT_NON_IP = -2
    321   ,
    322   /**
    323    * The socket is UNIX.
    324    */
    325   mhd_SKT_UNIX = -1
    326   ,
    327   /**
    328    * No socket
    329    */
    330   mhd_SKT_NO_SOCKET = MHD_AF_NONE
    331   ,
    332   /**
    333    * IPv4 only
    334    */
    335   mhd_SKT_IP_V4_ONLY = MHD_AF_INET4
    336   ,
    337   /**
    338    * IPv6 only
    339    */
    340   mhd_SKT_IP_V6_ONLY = MHD_AF_INET6
    341   ,
    342   /**
    343    * IPv6 with dual stack enabled
    344    */
    345   mhd_SKT_IP_DUAL_REQUIRED = MHD_AF_DUAL
    346   ,
    347   /**
    348    * Try IPv6 with dual stack then IPv4
    349    */
    350   mhd_SKT_IP_V4_WITH_V6_OPT = MHD_AF_DUAL_v6_OPTIONAL
    351   ,
    352   /**
    353    * IPv6 with optional dual stack
    354    */
    355   mhd_SKT_IP_V6_WITH_V4_OPT = MHD_AF_DUAL_v4_OPTIONAL
    356   ,
    357   /**
    358    * Try IPv4 then IPv6 with optional dual stack
    359    */
    360   mhd_SKT_IP_V4_WITH_FALLBACK = 16
    361 };
    362 
    363 /**
    364  * Create socket, bind to the address and start listening on the socket.
    365  *
    366  * The socket is assigned to the daemon as listening FD.
    367  * @param d the daemon to use
    368  * @param s the user settings
    369  * @param v6_tried true if IPv6 has been tried already
    370  * @param force_v6_any_dual true if IPv6 is forced with dual stack either
    371  *                          enabled or not
    372  * @param prev_bnd_lstn_err if this function was already tried with another and
    373  *                          failed to bind or to start listening then
    374  *                          this parameter must be set to respecting status
    375  *                          code, otherwise this parameter must be #MHD_SC_OK
    376  * @return #MHD_SC_OK on success,
    377  *         the error code otherwise (no error printed to log if result is
    378  *         #MHD_SC_LISTEN_SOCKET_BIND_FAILED or #MHD_SC_LISTEN_FAILURE)
    379  */
    380 static enum MHD_StatusCode
    381 create_bind_listen_stream_socket_inner (struct MHD_Daemon *restrict d,
    382                                         struct DaemonOptions *restrict s,
    383                                         bool v6_tried,
    384                                         bool force_v6_any_dual,
    385                                         enum MHD_StatusCode prev_bnd_lstn_err)
    386 {
    387   MHD_Socket sk;
    388   enum mhd_CreateSktType sk_type;
    389   bool sk_already_listening;
    390   union mhd_SockaddrAny sa_all;
    391   const struct sockaddr *p_use_sa;
    392   socklen_t use_sa_size;
    393   uint_least16_t sk_port;
    394   bool is_non_block;
    395   bool is_non_inhr;
    396   enum MHD_StatusCode ret;
    397 
    398   sk = MHD_INVALID_SOCKET;
    399   sk_type = mhd_SKT_NO_SOCKET;
    400   sk_already_listening = false;
    401   p_use_sa = NULL;
    402   use_sa_size = 0;
    403   sk_port = 0;
    404 
    405 #ifndef HAVE_INET6
    406   mhd_assert (!v6_tried);
    407   mhd_assert (!force_v6_any_dual);
    408 #endif
    409   mhd_assert (mhd_SKT_NO_SOCKET == sk_type); /* Mute analyser warning */
    410 
    411   if (MHD_INVALID_SOCKET != s->listen_socket)
    412   {
    413     mhd_assert (!v6_tried);
    414     mhd_assert (!force_v6_any_dual);
    415     /* Check for options conflicts */
    416     if (0 != s->bind_sa.v_sa_len)
    417     {
    418       mhd_LOG_MSG (d, MHD_SC_OPTIONS_CONFLICT, \
    419                    "MHD_D_O_BIND_SA cannot be used together " \
    420                    "with MHD_D_O_LISTEN_SOCKET");
    421       return MHD_SC_OPTIONS_CONFLICT;
    422     }
    423     else if (MHD_AF_NONE != s->bind_port.v_af)
    424     {
    425       mhd_LOG_MSG (d, MHD_SC_OPTIONS_CONFLICT, \
    426                    "MHD_D_O_BIND_PORT cannot be used together " \
    427                    "with MHD_D_O_LISTEN_SOCKET");
    428       return MHD_SC_OPTIONS_CONFLICT;
    429     }
    430 
    431     /* No options conflicts */
    432     sk = s->listen_socket;
    433     s->listen_socket = MHD_INVALID_SOCKET; /* Prevent closing with settings cleanup */
    434     sk_type = mhd_SKT_UNKNOWN;
    435     sk_already_listening = true;
    436   }
    437   else if ((0 != s->bind_sa.v_sa_len) || (MHD_AF_NONE != s->bind_port.v_af))
    438   {
    439     if (0 != s->bind_sa.v_sa_len)
    440     {
    441       mhd_assert (!v6_tried);
    442       mhd_assert (!force_v6_any_dual);
    443 
    444       /* Check for options conflicts */
    445       if (MHD_AF_NONE != s->bind_port.v_af)
    446       {
    447         mhd_LOG_MSG (d, MHD_SC_OPTIONS_CONFLICT, \
    448                      "MHD_D_O_BIND_SA cannot be used together " \
    449                      "with MHD_D_O_BIND_PORT");
    450         return MHD_SC_OPTIONS_CONFLICT;
    451       }
    452 
    453       /* No options conflicts */
    454       switch (s->bind_sa.v_sa->sa_family)
    455       {
    456       case AF_INET:
    457         sk_type = mhd_SKT_IP_V4_ONLY;
    458         if (sizeof(sa_all.sa_i4) > s->bind_sa.v_sa_len)
    459         {
    460           mhd_LOG_MSG (d, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \
    461                        "The size of the provided sockaddr does not match "
    462                        "used address family");
    463           return MHD_SC_CONFIGURATION_WRONG_SA_SIZE;
    464         }
    465         memcpy (&(sa_all.sa_i4), s->bind_sa.v_sa, sizeof(sa_all.sa_i4));
    466         sk_port = (uint_least16_t)ntohs (sa_all.sa_i4.sin_port);
    467 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
    468         mhd_STATIC_ASSERT_STMT (
    469           sizeof(sa_all.sa_i4) == (uint8_t)sizeof(sa_all.sa_i4),
    470           "The sockaddr_in size must fit into uint8_t");
    471         sa_all.sa_i4.sin_len = (uint8_t)sizeof(sa_all.sa_i4);
    472 #endif
    473         p_use_sa = (struct sockaddr *)&(sa_all.sa_i4);
    474         use_sa_size = (socklen_t)sizeof(sa_all.sa_i4);
    475         break;
    476 #ifdef HAVE_INET6
    477       case AF_INET6:
    478         sk_type = mhd_SKT_IP_V6_ONLY;
    479         if (sizeof(sa_all.sa_i6) > s->bind_sa.v_sa_len)
    480         {
    481           mhd_LOG_MSG (d, MHD_SC_CONFIGURATION_WRONG_SA_SIZE, \
    482                        "The size of the provided sockaddr does not match "
    483                        "used address family");
    484           return MHD_SC_CONFIGURATION_WRONG_SA_SIZE;
    485         }
    486         memcpy (&(sa_all.sa_i6), s->bind_sa.v_sa, s->bind_sa.v_sa_len);
    487         sk_port = (uint_least16_t)ntohs (sa_all.sa_i6.sin6_port);
    488 #  ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
    489         mhd_STATIC_ASSERT_STMT (
    490           sizeof(sa_all.sa_i6) == (uint8_t)sizeof(sa_all.sa_i6),
    491           "The sockaddr_in6 size must fit into uint8_t");
    492         sa_all.sa_i6.sin6_len = (uint8_t)sizeof(sa_all.sa_i6);
    493 #  endif
    494         p_use_sa = (struct sockaddr *)&(sa_all.sa_i6);
    495         use_sa_size = (socklen_t)sizeof(sa_all.sa_i6);
    496         break;
    497 #endif /* HAVE_INET6 */
    498 #ifdef MHD_AF_UNIX
    499       case MHD_AF_UNIX:
    500         sk_type = mhd_SKT_UNIX;
    501         p_use_sa = NULL; /* To be set below */
    502         break;
    503 #endif /* MHD_AF_UNIX */
    504       default:
    505         sk_type = mhd_SKT_UNKNOWN;
    506         p_use_sa = NULL; /* To be set below */
    507         break;
    508       }
    509 
    510       if (s->bind_sa.v_dual)
    511       {
    512         if (mhd_SKT_IP_V6_ONLY != sk_type)
    513         {
    514           mhd_LOG_MSG (d, MHD_SC_LISTEN_DUAL_STACK_NOT_SUITABLE, \
    515                        "IP dual stack is not possible for provided sockaddr");
    516         }
    517 #ifdef HAVE_INET6
    518         else
    519         {
    520 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    521           sk_type = mhd_SKT_IP_DUAL_REQUIRED;
    522 #  else  /* ! IPV6_V6ONLY */
    523           mhd_LOG_MSG (d, \
    524                        MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED, \
    525                        "IP dual stack is not supported by this platform or " \
    526                        "by this MHD build");
    527 #  endif /* ! IPV6_V6ONLY */
    528         }
    529 #endif /* HAVE_INET6 */
    530       }
    531 
    532       if (NULL == p_use_sa)
    533       {
    534 #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) && \
    535         defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN)
    536         if ((((size_t)s->bind_sa.v_sa->sa_len) != s->bind_sa.v_sa_len)
    537             && (sizeof(sa_all) >= s->bind_sa.v_sa_len))
    538         {
    539           /* Fix embedded 'sa_len' member if possible */
    540           memcpy (&sa_all, s->bind_sa.v_sa, s->bind_sa.v_sa_len);
    541           mhd_assert (s->bind_sa.v_sa_len == (uint8_t)s->bind_sa.v_sa_len);
    542           sa_all.sa_stor.ss_len = (uint8_t)s->bind_sa.v_sa_len;
    543           p_use_sa = (const struct sockaddr *)&(sa_all.sa_stor);
    544         }
    545         else
    546 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN && HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
    547         p_use_sa = s->bind_sa.v_sa;
    548         use_sa_size = (socklen_t)s->bind_sa.v_sa_len;
    549       }
    550     }
    551     else /* if (MHD_AF_NONE != s->bind_port.v_af) */
    552     {
    553       /* No options conflicts */
    554       switch (s->bind_port.v_af)
    555       {
    556       case MHD_AF_NONE:
    557         mhd_assert (0);
    558         mhd_UNREACHABLE ();
    559         return MHD_SC_INTERNAL_ERROR;
    560       case MHD_AF_AUTO:
    561 #ifdef HAVE_INET6
    562 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    563         if (force_v6_any_dual)
    564           sk_type = mhd_SKT_IP_V6_WITH_V4_OPT;
    565         else if (v6_tried)
    566           sk_type = mhd_SKT_IP_V4_WITH_FALLBACK;
    567         else
    568           sk_type = mhd_SKT_IP_V4_WITH_V6_OPT;
    569 #  else  /* ! IPV6_V6ONLY */
    570         mhd_assert (!v6_tried);
    571         if (force_v6_any_dual)
    572           sk_type = mhd_SKT_IP_V6_ONLY;
    573         else
    574           sk_type = mhd_SKT_IP_V4_WITH_FALLBACK;
    575 #  endif /* ! IPV6_V6ONLY */
    576 #else  /* ! HAVE_INET6 */
    577         sk_type = mhd_SKT_IP_V4_ONLY;
    578 #endif /* ! HAVE_INET6 */
    579         break;
    580       case MHD_AF_INET4:
    581         mhd_assert (!v6_tried);
    582         mhd_assert (!force_v6_any_dual);
    583         sk_type = mhd_SKT_IP_V4_ONLY;
    584         break;
    585       case MHD_AF_INET6:
    586         mhd_assert (!v6_tried);
    587         mhd_assert (!force_v6_any_dual);
    588 #ifdef HAVE_INET6
    589         sk_type = mhd_SKT_IP_V6_ONLY;
    590 #else  /* ! HAVE_INET6 */
    591         mhd_LOG_MSG (d, MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD, \
    592                      "IPv6 is not supported by this MHD build or " \
    593                      "by this platform");
    594         return MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD;
    595 #endif /* ! HAVE_INET6 */
    596         break;
    597       case MHD_AF_DUAL:
    598         mhd_assert (!v6_tried);
    599         mhd_assert (!force_v6_any_dual);
    600 #ifdef HAVE_INET6
    601 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    602         sk_type = mhd_SKT_IP_DUAL_REQUIRED;
    603 #  else  /* ! IPV6_V6ONLY */
    604         mhd_LOG_MSG (d,
    605                      MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED, \
    606                      "IP dual stack is not supported by this platform or " \
    607                      "by this MHD build");
    608         sk_type = mhd_SKT_IP_V6_ONLY;
    609 #  endif /* ! IPV6_V6ONLY */
    610 #else  /* ! HAVE_INET6 */
    611         mhd_LOG_MSG (d, MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD, \
    612                      "IPv6 is not supported by this MHD build or " \
    613                      "by this platform");
    614         return MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD;
    615 #endif /* ! HAVE_INET6 */
    616         break;
    617       case MHD_AF_DUAL_v4_OPTIONAL:
    618         mhd_assert (!v6_tried);
    619         mhd_assert (!force_v6_any_dual);
    620 #ifdef HAVE_INET6
    621 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    622         sk_type = mhd_SKT_IP_V6_WITH_V4_OPT;
    623 #  else  /* ! IPV6_V6ONLY */
    624         sk_type = mhd_SKT_IP_V6_ONLY;
    625 #  endif /* ! IPV6_V6ONLY */
    626 #else  /* ! HAVE_INET6 */
    627         mhd_LOG_MSG (d, MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD, \
    628                      "IPv6 is not supported by this MHD build or " \
    629                      "by this platform");
    630         return MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD;
    631 #endif /* ! HAVE_INET6 */
    632         break;
    633       case MHD_AF_DUAL_v6_OPTIONAL:
    634         mhd_assert (!force_v6_any_dual);
    635 #ifdef HAVE_INET6
    636 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    637         sk_type = (!v6_tried) ?
    638                   mhd_SKT_IP_V4_WITH_V6_OPT : mhd_SKT_IP_V4_ONLY;
    639 #  else  /* ! IPV6_V6ONLY */
    640         mhd_assert (!v6_tried);
    641         sk_type = mhd_SKT_IP_V4_ONLY;
    642 #  endif /* ! IPV6_V6ONLY */
    643 #else  /* ! HAVE_INET6 */
    644         mhd_assert (!v6_tried);
    645         sk_type = mhd_SKT_IP_V4_ONLY;
    646 #endif /* ! HAVE_INET6 */
    647         break;
    648       default:
    649         mhd_LOG_MSG (d, MHD_SC_AF_NOT_SUPPORTED_BY_BUILD, \
    650                      "Unknown address family specified");
    651         return MHD_SC_AF_NOT_SUPPORTED_BY_BUILD;
    652       }
    653 
    654       mhd_assert (mhd_SKT_NO_SOCKET < sk_type);
    655 
    656       switch (sk_type)
    657       {
    658       case mhd_SKT_IP_V4_ONLY:
    659       case mhd_SKT_IP_V4_WITH_FALLBACK:
    660         /* Zeroing is not required, but may help on exotic platforms */
    661         memset (&(sa_all.sa_i4), 0, sizeof(sa_all.sa_i4));
    662         sa_all.sa_i4.sin_family = AF_INET;
    663         sa_all.sa_i4.sin_port = htons (s->bind_port.v_port);
    664         sa_all.sa_i4.sin_addr.s_addr = INADDR_ANY;
    665         if (0 != INADDR_ANY) /* Optimised at compile time */
    666           sa_all.sa_i4.sin_addr.s_addr = htonl (INADDR_ANY);
    667 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
    668         sa_all.sa_i4.sin_len = (uint8_t)sizeof (sa_all.sa_i4);
    669 #endif
    670         p_use_sa = (const struct sockaddr *)&(sa_all.sa_i4);
    671         use_sa_size = (socklen_t)sizeof (sa_all.sa_i4);
    672         break;
    673       case mhd_SKT_IP_V6_ONLY:
    674       case mhd_SKT_IP_DUAL_REQUIRED:
    675       case mhd_SKT_IP_V4_WITH_V6_OPT:
    676       case mhd_SKT_IP_V6_WITH_V4_OPT:
    677 #ifdef HAVE_INET6
    678         if (1)
    679         {
    680 #  ifdef IN6ADDR_ANY_INIT
    681           static const struct in6_addr static_in6any = IN6ADDR_ANY_INIT;
    682 #  endif
    683           /* Zeroing is required by POSIX */
    684           memset (&(sa_all.sa_i6), 0, sizeof(sa_all.sa_i6));
    685           sa_all.sa_i6.sin6_family = AF_INET6;
    686           sa_all.sa_i6.sin6_port = htons (s->bind_port.v_port);
    687 #  ifdef IN6ADDR_ANY_INIT /* Optional assignment at the address is all zeros anyway */
    688           sa_all.sa_i6.sin6_addr = static_in6any;
    689 #  endif
    690 #  ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
    691           sa_all.sa_i6.sin6_len = (uint8_t)sizeof (sa_all.sa_i6);
    692 #  endif
    693           p_use_sa = (const struct sockaddr *)&(sa_all.sa_i6);
    694           use_sa_size = (socklen_t)sizeof (sa_all.sa_i6);
    695         }
    696         break;
    697 #endif /* HAVE_INET6 */
    698       case mhd_SKT_UNKNOWN:
    699       case mhd_SKT_NON_IP:
    700       case mhd_SKT_UNIX:
    701       case mhd_SKT_NO_SOCKET:
    702       default:
    703         mhd_UNREACHABLE ();
    704         return MHD_SC_INTERNAL_ERROR;
    705       }
    706 
    707       sk_port = s->bind_port.v_port;
    708 
    709     }
    710   }
    711   else
    712   {
    713     /* No listen socket */
    714     d->net.listen.fd = MHD_INVALID_SOCKET;
    715     d->net.listen.is_broken = false;
    716     d->net.listen.type = mhd_SOCKET_TYPE_UNKNOWN;
    717     d->net.listen.non_block = false;
    718     d->net.listen.port = 0;
    719 
    720     return MHD_SC_OK;
    721   }
    722 
    723   mhd_assert (mhd_SKT_NO_SOCKET != sk_type);
    724   mhd_assert ((NULL != p_use_sa) || sk_already_listening);
    725   mhd_assert ((MHD_INVALID_SOCKET == sk) || sk_already_listening);
    726 
    727   if (MHD_INVALID_SOCKET == sk)
    728   {
    729     mhd_assert (NULL != p_use_sa);
    730 #if defined(MHD_SOCKETS_KIND_WINSOCK) && defined(WSA_FLAG_NO_HANDLE_INHERIT)
    731     /* May fail before Win7 SP1 */
    732     sk = WSASocketW (p_use_sa->sa_family, SOCK_STREAM, 0,
    733                      NULL, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
    734 
    735     if (MHD_INVALID_SOCKET == sk)
    736 #endif /* MHD_SOCKETS_KIND_WINSOCK && WSA_FLAG_NO_HANDLE_INHERIT */
    737     sk = socket (p_use_sa->sa_family,
    738                  SOCK_STREAM | mhd_SOCK_NONBLOCK
    739                  | mhd_SOCK_CLOEXEC | mhd_SOCK_NOSIGPIPE, 0);
    740 
    741     if (MHD_INVALID_SOCKET == sk)
    742     {
    743 #ifdef HAVE_INET6
    744       if (mhd_SKT_IP_V4_WITH_FALLBACK == sk_type)
    745         return create_bind_listen_stream_socket_inner (d,
    746                                                        s,
    747                                                        v6_tried,
    748                                                        true,
    749                                                        prev_bnd_lstn_err);
    750       if (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
    751         return create_bind_listen_stream_socket_inner (d,
    752                                                        s,
    753                                                        true,
    754                                                        false,
    755                                                        prev_bnd_lstn_err);
    756 #endif /* HAVE_INET6 */
    757 
    758       if (MHD_SC_OK != prev_bnd_lstn_err)
    759         return prev_bnd_lstn_err;
    760 
    761       if (mhd_SCKT_LERR_IS_AF ())
    762       {
    763         mhd_LOG_MSG (d, MHD_SC_AF_NOT_AVAILABLE, \
    764                      "The requested socket address family is rejected " \
    765                      "by the OS");
    766         return MHD_SC_AF_NOT_AVAILABLE;
    767       }
    768       mhd_LOG_MSG (d, MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET, \
    769                    "Failed to open listen socket");
    770 
    771       return MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET;
    772     }
    773     is_non_block = (0 != mhd_SOCK_NONBLOCK);
    774     is_non_inhr = (0 != mhd_SOCK_CLOEXEC);
    775   }
    776   else
    777   {
    778     is_non_block = false; /* Try to set non-block */
    779     is_non_inhr = false;  /* Try to set non-inheritable */
    780   }
    781 
    782   /* The listen socket must be closed if error code returned
    783      beyond this point */
    784 
    785   ret = MHD_SC_OK;
    786 
    787   do
    788   { /* The scope for automatic socket close for error returns */
    789     if (!mhd_FD_FITS_DAEMON (d, sk))
    790     {
    791       mhd_LOG_MSG (d, MHD_SC_LISTEN_FD_OUTSIDE_OF_SET_RANGE, \
    792                    "The listen FD value is higher than allowed");
    793       ret = MHD_SC_LISTEN_FD_OUTSIDE_OF_SET_RANGE;
    794       break;
    795     }
    796 
    797     if (!is_non_inhr)
    798     {
    799       if (!mhd_socket_noninheritable (sk))
    800         mhd_LOG_MSG (d, MHD_SC_LISTEN_SOCKET_NOINHERIT_FAILED, \
    801                      "OS refused to make the listen socket non-inheritable");
    802     }
    803 
    804     if (!sk_already_listening)
    805     {
    806 #ifdef HAVE_INET6
    807 #  ifdef HAVE_DCLR_IPV6_V6ONLY
    808       if ((mhd_SKT_IP_V6_ONLY == sk_type)
    809           || (mhd_SKT_IP_DUAL_REQUIRED == sk_type)
    810           || (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
    811           || (mhd_SKT_IP_V6_WITH_V4_OPT == sk_type)
    812           || (mhd_SKT_UNKNOWN == sk_type))
    813       {
    814         mhd_SCKT_OPT_BOOL no_dual_to_set;
    815         bool use_dual;
    816 
    817         use_dual = ((mhd_SKT_IP_DUAL_REQUIRED == sk_type)
    818                     || (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
    819                     || (mhd_SKT_IP_V6_WITH_V4_OPT == sk_type));
    820         no_dual_to_set = use_dual ? 0 : 1;
    821 
    822         if (0 != mhd_setsockopt (sk, IPPROTO_IPV6, IPV6_V6ONLY,
    823                                  (void *)&no_dual_to_set,
    824                                  sizeof (no_dual_to_set)))
    825         {
    826           mhd_SCKT_OPT_BOOL no_dual_current;
    827           socklen_t opt_size;
    828           bool state_unknown;
    829           bool state_match;
    830 
    831           no_dual_current = 0;
    832           opt_size = sizeof(no_dual_current);
    833 
    834           /* Some platforms forbid setting this options, but allow
    835              reading. */
    836           if ((0 != mhd_getsockopt (sk, IPPROTO_IPV6, IPV6_V6ONLY,
    837                                     (void *)&no_dual_current, &opt_size))
    838               || (((socklen_t)sizeof(no_dual_current)) < opt_size))
    839           {
    840             state_unknown = true;
    841             state_match = false;
    842           }
    843           else
    844           {
    845             state_unknown = false;
    846             state_match = ((!!no_dual_current) == (!!no_dual_to_set));
    847           }
    848 
    849           if (state_unknown || !state_match)
    850           {
    851             if (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
    852             {
    853               (void)mhd_socket_close (sk);
    854               return create_bind_listen_stream_socket_inner (d,
    855                                                              s,
    856                                                              true,
    857                                                              false,
    858                                                              prev_bnd_lstn_err);
    859             }
    860             if (!state_unknown)
    861             {
    862               /* The dual-stack state is definitely wrong */
    863               if (mhd_SKT_IP_V6_ONLY == sk_type)
    864               {
    865                 mhd_LOG_MSG ( \
    866                   d, MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_REJECTED, \
    867                   "Failed to disable IP dual-stack configuration " \
    868                   "for the listen socket");
    869                 ret = (MHD_SC_OK == prev_bnd_lstn_err) ?
    870                       MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_REJECTED :
    871                       prev_bnd_lstn_err;
    872                 break;
    873               }
    874               else if (mhd_SKT_UNKNOWN != sk_type)
    875               {
    876                 mhd_LOG_MSG ( \
    877                   d, MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_REJECTED, \
    878                   "Cannot enable IP dual-stack configuration " \
    879                   "for the listen socket");
    880                 if (mhd_SKT_IP_DUAL_REQUIRED == sk_type)
    881                 {
    882                   ret = (MHD_SC_OK == prev_bnd_lstn_err) ?
    883                         MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_REJECTED :
    884                         prev_bnd_lstn_err;
    885                   break;
    886                 }
    887               }
    888             }
    889             else
    890             {
    891               /* The dual-stack state is unknown */
    892               if (mhd_SKT_UNKNOWN != sk_type)
    893                 mhd_LOG_MSG (
    894                   d, MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_UNKNOWN, \
    895                   "Failed to set dual-stack (IPV6_ONLY) configuration " \
    896                   "for the listen socket, using system defaults");
    897             }
    898           }
    899         }
    900       }
    901 #  else  /* ! IPV6_V6ONLY */
    902       mhd_assert (mhd_SKT_IP_DUAL_REQUIRED != sk_type);
    903       mhd_assert (mhd_SKT_IP_V4_WITH_V6_OPT != sk_type);
    904       mhd_assert (mhd_SKT_IP_V6_WITH_V4_OPT != sk_type);
    905 #  endif /* ! IPV6_V6ONLY */
    906 #endif /* HAVE_INET6 */
    907 
    908       if (MHD_FOM_AUTO <= d->settings->tcp_fastopen.v_option)
    909       {
    910 #if defined(HAVE_DCLR_TCP_FASTOPEN)
    911         int fo_param;
    912 #  ifdef __linux__
    913         /* The parameter is the queue length */
    914         fo_param = (int)d->settings->tcp_fastopen.v_queue_length;
    915         if (0 == fo_param)
    916           fo_param = MHD_TCP_FASTOPEN_DEF_QUEUE_LEN;
    917 #  else  /* ! __linux__ */
    918         fo_param = 1; /* The parameter is on/off type of setting */
    919 #  endif /* ! __linux__ */
    920         if (0 != mhd_setsockopt (sk, IPPROTO_TCP, TCP_FASTOPEN,
    921                                  (const void *)&fo_param,
    922                                  sizeof (fo_param)))
    923         {
    924           mhd_LOG_MSG (d, MHD_SC_LISTEN_FAST_OPEN_FAILURE, \
    925                        "OS refused to enable TCP Fast Open on " \
    926                        "the listen socket");
    927           if (MHD_FOM_AUTO < d->settings->tcp_fastopen.v_option)
    928           {
    929             ret = MHD_SC_LISTEN_FAST_OPEN_FAILURE;
    930             break;
    931           }
    932         }
    933 #else  /* ! TCP_FASTOPEN */
    934         if (MHD_FOM_AUTO < d->settings->tcp_fastopen.v_option)
    935         {
    936           mhd_LOG_MSG (d, MHD_SC_LISTEN_FAST_OPEN_FAILURE, \
    937                        "The OS does not support TCP Fast Open");
    938           ret = MHD_SC_LISTEN_FAST_OPEN_FAILURE;
    939           break;
    940         }
    941 #endif
    942       }
    943 
    944       if (MHD_D_OPTION_BIND_TYPE_NOT_SHARED >= d->settings->listen_addr_reuse)
    945       {
    946 #ifndef MHD_SOCKETS_KIND_WINSOCK
    947 #  ifdef HAVE_DCLR_SO_REUSEADDR
    948         mhd_SCKT_OPT_BOOL on_val1 = 1;
    949         if (0 != mhd_setsockopt (sk, SOL_SOCKET, SO_REUSEADDR,
    950                                  (const void *)&on_val1, sizeof (on_val1)))
    951         {
    952           mhd_LOG_MSG (d, MHD_SC_LISTEN_PORT_REUSE_ENABLE_FAILED, \
    953                        "OS refused to enable address reuse on " \
    954                        "the listen socket");
    955         }
    956 #  else  /* ! SO_REUSEADDR */
    957         mhd_LOG_MSG (d, MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED, \
    958                      "The OS does not support address reuse for sockets");
    959 #  endif /* ! SO_REUSEADDR */
    960 #endif /* ! MHD_SOCKETS_KIND_WINSOCK */
    961         if (MHD_D_OPTION_BIND_TYPE_NOT_SHARED > d->settings->listen_addr_reuse)
    962         {
    963 #if defined(HAVE_DCLR_SO_REUSEPORT) || defined(MHD_SOCKETS_KIND_WINSOCK)
    964           int opt_name;
    965           mhd_SCKT_OPT_BOOL on_val2 = 1;
    966 #  ifndef MHD_SOCKETS_KIND_WINSOCK
    967           opt_name = SO_REUSEPORT;
    968 #  else  /* ! MHD_SOCKETS_KIND_WINSOCK */
    969           opt_name = SO_REUSEADDR; /* On W32 it is the same as SO_REUSEPORT on other platforms */
    970 #  endif /* ! MHD_SOCKETS_KIND_WINSOCK */
    971           if (0 != mhd_setsockopt (sk, \
    972                                    SOL_SOCKET, \
    973                                    opt_name, \
    974                                    (const void *)&on_val2, \
    975                                    sizeof (on_val2)))
    976           {
    977             mhd_LOG_MSG (d, MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED, \
    978                          "OS refused to enable address sharing " \
    979                          "on the listen socket");
    980             ret = MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED;
    981             break;
    982           }
    983 #else  /* ! SO_REUSEADDR && ! MHD_SOCKETS_KIND_WINSOCK */
    984           mhd_LOG_MSG (d, MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED, \
    985                        "The OS does not support address sharing for sockets");
    986           ret = MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED;
    987           break;
    988 #endif /* ! SO_REUSEADDR && ! MHD_SOCKETS_KIND_WINSOCK */
    989         }
    990       }
    991 #if defined(SO_EXCLUSIVEADDRUSE) || defined(SO_EXCLBIND)
    992       else if (MHD_D_OPTION_BIND_TYPE_EXCLUSIVE <=
    993                d->settings->listen_addr_reuse)
    994       {
    995         int opt_name;
    996         mhd_SCKT_OPT_BOOL on_val = 1;
    997 #  ifdef SO_EXCLUSIVEADDRUSE
    998         opt_name = SO_EXCLUSIVEADDRUSE;
    999 #  else
   1000         opt_name = SO_EXCLBIND;
   1001 #  endif
   1002         if (0 != mhd_setsockopt (sk, \
   1003                                  SOL_SOCKET, \
   1004                                  opt_name, \
   1005                                  (const void *)&on_val, \
   1006                                  sizeof (on_val)))
   1007         {
   1008           mhd_LOG_MSG (d, MHD_SC_LISTEN_ADDRESS_EXCLUSIVE_ENABLE_FAILED, \
   1009                        "OS refused to enable exclusive address use " \
   1010                        "on the listen socket");
   1011           ret = MHD_SC_LISTEN_ADDRESS_EXCLUSIVE_ENABLE_FAILED;
   1012           break;
   1013         }
   1014       }
   1015 #endif /* SO_EXCLUSIVEADDRUSE || SO_EXCLBIND */
   1016 
   1017       mhd_assert (NULL != p_use_sa);
   1018       mhd_assert (0 != use_sa_size);
   1019       if (0 != bind (sk, p_use_sa, use_sa_size))
   1020       {
   1021         ret = (MHD_SC_OK == prev_bnd_lstn_err) ?
   1022               MHD_SC_LISTEN_SOCKET_BIND_FAILED : prev_bnd_lstn_err;
   1023 #ifdef HAVE_INET6
   1024         if (mhd_SKT_IP_V4_WITH_FALLBACK == sk_type)
   1025         {
   1026           (void)mhd_socket_close (sk);
   1027           return create_bind_listen_stream_socket_inner (d,
   1028                                                          s,
   1029                                                          v6_tried,
   1030                                                          true,
   1031                                                          ret);
   1032         }
   1033         if (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
   1034         {
   1035           (void)mhd_socket_close (sk);
   1036           return create_bind_listen_stream_socket_inner (d,
   1037                                                          s,
   1038                                                          true,
   1039                                                          false,
   1040                                                          ret);
   1041         }
   1042 #endif /* HAVE_INET6 */
   1043         break;
   1044       }
   1045 
   1046       if (1)
   1047       {
   1048         int accept_queue_len;
   1049         accept_queue_len = (int)s->listen_backlog;
   1050         if (0 > accept_queue_len)
   1051           accept_queue_len = 0;
   1052         if (0 == accept_queue_len)
   1053         {
   1054 #if defined(SOMAXCONN) || defined(HAVE_DCLR_SOMAXCONN)
   1055           accept_queue_len = SOMAXCONN;
   1056 #else  /* ! SOMAXCONN */
   1057           accept_queue_len = 127; /* Should be the safe value */
   1058 #endif /* ! SOMAXCONN */
   1059         }
   1060         if (0 != listen (sk, accept_queue_len))
   1061         {
   1062           ret = MHD_SC_LISTEN_FAILURE;
   1063 #ifdef HAVE_INET6
   1064           if (mhd_SKT_IP_V4_WITH_FALLBACK == sk_type)
   1065           {
   1066             (void)mhd_socket_close (sk);
   1067             return create_bind_listen_stream_socket_inner (d,
   1068                                                            s,
   1069                                                            v6_tried,
   1070                                                            true,
   1071                                                            ret);
   1072           }
   1073           if (mhd_SKT_IP_V4_WITH_V6_OPT == sk_type)
   1074           {
   1075             (void)mhd_socket_close (sk);
   1076             return create_bind_listen_stream_socket_inner (d,
   1077                                                            s,
   1078                                                            true,
   1079                                                            false,
   1080                                                            ret);
   1081           }
   1082 #endif /* HAVE_INET6 */
   1083           break;
   1084         }
   1085       }
   1086     }
   1087     /* A valid listening socket is ready here */
   1088 
   1089     if (!is_non_block)
   1090     {
   1091       is_non_block = mhd_socket_nonblocking (sk);
   1092       if (!is_non_block)
   1093         mhd_LOG_MSG (d, MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE, \
   1094                      "OS refused to make the listen socket non-blocking");
   1095     }
   1096 
   1097     /* Set to the daemon only when the listening socket is fully ready */
   1098     d->net.listen.fd = sk;
   1099     d->net.listen.is_broken = false;
   1100     switch (sk_type)
   1101     {
   1102     case mhd_SKT_UNKNOWN:
   1103       d->net.listen.type = mhd_SOCKET_TYPE_UNKNOWN;
   1104       break;
   1105     case mhd_SKT_NON_IP:
   1106       d->net.listen.type = mhd_SOCKET_TYPE_NON_IP;
   1107       break;
   1108     case mhd_SKT_UNIX:
   1109       d->net.listen.type = mhd_SOCKET_TYPE_UNIX;
   1110       break;
   1111     case mhd_SKT_IP_V4_ONLY:
   1112     case mhd_SKT_IP_V6_ONLY:
   1113     case mhd_SKT_IP_DUAL_REQUIRED:
   1114     case mhd_SKT_IP_V4_WITH_V6_OPT:
   1115     case mhd_SKT_IP_V6_WITH_V4_OPT:
   1116     case mhd_SKT_IP_V4_WITH_FALLBACK:
   1117       d->net.listen.type = mhd_SOCKET_TYPE_IP;
   1118       break;
   1119     case mhd_SKT_NO_SOCKET:
   1120     default:
   1121       mhd_UNREACHABLE ();
   1122       return MHD_SC_INTERNAL_ERROR;
   1123     }
   1124     d->net.listen.non_block = is_non_block;
   1125     d->net.listen.port = sk_port;
   1126 
   1127     mhd_assert (ret == MHD_SC_OK);
   1128 
   1129     return MHD_SC_OK;
   1130 
   1131   } while (0);
   1132 
   1133   mhd_assert (MHD_SC_OK != ret); /* This should be only error returns here */
   1134   mhd_assert (MHD_INVALID_SOCKET != sk);
   1135   (void)mhd_socket_close (sk);
   1136   return ret;
   1137 }
   1138 
   1139 
   1140 /**
   1141  * Create socket, bind to the address and start listening on the socket.
   1142  *
   1143  * The socket is assigned to the daemon as listening FD.
   1144  *
   1145  * @param d the daemon to use
   1146  * @param s the user settings
   1147  * @return #MHD_SC_OK on success,
   1148  *         the error code otherwise (no error printed to log if result is
   1149  *         #MHD_SC_LISTEN_SOCKET_BIND_FAILED or #MHD_SC_LISTEN_FAILURE)
   1150  */
   1151 static enum MHD_StatusCode
   1152 create_bind_listen_stream_socket (struct MHD_Daemon *restrict d,
   1153                                   struct DaemonOptions *restrict s)
   1154 {
   1155   enum MHD_StatusCode ret;
   1156 
   1157   ret = create_bind_listen_stream_socket_inner (d,
   1158                                                 s,
   1159                                                 false,
   1160                                                 false,
   1161                                                 MHD_SC_OK);
   1162 #ifdef MHD_SUPPORT_LOG_FUNCTIONALITY
   1163   if (MHD_SC_LISTEN_SOCKET_BIND_FAILED == ret)
   1164     mhd_LOG_MSG (d, MHD_SC_LISTEN_SOCKET_BIND_FAILED, \
   1165                  "Failed to bind the listen socket");
   1166   else if (MHD_SC_LISTEN_FAILURE == ret)
   1167     mhd_LOG_MSG (d, MHD_SC_LISTEN_FAILURE, \
   1168                  "Failed to start listening on the listen socket");
   1169 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
   1170 
   1171   return ret;
   1172 }
   1173 
   1174 
   1175 #ifdef MHD_USE_GETSOCKNAME
   1176 /**
   1177  * Detect and set the type and port of the listening socket
   1178  * @param d the daemon to use
   1179  */
   1180 static MHD_FN_PAR_NONNULL_ (1) void
   1181 detect_listen_type_and_port (struct MHD_Daemon *restrict d)
   1182 {
   1183   union mhd_SockaddrAny sa_all;
   1184   socklen_t sa_size;
   1185   enum mhd_SocketType declared_type;
   1186 
   1187   mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd);
   1188   mhd_assert (0 == d->net.listen.port);
   1189   memset (&sa_all, 0, sizeof(sa_all)); /* Actually not required */
   1190   sa_size = (socklen_t)sizeof(sa_all);
   1191 
   1192   if (0 != getsockname (d->net.listen.fd, &(sa_all.sa), &sa_size))
   1193   {
   1194     if (mhd_SOCKET_TYPE_IP == d->net.listen.type)
   1195       mhd_LOG_MSG (d, MHD_SC_LISTEN_PORT_DETECT_FAILURE, \
   1196                    "Failed to detect the port number on the listening socket");
   1197     return;
   1198   }
   1199 
   1200   declared_type = d->net.listen.type;
   1201   if (0 == sa_size)
   1202   {
   1203 #  ifndef __linux__
   1204     /* Used on some non-Linux platforms */
   1205     d->net.listen.type = mhd_SOCKET_TYPE_UNIX;
   1206     d->net.listen.port = 0;
   1207 #  else  /* ! __linux__ */
   1208     (void)0;
   1209 #  endif /* ! __linux__ */
   1210   }
   1211   else
   1212   {
   1213     switch (sa_all.sa.sa_family)
   1214     {
   1215     case AF_INET:
   1216       d->net.listen.type = mhd_SOCKET_TYPE_IP;
   1217       d->net.listen.port = (uint_least16_t)ntohs (sa_all.sa_i4.sin_port);
   1218       break;
   1219 #  ifdef HAVE_INET6
   1220     case AF_INET6:
   1221       d->net.listen.type = mhd_SOCKET_TYPE_IP;
   1222       d->net.listen.port = (uint_least16_t)ntohs (sa_all.sa_i6.sin6_port);
   1223       break;
   1224 #  endif /* HAVE_INET6 */
   1225 #  ifdef MHD_AF_UNIX
   1226     case MHD_AF_UNIX:
   1227       d->net.listen.type = mhd_SOCKET_TYPE_UNIX;
   1228       d->net.listen.port = 0;
   1229       break;
   1230 #  endif /* MHD_AF_UNIX */
   1231     default:
   1232       d->net.listen.type = mhd_SOCKET_TYPE_UNKNOWN;
   1233       d->net.listen.port = 0;
   1234       break;
   1235     }
   1236   }
   1237 
   1238   if ((declared_type != d->net.listen.type)
   1239       && (mhd_SOCKET_TYPE_IP == declared_type))
   1240     mhd_LOG_MSG (d, MHD_SC_UNEXPECTED_SOCKET_ERROR, \
   1241                  "The type of listen socket is detected as non-IP, while " \
   1242                  "the socket has been created as an IP socket");
   1243 }
   1244 
   1245 
   1246 #else
   1247 #  define detect_listen_type_and_port(d) ((void) d)
   1248 #endif
   1249 
   1250 
   1251 #ifdef MHD_SUPPORT_EPOLL
   1252 
   1253 /**
   1254  * Initialise daemon's epoll FD
   1255  * The could be performed early to probe for epoll FD presence
   1256  * or, normally, during worker initialisation
   1257  * @param d the daemon object
   1258  * @param early_probing 'true' if this is early epoll probing
   1259  * @param log_failures set to true if errors logging should be suppressed
   1260  *                     when fallback options exist
   1261  * @return #MHD_SC_OK on success,
   1262  *         the error code otherwise
   1263  */
   1264 static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
   1265 init_epoll_fd (struct MHD_Daemon *restrict d,
   1266                bool early_probing,
   1267                bool log_failures)
   1268 {
   1269   int e_fd;
   1270   mhd_ASSUME (early_probing || log_failures);
   1271   mhd_assert ((mhd_POLL_TYPE_EPOLL == d->events.poll_type)
   1272               || (mhd_POLL_TYPE_NOT_SET_YET == d->events.poll_type));
   1273   mhd_assert (!mhd_WM_INT_IS_THREAD_PER_CONN (d->wmode_int));
   1274   mhd_assert (early_probing || d->dbg.net_inited);
   1275   mhd_assert (!early_probing || !d->dbg.net_inited);
   1276   mhd_assert ((mhd_POLL_TYPE_EPOLL != d->events.poll_type) \
   1277               || (NULL == d->events.data.epoll.events));
   1278 
   1279   if (!early_probing)
   1280   {
   1281     /* Full events initialisation */
   1282     mhd_ASSUME (mhd_POLL_TYPE_EPOLL == d->events.poll_type);
   1283     if (!mhd_D_HAS_MASTER (d))
   1284     {
   1285       mhd_assert (0 < d->events.data.epoll.early_fd);
   1286       /* Move early initialised epoll FD */
   1287       d->events.data.epoll.e_fd = d->events.data.epoll.early_fd;
   1288       d->events.data.epoll.early_fd = MHD_INVALID_SOCKET;
   1289       return MHD_SC_OK;
   1290     }
   1291 #  ifdef MHD_SUPPORT_THREADS
   1292     else
   1293     {
   1294       /* Worker daemon */
   1295       int early_fd;
   1296 
   1297       early_fd = d->threading.hier.master->events.data.epoll.early_fd;
   1298 
   1299       /* Move early initialised epoll FD if it is not yet taken */
   1300       if (MHD_INVALID_SOCKET != early_fd)
   1301       {
   1302         d->events.data.epoll.e_fd = early_fd;
   1303         d->threading.hier.master->events.data.epoll.early_fd =
   1304           MHD_INVALID_SOCKET;
   1305         return MHD_SC_OK;
   1306       }
   1307       /* Process with new epoll FD creation */
   1308     }
   1309 #  endif /* MHD_SUPPORT_THREADS */
   1310   }
   1311   else
   1312     mhd_ASSUME (mhd_POLL_TYPE_NOT_SET_YET == d->events.poll_type);
   1313 
   1314 #  ifdef HAVE_EPOLL_CREATE1
   1315   e_fd = epoll_create1 (EPOLL_CLOEXEC);
   1316 #  else  /* ! HAVE_EPOLL_CREATE1 */
   1317   e_fd = epoll_create (128); /* The number is usually ignored */
   1318   if (0 <= e_fd)
   1319   {
   1320     if (!mhd_socket_noninheritable (e_fd))
   1321       mhd_LOG_MSG (d, MHD_SC_EPOLL_CTL_CONFIGURE_NOINHERIT_FAILED, \
   1322                    "Failed to make epoll control FD non-inheritable");
   1323   }
   1324 #  endif /* ! HAVE_EPOLL_CREATE1 */
   1325   if (0 > e_fd)
   1326   {
   1327     if (log_failures)
   1328       mhd_LOG_MSG (d, MHD_SC_EPOLL_CTL_CREATE_FAILED, \
   1329                    "Failed to create epoll control FD");
   1330     return MHD_SC_EPOLL_CTL_CREATE_FAILED; /* Failure exit point */
   1331   }
   1332 
   1333   if (!mhd_FD_FITS_DAEMON (d, e_fd))
   1334   {
   1335     if (log_failures)
   1336       mhd_LOG_MSG (d, MHD_SC_EPOLL_CTL_OUTSIDE_OF_SET_RANGE, \
   1337                    "The epoll control FD value is higher than allowed");
   1338     (void)close (e_fd);
   1339     return MHD_SC_EPOLL_CTL_OUTSIDE_OF_SET_RANGE; /* Failure exit point */
   1340   }
   1341 
   1342   /* Needs to be set here as setting epoll data member 'early_fd' */
   1343   d->events.poll_type = mhd_POLL_TYPE_EPOLL;
   1344   if (!early_probing)
   1345     d->events.data.epoll.e_fd = e_fd;
   1346   else
   1347     d->events.data.epoll.early_fd = e_fd;
   1348 
   1349   return MHD_SC_OK; /* Success exit point */
   1350 }
   1351 
   1352 
   1353 /**
   1354  * Deinitialise daemon's epoll FD
   1355  * @param d the daemon object
   1356  */
   1357 MHD_FN_PAR_NONNULL_ (1) static void
   1358 deinit_epoll_fd (struct MHD_Daemon *restrict d)
   1359 {
   1360   mhd_assert (mhd_POLL_TYPE_EPOLL == d->events.poll_type);
   1361   mhd_assert (MHD_INVALID_SOCKET != d->events.data.epoll.e_fd);
   1362   mhd_assert (MHD_INVALID_SOCKET == d->events.data.epoll.early_fd);
   1363   close (d->events.data.epoll.e_fd);
   1364 }
   1365 
   1366 
   1367 #endif /* MHD_SUPPORT_EPOLL */
   1368 
   1369 
   1370 /**
   1371  * Choose sockets monitoring syscall and pre-initialise it
   1372  * @param d the daemon object
   1373  * @param s the user settings
   1374  * @return #MHD_SC_OK on success,
   1375  *         the error code otherwise
   1376  */
   1377 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
   1378   MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1379 daemon_choose_and_preinit_events (struct MHD_Daemon *restrict d,
   1380                                   struct DaemonOptions *restrict s)
   1381 {
   1382   enum mhd_IntPollType chosen_type;
   1383 
   1384   mhd_assert (mhd_POLL_TYPE_NOT_SET_YET == d->events.poll_type);
   1385 
   1386   mhd_assert ((mhd_WM_INT_EXTERNAL_EVENTS_EDGE != d->wmode_int) \
   1387               || (mhd_WM_INT_EXTERNAL_EVENTS_LEVEL != d->wmode_int) \
   1388               || (MHD_SPS_AUTO == s->poll_syscall));
   1389 
   1390   /* Check whether the provided parameter is in the range of expected values.
   1391      Reject unsupported or disabled values. */
   1392   switch (s->poll_syscall)
   1393   {
   1394   case MHD_SPS_AUTO:
   1395     chosen_type = mhd_POLL_TYPE_NOT_SET_YET;
   1396     break;
   1397   case MHD_SPS_SELECT:
   1398     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1399 #ifndef MHD_SUPPORT_SELECT
   1400     mhd_LOG_MSG (d, MHD_SC_SELECT_SYSCALL_NOT_AVAILABLE, \
   1401                  "'select()' is not supported by the platform or " \
   1402                  "this MHD build");
   1403     return MHD_SC_SELECT_SYSCALL_NOT_AVAILABLE;
   1404 #else  /* MHD_SUPPORT_SELECT */
   1405     chosen_type = mhd_POLL_TYPE_SELECT;
   1406 #endif /* MHD_SUPPORT_SELECT */
   1407     break;
   1408   case MHD_SPS_POLL:
   1409     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1410 #ifndef MHD_SUPPORT_POLL
   1411     mhd_LOG_MSG (d, MHD_SC_POLL_SYSCALL_NOT_AVAILABLE, \
   1412                  "'poll()' is not supported by the platform or " \
   1413                  "this MHD build");
   1414     return MHD_SC_POLL_SYSCALL_NOT_AVAILABLE;
   1415 #else  /* MHD_SUPPORT_POLL */
   1416     chosen_type = mhd_POLL_TYPE_POLL;
   1417 #endif /* MHD_SUPPORT_POLL */
   1418     break;
   1419   case MHD_SPS_EPOLL:
   1420     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1421     mhd_assert (!mhd_WM_INT_IS_THREAD_PER_CONN (d->wmode_int));
   1422 #ifndef MHD_SUPPORT_EPOLL
   1423     mhd_LOG_MSG (d, MHD_SC_EPOLL_SYSCALL_NOT_AVAILABLE, \
   1424                  "'epoll' is not supported by the platform or " \
   1425                  "this MHD build");
   1426     return MHD_SC_EPOLL_SYSCALL_NOT_AVAILABLE;
   1427 #else  /* MHD_SUPPORT_EPOLL */
   1428     chosen_type = mhd_POLL_TYPE_EPOLL;
   1429 #endif /* MHD_SUPPORT_EPOLL */
   1430     break;
   1431   case MHD_SPS_KQUEUE:
   1432     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1433     mhd_assert (!mhd_WM_INT_IS_THREAD_PER_CONN (d->wmode_int));
   1434 #ifndef MHD_SUPPORT_KQUEUE
   1435     mhd_LOG_MSG (d, MHD_SC_KQUEUE_SYSCALL_NOT_AVAILABLE, \
   1436                  "'kqueue' is not supported by the platform or " \
   1437                  "this MHD build");
   1438     return MHD_SC_KQUEUE_SYSCALL_NOT_AVAILABLE;
   1439 #else  /* MHD_SUPPORT_EPOLL */
   1440     chosen_type = mhd_POLL_TYPE_KQUEUE;
   1441 #endif /* MHD_SUPPORT_EPOLL */
   1442     break;
   1443   default:
   1444     mhd_LOG_MSG (d, MHD_SC_CONFIGURATION_UNEXPECTED_SPS,
   1445                  "Wrong socket polling syscall specified");
   1446     return MHD_SC_CONFIGURATION_UNEXPECTED_SPS;
   1447   }
   1448 
   1449 #ifdef MHD_SUPPORT_HTTPS
   1450   if ((mhd_WM_INT_EXTERNAL_EVENTS_EDGE == (d)->wmode_int)
   1451       || mhd_POLL_TYPE_INT_IS_EDGE_TRIG (chosen_type))
   1452   { /* Edge-triggered polling chosen */
   1453     if (MHD_TLS_BACKEND_NONE != s->tls)
   1454     {
   1455       if (!mhd_tls_is_edge_trigg_supported (s))
   1456       {
   1457 #  ifdef MHD_SUPPORT_LOG_FUNCTIONALITY
   1458         if (MHD_TLS_BACKEND_ANY == s->tls)
   1459           mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \
   1460                        "Edge-triggered sockets polling cannot be used "
   1461                        "with available TLS backends");
   1462         else
   1463           mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \
   1464                        "Edge-triggered sockets polling cannot be used "
   1465                        "with selected TLS backend");
   1466 #  endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
   1467         return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS;
   1468       }
   1469     }
   1470   }
   1471 #endif /* MHD_SUPPORT_HTTPS */
   1472 
   1473   mhd_assert (mhd_POLL_TYPE_EXT != chosen_type);
   1474   mhd_ASSUME ((mhd_POLL_TYPE_NOT_SET_YET != chosen_type) \
   1475               || (MHD_SPS_AUTO == s->poll_syscall));
   1476 
   1477   if (mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1478   {
   1479     if (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int))
   1480       chosen_type = mhd_POLL_TYPE_EXT;
   1481   }
   1482 
   1483 #if defined(MHD_SUPPORT_EPOLL) || defined(MHD_SUPPORT_KQUEUE)
   1484   /* Try edge-triggered polling */
   1485   if ((mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1486       || mhd_POLL_TYPE_INT_IS_KQUEUE (chosen_type)
   1487       || mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type))
   1488   {
   1489     bool et_allowed;
   1490 
   1491     et_allowed = true;
   1492     if (mhd_WM_INT_IS_THREAD_PER_CONN (d->wmode_int))
   1493     {
   1494       mhd_assert (!mhd_POLL_TYPE_INT_IS_KQUEUE (chosen_type));
   1495       mhd_assert (!mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type));
   1496       et_allowed = false;
   1497     }
   1498 #  ifdef MHD_SUPPORT_HTTPS
   1499     else if (MHD_TLS_BACKEND_NONE != s->tls)
   1500       et_allowed = mhd_tls_is_edge_trigg_supported (s);
   1501 #  endif /* MHD_SUPPORT_HTTPS */
   1502 
   1503     if (et_allowed)
   1504     {
   1505       mhd_ASSUME ((mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1506                   || mhd_POLL_TYPE_INT_IS_KQUEUE (chosen_type)
   1507                   || mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type));
   1508 
   1509 #  if defined(MHD_SUPPORT_KQUEUE)
   1510       if ((mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1511           || mhd_POLL_TYPE_INT_IS_KQUEUE (chosen_type))
   1512         chosen_type = mhd_POLL_TYPE_KQUEUE; /* No need to perform additional checking here */
   1513 #  endif /* MHD_SUPPORT_KQUEUE */
   1514 #  ifdef MHD_SUPPORT_EPOLL
   1515       if ((mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1516           || mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type))
   1517       {
   1518         /* epoll - need to be probed here as it can be disabled in kernel */
   1519         enum MHD_StatusCode epoll_res;
   1520         epoll_res = init_epoll_fd (d,
   1521                                    true,
   1522                                    mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type));
   1523         if (MHD_SC_OK != epoll_res)
   1524         {
   1525           if (mhd_POLL_TYPE_INT_IS_EPOLL (chosen_type))
   1526             return epoll_res;
   1527           mhd_assert (mhd_POLL_TYPE_NOT_SET_YET == chosen_type);
   1528         }
   1529         else
   1530           chosen_type = mhd_POLL_TYPE_EPOLL;
   1531       }
   1532 #  endif /* ! MHD_SUPPORT_EPOLL */
   1533     }
   1534     else
   1535       mhd_assert (mhd_POLL_TYPE_NOT_SET_YET == chosen_type);
   1536   }
   1537 #  ifdef MHD_SUPPORT_EPOLL
   1538   mhd_assert ((mhd_POLL_TYPE_EPOLL != d->events.poll_type) \
   1539               || (0 < d->events.data.epoll.early_fd));
   1540   mhd_assert ((mhd_POLL_TYPE_EPOLL == d->events.poll_type) == \
   1541               (mhd_POLL_TYPE_EPOLL == chosen_type));
   1542 #  endif /* ! MHD_SUPPORT_EPOLL */
   1543 #endif /* ! MHD_SUPPORT_EPOLL */
   1544 
   1545   if (mhd_POLL_TYPE_NOT_SET_YET == chosen_type)
   1546   {
   1547 #if defined(MHD_SUPPORT_POLL)
   1548     chosen_type = mhd_POLL_TYPE_POLL;
   1549 #elif defined(MHD_SUPPORT_SELECT)
   1550     chosen_type = mhd_POLL_TYPE_SELECT;
   1551 #else
   1552     mhd_LOG_MSG (d, MHD_SC_FEATURE_DISABLED, \
   1553                  "All suitable internal sockets polling technologies are " \
   1554                  "disabled in this MHD build");
   1555     return MHD_SC_FEATURE_DISABLED;
   1556 #endif
   1557   }
   1558 
   1559   switch (chosen_type)
   1560   {
   1561   case mhd_POLL_TYPE_EXT:
   1562     mhd_assert ((MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL == s->work_mode.mode) \
   1563                 || (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE == s->work_mode.mode));
   1564     mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1565     d->events.poll_type = mhd_POLL_TYPE_EXT;
   1566     d->events.data.extr.cb_data.cb =
   1567       s->work_mode.params.v_external_event_loop_cb.reg_cb;
   1568     d->events.data.extr.cb_data.cls =
   1569       s->work_mode.params.v_external_event_loop_cb.reg_cb_cls;
   1570     d->events.data.extr.reg_all = (MHD_NO != s->reregister_all);
   1571 #ifdef MHD_SUPPORT_THREADS
   1572     d->events.data.extr.itc_data.app_cntx = NULL;
   1573 #endif /* MHD_SUPPORT_THREADS */
   1574     d->events.data.extr.listen_data.app_cntx = NULL;
   1575     break;
   1576 #ifdef MHD_SUPPORT_SELECT
   1577   case mhd_POLL_TYPE_SELECT:
   1578     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1579     mhd_assert (MHD_WM_EXTERNAL_SINGLE_FD_WATCH != s->work_mode.mode);
   1580     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL != s->work_mode.mode);
   1581     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE != s->work_mode.mode);
   1582     mhd_assert (MHD_NO == s->reregister_all);
   1583     d->events.poll_type = mhd_POLL_TYPE_SELECT;
   1584     d->events.data.select.rfds = NULL; /* Memory allocated during event and threads init */
   1585     d->events.data.select.wfds = NULL; /* Memory allocated during event and threads init */
   1586     d->events.data.select.efds = NULL; /* Memory allocated during event and threads init */
   1587     break;
   1588 #endif /* MHD_SUPPORT_SELECT */
   1589 #ifdef MHD_SUPPORT_POLL
   1590   case mhd_POLL_TYPE_POLL:
   1591     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1592     mhd_assert (MHD_WM_EXTERNAL_SINGLE_FD_WATCH != s->work_mode.mode);
   1593     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL != s->work_mode.mode);
   1594     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE != s->work_mode.mode);
   1595     mhd_assert (MHD_NO == s->reregister_all);
   1596     d->events.poll_type = mhd_POLL_TYPE_POLL;
   1597     d->events.data.poll.fds = NULL; /* Memory allocated during event and threads init */
   1598     d->events.data.poll.rel = NULL; /* Memory allocated during event and threads init */
   1599     break;
   1600 #endif /* MHD_SUPPORT_POLL */
   1601 #ifdef MHD_SUPPORT_EPOLL
   1602   case mhd_POLL_TYPE_EPOLL:
   1603     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1604     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL != s->work_mode.mode);
   1605     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE != s->work_mode.mode);
   1606     mhd_assert (MHD_NO == s->reregister_all);
   1607     /* Pre-initialised by init_epoll_fd() */
   1608     mhd_assert (mhd_POLL_TYPE_EPOLL == d->events.poll_type);
   1609     mhd_assert (0 <= d->events.data.epoll.early_fd);
   1610     d->events.data.epoll.events = NULL; /* Memory allocated during event and threads init */
   1611     d->events.data.epoll.num_elements = 0;
   1612     break;
   1613 #endif /* MHD_SUPPORT_EPOLL */
   1614 #ifdef MHD_SUPPORT_KQUEUE
   1615   case mhd_POLL_TYPE_KQUEUE:
   1616     mhd_assert (!mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   1617     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL != s->work_mode.mode);
   1618     mhd_assert (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE != s->work_mode.mode);
   1619     mhd_assert (MHD_NO == s->reregister_all);
   1620     d->events.poll_type = mhd_POLL_TYPE_KQUEUE;
   1621     d->events.data.kq.kq_fd = -1;
   1622     d->events.data.kq.kes = NULL;
   1623     d->events.data.kq.num_elements = 0u;
   1624     break;
   1625 #endif /* MHD_SUPPORT_KQUEUE */
   1626 #ifndef MHD_SUPPORT_SELECT
   1627   case mhd_POLL_TYPE_SELECT:
   1628 #endif /* ! MHD_SUPPORT_SELECT */
   1629 #ifndef MHD_SUPPORT_POLL
   1630   case mhd_POLL_TYPE_POLL:
   1631 #endif /* ! MHD_SUPPORT_POLL */
   1632   case mhd_POLL_TYPE_NOT_SET_YET:
   1633   default:
   1634     mhd_UNREACHABLE ();
   1635     return MHD_SC_INTERNAL_ERROR;
   1636   }
   1637   return MHD_SC_OK;
   1638 }
   1639 
   1640 
   1641 /**
   1642  * Initialise network/sockets for the daemon.
   1643  * Also choose events mode / sockets polling syscall.
   1644  * @param d the daemon object
   1645  * @param s the user settings
   1646  * @return #MHD_SC_OK on success,
   1647  *         the error code otherwise
   1648  */
   1649 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
   1650   MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1651 daemon_init_net (struct MHD_Daemon *restrict d,
   1652                  struct DaemonOptions *restrict s)
   1653 {
   1654   enum MHD_StatusCode ret;
   1655 
   1656   mhd_assert (!d->dbg.net_inited);
   1657   mhd_assert (!d->dbg.net_deinited);
   1658 #ifdef MHD_SOCKETS_KIND_POSIX
   1659   d->net.cfg.max_fd_num = s->fd_number_limit;
   1660 #endif /* MHD_SOCKETS_KIND_POSIX */
   1661 
   1662   ret = daemon_choose_and_preinit_events (d, s);
   1663   if (MHD_SC_OK != ret)
   1664     return ret;
   1665 
   1666   mhd_assert (mhd_POLL_TYPE_NOT_SET_YET != d->events.poll_type);
   1667 
   1668   /* No direct return of error codes is allowed beyond this point.
   1669      Deinit/cleanup must be performed before return of any error. */
   1670 
   1671 #if defined(MHD_SOCKETS_KIND_POSIX) && defined(MHD_SUPPORT_SELECT)
   1672   if (mhd_POLL_TYPE_SELECT == d->events.poll_type)
   1673   {
   1674     if ((MHD_INVALID_SOCKET == d->net.cfg.max_fd_num)
   1675         || (FD_SETSIZE < d->net.cfg.max_fd_num))
   1676       d->net.cfg.max_fd_num = FD_SETSIZE;
   1677   }
   1678 #endif /* MHD_SOCKETS_KIND_POSIX && MHD_SUPPORT_SELECT */
   1679 
   1680   if (MHD_SC_OK == ret)
   1681   {
   1682     ret = create_bind_listen_stream_socket (d, s);
   1683 
   1684     if (MHD_SC_OK == ret)
   1685     {
   1686       if ((MHD_INVALID_SOCKET != d->net.listen.fd)
   1687           && !d->net.listen.non_block
   1688           && (mhd_D_HAS_EDGE_TRIGG (d)
   1689               || mhd_WM_INT_IS_THREAD_POOL (d->wmode_int)))
   1690       {
   1691         mhd_LOG_MSG (d, MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE, \
   1692                      "The selected daemon work mode requires listening socket "
   1693                      "in non-blocking mode");
   1694         ret = MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE;
   1695       }
   1696 
   1697       if (MHD_SC_OK == ret)
   1698       {
   1699         if ((MHD_INVALID_SOCKET != d->net.listen.fd)
   1700             && ((0 == d->net.listen.port)
   1701                 || (mhd_SOCKET_TYPE_UNKNOWN == d->net.listen.type)))
   1702           detect_listen_type_and_port (d);
   1703 
   1704 #ifndef NDEBUG
   1705         d->dbg.net_inited = true;
   1706 #endif
   1707         return MHD_SC_OK; /* Success exit point */
   1708       }
   1709 
   1710       /* Below is a cleanup path */
   1711       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1712         mhd_socket_close (d->net.listen.fd);
   1713     }
   1714   }
   1715 
   1716 #ifdef MHD_SUPPORT_EPOLL
   1717   /* Special case for epoll: epoll FD is probed early in events
   1718      pre-initialisation and is not moved to events epoll FD therefore
   1719      it needs cleanup here */
   1720   if (mhd_POLL_TYPE_EPOLL == d->events.poll_type)
   1721   {
   1722     mhd_assert (MHD_INVALID_SOCKET != d->events.data.epoll.early_fd);
   1723     close (d->events.data.epoll.early_fd);
   1724   }
   1725 #endif /* MHD_SUPPORT_EPOLL */
   1726 
   1727   mhd_assert (MHD_SC_OK != ret);
   1728 
   1729   return ret;
   1730 }
   1731 
   1732 
   1733 /**
   1734  * Deinitialise daemon's network data
   1735  * @param d the daemon object
   1736  */
   1737 MHD_FN_PAR_NONNULL_ (1) static void
   1738 daemon_deinit_net (struct MHD_Daemon *restrict d)
   1739 {
   1740   mhd_assert (d->dbg.net_inited);
   1741   mhd_assert (!d->dbg.net_deinited);
   1742   mhd_assert (mhd_POLL_TYPE_NOT_SET_YET != d->events.poll_type);
   1743 #ifdef MHD_SUPPORT_EPOLL
   1744   /* Special case for epoll: epoll FD is probed early in events
   1745      pre-initialisation and could be not moved yet to events epoll FD
   1746      therefore it needs cleanup here */
   1747   if ((mhd_POLL_TYPE_EPOLL == d->events.poll_type)
   1748       && (MHD_INVALID_SOCKET != d->events.data.epoll.early_fd))
   1749   {
   1750     mhd_assert (0 < d->events.data.epoll.early_fd);
   1751     close (d->events.data.epoll.early_fd);
   1752   }
   1753 #endif /* MHD_SUPPORT_EPOLL */
   1754   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1755     mhd_socket_close (d->net.listen.fd);
   1756 
   1757 #ifndef NDEBUG
   1758   d->dbg.net_deinited = true;
   1759 #endif
   1760 }
   1761 
   1762 
   1763 #if 0
   1764 void
   1765 dauth_init (struct MHD_Daemon *restrict d,
   1766             struct DaemonOptions *restrict s)
   1767 {
   1768   mhd_assert ((NULL == s->random_entropy.v_buf) \
   1769               || (0 != s->random_entropy.v_buf_size));
   1770   mhd_assert ((0 == s->random_entropy.v_buf_size) \
   1771               || (NULL != s->random_entropy.v_buf));
   1772 }
   1773 
   1774 
   1775 #endif
   1776 
   1777 #ifdef MHD_SUPPORT_AUTH_DIGEST
   1778 /**
   1779  * Initialise daemon Digest Auth data
   1780  * @param d the daemon object
   1781  * @param s the user settings
   1782  * @return #MHD_SC_OK on success,
   1783  *         the error code otherwise
   1784  */
   1785 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
   1786   MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1787 daemon_init_auth_digest (struct MHD_Daemon *restrict d,
   1788                          struct DaemonOptions *restrict s)
   1789 {
   1790   enum MHD_StatusCode ret;
   1791   size_t nonces_num;
   1792 
   1793   if (0 == s->random_entropy.v_buf_size)
   1794   {
   1795     /* No initialisation needed */
   1796 #  ifndef HAVE_NULL_PTR_ALL_ZEROS
   1797     d->auth_dg.entropy.data = NULL;
   1798     d->auth_dg.nonces = NULL;
   1799 #  endif
   1800     return MHD_SC_OK;
   1801   }
   1802   nonces_num = s->auth_digest_map_size;
   1803   if (0 == nonces_num)
   1804     nonces_num = 1000;
   1805   d->auth_dg.nonces = (struct mhd_DaemonAuthDigestNonceData *)
   1806                       mhd_calloc (nonces_num, \
   1807                                   sizeof(struct mhd_DaemonAuthDigestNonceData));
   1808   if (NULL == d->auth_dg.nonces)
   1809   {
   1810     mhd_LOG_MSG (d, \
   1811                  MHD_SC_DAEMON_MEM_ALLOC_FAILURE, \
   1812                  "Failed to allocate memory for Digest Auth array");
   1813     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
   1814   }
   1815   d->auth_dg.cfg.nonces_num = nonces_num;
   1816 
   1817   if (!mhd_mutex_init (&(d->auth_dg.nonces_lock)))
   1818   {
   1819     mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   1820                  "Failed to initialise mutex for the Digest Auth data");
   1821     ret = MHD_SC_MUTEX_INIT_FAILURE;
   1822   }
   1823   else
   1824   {
   1825     if (!mhd_atomic_counter_init (&(d->auth_dg.num_gen_nonces), 0))
   1826     {
   1827       mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   1828                    "Failed to initialise mutex for the Digest Auth data");
   1829       ret = MHD_SC_MUTEX_INIT_FAILURE;
   1830     }
   1831     else
   1832     {
   1833       /* Move ownership of the entropy buffer */
   1834       d->auth_dg.entropy.data = (char *)s->random_entropy.v_buf;
   1835       d->auth_dg.entropy.size = s->random_entropy.v_buf_size;
   1836       s->random_entropy.v_buf = NULL;
   1837       s->random_entropy.v_buf_size = 0;
   1838 
   1839       d->auth_dg.cfg.nonce_tmout = s->auth_digest_nonce_timeout;
   1840       if (0 == d->auth_dg.cfg.nonce_tmout)
   1841         d->auth_dg.cfg.nonce_tmout = MHD_AUTH_DIGEST_DEF_TIMEOUT;
   1842       d->auth_dg.cfg.def_max_nc = s->auth_digest_def_max_nc;
   1843       if (0 == d->auth_dg.cfg.def_max_nc)
   1844         d->auth_dg.cfg.def_max_nc = MHD_AUTH_DIGEST_DEF_MAX_NC;
   1845 
   1846       return MHD_SC_OK; /* Success exit point */
   1847     }
   1848     mhd_mutex_destroy_chk (&(d->auth_dg.nonces_lock));
   1849   }
   1850 
   1851   free (d->auth_dg.nonces);
   1852   mhd_assert (MHD_SC_OK != ret);
   1853   return ret; /* Failure exit point */
   1854 }
   1855 
   1856 
   1857 /**
   1858  * Deinitialise daemon Digest Auth data
   1859  * @param d the daemon object
   1860  */
   1861 MHD_FN_PAR_NONNULL_ (1) static void
   1862 daemon_deinit_auth_digest (struct MHD_Daemon *restrict d)
   1863 {
   1864   if (0 == d->auth_dg.entropy.size)
   1865     return; /* Digest Auth not used, nothing to deinitialise */
   1866 
   1867   mhd_assert (NULL != d->auth_dg.entropy.data);
   1868   free (d->auth_dg.entropy.data);
   1869   mhd_atomic_counter_deinit (&(d->auth_dg.num_gen_nonces));
   1870   mhd_mutex_destroy_chk (&(d->auth_dg.nonces_lock));
   1871   mhd_assert (NULL != d->auth_dg.nonces);
   1872   free (d->auth_dg.nonces);
   1873 }
   1874 
   1875 
   1876 #else  /* MHD_SUPPORT_AUTH_DIGEST */
   1877 #  define daemon_init_auth_digest(d, s)  (MHD_SC_OK)
   1878 #  define daemon_deinit_auth_digest(d)  ((void) 0)
   1879 #endif /* MHD_SUPPORT_AUTH_DIGEST */
   1880 
   1881 
   1882 /**
   1883  * Initialise daemon TLS data
   1884  * @param d the daemon object
   1885  * @param s the user settings
   1886  * @return #MHD_SC_OK on success,
   1887  *         the error code otherwise
   1888  */
   1889 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
   1890   MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1891 daemon_init_tls (struct MHD_Daemon *restrict d,
   1892                  struct DaemonOptions *restrict s)
   1893 {
   1894 #ifdef MHD_SUPPORT_HTTPS
   1895   mhd_StatusCodeInt ret;
   1896 #endif /* MHD_SUPPORT_HTTPS */
   1897 
   1898   mhd_assert (!d->dbg.tls_inited);
   1899 #ifdef MHD_SUPPORT_HTTPS
   1900   d->tls = NULL;
   1901 #endif
   1902 
   1903   if (MHD_TLS_BACKEND_NONE == s->tls)
   1904   {
   1905 #ifndef NDEBUG
   1906     d->dbg.tls_inited = true;
   1907 #endif
   1908     return MHD_SC_OK;
   1909   }
   1910 #ifndef MHD_SUPPORT_HTTPS
   1911   mhd_LOG_MSG (d, \
   1912                MHD_SC_TLS_DISABLED, \
   1913                "HTTPS is not supported by this MHD build");
   1914   return MHD_SC_TLS_DISABLED;
   1915 #else  /* MHD_SUPPORT_HTTPS */
   1916   if (1)
   1917   {
   1918     enum mhd_TlsBackendAvailable tls_avail;
   1919 
   1920     tls_avail = mhd_tls_is_backend_available (s);
   1921     if (mhd_TLS_BACKEND_AVAIL_NOT_SUPPORTED == tls_avail)
   1922     {
   1923       mhd_LOG_MSG (d, \
   1924                    MHD_SC_TLS_BACKEND_UNSUPPORTED, \
   1925                    "The requested TLS backend is not supported " \
   1926                    "by this MHD build");
   1927       return MHD_SC_TLS_BACKEND_UNSUPPORTED;
   1928     }
   1929     else if (mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE == tls_avail)
   1930     {
   1931       mhd_LOG_MSG (d, \
   1932                    MHD_SC_TLS_BACKEND_UNAVAILABLE, \
   1933                    "The requested TLS backend is not available");
   1934       return MHD_SC_TLS_BACKEND_UNAVAILABLE;
   1935     }
   1936   }
   1937   ret = mhd_tls_daemon_init (d,
   1938                              mhd_D_HAS_EDGE_TRIGG (d),
   1939                              s,
   1940                              &(d->tls));
   1941   mhd_assert ((MHD_SC_OK == ret) || (NULL == d->tls));
   1942   mhd_assert ((MHD_SC_OK != ret) || (NULL != d->tls));
   1943 #  ifndef NDEBUG
   1944   d->dbg.tls_inited = (MHD_SC_OK == ret);
   1945 #  endif
   1946   return (enum MHD_StatusCode)ret;
   1947 #endif /* MHD_SUPPORT_HTTPS */
   1948 }
   1949 
   1950 
   1951 /**
   1952  * Deinitialise daemon TLS data
   1953  * @param d the daemon object
   1954  */
   1955 MHD_FN_PAR_NONNULL_ (1) static void
   1956 daemon_deinit_tls (struct MHD_Daemon *restrict d)
   1957 {
   1958   mhd_assert (d->dbg.tls_inited);
   1959 #ifdef MHD_SUPPORT_HTTPS
   1960   if (NULL != d->tls)
   1961   {
   1962     mhd_tls_thread_cleanup (d->tls);
   1963     mhd_tls_daemon_deinit (d->tls);
   1964   }
   1965 #elif defined(NDEBUG)
   1966   (void)d;  /* Mute compiler warning */
   1967 #endif
   1968 }
   1969 
   1970 
   1971 /**
   1972  * Initialise large buffer tracking.
   1973  * @param d the daemon object
   1974  * @param s the user settings
   1975  * @return #MHD_SC_OK on success,
   1976  *         the error code otherwise
   1977  */
   1978 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
   1979   MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1980 daemon_init_large_buf (struct MHD_Daemon *restrict d,
   1981                        struct DaemonOptions *restrict s)
   1982 {
   1983   mhd_assert (!mhd_D_HAS_MASTER (d));
   1984   mhd_assert (0 != d->conns.cfg.count_limit);
   1985   mhd_assert (0 != d->conns.cfg.mem_pool_size);
   1986 
   1987   d->req_cfg.large_buf.space_left = s->large_pool_size;
   1988   if (SIZE_MAX == d->req_cfg.large_buf.space_left)
   1989     d->req_cfg.large_buf.space_left =
   1990       (d->conns.cfg.count_limit * d->conns.cfg.mem_pool_size) / 32;   /* Use ~3% of the maximum memory used by connections */
   1991 
   1992 #ifndef NDEBUG
   1993   d->dbg.initial_lbuf_size = d->req_cfg.large_buf.space_left;
   1994 #endif
   1995 
   1996   if (!mhd_mutex_init_short (&(d->req_cfg.large_buf.lock)))
   1997   {
   1998     mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   1999                  "Failed to initialise mutex for the global large buffer.");
   2000     return MHD_SC_MUTEX_INIT_FAILURE;
   2001   }
   2002   return MHD_SC_OK;
   2003 }
   2004 
   2005 
   2006 /**
   2007  * Deinitialise large buffer tracking.
   2008  * @param d the daemon object
   2009  */
   2010 static MHD_FN_PAR_NONNULL_ (1) void
   2011 daemon_deinit_large_buf (struct MHD_Daemon *restrict d)
   2012 {
   2013   /* All large buffer allocations must be freed / deallocated earlier */
   2014   mhd_assert (d->dbg.initial_lbuf_size == d->req_cfg.large_buf.space_left);
   2015   mhd_mutex_destroy_chk (&(d->req_cfg.large_buf.lock));
   2016 }
   2017 
   2018 
   2019 /**
   2020  * Initialise ACME data.
   2021  * @param d the daemon object
   2022  * @param s the user settings
   2023  * @return #MHD_SC_OK on success,
   2024  *         the error code otherwise
   2025  */
   2026 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   2027 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2028 daemon_init_acme (struct MHD_Daemon *restrict d,
   2029                   struct DaemonOptions *restrict s)
   2030 {
   2031   mhd_assert (!mhd_D_HAS_MASTER (d));
   2032 
   2033 #ifndef mhd_HAVE_TLS_ACME
   2034   if (s->acme_alpn_required)
   2035   {
   2036     mhd_LOG_MSG (d, MHD_SC_FEATURE_DISABLED,
   2037                  "ACME ALPN challenge is not supported by this MHD build");
   2038     return MHD_SC_FEATURE_DISABLED;
   2039   }
   2040 #endif /* mhd_HAVE_TLS_ACME */
   2041 
   2042 #ifdef MHD_SUPPORT_ACME
   2043   if (!mhd_D_HAS_TLS (d))
   2044   {
   2045     if (s->acme_alpn_required)
   2046     {
   2047       mhd_LOG_MSG (d, MHD_SC_DAEMON_HAS_TLS_DISABLED,
   2048                    "ACME ALPN challenge requires TLS to be enabled");
   2049       return MHD_SC_DAEMON_HAS_TLS_DISABLED;
   2050     }
   2051   }
   2052 #  ifdef MHD_SUPPORT_HTTPS
   2053   else
   2054   {
   2055     mhd_StatusCodeInt res_i;
   2056     res_i = mhd_daemon_acme_certs_init (d);
   2057     return (enum MHD_StatusCode)res_i;
   2058   }
   2059 #  endif /* MHD_SUPPORT_HTTPS */
   2060 #else  /* ! MHD_SUPPORT_ACME */
   2061   (void)d;  /* Unused */
   2062 #endif /* ! MHD_SUPPORT_ACME */
   2063 
   2064   return MHD_SC_OK; /* Success exit point */
   2065 }
   2066 
   2067 
   2068 #ifdef MHD_SUPPORT_ACME
   2069 
   2070 /**
   2071  * Deinitialise ACME data.
   2072  * @param d the daemon object
   2073  */
   2074 static MHD_FN_PAR_NONNULL_ (1) void
   2075 daemon_deinit_acme (struct MHD_Daemon *restrict d)
   2076 {
   2077   mhd_assert (!mhd_D_HAS_MASTER (d));
   2078 
   2079 #  ifdef MHD_SUPPORT_HTTPS
   2080   if (mhd_D_HAS_TLS (d))
   2081     mhd_daemon_acme_certs_deinit (d);
   2082 #  else
   2083   (void)d;  /* Unused */
   2084 #  endif
   2085 }
   2086 
   2087 
   2088 #else  /* ! MHD_SUPPORT_ACME */
   2089 #  define daemon_deinit_acme(d)   ((void) d)
   2090 #endif /* ! MHD_SUPPORT_ACME */
   2091 
   2092 #ifdef MHD_SUPPORT_KQUEUE
   2093 
   2094 /**
   2095  * Initialise daemon's kqueue FD
   2096  * @param d the daemon object
   2097  * @return #MHD_SC_OK on success,
   2098  *         the error code otherwise
   2099  */
   2100 static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
   2101 init_kqueue_fd (struct MHD_Daemon *restrict d)
   2102 {
   2103   int kq_fd;
   2104   mhd_assert (mhd_POLL_TYPE_KQUEUE == d->events.poll_type);
   2105   mhd_assert (!mhd_WM_INT_IS_THREAD_PER_CONN (d->wmode_int));
   2106   mhd_assert (d->dbg.net_inited);
   2107   mhd_assert (MHD_INVALID_SOCKET == d->events.data.kq.kq_fd);
   2108   mhd_assert (NULL == d->events.data.kq.kes);
   2109   mhd_assert (0u == d->events.data.kq.num_elements);
   2110 
   2111   kq_fd = mhd_kqueue ();
   2112   if (0 > kq_fd)
   2113   {
   2114     mhd_LOG_MSG (d, MHD_SC_KQUEUE_FD_CREATE_FAILED, \
   2115                  "Failed to create kqueue FD");
   2116     return MHD_SC_KQUEUE_FD_CREATE_FAILED; /* Failure exit point */
   2117   }
   2118 
   2119   if (!mhd_FD_FITS_DAEMON (d, kq_fd))
   2120   {
   2121     mhd_LOG_MSG (d, MHD_SC_KQUEUE_FD_OUTSIDE_OF_SET_RANGE, \
   2122                  "The kqueue FD value is higher than allowed");
   2123     (void)close (kq_fd);
   2124     return MHD_SC_KQUEUE_FD_OUTSIDE_OF_SET_RANGE; /* Failure exit point */
   2125   }
   2126 
   2127   if (!mhd_KQUEUE_HAS_CLOEXEC_SET ())
   2128   {
   2129     if (!mhd_socket_noninheritable (kq_fd))
   2130       mhd_LOG_MSG (d, MHD_SC_KQUEUE_FD_SET_NOINHERIT_FAILED, \
   2131                    "Failed to make kqueue FD non-inheritable");
   2132   }
   2133   d->events.data.kq.kq_fd = kq_fd;
   2134 
   2135   return MHD_SC_OK; /* Success exit point */
   2136 }
   2137 
   2138 
   2139 /**
   2140  * Deinitialise daemon's kqueue FD
   2141  * @param d the daemon object
   2142  */
   2143 MHD_FN_PAR_NONNULL_ (1) static void
   2144 deinit_kqueue_fd (struct MHD_Daemon *restrict d)
   2145 {
   2146   mhd_assert (mhd_POLL_TYPE_KQUEUE == d->events.poll_type);
   2147   mhd_assert (0 < d->events.data.kq.kq_fd);
   2148   close (d->events.data.kq.kq_fd);
   2149 }
   2150 
   2151 
   2152 #endif /* MHD_SUPPORT_KQUEUE */
   2153 
   2154 
   2155 /**
   2156  * Initialise daemon's events polling FD (if used by polling function)
   2157  * @param d the daemon object
   2158  * @return #MHD_SC_OK on success,
   2159  *         the error code otherwise
   2160  */
   2161 static MHD_FN_PAR_NONNULL_ (1)
   2162 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2163 init_events_fd (struct MHD_Daemon *restrict d)
   2164 {
   2165   enum MHD_StatusCode res;
   2166 
   2167   res = MHD_SC_OK;
   2168   switch (d->events.poll_type)
   2169   {
   2170   case mhd_POLL_TYPE_EXT:
   2171     break;
   2172 #ifdef MHD_SUPPORT_SELECT
   2173   case mhd_POLL_TYPE_SELECT:
   2174     break;
   2175 #endif /* MHD_SUPPORT_SELECT */
   2176 #ifdef MHD_SUPPORT_POLL
   2177   case mhd_POLL_TYPE_POLL:
   2178     break;
   2179 #endif /* MHD_SUPPORT_POLL */
   2180 #ifdef MHD_SUPPORT_EPOLL
   2181   case mhd_POLL_TYPE_EPOLL:
   2182     res = init_epoll_fd (d,
   2183                          false,
   2184                          true);
   2185     break;
   2186 #endif /* MHD_SUPPORT_EPOLL */
   2187 #ifdef MHD_SUPPORT_KQUEUE
   2188   case mhd_POLL_TYPE_KQUEUE:
   2189     res = init_kqueue_fd (d);
   2190     break;
   2191 #endif /* MHD_SUPPORT_KQUEUE */
   2192 #ifndef MHD_SUPPORT_SELECT
   2193   case mhd_POLL_TYPE_SELECT:
   2194 #endif /* ! MHD_SUPPORT_SELECT */
   2195 #ifndef MHD_SUPPORT_POLL
   2196   case mhd_POLL_TYPE_POLL:
   2197 #endif /* ! MHD_SUPPORT_POLL */
   2198   case mhd_POLL_TYPE_NOT_SET_YET:
   2199   default:
   2200     mhd_UNREACHABLE ();
   2201     return MHD_SC_INTERNAL_ERROR;
   2202   }
   2203 
   2204 #ifndef NDEBUG
   2205   if (MHD_SC_OK == res)
   2206     d->dbg.events_fd_inited = true;
   2207 #endif /* ! NDEBUG */
   2208 
   2209   return res;
   2210 }
   2211 
   2212 
   2213 /**
   2214  * Deinitialise daemon's events polling FD (if used by polling function)
   2215  * @param d the daemon object
   2216  */
   2217 static MHD_FN_PAR_NONNULL_ (1) void
   2218 deinit_events_fd (struct MHD_Daemon *restrict d)
   2219 {
   2220   mhd_assert (d->dbg.events_fd_inited);
   2221 
   2222   switch (d->events.poll_type)
   2223   {
   2224   case mhd_POLL_TYPE_EXT:
   2225     return;
   2226 #ifdef MHD_SUPPORT_SELECT
   2227   case mhd_POLL_TYPE_SELECT:
   2228     return;
   2229 #endif /* MHD_SUPPORT_SELECT */
   2230 #ifdef MHD_SUPPORT_POLL
   2231   case mhd_POLL_TYPE_POLL:
   2232     return;
   2233 #endif /* MHD_SUPPORT_POLL */
   2234 #ifdef MHD_SUPPORT_EPOLL
   2235   case mhd_POLL_TYPE_EPOLL:
   2236     deinit_epoll_fd (d);
   2237     return;
   2238 #endif /* MHD_SUPPORT_EPOLL */
   2239 #ifdef MHD_SUPPORT_KQUEUE
   2240   case mhd_POLL_TYPE_KQUEUE:
   2241     deinit_kqueue_fd (d);
   2242     return;
   2243 #endif /* MHD_SUPPORT_KQUEUE */
   2244 #ifndef MHD_SUPPORT_SELECT
   2245   case mhd_POLL_TYPE_SELECT:
   2246 #endif /* ! MHD_SUPPORT_SELECT */
   2247 #ifndef MHD_SUPPORT_POLL
   2248   case mhd_POLL_TYPE_POLL:
   2249 #endif /* ! MHD_SUPPORT_POLL */
   2250   case mhd_POLL_TYPE_NOT_SET_YET:
   2251   default:
   2252     mhd_UNREACHABLE ();
   2253   }
   2254   return;
   2255 }
   2256 
   2257 
   2258 /**
   2259  * Finish initialisation of events processing
   2260  * @param d the daemon object
   2261  * @return #MHD_SC_OK on success,
   2262  *         the error code otherwise
   2263  */
   2264 static MHD_FN_PAR_NONNULL_ (1)
   2265 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2266 allocate_events (struct MHD_Daemon *restrict d)
   2267 {
   2268 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_EPOLL)
   2269   /**
   2270    * The number of elements to be monitored by sockets polling function
   2271    */
   2272   unsigned int num_fd_elems;
   2273   num_fd_elems = 0;
   2274 #  ifdef MHD_SUPPORT_THREADS
   2275   ++num_fd_elems;  /* For the ITC */
   2276 #  endif
   2277   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2278     ++num_fd_elems;  /* For the listening socket */
   2279   if (!mhd_D_HAS_THR_PER_CONN (d))
   2280     num_fd_elems += d->conns.cfg.count_limit;
   2281 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_EPOLL */
   2282 
   2283   mhd_assert (0 != d->conns.cfg.count_limit);
   2284   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2285   mhd_assert (!d->dbg.events_allocated);
   2286 
   2287   mhd_DLINKEDL_INIT_LIST (&(d->events), proc_ready);
   2288 
   2289   switch (d->events.poll_type)
   2290   {
   2291   case mhd_POLL_TYPE_EXT:
   2292     mhd_assert (NULL != d->events.data.extr.cb_data.cb);
   2293     /* Nothing to do: allocation is not needed */
   2294 #ifndef NDEBUG
   2295     d->dbg.events_allocated = true;
   2296 #endif
   2297     return MHD_SC_OK; /* Success exit point */
   2298     break;
   2299 #ifdef MHD_SUPPORT_SELECT
   2300   case mhd_POLL_TYPE_SELECT:
   2301     /* The pointers have been set to NULL during pre-initialisations of the events */
   2302     mhd_assert (NULL == d->events.data.select.rfds);
   2303     mhd_assert (NULL == d->events.data.select.wfds);
   2304     mhd_assert (NULL == d->events.data.select.efds);
   2305     d->events.data.select.rfds = (fd_set *)malloc (sizeof(fd_set));
   2306     if (NULL != d->events.data.select.rfds)
   2307     {
   2308       d->events.data.select.wfds = (fd_set *)malloc (sizeof(fd_set));
   2309       if (NULL != d->events.data.select.wfds)
   2310       {
   2311         d->events.data.select.efds = (fd_set *)malloc (sizeof(fd_set));
   2312         if (NULL != d->events.data.select.efds)
   2313         {
   2314 #  ifndef NDEBUG
   2315           d->dbg.num_events_elements = FD_SETSIZE;
   2316           d->dbg.events_allocated = true;
   2317 #  endif
   2318           return MHD_SC_OK; /* Success exit point */
   2319         }
   2320 
   2321         free (d->events.data.select.wfds);
   2322       }
   2323       free (d->events.data.select.rfds);
   2324     }
   2325     mhd_LOG_MSG (d, MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE, \
   2326                  "Failed to allocate memory for fd_sets for the daemon");
   2327     return MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE;
   2328     break;
   2329 #endif /* MHD_SUPPORT_SELECT */
   2330 #ifdef MHD_SUPPORT_POLL
   2331   case mhd_POLL_TYPE_POLL:
   2332     /* The pointers have been set to NULL during pre-initialisations of the events */
   2333     mhd_assert (NULL == d->events.data.poll.fds);
   2334     mhd_assert (NULL == d->events.data.poll.rel);
   2335     if ((num_fd_elems > d->conns.cfg.count_limit) /* Check for value overflow */
   2336         || (mhd_D_HAS_THR_PER_CONN (d)))
   2337     {
   2338       d->events.data.poll.fds =
   2339         (struct pollfd *)malloc (sizeof(struct pollfd) * num_fd_elems);
   2340       if (NULL != d->events.data.poll.fds)
   2341       {
   2342         d->events.data.poll.rel =
   2343           (union mhd_SocketRelation *)malloc (sizeof(union mhd_SocketRelation)
   2344                                               * num_fd_elems);
   2345         if (NULL != d->events.data.poll.rel)
   2346         {
   2347 #  ifndef NDEBUG
   2348           d->dbg.num_events_elements = num_fd_elems;
   2349           d->dbg.events_allocated = true;
   2350 #  endif
   2351           return MHD_SC_OK; /* Success exit point */
   2352         }
   2353         free (d->events.data.poll.fds);
   2354       }
   2355     }
   2356     mhd_LOG_MSG (d, MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE, \
   2357                  "Failed to allocate memory for poll fds for the daemon");
   2358     return MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE;
   2359     break;
   2360 #endif /* MHD_SUPPORT_POLL */
   2361 #ifdef MHD_SUPPORT_EPOLL
   2362   case mhd_POLL_TYPE_EPOLL:
   2363     mhd_ASSUME (!mhd_D_HAS_THR_PER_CONN (d));
   2364     /* The event FD has been created by event FD initialisation */
   2365     mhd_assert (MHD_INVALID_SOCKET != d->events.data.epoll.e_fd);
   2366     mhd_assert (MHD_INVALID_SOCKET == d->events.data.epoll.early_fd);
   2367     /* The pointer has been set to NULL during pre-initialisation of the events */
   2368     mhd_assert (NULL == d->events.data.epoll.events);
   2369     mhd_assert (0 == d->events.data.epoll.num_elements);
   2370     if (1)
   2371     {
   2372       const unsigned int upper_limit = (sizeof(void *) >= 8) ? 4096u : 1024u;
   2373 
   2374       mhd_assert (0 < (int)upper_limit);
   2375       mhd_assert (upper_limit == (unsigned int)(size_t)upper_limit);
   2376 
   2377       if (num_fd_elems < d->conns.cfg.count_limit) /* Check for value overflow */
   2378         num_fd_elems = upper_limit;
   2379       /* Trade neglectable performance penalty for memory saving */
   2380       /* Very large amount of new events processed in batches */
   2381       else if (num_fd_elems > upper_limit)
   2382         num_fd_elems = upper_limit;
   2383 
   2384       d->events.data.epoll.events =
   2385         (struct epoll_event *)malloc (sizeof(struct epoll_event)
   2386                                       * num_fd_elems);
   2387       if (NULL != d->events.data.epoll.events)
   2388       {
   2389         d->events.data.epoll.num_elements = num_fd_elems;
   2390 #  ifndef NDEBUG
   2391         d->dbg.num_events_elements = num_fd_elems;
   2392         d->dbg.events_allocated = true;
   2393 #  endif
   2394         return MHD_SC_OK; /* Success exit point */
   2395       }
   2396     }
   2397     mhd_LOG_MSG (d, MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE, \
   2398                  "Failed to allocate memory for epoll events for the daemon");
   2399     return MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE;
   2400     break;
   2401 #endif /* MHD_SUPPORT_EPOLL */
   2402 #ifdef MHD_SUPPORT_KQUEUE
   2403   case mhd_POLL_TYPE_KQUEUE:
   2404     mhd_ASSUME (!mhd_D_HAS_THR_PER_CONN (d));
   2405     /* The event FD has been created by event FD initialisation */
   2406     mhd_assert (0 < d->events.data.kq.kq_fd);
   2407     /* The pointer has been set to NULL during pre-initialisation of the events */
   2408     mhd_assert (NULL == d->events.data.kq.kes);
   2409     mhd_assert (0u == d->events.data.kq.num_elements);
   2410     if (1)
   2411     {
   2412       const unsigned int upper_limit = (sizeof(void *) >= 8) ? 4096u : 1024u;
   2413       unsigned int num_event_elems = 0;
   2414 
   2415       mhd_assert (0 < (int)upper_limit);
   2416       mhd_assert (upper_limit == (unsigned int)(size_t)upper_limit);
   2417 
   2418 #  ifdef MHD_SUPPORT_THREADS
   2419       ++num_event_elems;  /* For the ITC */
   2420 #  endif
   2421       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2422         ++num_event_elems;  /* For the listening socket */
   2423 
   2424       /* kqueue needs slots for individual combinations of FD + filter (send/recv)  */
   2425       num_event_elems += 2 * d->conns.cfg.count_limit;
   2426       if (d->conns.cfg.count_limit > (num_event_elems / 2)) /* Check for overflow */
   2427         num_event_elems = upper_limit;
   2428       /* Trade neglectable performance penalty for memory saving */
   2429       /* Very large amount of new events processed in batches */
   2430       else if (upper_limit < num_event_elems)
   2431         num_event_elems = upper_limit;
   2432 
   2433       /* Make sure that run-time overflow check is easy */
   2434       mhd_assert (((int)num_event_elems) > 0);
   2435       mhd_assert (((int)(num_event_elems + 1)) > 0);
   2436 
   2437       d->events.data.kq.kes =
   2438         (struct kevent *)malloc (sizeof(struct kevent) * num_event_elems);
   2439       if (NULL != d->events.data.kq.kes)
   2440       {
   2441         d->events.data.kq.num_elements = num_event_elems;
   2442 #  ifndef NDEBUG
   2443         d->dbg.num_events_elements = num_event_elems;
   2444         d->dbg.events_allocated = true;
   2445 #  endif
   2446         return MHD_SC_OK; /* Success exit point */
   2447       }
   2448     }
   2449     mhd_LOG_MSG (d, MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE, \
   2450                  "Failed to allocate memory for kqueue events for the daemon");
   2451     return MHD_SC_EVENTS_MEMORY_ALLOCATE_FAILURE;
   2452     break;
   2453 #endif /* MHD_SUPPORT_KQUEUE */
   2454 #ifndef MHD_SUPPORT_SELECT
   2455   case mhd_POLL_TYPE_SELECT:
   2456 #endif /* ! MHD_SUPPORT_SELECT */
   2457 #ifndef MHD_SUPPORT_POLL
   2458   case mhd_POLL_TYPE_POLL:
   2459 #endif /* ! MHD_SUPPORT_POLL */
   2460   case mhd_POLL_TYPE_NOT_SET_YET:
   2461   default:
   2462     mhd_UNREACHABLE ();
   2463     break;
   2464   }
   2465   mhd_UNREACHABLE ();
   2466   return MHD_SC_INTERNAL_ERROR;
   2467 }
   2468 
   2469 
   2470 /**
   2471  * Deallocate events data
   2472  * @param d the daemon object
   2473  */
   2474 static MHD_FN_PAR_NONNULL_ (1) void
   2475 deallocate_events (struct MHD_Daemon *restrict d)
   2476 {
   2477   mhd_assert (d->dbg.events_allocated);
   2478   mhd_assert (0 != d->conns.cfg.count_limit);
   2479   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2480   switch (d->events.poll_type)
   2481   {
   2482   case mhd_POLL_TYPE_EXT:
   2483     break;
   2484 #ifdef MHD_SUPPORT_SELECT
   2485   case mhd_POLL_TYPE_SELECT:
   2486     mhd_assert (NULL != d->events.data.select.efds);
   2487     mhd_assert (NULL != d->events.data.select.wfds);
   2488     mhd_assert (NULL != d->events.data.select.rfds);
   2489     free (d->events.data.select.efds);
   2490     free (d->events.data.select.wfds);
   2491     free (d->events.data.select.rfds);
   2492     break;
   2493 #endif /* MHD_SUPPORT_SELECT */
   2494 #ifdef MHD_SUPPORT_POLL
   2495   case mhd_POLL_TYPE_POLL:
   2496     mhd_assert (NULL != d->events.data.poll.rel);
   2497     mhd_assert (NULL != d->events.data.poll.fds);
   2498     free (d->events.data.poll.rel);
   2499     free (d->events.data.poll.fds);
   2500     break;
   2501 #endif /* MHD_SUPPORT_POLL */
   2502 #ifdef MHD_SUPPORT_EPOLL
   2503   case mhd_POLL_TYPE_EPOLL:
   2504     mhd_assert (0 != d->events.data.epoll.num_elements);
   2505     mhd_assert (NULL != d->events.data.epoll.events);
   2506     free (d->events.data.epoll.events);
   2507     break;
   2508 #endif /* MHD_SUPPORT_EPOLL */
   2509 #ifdef MHD_SUPPORT_KQUEUE
   2510   case mhd_POLL_TYPE_KQUEUE:
   2511     mhd_assert (0 != d->events.data.kq.num_elements);
   2512     mhd_assert (NULL != d->events.data.kq.kes);
   2513     free (d->events.data.kq.kes);
   2514     break;
   2515 #endif /* MHD_SUPPORT_KQUEUE */
   2516 #ifndef MHD_SUPPORT_SELECT
   2517   case mhd_POLL_TYPE_SELECT:
   2518 #endif /* ! MHD_SUPPORT_SELECT */
   2519 #ifndef MHD_SUPPORT_POLL
   2520   case mhd_POLL_TYPE_POLL:
   2521 #endif /* ! MHD_SUPPORT_POLL */
   2522   case mhd_POLL_TYPE_NOT_SET_YET:
   2523   default:
   2524     mhd_UNREACHABLE_D ("Wrong workflow");
   2525   }
   2526 #ifndef NDEBUG
   2527   d->dbg.events_allocated = false;
   2528 #endif
   2529   return;
   2530 }
   2531 
   2532 
   2533 /**
   2534  * Initialise daemon's ITC
   2535  * @param d the daemon object
   2536  * @return #MHD_SC_OK on success,
   2537  *         the error code otherwise
   2538  */
   2539 static MHD_FN_PAR_NONNULL_ (1)
   2540 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2541 init_itc (struct MHD_Daemon *restrict d)
   2542 {
   2543   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   2544   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2545 #ifdef MHD_SUPPORT_THREADS
   2546   // TODO: add and process "thread unsafe" daemon's option
   2547   if (!mhd_itc_init (&(d->threading.itc)))
   2548   {
   2549 #  if defined(MHD_ITC_EVENTFD_)
   2550     mhd_LOG_MSG ( \
   2551       d, MHD_SC_ITC_INITIALIZATION_FAILED, \
   2552       "Failed to initialise eventFD for inter-thread communication");
   2553 #  elif defined(MHD_ITC_PIPE_)
   2554     mhd_LOG_MSG ( \
   2555       d, MHD_SC_ITC_INITIALIZATION_FAILED, \
   2556       "Failed to create a pipe for inter-thread communication");
   2557 #  elif defined(MHD_ITC_SOCKETPAIR_)
   2558     mhd_LOG_MSG ( \
   2559       d, MHD_SC_ITC_INITIALIZATION_FAILED, \
   2560       "Failed to create a socketpair for inter-thread communication");
   2561 #  else
   2562 #    warning Missing expicit handling of the ITC type
   2563     mhd_LOG_MSG ( \
   2564       d, MHD_SC_ITC_INITIALIZATION_FAILED, \
   2565       "Failed to initialise inter-thread communication");
   2566 #  endif
   2567     return MHD_SC_ITC_INITIALIZATION_FAILED;
   2568   }
   2569   if (!mhd_FD_FITS_DAEMON (d, mhd_itc_r_fd (d->threading.itc)))
   2570   {
   2571     mhd_LOG_MSG (d, MHD_SC_ITC_FD_OUTSIDE_OF_SET_RANGE, \
   2572                  "The inter-thread communication FD value is " \
   2573                  "higher than allowed");
   2574     (void)mhd_itc_destroy (d->threading.itc);
   2575     mhd_itc_set_invalid (&(d->threading.itc));
   2576     return MHD_SC_ITC_FD_OUTSIDE_OF_SET_RANGE;
   2577   }
   2578 #else  /* ! MHD_SUPPORT_THREADS */
   2579   (void)d;  /* Unused */
   2580 #endif /* ! MHD_SUPPORT_THREADS */
   2581   return MHD_SC_OK;
   2582 }
   2583 
   2584 
   2585 /**
   2586  * Deallocate events data
   2587  * @param d the daemon object
   2588  */
   2589 static MHD_FN_PAR_NONNULL_ (1) void
   2590 deinit_itc (struct MHD_Daemon *restrict d)
   2591 {
   2592   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   2593   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2594 #ifdef MHD_SUPPORT_THREADS
   2595   // TODO: add and process "thread unsafe" daemon's option
   2596   mhd_assert (!mhd_ITC_IS_INVALID (d->threading.itc));
   2597   (void)mhd_itc_destroy (d->threading.itc);
   2598 #else  /* ! MHD_SUPPORT_THREADS */
   2599   (void)d;  /* Unused */
   2600 #endif /* ! MHD_SUPPORT_THREADS */
   2601 }
   2602 
   2603 
   2604 /**
   2605  * The final part of events initialisation: pre-add ITC and listening FD to
   2606  * the monitored items (if supported by monitoring syscall).
   2607  * @param d the daemon object
   2608  * @return #MHD_SC_OK on success,
   2609  *         the error code otherwise
   2610  */
   2611 static MHD_FN_PAR_NONNULL_ (1)
   2612 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2613 init_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
   2614 {
   2615   mhd_assert (d->dbg.net_inited);
   2616   mhd_assert (!d->dbg.net_deinited);
   2617   mhd_assert (d->dbg.events_allocated);
   2618   mhd_assert (!d->dbg.events_fully_inited);
   2619   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2620 #ifdef MHD_SUPPORT_THREADS
   2621   mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   2622 #endif
   2623 
   2624   d->events.accept_pending = false;
   2625 
   2626   switch (d->events.poll_type)
   2627   {
   2628   case mhd_POLL_TYPE_EXT:
   2629     mhd_assert (NULL != d->events.data.extr.cb_data.cb);
   2630 #ifdef MHD_SUPPORT_THREADS
   2631     d->events.data.extr.itc_data.is_active = false;
   2632     d->events.data.extr.itc_data.is_broken = false;
   2633 #endif /* MHD_SUPPORT_THREADS */
   2634     if (!d->events.data.extr.reg_all)
   2635     {
   2636       bool itc_reg_succeed;
   2637 
   2638       /* Register daemon's FDs now */
   2639 #ifdef MHD_SUPPORT_THREADS
   2640       d->events.data.extr.itc_data.app_cntx =
   2641         mhd_daemon_extr_event_reg (d,
   2642                                    mhd_itc_r_fd (d->threading.itc),
   2643                                    MHD_FD_STATE_RECV_EXCEPT,
   2644                                    NULL,
   2645                                    (struct MHD_EventUpdateContext *)
   2646                                    mhd_SOCKET_REL_MARKER_ITC);
   2647       itc_reg_succeed = (NULL != d->events.data.extr.itc_data.app_cntx);
   2648 #else  /* ! MHD_SUPPORT_THREADS */
   2649       itc_reg_succeed = true;
   2650 #endif /* ! MHD_SUPPORT_THREADS */
   2651       if (itc_reg_succeed)
   2652       {
   2653         if (MHD_INVALID_SOCKET == d->net.listen.fd)
   2654         {
   2655           d->events.data.extr.listen_data.app_cntx = NULL;
   2656           return MHD_SC_OK; /* Success exit point */
   2657         }
   2658 
   2659         /* Need to register the listen FD */
   2660         d->events.data.extr.listen_data.app_cntx =
   2661           mhd_daemon_extr_event_reg (d,
   2662                                      d->net.listen.fd,
   2663                                      MHD_FD_STATE_RECV_EXCEPT,
   2664                                      NULL,
   2665                                      (struct MHD_EventUpdateContext *)
   2666                                      mhd_SOCKET_REL_MARKER_LISTEN);
   2667         if (NULL != d->events.data.extr.listen_data.app_cntx)
   2668           return MHD_SC_OK; /* Success exit point */
   2669 
   2670         /* Below is a clean-up path for 'case mhd_POLL_TYPE_EXT:' */
   2671 #ifdef MHD_SUPPORT_THREADS
   2672         /* De-register ITC FD */
   2673         (void)mhd_daemon_extr_event_reg (d,
   2674                                          mhd_itc_r_fd (d->threading.itc),
   2675                                          MHD_FD_STATE_NONE,
   2676                                          d->events.data.extr.itc_data.app_cntx,
   2677                                          (struct MHD_EventUpdateContext *)
   2678                                          mhd_SOCKET_REL_MARKER_ITC);
   2679         d->events.data.extr.itc_data.app_cntx = NULL;
   2680 #endif /* MHD_SUPPORT_THREADS */
   2681       }
   2682 
   2683       mhd_LOG_MSG (d, MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE, \
   2684                    "Failed to register daemon FDs in the application "
   2685                    "(external events) monitoring.");
   2686       return MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE;
   2687     }
   2688     else
   2689     {
   2690       /* Daemons FDs are repeatedly registered every processing cycle */
   2691 #ifdef MHD_SUPPORT_THREADS
   2692       d->events.data.extr.itc_data.app_cntx = NULL;
   2693 #endif /* MHD_SUPPORT_THREADS */
   2694       d->events.data.extr.listen_data.app_cntx = NULL;
   2695       return MHD_SC_OK;
   2696     }
   2697     break;
   2698 #ifdef MHD_SUPPORT_SELECT
   2699   case mhd_POLL_TYPE_SELECT:
   2700     mhd_assert (NULL != d->events.data.select.rfds);
   2701     mhd_assert (NULL != d->events.data.select.wfds);
   2702     mhd_assert (NULL != d->events.data.select.efds);
   2703     /* Nothing to do when using 'select()' */
   2704     return MHD_SC_OK;
   2705     break;
   2706 #endif /* MHD_SUPPORT_SELECT */
   2707 #ifdef MHD_SUPPORT_POLL
   2708   case mhd_POLL_TYPE_POLL:
   2709     mhd_assert (NULL != d->events.data.poll.fds);
   2710     mhd_assert (NULL != d->events.data.poll.rel);
   2711     if (1)
   2712     {
   2713       unsigned int i;
   2714       i = 0;
   2715 #  ifdef MHD_SUPPORT_THREADS
   2716       d->events.data.poll.fds[i].fd = mhd_itc_r_fd (d->threading.itc);
   2717       d->events.data.poll.fds[i].events = POLLIN;
   2718       d->events.data.poll.rel[i].fd_id = mhd_SOCKET_REL_MARKER_ITC;
   2719       ++i;
   2720 #  endif
   2721       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2722       {
   2723         d->events.data.poll.fds[i].fd = d->net.listen.fd;
   2724         d->events.data.poll.fds[i].events = POLLIN;
   2725         d->events.data.poll.rel[i].fd_id = mhd_SOCKET_REL_MARKER_LISTEN;
   2726       }
   2727     }
   2728     return MHD_SC_OK;
   2729     break;
   2730 #endif /* MHD_SUPPORT_POLL */
   2731 #ifdef MHD_SUPPORT_EPOLL
   2732   case mhd_POLL_TYPE_EPOLL:
   2733     mhd_assert (MHD_INVALID_SOCKET != d->events.data.epoll.e_fd);
   2734     mhd_assert (MHD_INVALID_SOCKET == d->events.data.epoll.early_fd);
   2735     mhd_assert (NULL != d->events.data.epoll.events);
   2736     mhd_assert (0 < d->events.data.epoll.num_elements);
   2737     if (1)
   2738     {
   2739       struct epoll_event reg_event;
   2740 #  ifdef MHD_SUPPORT_THREADS
   2741       reg_event.events = EPOLLIN | EPOLLET;
   2742       reg_event.data.u64 = (uint64_t)mhd_SOCKET_REL_MARKER_ITC;  /* uint64_t is used in the epoll header */
   2743       if (0 != epoll_ctl (d->events.data.epoll.e_fd, EPOLL_CTL_ADD,
   2744                           mhd_itc_r_fd (d->threading.itc), &reg_event))
   2745       {
   2746         mhd_LOG_MSG (d, MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE, \
   2747                      "Failed to add ITC FD to the epoll monitoring.");
   2748         return MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE;
   2749       }
   2750       mhd_dbg_print_fd_mon_req ("ITC", \
   2751                                 mhd_itc_r_fd (d->threading.itc), \
   2752                                 true, \
   2753                                 false, \
   2754                                 false);
   2755 #  endif
   2756       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2757       {
   2758         reg_event.events = EPOLLIN;
   2759         reg_event.data.u64 = (uint64_t)mhd_SOCKET_REL_MARKER_LISTEN;  /* uint64_t is used in the epoll header */
   2760         if (0 != epoll_ctl (d->events.data.epoll.e_fd, EPOLL_CTL_ADD,
   2761                             d->net.listen.fd, &reg_event))
   2762         {
   2763           mhd_LOG_MSG (d, MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE, \
   2764                        "Failed to add listening FD to the epoll monitoring.");
   2765           return MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE;
   2766         }
   2767         mhd_dbg_print_fd_mon_req ("lstn", \
   2768                                   d->net.listen.fd, \
   2769                                   true, \
   2770                                   false, \
   2771                                   false);
   2772       }
   2773     }
   2774     return MHD_SC_OK;
   2775     break;
   2776 #endif /* MHD_SUPPORT_EPOLL */
   2777 #ifdef MHD_SUPPORT_KQUEUE
   2778   case mhd_POLL_TYPE_KQUEUE:
   2779     mhd_assert (0 < d->events.data.kq.kq_fd);
   2780     mhd_assert (NULL != d->events.data.kq.kes);
   2781     mhd_assert (2u < d->events.data.kq.num_elements);
   2782     if (1)
   2783     {
   2784       int num_elemnts;
   2785 
   2786       num_elemnts = 0;
   2787 #  ifdef MHD_SUPPORT_THREADS
   2788       mhd_KE_SET (d->events.data.kq.kes + num_elemnts,
   2789                   mhd_itc_r_fd (d->threading.itc),
   2790                   EVFILT_READ,
   2791                   EV_ADD, /* level trigger */
   2792                   mhd_SOCKET_REL_PTRMARKER_ITC);
   2793       mhd_dbg_print_kevent_change ("ITC",
   2794                                    d->events.data.kq.kes + num_elemnts);
   2795       ++num_elemnts;
   2796 #  endif
   2797       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2798       {
   2799         mhd_KE_SET (d->events.data.kq.kes + num_elemnts,
   2800                     d->net.listen.fd,
   2801                     EVFILT_READ,
   2802                     EV_ADD, /* level trigger */
   2803                     mhd_SOCKET_REL_PTRMARKER_LISTEN);
   2804 
   2805         mhd_dbg_print_kevent_change ("lstn",
   2806                                      d->events.data.kq.kes + num_elemnts);
   2807         ++num_elemnts;
   2808       }
   2809 
   2810       if (0 != num_elemnts)
   2811       {
   2812         static const struct timespec zero_timeout = {0, 0};
   2813         int res;
   2814 
   2815 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2816         fprintf (stderr,
   2817                  "### (Starting) kevent(%d, changes, %d, [NULL], "
   2818                  "0, [0, 0])...\n",
   2819                  d->events.data.kq.kq_fd,
   2820                  num_elemnts);
   2821 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2822         res = kevent (d->events.data.kq.kq_fd,
   2823                       d->events.data.kq.kes,
   2824                       num_elemnts,
   2825                       NULL,
   2826                       0,
   2827                       &zero_timeout);
   2828 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2829         fprintf (stderr,
   2830                  "### (Finished) kevent(%d, changes, %d, [NULL], "
   2831                  "0, [0, 0]) -> %d\n",
   2832                  d->events.data.kq.kq_fd,
   2833                  num_elemnts,
   2834                  res);
   2835 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2836         if (0 != res)
   2837         {
   2838           mhd_LOG_MSG (d, MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE, \
   2839                        "Failed to add ITC or listening FD to the "
   2840                        "kqueue monitoring.");
   2841           return MHD_SC_EVENTS_REG_DAEMON_FDS_FAILURE;
   2842         }
   2843       }
   2844     }
   2845     return MHD_SC_OK;
   2846     break;
   2847 #endif /* MHD_SUPPORT_KQUEUE */
   2848 #ifndef MHD_SUPPORT_SELECT
   2849   case mhd_POLL_TYPE_SELECT:
   2850 #endif /* ! MHD_SUPPORT_SELECT */
   2851 #ifndef MHD_SUPPORT_POLL
   2852   case mhd_POLL_TYPE_POLL:
   2853 #endif /* ! MHD_SUPPORT_POLL */
   2854   case mhd_POLL_TYPE_NOT_SET_YET:
   2855   default:
   2856     mhd_UNREACHABLE ();
   2857     break;
   2858   }
   2859   mhd_UNREACHABLE ();
   2860   return MHD_SC_INTERNAL_ERROR;
   2861 }
   2862 
   2863 
   2864 /**
   2865  * The initial part of events de-initialisation: remove ITC and listening FD
   2866  * from the monitored items (if supported by monitoring syscall).
   2867  * @param d the daemon object
   2868  */
   2869 static MHD_FN_PAR_NONNULL_ (1) void
   2870 deinit_daemon_fds_monitoring (struct MHD_Daemon *restrict d)
   2871 {
   2872   mhd_assert (d->dbg.events_fully_inited);
   2873 
   2874   switch (d->events.poll_type)
   2875   {
   2876   case mhd_POLL_TYPE_EXT:
   2877     if (NULL != d->events.data.extr.listen_data.app_cntx)
   2878       (void)mhd_daemon_extr_event_reg (
   2879         d,
   2880         d->net.listen.fd,
   2881         MHD_FD_STATE_NONE,
   2882         d->events.data.extr.listen_data.app_cntx,
   2883         (struct MHD_EventUpdateContext *)mhd_SOCKET_REL_MARKER_LISTEN);
   2884 #ifdef MHD_SUPPORT_THREADS
   2885     if (NULL != d->events.data.extr.itc_data.app_cntx)
   2886       (void)mhd_daemon_extr_event_reg (d,
   2887                                        mhd_itc_r_fd (d->threading.itc),
   2888                                        MHD_FD_STATE_NONE,
   2889                                        d->events.data.extr.itc_data.app_cntx,
   2890                                        (struct MHD_EventUpdateContext *)
   2891                                        mhd_SOCKET_REL_MARKER_ITC);
   2892 #endif /* MHD_SUPPORT_THREADS */
   2893     return;
   2894 #ifdef MHD_SUPPORT_SELECT
   2895   case mhd_POLL_TYPE_SELECT:
   2896     /* Nothing to do when using 'select()' */
   2897     return;
   2898     break;
   2899 #endif /* MHD_SUPPORT_SELECT */
   2900 #ifdef MHD_SUPPORT_POLL
   2901   case mhd_POLL_TYPE_POLL:
   2902     /* Nothing to do when using 'poll()' */
   2903     return;
   2904     break;
   2905 #endif /* MHD_SUPPORT_POLL */
   2906 #ifdef MHD_SUPPORT_EPOLL
   2907   case mhd_POLL_TYPE_EPOLL:
   2908     /* Nothing to do when using epoll.
   2909        Monitoring stopped by closing epoll FD. */
   2910     return;
   2911     break;
   2912 #endif /* MHD_SUPPORT_EPOLL */
   2913 #ifdef MHD_SUPPORT_KQUEUE
   2914   case mhd_POLL_TYPE_KQUEUE:
   2915     /* Nothing to do when using kqueue.
   2916        Monitoring stopped by closing kqueue FD. */
   2917     return;
   2918     break;
   2919 #endif /* MHD_SUPPORT_EPOLL */
   2920 #ifndef MHD_SUPPORT_SELECT
   2921   case mhd_POLL_TYPE_SELECT:
   2922 #endif /* ! MHD_SUPPORT_SELECT */
   2923 #ifndef MHD_SUPPORT_POLL
   2924   case mhd_POLL_TYPE_POLL:
   2925 #endif /* ! MHD_SUPPORT_POLL */
   2926   case mhd_POLL_TYPE_NOT_SET_YET:
   2927   default:
   2928     mhd_UNREACHABLE ();
   2929     break;
   2930   }
   2931   mhd_UNREACHABLE ();
   2932 }
   2933 
   2934 
   2935 /**
   2936  * Initialise daemon connections' data.
   2937  * @param d the daemon object
   2938  * @param s the user settings
   2939  * @return #MHD_SC_OK on success,
   2940  *         the error code otherwise
   2941  */
   2942 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   2943 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   2944 init_individual_conns (struct MHD_Daemon *restrict d,
   2945                        struct DaemonOptions *restrict s)
   2946 {
   2947   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   2948   mhd_assert (0 != d->conns.cfg.count_limit);
   2949 
   2950   mhd_DLINKEDL_INIT_LIST (&(d->conns), all_conn);
   2951   mhd_DLINKEDL_INIT_LIST (&(d->conns), def_timeout);
   2952   mhd_DLINKEDL_INIT_LIST (&(d->conns), cust_timeout);
   2953   d->conns.count = 0;
   2954   d->conns.block_new = false;
   2955 
   2956   d->conns.cfg.mem_pool_size = s->conn_memory_limit;
   2957   if (0 == d->conns.cfg.mem_pool_size)
   2958     d->conns.cfg.mem_pool_size = 32 * 1024;
   2959   else if (256 > d->conns.cfg.mem_pool_size)
   2960     d->conns.cfg.mem_pool_size = 256;
   2961 
   2962   switch (s->conn_buff_zeroing)
   2963   {
   2964   case MHD_CONN_BUFFER_ZEROING_DISABLED:
   2965     d->conns.cfg.mem_pool_zeroing = MHD_MEMPOOL_ZEROING_NEVER;
   2966     break;
   2967   case MHD_CONN_BUFFER_ZEROING_BASIC:
   2968     d->conns.cfg.mem_pool_zeroing = MHD_MEMPOOL_ZEROING_ON_RESET;
   2969     break;
   2970   case MHD_CONN_BUFFER_ZEROING_HEAVY:
   2971   default:
   2972     d->conns.cfg.mem_pool_zeroing = MHD_MEMPOOL_ZEROING_ALWAYS;
   2973     break;
   2974   }
   2975 
   2976 #ifdef MHD_SUPPORT_UPGRADE
   2977   mhd_DLINKEDL_INIT_LIST (&(d->conns.upgr), upgr_cleanup);
   2978   if (!mhd_mutex_init (&(d->conns.upgr.ucu_lock)))
   2979   {
   2980     mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   2981                  "Failed to initialise mutex for the upgraded " \
   2982                  "connection list.");
   2983     return MHD_SC_MUTEX_INIT_FAILURE;
   2984   }
   2985 #endif /* MHD_SUPPORT_UPGRADE */
   2986 
   2987 #ifndef NDEBUG
   2988   d->dbg.connections_inited = true;
   2989 #endif
   2990   return MHD_SC_OK;
   2991 }
   2992 
   2993 
   2994 /**
   2995  * Deinitialise daemon connections' data.
   2996  * @param d the daemon object
   2997  */
   2998 static MHD_FN_PAR_NONNULL_ (1) void
   2999 deinit_individual_conns (struct MHD_Daemon *restrict d)
   3000 {
   3001 #ifdef MHD_SUPPORT_UPGRADE
   3002   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->conns.upgr), upgr_cleanup));
   3003   mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns.upgr), upgr_cleanup));
   3004 
   3005   mhd_mutex_destroy_chk (&(d->conns.upgr.ucu_lock));
   3006 #endif /* MHD_SUPPORT_UPGRADE */
   3007 
   3008   mhd_assert (0 != d->conns.cfg.mem_pool_size);
   3009   mhd_assert (0 == d->conns.count);
   3010   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->conns), cust_timeout));
   3011   mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns), cust_timeout));
   3012   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->conns), def_timeout));
   3013   mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns), def_timeout));
   3014   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn));
   3015   mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns), all_conn));
   3016 }
   3017 
   3018 
   3019 /**
   3020  * Prepare daemon-local (worker daemon for thread pool mode) threading data
   3021  * and finish events initialising.
   3022  * To be used only with non-master daemons.
   3023  * Do not start the thread even if configured for the internal threads.
   3024  * @param d the daemon object
   3025  * @return #MHD_SC_OK on success,
   3026  *         the error code otherwise
   3027  */
   3028 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3029 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3030 init_individual_thread_data_events_conns (struct MHD_Daemon *restrict d,
   3031                                           struct DaemonOptions *restrict s)
   3032 {
   3033   enum MHD_StatusCode res;
   3034   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   3035   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   3036   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3037   mhd_assert (!d->dbg.connections_inited);
   3038 
   3039   res = init_events_fd (d);
   3040   if (MHD_SC_OK != res)
   3041     return res;
   3042 
   3043   res = allocate_events (d);
   3044   if (MHD_SC_OK == res)
   3045   {
   3046     res = init_itc (d);
   3047     if (MHD_SC_OK == res)
   3048     {
   3049       res = init_daemon_fds_monitoring (d);
   3050 
   3051       if (MHD_SC_OK == res)
   3052       {
   3053 #ifndef NDEBUG
   3054         d->dbg.events_fully_inited = true;
   3055 #endif
   3056 #ifdef MHD_SUPPORT_THREADS
   3057         mhd_thread_handle_ID_set_invalid (&(d->threading.tid));
   3058         d->threading.stop_requested = false;
   3059 #endif /* MHD_SUPPORT_THREADS */
   3060 #ifndef NDEBUG
   3061         d->dbg.threading_inited = true;
   3062 #endif
   3063 
   3064         res = init_individual_conns (d, s);
   3065         if (MHD_SC_OK == res)
   3066           return MHD_SC_OK;
   3067 
   3068         /* Below is a clean-up path */
   3069 
   3070         deinit_daemon_fds_monitoring (d);
   3071       }
   3072       deinit_itc (d);
   3073     }
   3074     deallocate_events (d);
   3075   }
   3076   deinit_events_fd (d);
   3077 
   3078   mhd_assert (MHD_SC_OK != res);
   3079   return res;
   3080 }
   3081 
   3082 
   3083 /**
   3084  * Deinit daemon-local (worker daemon for thread pool mode) threading data
   3085  * and deallocate events.
   3086  * To be used only with non-master daemons.
   3087  * The internal thread (is any) must be stopped already.
   3088  * @param d the daemon object
   3089  */
   3090 static MHD_FN_PAR_NONNULL_ (1) void
   3091 deinit_individual_thread_data_events_conns (struct MHD_Daemon *restrict d)
   3092 {
   3093   deinit_individual_conns (d);
   3094   deinit_daemon_fds_monitoring (d);
   3095   deinit_itc (d);
   3096   deallocate_events (d);
   3097   deinit_events_fd (d);
   3098   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn));
   3099   mhd_assert (NULL == mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready));
   3100 #ifndef NDEBUG
   3101   d->dbg.events_fully_inited = false;
   3102 #endif
   3103 }
   3104 
   3105 
   3106 /**
   3107  * Initialise the data specific only for the worker daemon.
   3108  * @param d the daemon object
   3109  * @return #MHD_SC_OK on success,
   3110  *         the error code otherwise
   3111  */
   3112 static MHD_FN_PAR_NONNULL_ (1)
   3113 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3114 init_worker_only_data (struct MHD_Daemon *restrict d)
   3115 {
   3116   enum MHD_StatusCode res;
   3117   struct mhd_DaemonExtAddedConnectionsWorker *worker_only_data =
   3118     &(d->events.act_req.ext_added.worker);
   3119 
   3120   mhd_assert (!mhd_D_HAS_WORKERS (d));
   3121   mhd_assert (d->dbg.net_inited);
   3122   mhd_assert (!d->dbg.worker_only_inited);
   3123   mhd_assert (mhd_D_HAS_MASTER (d) || !d->dbg.master_only_inited);
   3124   mhd_assert (!mhd_D_HAS_MASTER (d) || d->dbg.master_only_inited);   /* Copied from master daemon */
   3125 
   3126 #ifndef NDEBUG
   3127   /* "master"-only data will be overwritten here without de-initialising */
   3128   d->dbg.master_only_inited = false;
   3129 #endif /* ! NDEBUG */
   3130 
   3131   mhd_DLINKEDL_INIT_LIST (worker_only_data, queue);
   3132 
   3133   if (!mhd_mutex_init (&(worker_only_data->q_lock)))
   3134   {
   3135     mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   3136                  "Failed to initialise mutex for externally added "
   3137                  "connections");
   3138     res = MHD_SC_MUTEX_INIT_FAILURE;
   3139   }
   3140   else
   3141     res = MHD_SC_OK;
   3142 
   3143 #ifndef NDEBUG
   3144   if (MHD_SC_OK == res)
   3145     d->dbg.worker_only_inited = true;
   3146 #endif /* ! NDEBUG */
   3147 
   3148   return res;
   3149 }
   3150 
   3151 
   3152 /**
   3153  * De-initialise the data specific only for the worker daemon.
   3154  * @param d the daemon object
   3155  */
   3156 static MHD_FN_PAR_NONNULL_ (1) void
   3157 deinit_worker_only_data (struct MHD_Daemon *restrict d)
   3158 {
   3159   struct mhd_DaemonExtAddedConnectionsWorker *worker_only_data =
   3160     &(d->events.act_req.ext_added.worker);
   3161   struct mhd_DaemonExtAddedConn *q_e;
   3162 
   3163   mhd_assert (!mhd_D_HAS_WORKERS (d));
   3164   mhd_assert (d->dbg.net_inited);
   3165   mhd_assert (d->dbg.worker_only_inited);
   3166   mhd_assert (!d->dbg.master_only_inited);
   3167 
   3168   /* Clean-up all unprocessed entries */
   3169 
   3170   for (q_e = mhd_DLINKEDL_GET_FIRST (worker_only_data, queue);
   3171        NULL != q_e;
   3172        q_e = mhd_DLINKEDL_GET_FIRST (worker_only_data, queue))
   3173   {
   3174     mhd_ASSUME (NULL == mhd_DLINKEDL_GET_PREV (q_e, queue));
   3175     mhd_DLINKEDL_DEL (worker_only_data, q_e, queue);
   3176     mhd_socket_close (q_e->skt);
   3177 
   3178     if (NULL != q_e->addr)
   3179       free (q_e->addr);
   3180 
   3181     free (q_e);
   3182   }
   3183 
   3184   mhd_mutex_destroy_chk (&(worker_only_data->q_lock));
   3185 
   3186 #ifndef NDEBUG
   3187   d->dbg.worker_only_inited = false;
   3188 #endif /* ! NDEBUG */
   3189 }
   3190 
   3191 
   3192 /**
   3193  * Initialise worker daemon (the only daemon or member of the worker pool)
   3194  * worker-specific daemon data, individual thread data and finish events
   3195  * initialising.
   3196  * To be used only with non-master daemons.
   3197  * Do not start the thread even if configured for the internal threads.
   3198  * @param d the daemon object
   3199  * @return #MHD_SC_OK on success,
   3200  *         the error code otherwise
   3201  */
   3202 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3203 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3204 init_worker (struct MHD_Daemon *restrict d,
   3205              struct DaemonOptions *restrict s)
   3206 {
   3207   enum MHD_StatusCode res;
   3208   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3209 
   3210   res = init_worker_only_data (d);
   3211 
   3212   if (MHD_SC_OK == res)
   3213   {
   3214     res = init_individual_thread_data_events_conns (d,
   3215                                                     s);
   3216 
   3217     if (MHD_SC_OK == res)
   3218       return MHD_SC_OK;
   3219 
   3220     /* Below is a clean-up path */
   3221 
   3222     deinit_worker_only_data (d);
   3223   }
   3224 
   3225   mhd_assert (MHD_SC_OK != res);
   3226 
   3227   return res;
   3228 }
   3229 
   3230 
   3231 /**
   3232  * De-initialise worker daemon (the only daemon or member of the worker pool)
   3233  * worker-specific daemon data, individual thread data and finish events
   3234  * initialising.
   3235  * To be used only with non-master daemons.
   3236  * The internal thread (is any) must be stopped already.
   3237  * @param d the daemon object
   3238  */
   3239 static MHD_FN_PAR_NONNULL_ (1) void
   3240 deinit_worker (struct MHD_Daemon *restrict d)
   3241 {
   3242   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3243 
   3244   deinit_individual_thread_data_events_conns (d);
   3245 
   3246   deinit_worker_only_data (d);
   3247 }
   3248 
   3249 
   3250 /**
   3251  * Set the maximum number of handled connections for the daemon.
   3252  * Works only for global limit, does not work for the worker daemon.
   3253  * @param d the daemon object
   3254  * @param s the user settings
   3255  * @return #MHD_SC_OK on success,
   3256  *         the error code otherwise
   3257  */
   3258 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3259 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3260 set_connections_total_limits (struct MHD_Daemon *restrict d,
   3261                               struct DaemonOptions *restrict s)
   3262 {
   3263   unsigned int limit_by_conf;
   3264   unsigned int limit_by_num;
   3265   unsigned int limit_by_select;
   3266   unsigned int resulting_limit;
   3267   bool error_by_fd_setsize;
   3268   unsigned int num_worker_daemons;
   3269 
   3270   mhd_assert (!mhd_D_HAS_MASTER (d));
   3271   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   3272 
   3273   num_worker_daemons = 1;
   3274 #ifdef MHD_SUPPORT_THREADS
   3275   if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL == d->wmode_int)
   3276   {
   3277     mhd_assert (MHD_WM_WORKER_THREADS == s->work_mode.mode);
   3278     if ((0 != s->global_connection_limit)
   3279         && (0 != s->work_mode.params.num_worker_threads)
   3280         && (s->global_connection_limit <
   3281             s->work_mode.params.num_worker_threads))
   3282     {
   3283       mhd_LOG_MSG ( \
   3284         d, MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL, \
   3285         "The limit specified by MHD_D_O_GLOBAL_CONNECTION_LIMIT is smaller " \
   3286         "then the number of worker threads.");
   3287       return MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL;
   3288     }
   3289   }
   3290   if (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type))
   3291     num_worker_daemons = s->work_mode.params.num_worker_threads;
   3292 #endif /* MHD_SUPPORT_THREADS */
   3293 
   3294   limit_by_conf = s->global_connection_limit;
   3295   limit_by_num = UINT_MAX;
   3296   limit_by_select = UINT_MAX;
   3297   mhd_assert (UINT_MAX == limit_by_num); /* Mute analyser warning */
   3298 
   3299   error_by_fd_setsize = false;
   3300 #ifdef MHD_SOCKETS_KIND_POSIX
   3301   if (1)
   3302   {
   3303     limit_by_num = (unsigned int)d->net.cfg.max_fd_num;
   3304     if (0 != limit_by_num)
   3305     {
   3306       /* Find the upper limit.
   3307          The real limit is lower, as any other process FDs will use the slots
   3308          in the allowed numbers range */
   3309       limit_by_num -= 3; /* The numbers zero, one and two are used typically */
   3310 #  ifdef MHD_SUPPORT_THREADS
   3311       limit_by_num -= mhd_ITC_NUM_FDS * num_worker_daemons;
   3312 #  endif /* MHD_SUPPORT_THREADS */
   3313       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   3314         --limit_by_num; /* One FD is used for the listening socket */
   3315       if ((num_worker_daemons > limit_by_num)
   3316           || (limit_by_num >
   3317               (unsigned int)d->net.cfg.max_fd_num) /* Underflow */)
   3318       {
   3319         if (d->net.cfg.max_fd_num == s->fd_number_limit)
   3320         {
   3321           mhd_LOG_MSG ( \
   3322             d, MHD_SC_MAX_FD_NUMBER_LIMIT_TOO_STRICT, \
   3323             "The limit specified by MHD_D_O_FD_NUMBER_LIMIT is too strict " \
   3324             "for this daemon settings.");
   3325           return MHD_SC_MAX_FD_NUMBER_LIMIT_TOO_STRICT;
   3326         }
   3327         else
   3328         {
   3329           mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type);
   3330           error_by_fd_setsize = true;
   3331         }
   3332       }
   3333     }
   3334     else
   3335       limit_by_num = (unsigned int)INT_MAX;
   3336   }
   3337 #elif defined(MHD_SOCKETS_KIND_WINSOCK)
   3338   if (1)
   3339   {
   3340 #  ifdef MHD_SUPPORT_SELECT
   3341     if ((mhd_DAEMON_TYPE_SINGLE == d->threading.d_type)
   3342         && (mhd_POLL_TYPE_SELECT == d->events.poll_type))
   3343     {
   3344       /* W32 limits the total number (count) of sockets used for select() */
   3345       unsigned int limit_per_worker;
   3346 
   3347       limit_per_worker = FD_SETSIZE;
   3348       if (MHD_INVALID_SOCKET != d->net.listen.fd)
   3349         --limit_per_worker;  /* The slot for the listening socket */
   3350 #    ifdef MHD_SUPPORT_THREADS
   3351       --limit_per_worker;  /* The slot for the ITC */
   3352 #    endif /* MHD_SUPPORT_THREADS */
   3353       if ((0 == limit_per_worker) || (limit_per_worker > FD_SETSIZE))
   3354         error_by_fd_setsize = true;
   3355       else
   3356       {
   3357         limit_by_select = limit_per_worker * num_worker_daemons;
   3358         if (limit_by_select / limit_per_worker != num_worker_daemons)
   3359           limit_by_select = UINT_MAX;
   3360       }
   3361     }
   3362 #  endif /* MHD_SUPPORT_SELECT */
   3363     (void)0;  /* Mute compiler warning */
   3364   }
   3365 #endif /* MHD_SOCKETS_KIND_POSIX */
   3366   if (error_by_fd_setsize)
   3367   {
   3368     mhd_LOG_MSG ( \
   3369       d, MHD_SC_SYS_FD_SETSIZE_TOO_STRICT, \
   3370       "The FD_SETSIZE is too strict to run daemon with the polling " \
   3371       "by select() and with the specified number of workers.");
   3372     return MHD_SC_SYS_FD_SETSIZE_TOO_STRICT;
   3373   }
   3374 
   3375   if (0 != limit_by_conf)
   3376   {
   3377     /* The number has bet set explicitly */
   3378     resulting_limit = limit_by_conf;
   3379   }
   3380   else
   3381   {
   3382     /* No user configuration provided */
   3383     unsigned int suggested_limit;
   3384 #ifndef MHD_SOCKETS_KIND_WINSOCK
   3385 #  define TYPICAL_NOFILES_LIMIT (1024) /* The usual limit for the number of open FDs */
   3386     suggested_limit = TYPICAL_NOFILES_LIMIT;
   3387     suggested_limit -= 3; /* The numbers zero, one and two are used typically */
   3388 #  ifdef MHD_SUPPORT_THREADS
   3389     suggested_limit -= mhd_ITC_NUM_FDS * num_worker_daemons;
   3390 #  endif /* MHD_SUPPORT_THREADS */
   3391     if (MHD_INVALID_SOCKET != d->net.listen.fd)
   3392       --suggested_limit; /* One FD is used for the listening socket */
   3393     if (suggested_limit > TYPICAL_NOFILES_LIMIT)
   3394       suggested_limit = 0; /* Overflow */
   3395 #else  /* MHD_SOCKETS_KIND_WINSOCK */
   3396 #  ifdef _WIN64
   3397     suggested_limit = 2048;
   3398 #  else
   3399     suggested_limit = 1024;
   3400 #  endif
   3401 #endif /* MHD_SOCKETS_KIND_WINSOCK */
   3402     if (suggested_limit < num_worker_daemons)
   3403     {
   3404       /* Use at least one connection for every worker daemon and
   3405          let the system to restrict the new connections if they are above
   3406          the system limits. */
   3407       suggested_limit = num_worker_daemons;
   3408     }
   3409     resulting_limit = suggested_limit;
   3410   }
   3411   if (resulting_limit > limit_by_num)
   3412     resulting_limit = limit_by_num;
   3413 
   3414   if (resulting_limit > limit_by_select)
   3415     resulting_limit = limit_by_select;
   3416 
   3417   mhd_assert (resulting_limit >= num_worker_daemons);
   3418   d->conns.cfg.count_limit = resulting_limit;
   3419   if (d->conns.cfg.per_ip_limit <= d->conns.cfg.count_limit)
   3420     d->conns.cfg.per_ip_limit = 0; /* Already enforced by global limit */
   3421 
   3422   return MHD_SC_OK;
   3423 }
   3424 
   3425 
   3426 /**
   3427  * Set correct daemon threading type.
   3428  * Set the number of workers for thread pool type.
   3429  * @param d the daemon object
   3430  * @return #MHD_SC_OK on success,
   3431  *         the error code otherwise
   3432  */
   3433 MHD_FN_PAR_NONNULL_ (1) \
   3434   MHD_FN_MUST_CHECK_RESULT_ static inline enum MHD_StatusCode
   3435 set_d_threading_type (struct MHD_Daemon *restrict d)
   3436 {
   3437   switch (d->wmode_int)
   3438   {
   3439   case mhd_WM_INT_EXTERNAL_EVENTS_EDGE:
   3440   case mhd_WM_INT_EXTERNAL_EVENTS_LEVEL:
   3441     mhd_assert (!mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3442     mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
   3443     mhd_assert (NULL != d->events.data.extr.cb_data.cb);
   3444 #ifdef MHD_SUPPORT_THREADS
   3445     d->threading.d_type = mhd_DAEMON_TYPE_SINGLE;
   3446 #endif /* MHD_SUPPORT_THREADS */
   3447     return MHD_SC_OK;
   3448   case mhd_WM_INT_INTERNAL_EVENTS_NO_THREADS:
   3449     mhd_assert (!mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3450     mhd_assert (mhd_POLL_TYPE_EXT != d->events.poll_type);
   3451 #ifdef MHD_SUPPORT_THREADS
   3452     d->threading.d_type = mhd_DAEMON_TYPE_SINGLE;
   3453 #endif /* MHD_SUPPORT_THREADS */
   3454     return MHD_SC_OK;
   3455 #ifdef MHD_SUPPORT_THREADS
   3456   case mhd_WM_INT_INTERNAL_EVENTS_ONE_THREAD:
   3457     mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3458     mhd_assert (mhd_POLL_TYPE_EXT != d->events.poll_type);
   3459     d->threading.d_type = mhd_DAEMON_TYPE_SINGLE;
   3460     return MHD_SC_OK;
   3461   case mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION:
   3462     mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3463     mhd_assert (mhd_POLL_TYPE_EXT != d->events.poll_type);
   3464     mhd_assert (!mhd_POLL_TYPE_INT_IS_EPOLL (d->events.poll_type));
   3465     mhd_assert (!mhd_POLL_TYPE_INT_IS_KQUEUE (d->events.poll_type));
   3466     d->threading.d_type = mhd_DAEMON_TYPE_LISTEN_ONLY;
   3467     return MHD_SC_OK;
   3468   case mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL:
   3469     mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3470     mhd_assert (mhd_POLL_TYPE_EXT != d->events.poll_type);
   3471     d->threading.d_type = mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY;
   3472     return MHD_SC_OK;
   3473 #endif /* MHD_SUPPORT_THREADS */
   3474   default:
   3475     break;
   3476   }
   3477   mhd_UNREACHABLE ();
   3478   return MHD_SC_INTERNAL_ERROR;
   3479 }
   3480 
   3481 
   3482 #ifdef MHD_SUPPORT_THREADS
   3483 
   3484 /**
   3485  * De-initialise workers pool, including workers daemons.
   3486  * The threads must be not running.
   3487  * @param d the daemon object
   3488  * @param num_workers the number of workers to deinit
   3489  */
   3490 static MHD_FN_PAR_NONNULL_ (1) void
   3491 deinit_workers_pool (struct MHD_Daemon *restrict d,
   3492                      unsigned int num_workers)
   3493 {
   3494   unsigned int i;
   3495   mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3496   mhd_assert (NULL != d->threading.hier.pool.workers);
   3497   mhd_assert ((2 <= d->threading.hier.pool.num) \
   3498               || (mhd_DAEMON_STATE_STARTING == d->state));
   3499   mhd_assert ((num_workers == d->threading.hier.pool.num) \
   3500               || (mhd_DAEMON_STATE_STARTING == d->state));
   3501   mhd_assert ((mhd_DAEMON_STATE_STOPPING == d->state) \
   3502               || (mhd_DAEMON_STATE_STARTING == d->state));
   3503 
   3504   /* Deinitialise in reverse order */
   3505   for (i = num_workers - 1; num_workers > i; --i)
   3506   { /* Note: loop exits after underflow of 'i' */
   3507     struct MHD_Daemon *const worker = d->threading.hier.pool.workers + i;
   3508     deinit_worker (worker);
   3509   }
   3510   free (d->threading.hier.pool.workers);
   3511 #  ifndef NDEBUG
   3512   d->dbg.thread_pool_inited = false;
   3513 #  endif
   3514 }
   3515 
   3516 
   3517 /**
   3518  * Nullify worker daemon member that copied from master daemon but must not
   3519  * be used in worker
   3520  * @param d the daemon object
   3521  */
   3522 static MHD_FN_PAR_NONNULL_ (1) void
   3523 reset_master_only_areas (struct MHD_Daemon *restrict d)
   3524 {
   3525 #  ifdef MHD_SUPPORT_EPOLL
   3526   /* In release builds this is done mostly for safety as @a early_fd is used
   3527      in workers only for asserts */
   3528   if (mhd_POLL_TYPE_EPOLL == d->events.poll_type)
   3529     d->events.data.epoll.early_fd = MHD_INVALID_SOCKET;
   3530 #  endif /* MHD_SUPPORT_EPOLL */
   3531 
   3532 #  ifdef MHD_SUPPORT_AUTH_DIGEST
   3533   memset (&(d->auth_dg.nonces_lock),
   3534           0x7F,
   3535           sizeof(d->auth_dg.nonces_lock));
   3536 #  endif
   3537   /* Not needed. It is initialised later */
   3538   /* memset (&(d->req_cfg.large_buf), 0, sizeof(d->req_cfg.large_buf)); */
   3539   (void)d;
   3540 }
   3541 
   3542 
   3543 /**
   3544  * Initialise workers pool, including workers daemons.
   3545  * Do not start the threads.
   3546  * @param d the daemon object
   3547  * @param s the user settings
   3548  * @return #MHD_SC_OK on success,
   3549  *         the error code otherwise
   3550  */
   3551 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3552 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3553 init_workers_pool (struct MHD_Daemon *restrict d,
   3554                    struct DaemonOptions *restrict s)
   3555 {
   3556   enum MHD_StatusCode res;
   3557   size_t workers_pool_size;
   3558   unsigned int conn_per_daemon;
   3559   unsigned int num_workers;
   3560   unsigned int conn_remainder;
   3561   unsigned int i;
   3562 
   3563   mhd_assert (d->dbg.net_inited);
   3564   mhd_assert (!d->dbg.net_deinited);
   3565   mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL == d->wmode_int);
   3566   mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3567   mhd_assert (mhd_POLL_TYPE_NOT_SET_YET < d->events.poll_type);
   3568   mhd_assert (1 < s->work_mode.params.num_worker_threads);
   3569   mhd_assert (0 != d->conns.cfg.count_limit);
   3570   mhd_assert (s->work_mode.params.num_worker_threads <= \
   3571               d->conns.cfg.count_limit);
   3572   mhd_assert (!d->dbg.thread_pool_inited);
   3573 
   3574   num_workers = s->work_mode.params.num_worker_threads;
   3575   workers_pool_size =
   3576     (sizeof(struct MHD_Daemon) * num_workers);
   3577   if (workers_pool_size / num_workers != sizeof(struct MHD_Daemon))
   3578   { /* Overflow */
   3579     mhd_LOG_MSG ( \
   3580       d, MHD_SC_THREAD_POOL_MEM_ALLOC_FAILURE, \
   3581       "The size of the thread pool is too large.");
   3582     return MHD_SC_THREAD_POOL_MEM_ALLOC_FAILURE;
   3583   }
   3584 
   3585 #  ifndef NDEBUG
   3586   mhd_itc_set_invalid (&(d->threading.itc));
   3587   mhd_thread_handle_ID_set_invalid (&(d->threading.tid));
   3588 #  endif
   3589 
   3590   d->threading.hier.pool.workers = (struct MHD_Daemon *)
   3591                                    malloc (workers_pool_size);
   3592   if (NULL == d->threading.hier.pool.workers)
   3593   {
   3594     mhd_LOG_MSG ( \
   3595       d, MHD_SC_THREAD_POOL_MEM_ALLOC_FAILURE, \
   3596       "Failed to allocate memory for the thread pool.");
   3597     return MHD_SC_THREAD_POOL_MEM_ALLOC_FAILURE;
   3598   }
   3599 
   3600   conn_per_daemon = d->conns.cfg.count_limit / num_workers;
   3601   conn_remainder = d->conns.cfg.count_limit % num_workers;
   3602   res = MHD_SC_OK;
   3603   for (i = 0; num_workers > i; ++i)
   3604   {
   3605     struct MHD_Daemon *restrict const worker =
   3606       d->threading.hier.pool.workers + i;
   3607     memcpy (worker, d, sizeof(struct MHD_Daemon));
   3608     reset_master_only_areas (worker);
   3609 
   3610     worker->threading.d_type = mhd_DAEMON_TYPE_WORKER;
   3611     worker->threading.hier.master = d;
   3612     worker->conns.cfg.count_limit = conn_per_daemon;
   3613     if (conn_remainder > i)
   3614       worker->conns.cfg.count_limit++; /* Distribute the reminder */
   3615 #  ifdef MHD_SUPPORT_EPOLL
   3616     mhd_assert ((mhd_POLL_TYPE_EPOLL != worker->events.poll_type)
   3617                 || (0 != i)
   3618                 || (0 < d->events.data.epoll.early_fd));
   3619     mhd_assert ((mhd_POLL_TYPE_EPOLL != worker->events.poll_type)
   3620                 || (0 == i)
   3621                 || (MHD_INVALID_SOCKET == d->events.data.epoll.early_fd));
   3622 #  endif /* MHD_SUPPORT_EPOLL */
   3623     res = init_worker (worker,
   3624                        s);
   3625     if (MHD_SC_OK != res)
   3626       break;
   3627   }
   3628   if (num_workers == i)
   3629   {
   3630     mhd_assert (MHD_SC_OK == res);
   3631 #  ifndef NDEBUG
   3632     d->dbg.thread_pool_inited = true;
   3633     d->dbg.threading_inited = true;
   3634 #  endif
   3635     d->threading.hier.pool.num = num_workers;
   3636     return MHD_SC_OK;
   3637   }
   3638 
   3639   /* Below is a clean-up */
   3640 
   3641   mhd_assert (MHD_SC_OK != res);
   3642   deinit_workers_pool (d, i);
   3643   return res;
   3644 }
   3645 
   3646 
   3647 /**
   3648  * Initialise data specific only for the master daemon.
   3649  * @param d the daemon object
   3650  * @return #MHD_SC_OK on success,
   3651  *         the error code otherwise
   3652  */
   3653 static MHD_FN_PAR_NONNULL_ (1)
   3654 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3655 init_master_only_data (struct MHD_Daemon *restrict d)
   3656 {
   3657   enum MHD_StatusCode res;
   3658 
   3659   mhd_assert (mhd_D_HAS_WORKERS (d));
   3660   mhd_assert (d->dbg.net_inited);
   3661   mhd_assert (!d->dbg.master_only_inited);
   3662   mhd_assert (!d->dbg.worker_only_inited);
   3663 
   3664   if (!mhd_atomic_counter_init ( \
   3665         &(d->events.act_req.ext_added.master.next_d_idx),
   3666         0))
   3667   {
   3668     mhd_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
   3669                  "Failed to initialise atomic counter for externally added "
   3670                  "connections");
   3671     res = MHD_SC_MUTEX_INIT_FAILURE;
   3672   }
   3673   else
   3674     res = MHD_SC_OK;
   3675 
   3676 #  ifndef NDEBUG
   3677   if (MHD_SC_OK == res)
   3678     d->dbg.master_only_inited = true;
   3679 #  endif /* ! NDEBUG */
   3680 
   3681   return res;
   3682 }
   3683 
   3684 
   3685 /**
   3686  * De-initialise data specific only for the master daemon.
   3687  * @param d the daemon object
   3688  */
   3689 static MHD_FN_PAR_NONNULL_ (1) void
   3690 deinit_master_only_data (struct MHD_Daemon *restrict d)
   3691 {
   3692   mhd_assert (mhd_D_HAS_WORKERS (d));
   3693   mhd_assert (d->dbg.master_only_inited);
   3694   mhd_assert (!d->dbg.worker_only_inited);
   3695 
   3696   mhd_atomic_counter_deinit (&(d->events.act_req.ext_added.master.next_d_idx));
   3697 
   3698 #  ifndef NDEBUG
   3699   d->dbg.master_only_inited = false;
   3700 #  endif /* ! NDEBUG */
   3701 }
   3702 
   3703 
   3704 /**
   3705  * Initialise individual events, connection data for the "master" daemon,
   3706  * including master-only data, the workers pool, and the workers daemons,
   3707  * including individual worker-specific threading and other data.
   3708  * Do not start the threads.
   3709  * @param d the daemon object
   3710  * @param s the user settings
   3711  * @return #MHD_SC_OK on success,
   3712  *         the error code otherwise
   3713  */
   3714 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3715 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3716 init_master (struct MHD_Daemon *restrict d,
   3717              struct DaemonOptions *restrict s)
   3718 {
   3719   enum MHD_StatusCode res;
   3720   mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3721 
   3722   res = init_master_only_data (d);
   3723   if (MHD_SC_OK != res)
   3724     return res;
   3725 
   3726   res = init_workers_pool (d,
   3727                            s);
   3728   if (MHD_SC_OK == res)
   3729   {
   3730     /* Copy some settings to the master daemon */
   3731     d->conns.cfg.mem_pool_size =
   3732       d->threading.hier.pool.workers[0].conns.cfg.mem_pool_size;
   3733 
   3734     return res;
   3735   }
   3736 
   3737   /* Below is a clean-up path */
   3738 
   3739   deinit_master_only_data (d);
   3740 
   3741   mhd_assert (MHD_SC_OK != res);
   3742   return res;
   3743 }
   3744 
   3745 
   3746 /**
   3747  * De-initialise individual events, connection data for the "master" daemon,
   3748  * including master-only data, the workers pool, and the workers daemons,
   3749  * including individual worker-specific threading and other data.
   3750  * The threads must be not running.
   3751  * @param d the daemon object
   3752  */
   3753 static MHD_FN_PAR_NONNULL_ (1) void
   3754 deinit_master (struct MHD_Daemon *restrict d)
   3755 {
   3756   deinit_workers_pool (d,
   3757                        d->threading.hier.pool.num);
   3758 
   3759   deinit_master_only_data (d);
   3760 }
   3761 
   3762 
   3763 #endif /* MHD_SUPPORT_THREADS */
   3764 
   3765 /**
   3766  * Initialise threading and inter-thread communications.
   3767  * Also finish initialisation of events processing and initialise daemon's
   3768  * connection data.
   3769  * Do not start the thread even if configured for the internal threads.
   3770  * @param d the daemon object
   3771  * @param s the user settings
   3772  * @return #MHD_SC_OK on success,
   3773  *         the error code otherwise
   3774  */
   3775 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   3776 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3777 daemon_init_threading_and_conn (struct MHD_Daemon *restrict d,
   3778                                 struct DaemonOptions *restrict s)
   3779 {
   3780   enum MHD_StatusCode res;
   3781 
   3782   mhd_assert (d->dbg.net_inited);
   3783   mhd_assert (!d->dbg.net_deinited);
   3784   mhd_assert (mhd_POLL_TYPE_NOT_SET_YET != d->events.poll_type);
   3785 
   3786   res = set_d_threading_type (d);
   3787   if (MHD_SC_OK != res)
   3788     return res;
   3789 
   3790   res = set_connections_total_limits (d, s);
   3791   if (MHD_SC_OK != res)
   3792     return res;
   3793 
   3794 #ifdef MHD_SUPPORT_THREADS
   3795   d->threading.cfg.stack_size = s->stack_size;
   3796 #endif /* MHD_SUPPORT_THREADS */
   3797 
   3798   if (!mhd_D_HAS_WORKERS (d))
   3799     res = init_worker (d,
   3800                        s);
   3801 #ifdef MHD_SUPPORT_THREADS
   3802   else
   3803     res = init_master (d,
   3804                        s);
   3805 #endif /* MHD_SUPPORT_THREADS */
   3806 
   3807   if (MHD_SC_OK == res)
   3808   {
   3809     mhd_assert (d->dbg.events_allocated \
   3810                 || mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3811     mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type) \
   3812                 || !d->dbg.events_allocated);
   3813     mhd_assert (!d->dbg.thread_pool_inited \
   3814                 || mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3815     mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type) \
   3816                 || d->dbg.thread_pool_inited);
   3817     mhd_assert (!mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
   3818     mhd_assert (!d->dbg.events_allocated || d->dbg.connections_inited);
   3819     mhd_assert (!d->dbg.connections_inited || d->dbg.events_allocated);
   3820   }
   3821   return res;
   3822 }
   3823 
   3824 
   3825 /**
   3826  * De-initialise threading and inter-thread communications.
   3827  * Also deallocate events and de-initialise daemon's connection data.
   3828  * No daemon-manged threads should be running.
   3829  * @param d the daemon object
   3830  */
   3831 static MHD_FN_PAR_NONNULL_ (1) void
   3832 daemon_deinit_threading_and_conn (struct MHD_Daemon *restrict d)
   3833 {
   3834   mhd_assert (d->dbg.net_inited);
   3835   mhd_assert (!d->dbg.net_deinited);
   3836   mhd_assert (d->dbg.threading_inited);
   3837   mhd_assert (!mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
   3838   if (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type))
   3839   {
   3840     mhd_assert (!mhd_WM_INT_IS_THREAD_POOL (d->wmode_int));
   3841     mhd_assert (d->dbg.connections_inited);
   3842     mhd_assert (d->dbg.events_allocated);
   3843     mhd_assert (!d->dbg.thread_pool_inited);
   3844     deinit_worker (d);
   3845   }
   3846   else
   3847   {
   3848 #ifdef MHD_SUPPORT_THREADS
   3849     mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL == d->wmode_int);
   3850     mhd_assert (!d->dbg.connections_inited);
   3851     mhd_assert (!d->dbg.events_allocated);
   3852     mhd_assert (d->dbg.thread_pool_inited);
   3853     deinit_master (d);
   3854 #else  /* ! MHD_SUPPORT_THREADS */
   3855     mhd_assert (0 && "Impossible value");
   3856     mhd_UNREACHABLE ();
   3857     (void)0;
   3858 #endif /* ! MHD_SUPPORT_THREADS */
   3859   }
   3860 }
   3861 
   3862 
   3863 #ifdef MHD_SUPPORT_THREADS
   3864 
   3865 /**
   3866  * Start the daemon individual single thread.
   3867  * Works both for single thread daemons and for worker daemon for thread
   3868  * pool mode.
   3869  * Must be called only for daemons with internal threads.
   3870  * @param d the daemon object, must be completely initialised
   3871  * @return #MHD_SC_OK on success,
   3872  *         the error code otherwise
   3873  */
   3874 static MHD_FN_PAR_NONNULL_ (1)
   3875 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   3876 start_individual_daemon_thread (struct MHD_Daemon *restrict d)
   3877 {
   3878   mhd_assert (d->dbg.threading_inited);
   3879   mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3880   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   3881   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3882   mhd_assert (!mhd_thread_handle_ID_is_valid_handle (d->threading.tid));
   3883 
   3884   if (mhd_DAEMON_TYPE_SINGLE == d->threading.d_type)
   3885   {
   3886     if (!mhd_create_named_thread ( \
   3887           &(d->threading.tid), "MHD-single", \
   3888           d->threading.cfg.stack_size, \
   3889           &mhd_worker_all_events, \
   3890           (void *)d))
   3891     {
   3892       mhd_LOG_MSG (d, MHD_SC_THREAD_MAIN_LAUNCH_FAILURE, \
   3893                    "Failed to start daemon main thread.");
   3894       return MHD_SC_THREAD_MAIN_LAUNCH_FAILURE;
   3895     }
   3896   }
   3897   else if (mhd_DAEMON_TYPE_WORKER == d->threading.d_type)
   3898   {
   3899     if (!mhd_create_named_thread ( \
   3900           &(d->threading.tid), "MHD-worker", \
   3901           d->threading.cfg.stack_size, \
   3902           &mhd_worker_all_events, \
   3903           (void *)d))
   3904     {
   3905       mhd_LOG_MSG (d, MHD_SC_THREAD_WORKER_LAUNCH_FAILURE, \
   3906                    "Failed to start daemon worker thread.");
   3907       return MHD_SC_THREAD_WORKER_LAUNCH_FAILURE;
   3908     }
   3909   }
   3910   else if (mhd_DAEMON_TYPE_LISTEN_ONLY == d->threading.d_type)
   3911   {
   3912     if (!mhd_create_named_thread ( \
   3913           &(d->threading.tid), "MHD-listen", \
   3914           d->threading.cfg.stack_size, \
   3915           &mhd_worker_listening_only, \
   3916           (void *)d))
   3917     {
   3918       mhd_LOG_MSG (d, MHD_SC_THREAD_LISTENING_LAUNCH_FAILURE, \
   3919                    "Failed to start daemon listening thread.");
   3920       return MHD_SC_THREAD_LISTENING_LAUNCH_FAILURE;
   3921     }
   3922   }
   3923   else
   3924   {
   3925     mhd_assert (0 && "Impossible value");
   3926     mhd_UNREACHABLE ();
   3927     return MHD_SC_INTERNAL_ERROR;
   3928   }
   3929   mhd_assert (mhd_thread_handle_ID_is_valid_handle (d->threading.tid));
   3930   return MHD_SC_OK;
   3931 }
   3932 
   3933 
   3934 /**
   3935  * Stop the daemon individual single thread.
   3936  * Works both for single thread daemons and for worker daemon for thread
   3937  * pool mode.
   3938  * Must be called only for daemons with internal threads.
   3939  * @param d the daemon object, must be completely initialised
   3940  */
   3941 MHD_FN_PAR_NONNULL_ (1) static void
   3942 stop_individual_daemon_thread (struct MHD_Daemon *restrict d)
   3943 {
   3944   mhd_assert (d->dbg.threading_inited);
   3945   mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   3946   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   3947   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3948   mhd_assert ((mhd_DAEMON_STATE_STOPPING == d->state) \
   3949               || (mhd_DAEMON_STATE_STARTING == d->state));
   3950   mhd_assert (mhd_thread_handle_ID_is_valid_handle (d->threading.tid));
   3951 
   3952   d->threading.stop_requested = true;
   3953 
   3954   mhd_daemon_trigger_itc (d);
   3955   if (!mhd_thread_handle_ID_join_thread (d->threading.tid))
   3956   {
   3957     mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_ERROR, \
   3958                  "Failed to stop daemon main thread.");
   3959   }
   3960 }
   3961 
   3962 
   3963 /**
   3964  * Stop all worker threads in the thread pool.
   3965  * Must be called only for master daemons with thread pool.
   3966  * @param d the daemon object, the workers threads must be running
   3967  * @param num_workers the number of threads to stop
   3968  */
   3969 static MHD_FN_PAR_NONNULL_ (1) void
   3970 stop_worker_pool_threads (struct MHD_Daemon *restrict d,
   3971                           unsigned int num_workers)
   3972 {
   3973   unsigned int i;
   3974   mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   3975   mhd_assert (NULL != d->threading.hier.pool.workers);
   3976   mhd_assert (0 != d->threading.hier.pool.num);
   3977   mhd_assert (d->dbg.thread_pool_inited);
   3978   mhd_assert (2 <= d->threading.hier.pool.num);
   3979   mhd_assert ((num_workers == d->threading.hier.pool.num) \
   3980               || (mhd_DAEMON_STATE_STARTING == d->state));
   3981   mhd_assert ((mhd_DAEMON_STATE_STOPPING == d->state) \
   3982               || (mhd_DAEMON_STATE_STARTING == d->state));
   3983 
   3984   /* Process all the threads in the reverse order */
   3985 
   3986   /* Trigger all threads */
   3987   for (i = num_workers - 1; num_workers > i; --i)
   3988   { /* Note: loop exits after underflow of 'i' */
   3989     d->threading.hier.pool.workers[i].threading.stop_requested = true;
   3990     mhd_assert (mhd_ITC_IS_VALID ( \
   3991                   d->threading.hier.pool.workers[i].threading.itc));
   3992     mhd_daemon_trigger_itc (d->threading.hier.pool.workers + i);
   3993   }
   3994 
   3995   /* Collect all threads */
   3996   for (i = num_workers - 1; num_workers > i; --i)
   3997   { /* Note: loop exits after underflow of 'i' */
   3998     struct MHD_Daemon *const restrict worker =
   3999       d->threading.hier.pool.workers + i;
   4000     mhd_assert (mhd_thread_handle_ID_is_valid_handle (worker->threading.tid));
   4001     if (!mhd_thread_handle_ID_join_thread (worker->threading.tid))
   4002     {
   4003       mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_ERROR, \
   4004                    "Failed to stop a worker thread.");
   4005     }
   4006   }
   4007 }
   4008 
   4009 
   4010 /**
   4011  * Start the workers pool threads.
   4012  * Must be called only for master daemons with thread pool.
   4013  * @param d the daemon object, must be completely initialised
   4014  * @return #MHD_SC_OK on success,
   4015  *         the error code otherwise
   4016  */
   4017 static MHD_FN_PAR_NONNULL_ (1)
   4018 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   4019 start_worker_pool_threads (struct MHD_Daemon *restrict d)
   4020 {
   4021   enum MHD_StatusCode res;
   4022   unsigned int i;
   4023 
   4024   mhd_assert (d->dbg.threading_inited);
   4025   mhd_assert (mhd_WM_INT_HAS_THREADS (d->wmode_int));
   4026   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   4027   mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   4028   mhd_assert (d->dbg.thread_pool_inited);
   4029   mhd_assert (2 <= d->threading.hier.pool.num);
   4030 
   4031   res = MHD_SC_OK;
   4032 
   4033   for (i = 0; d->threading.hier.pool.num > i; ++i)
   4034   {
   4035     res = start_individual_daemon_thread (d->threading.hier.pool.workers + i);
   4036     if (MHD_SC_OK != res)
   4037       break;
   4038   }
   4039   if (d->threading.hier.pool.num == i)
   4040   {
   4041     mhd_assert (MHD_SC_OK == res);
   4042     return MHD_SC_OK;
   4043   }
   4044 
   4045   stop_worker_pool_threads (d, i);
   4046   mhd_assert (MHD_SC_OK != res);
   4047   return res;
   4048 }
   4049 
   4050 
   4051 #endif /* MHD_SUPPORT_THREADS */
   4052 
   4053 /**
   4054  * Start the daemon internal threads, if the daemon configured to use them.
   4055  * @param d the daemon object, must be completely initialised
   4056  * @return #MHD_SC_OK on success,
   4057  *         the error code otherwise
   4058  */
   4059 static MHD_FN_PAR_NONNULL_ (1)
   4060 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   4061 daemon_start_threads (struct MHD_Daemon *restrict d)
   4062 {
   4063   mhd_assert (d->dbg.net_inited);
   4064   mhd_assert (!d->dbg.net_deinited);
   4065   mhd_assert (d->dbg.threading_inited);
   4066   mhd_assert (!mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
   4067   if (mhd_WM_INT_HAS_THREADS (d->wmode_int))
   4068   {
   4069 #ifdef MHD_SUPPORT_THREADS
   4070     if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL != d->wmode_int)
   4071     {
   4072       mhd_assert (d->dbg.threading_inited);
   4073       mhd_assert (mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY != d->threading.d_type);
   4074       return start_individual_daemon_thread (d);
   4075     }
   4076     else
   4077     {
   4078       mhd_assert (d->dbg.thread_pool_inited);
   4079       mhd_assert (mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY == d->threading.d_type);
   4080       return start_worker_pool_threads (d);
   4081     }
   4082 #else  /* ! MHD_SUPPORT_THREADS */
   4083     mhd_assert (0 && "Impossible value");
   4084     mhd_UNREACHABLE ();
   4085     return MHD_SC_INTERNAL_ERROR;
   4086 #endif /* ! MHD_SUPPORT_THREADS */
   4087   }
   4088   return MHD_SC_OK;
   4089 }
   4090 
   4091 
   4092 /**
   4093  * Stop the daemon internal threads, if the daemon configured to use them.
   4094  * @param d the daemon object to stop threads
   4095  */
   4096 static MHD_FN_PAR_NONNULL_ (1) void
   4097 daemon_stop_threads (struct MHD_Daemon *restrict d)
   4098 {
   4099   mhd_assert (d->dbg.net_inited);
   4100   mhd_assert (!d->dbg.net_deinited);
   4101   mhd_assert (d->dbg.threading_inited);
   4102   if (mhd_WM_INT_HAS_THREADS (d->wmode_int))
   4103   {
   4104 #ifdef MHD_SUPPORT_THREADS
   4105     if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_POOL != d->wmode_int)
   4106     {
   4107       mhd_assert (d->dbg.threading_inited);
   4108       mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   4109       stop_individual_daemon_thread (d);
   4110       return;
   4111     }
   4112     else
   4113     {
   4114       mhd_assert (d->dbg.thread_pool_inited);
   4115       mhd_assert (mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   4116       stop_worker_pool_threads (d, d->threading.hier.pool.num);
   4117       return;
   4118     }
   4119 #else  /* ! MHD_SUPPORT_THREADS */
   4120     mhd_UNREACHABLE ();
   4121     return;
   4122 #endif /* ! MHD_SUPPORT_THREADS */
   4123   }
   4124 }
   4125 
   4126 
   4127 /**
   4128  * Close all daemon connections for modes without internal threads
   4129  * @param d the daemon object
   4130  */
   4131 static MHD_FN_PAR_NONNULL_ (1) void
   4132 daemon_close_connections (struct MHD_Daemon *restrict d)
   4133 {
   4134   if (mhd_WM_INT_HAS_THREADS (d->wmode_int))
   4135   {
   4136     /* In these modes connections must be closed in the daemon thread */
   4137     mhd_assert (NULL == mhd_DLINKEDL_GET_LAST (&(d->conns), all_conn));
   4138     return;
   4139   }
   4140 
   4141   mhd_daemon_close_all_conns (d);
   4142 }
   4143 
   4144 
   4145 /**
   4146  * Internal daemon initialisation function.
   4147  * This function calls all required initialisation stages one-by-one.
   4148  * @param d the daemon object
   4149  * @param s the user settings
   4150  * @return #MHD_SC_OK on success,
   4151  *         the error code otherwise
   4152  */
   4153 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
   4154 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   4155 daemon_start_internal (struct MHD_Daemon *restrict d,
   4156                        struct DaemonOptions *restrict s)
   4157 {
   4158   enum MHD_StatusCode res;
   4159 
   4160   res = daemon_set_basic_settings (d, s);
   4161   if (MHD_SC_OK != res)
   4162     return res;
   4163 
   4164   res = daemon_set_work_mode (d, s);
   4165   if (MHD_SC_OK != res)
   4166     return res;
   4167 
   4168   res = daemon_init_net (d, s);
   4169   if (MHD_SC_OK != res)
   4170     return res;
   4171 
   4172   mhd_assert (d->dbg.net_inited);
   4173 
   4174   res = daemon_init_auth_digest (d, s);
   4175 
   4176   if (MHD_SC_OK == res)
   4177   {
   4178     res = daemon_init_tls (d, s);
   4179     if (MHD_SC_OK == res)
   4180     {
   4181       mhd_assert (d->dbg.tls_inited);
   4182       res = daemon_init_threading_and_conn (d, s);
   4183       if (MHD_SC_OK == res)
   4184       {
   4185         mhd_assert (d->dbg.threading_inited);
   4186         mhd_assert (!mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
   4187 
   4188         res = daemon_init_large_buf (d, s);
   4189         if (MHD_SC_OK == res)
   4190         {
   4191           res = daemon_init_acme (d, s);
   4192           if (MHD_SC_OK == res)
   4193           {
   4194             res = daemon_start_threads (d);
   4195             if (MHD_SC_OK == res)
   4196             {
   4197               return MHD_SC_OK; /* Success exit point */
   4198             }
   4199 
   4200             /* Below is a clean-up path */
   4201             daemon_deinit_acme (d);
   4202           }
   4203           daemon_deinit_large_buf (d);
   4204         }
   4205         daemon_deinit_threading_and_conn (d);
   4206       }
   4207       daemon_deinit_tls (d);
   4208     }
   4209     daemon_deinit_auth_digest (d);
   4210   }
   4211   daemon_deinit_net (d);
   4212   mhd_assert (MHD_SC_OK != res);
   4213   return res; /* Failure exit point */
   4214 }
   4215 
   4216 
   4217 MHD_EXTERN_
   4218 MHD_FN_PAR_NONNULL_ (1) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   4219 MHD_daemon_start (struct MHD_Daemon *daemon)
   4220 {
   4221   struct MHD_Daemon *const d = daemon; /* a short alias */
   4222   struct DaemonOptions *const s = daemon->settings; /* a short alias */
   4223   enum MHD_StatusCode res;
   4224 
   4225   if (mhd_DAEMON_STATE_NOT_STARTED != daemon->state)
   4226     return MHD_SC_TOO_LATE;
   4227 
   4228   mhd_assert (NULL != s);
   4229 
   4230   d->state = mhd_DAEMON_STATE_STARTING;
   4231   res = daemon_start_internal (d, s);
   4232 
   4233   d->settings = NULL;
   4234   dsettings_release (s);
   4235 
   4236   d->state =
   4237     (MHD_SC_OK == res) ? mhd_DAEMON_STATE_STARTED : mhd_DAEMON_STATE_FAILED;
   4238 
   4239   return res;
   4240 }
   4241 
   4242 
   4243 MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ void
   4244 MHD_daemon_destroy (struct MHD_Daemon *daemon)
   4245 {
   4246   bool not_yet_started = (mhd_DAEMON_STATE_NOT_STARTED == daemon->state);
   4247   bool has_failed = (mhd_DAEMON_STATE_FAILED == daemon->state);
   4248   mhd_assert (mhd_DAEMON_STATE_STOPPING > daemon->state);
   4249   mhd_assert (mhd_DAEMON_STATE_STARTING != daemon->state);
   4250 
   4251   daemon->state = mhd_DAEMON_STATE_STOPPING;
   4252   if (not_yet_started)
   4253   {
   4254     mhd_assert (NULL != daemon->settings);
   4255     dsettings_release (daemon->settings);
   4256   }
   4257   else if (!has_failed)
   4258   {
   4259     mhd_assert (NULL == daemon->settings);
   4260     mhd_assert (daemon->dbg.threading_inited);
   4261 
   4262     daemon_stop_threads (daemon);
   4263 
   4264     daemon_close_connections (daemon);
   4265 
   4266     daemon_deinit_threading_and_conn (daemon);
   4267 
   4268     daemon_deinit_acme (daemon);
   4269 
   4270     daemon_deinit_large_buf (daemon);
   4271 
   4272     daemon_deinit_tls (daemon);
   4273 
   4274     daemon_deinit_auth_digest (daemon);
   4275 
   4276     daemon_deinit_net (daemon);
   4277   }
   4278   daemon->state = mhd_DAEMON_STATE_STOPPED; /* Useful only for debugging */
   4279 
   4280   free (daemon);
   4281 
   4282   mhd_lib_deinit_global_if_needed ();
   4283 }