libmicrohttpd2

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

events_process.c (87242B)


      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/events_process.c
     41  * @brief  The implementation of events processing functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 #include "events_process.h"
     47 
     48 #include "mhd_assert.h"
     49 #include "mhd_unreachable.h"
     50 
     51 #include "mhd_predict.h"
     52 
     53 #if defined(MHD_USE_TRACE_SUSPEND_RESUME) || defined(MHD_USE_TRACE_POLLING_FDS)
     54 #  include <stdio.h>
     55 #  include <string.h>
     56 #endif /* MHD_USE_TRACE_SUSPEND_RESUME || MHD_USE_TRACE_POLLING_FDS */
     57 
     58 #include "mhd_locks.h"
     59 
     60 #include "mhd_socket_type.h"
     61 #include "sys_poll.h"
     62 #include "sys_select.h"
     63 #ifdef MHD_SUPPORT_EPOLL
     64 #  include <sys/epoll.h>
     65 #endif
     66 #include "sys_kqueue.h"
     67 #ifdef MHD_SOCKETS_KIND_POSIX
     68 #  include "sys_errno.h"
     69 #endif
     70 
     71 #include "mhd_itc.h"
     72 
     73 #include "mhd_panic.h"
     74 #include "mhd_dbg_print.h"
     75 
     76 #include "mhd_sockets_macros.h"
     77 #include "mhd_socket_error_funcs.h"
     78 
     79 #include "mhd_daemon.h"
     80 #include "mhd_connection.h"
     81 
     82 #include "mhd_mono_clock.h"
     83 
     84 #include "conn_timeout.h"
     85 #include "conn_mark_ready.h"
     86 #include "daemon_logger.h"
     87 #include "daemon_add_conn.h"
     88 #include "daemon_funcs.h"
     89 #include "conn_data_process.h"
     90 #include "stream_funcs.h"
     91 #include "extr_events_funcs.h"
     92 
     93 #ifdef MHD_SUPPORT_UPGRADE
     94 #  include "upgrade_proc.h"
     95 #endif /* MHD_SUPPORT_UPGRADE */
     96 
     97 #ifdef MHD_SUPPORT_HTTPS
     98 #  include "mhd_tls_funcs.h"
     99 #endif
    100 
    101 #ifdef MHD_SUPPORT_HTTP2
    102 #  include "h2/h2_comm.h"
    103 #endif
    104 
    105 #include "mhd_public_api.h"
    106 
    107 #ifdef MHD_USE_TRACE_POLLING_FDS
    108 /**
    109  * Debug-printf request of FD polling/monitoring
    110  * @param fd_name the name of FD ("ITC", "lstn" or "conn")
    111  * @param fd the FD value
    112  * @param r_ready the request for read (or receive) readiness
    113  * @param w_ready the request for write (or send) readiness
    114  * @param e_ready the request for exception (or error) readiness
    115  */
    116 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    117 mhd_dbg_print_fd_mon_req (const char *fd_name,
    118                           MHD_Socket fd,
    119                           bool r_ready,
    120                           bool w_ready,
    121                           bool e_ready)
    122 {
    123   char state_str[] = "x:x:x";
    124   state_str[0] = r_ready ? 'R' : '-';
    125   state_str[2] = w_ready ? 'W' : '-';
    126   state_str[4] = e_ready ? 'E' : '-';
    127 
    128   fprintf (stderr,
    129            "### Set FD watching: %4s [%2llu] for %s\n",
    130            fd_name,
    131            (unsigned long long)fd,
    132            state_str);
    133 }
    134 
    135 
    136 /**
    137  * Debug-printf reported (by polling) status of FD
    138  * @param fd_name the name of FD ("ITC", "lstn" or "conn")
    139  * @param fd the FD value
    140  * @param r_ready the read (or receive) readiness
    141  * @param w_ready the write (or send) readiness
    142  * @param e_ready the exception (or error) readiness
    143  */
    144 static MHD_FN_PAR_NONNULL_ALL_ void
    145 dbg_print_fd_state_update (const char *fd_name,
    146                            MHD_Socket fd,
    147                            bool r_ready,
    148                            bool w_ready,
    149                            bool e_ready)
    150 {
    151   char state_str[] = "x:x:x";
    152   state_str[0] = r_ready ? 'R' : '-';
    153   state_str[2] = w_ready ? 'W' : '-';
    154   state_str[4] = e_ready ? 'E' : '-';
    155 
    156   fprintf (stderr,
    157            "### FD state update: %4s [%2llu]  -> %s\n",
    158            fd_name,
    159            (unsigned long long)fd,
    160            state_str);
    161 }
    162 
    163 
    164 #  ifdef MHD_SUPPORT_KQUEUE
    165 
    166 static const char *
    167 mhd_dbg_kefilter_to_name (const struct kevent *ke)
    168 {
    169   switch (ke->filter)
    170   {
    171   case EVFILT_READ:
    172     return "READ ";
    173   case EVFILT_WRITE:
    174     return "WRITE";
    175   default:
    176     break;
    177   }
    178   return "OTHER";
    179 }
    180 
    181 
    182 #    define mhd_DBG_KEFLAGS_BUF_SIZE    512
    183 
    184 static void
    185 mdd_dbg_keflags_to_text (const struct kevent *ke,
    186                          char buf[mhd_DBG_KEFLAGS_BUF_SIZE])
    187 {
    188   static const size_t buf_size = mhd_DBG_KEFLAGS_BUF_SIZE;
    189   size_t len = 0u;
    190   const unsigned int keflags = ke->flags;
    191   unsigned int extra_flags;
    192   buf[0] = '\0';
    193 
    194   if (0 != (EV_ADD & keflags))
    195     strcat (buf, "ADD|");
    196   if (0 != (EV_ENABLE & keflags))
    197     strcat (buf, "ENABLE|");
    198   if (0 != (EV_DISABLE & keflags))
    199     strcat (buf, "DISABLE|");
    200   if (0 != (EV_DISPATCH & keflags))
    201     strcat (buf, "DISPATCH|");
    202   if (0 != (EV_DELETE & keflags))
    203     strcat (buf, "DELETE|");
    204   if (0 != (EV_RECEIPT & keflags))
    205     strcat (buf, "RECEIPT|");
    206   if (0 != (EV_ONESHOT & keflags))
    207     strcat (buf, "ONESHOT|");
    208   if (0 != (EV_CLEAR & keflags))
    209     strcat (buf, "CLEAR|");
    210   if (0 != (EV_EOF & keflags))
    211     strcat (buf, "EOF|");
    212   if (0 != (EV_ERROR & keflags))
    213     strcat (buf, "ERROR|");
    214 #    ifdef EV_KEEPUDATA
    215   if (0 != (EV_KEEPUDATA & keflags))
    216     strcat (buf, "KEEPUDATA|");
    217 #    endif /* EV_KEEPUDATA */
    218 
    219   len = strlen (buf);
    220   mhd_assert (buf_size > len);
    221 
    222   extra_flags =
    223     (~((unsigned int)(EV_ADD | EV_ENABLE | EV_DISABLE | EV_DISPATCH | EV_DELETE
    224                       | EV_RECEIPT | EV_ONESHOT | EV_CLEAR | EV_EOF | EV_ERROR
    225                       | mhd_EV_KEEPUDATA_OR_ZERO))) & keflags;
    226 
    227   if (0u != extra_flags)
    228   {
    229     (void)snprintf (buf + len,
    230                     buf_size - len,
    231                     "0x%02X|",
    232                     extra_flags);
    233     len = strlen (buf);
    234     mhd_assert (buf_size > len);
    235   }
    236 
    237   if (0u == len)
    238     strcpy (buf, "0");
    239   else
    240     buf[len - 1u] = '\0'; /* Erase last '|' */
    241 }
    242 
    243 
    244 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    245 mhd_dbg_print_kevent (const char *fd_name,
    246                       const struct kevent *ke,
    247                       bool update_req)
    248 {
    249   char flags_txt[mhd_DBG_KEFLAGS_BUF_SIZE];
    250   const char *action_name =
    251     update_req ? "Update FD watching" : "FD state update";
    252 
    253   mdd_dbg_keflags_to_text (ke,
    254                            flags_txt);
    255 
    256   fprintf (stderr,
    257            "### %s: %4s [%2llu]; filter: %s; flags: %s;\t"
    258            "fflags: %u;\tdata %lld\n",
    259            action_name,
    260            fd_name,
    261            (unsigned long long)ke->ident,
    262            mhd_dbg_kefilter_to_name (ke),
    263            flags_txt,
    264            (unsigned int)ke->fflags,
    265            (long long)ke->data);
    266 }
    267 
    268 
    269 #  endif /* MHD_SUPPORT_KQUEUE */
    270 
    271 #else  /* ! MHD_USE_TRACE_POLLING_FDS */
    272 #  define dbg_print_fd_state_update(fd_n, fd, r_ready, w_ready, e_ready) \
    273           ((void) 0)
    274 #  ifdef MHD_SUPPORT_KQUEUE
    275 #    define mhd_dbg_print_kq_fd_mon_req(fd_name, ke)
    276 #  endif /* MHD_SUPPORT_KQUEUE */
    277 #endif /* ! MHD_USE_TRACE_POLLING_FDS */
    278 
    279 #ifdef MHD_SUPPORT_THREADS
    280 /**
    281  * Log error message about broken ITC
    282  * @param d the daemon to use
    283  */
    284 static MHD_FN_PAR_NONNULL_ALL_ void
    285 log_itc_broken (struct MHD_Daemon *restrict d)
    286 {
    287   mhd_LOG_MSG (d, \
    288                MHD_SC_ITC_STATUS_ERROR, \
    289                "System reported that ITC has an error status or broken.");
    290 }
    291 
    292 
    293 #endif /* MHD_SUPPORT_THREADS */
    294 
    295 /**
    296  * Log error message about broken listen socket
    297  * @param d the daemon to use
    298  */
    299 static MHD_FN_PAR_NONNULL_ALL_ void
    300 log_listen_broken (struct MHD_Daemon *restrict d)
    301 {
    302   mhd_LOG_MSG (d, MHD_SC_LISTEN_STATUS_ERROR, \
    303                "System reported that the listening socket has an error " \
    304                "status or broken. The daemon will not listen any more.");
    305 }
    306 
    307 
    308 static MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t
    309 mhd_daemon_get_wait_erliest_timeout (const struct MHD_Daemon *restrict d)
    310 {
    311   uint_fast64_t ret;
    312   uint_fast64_t cur_milsec;
    313   const struct MHD_Connection *c;
    314 
    315   c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout));
    316   if ((NULL == c)
    317       && (NULL == mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout))))
    318     return MHD_WAIT_INDEFINITELY;
    319 
    320   /* Do not use mhd_daemon_get_milsec_counter() as actual time is required
    321      here */
    322   cur_milsec = mhd_monotonic_msec_counter ();
    323 
    324   /* Check just the first connection in the ordered "default timeout" list */
    325   if (NULL != c)
    326     ret = mhd_conn_get_timeout_left (c,
    327                                      cur_milsec);
    328   else
    329     ret = MHD_WAIT_INDEFINITELY;
    330 
    331   for (c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout));
    332        (NULL != c) && (0u != ret);
    333        c = mhd_DLINKEDL_GET_PREV (&(c->timeout),
    334                                   tmout_list))
    335   {
    336     uint_fast64_t conn_tmout_left;
    337     conn_tmout_left = mhd_conn_get_timeout_left (c,
    338                                                  cur_milsec);
    339     if (ret > conn_tmout_left)
    340       ret = conn_tmout_left;
    341   }
    342 
    343   return ret;
    344 }
    345 
    346 
    347 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t
    348 mhd_daemon_get_wait_max (const struct MHD_Daemon *restrict d)
    349 {
    350   uint_fast64_t ret;
    351 
    352   mhd_assert (!mhd_D_HAS_WORKERS (d));
    353 
    354   if (d->events.accept_pending && !d->conns.block_new)
    355   {
    356 #ifdef MHD_USE_TRACE_POLLING_FDS
    357     fprintf (stderr,
    358              "### mhd_daemon_get_wait_max(daemon) -> zero "
    359              "(accept new conn pending)\n");
    360 #endif
    361     return 0;
    362   }
    363   if (d->events.act_req.resume)
    364   {
    365 #ifdef MHD_USE_TRACE_POLLING_FDS
    366     fprintf (stderr,
    367              "### mhd_daemon_get_wait_max(daemon) -> zero "
    368              "(resume connection pending)\n");
    369 #endif
    370     return 0;
    371   }
    372   if (NULL != mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready))
    373   {
    374 #ifdef MHD_USE_TRACE_POLLING_FDS
    375     fprintf (stderr,
    376              "### mhd_daemon_get_wait_max(daemon) -> zero "
    377              "(connection(s) is already ready)\n");
    378 #endif
    379     return 0;
    380   }
    381   if (NULL != mhd_DLINKEDL_GET_FIRST (&(d->events.act_req.ext_added.worker),
    382                                       queue))
    383   {
    384 #ifdef MHD_USE_TRACE_POLLING_FDS
    385     fprintf (stderr,
    386              "### mhd_daemon_get_wait_max(daemon) -> zero "
    387              "(externally added connection(s) pending)\n");
    388 #endif
    389     return 0;
    390   }
    391 #ifdef MHD_SUPPORT_KQUEUE
    392   if (mhd_D_IS_USING_KQUEUE (d))
    393   {
    394     if ((NULL != mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn))
    395         && !mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn)->events.kq.monitored)
    396     {
    397 #  ifdef MHD_USE_TRACE_POLLING_FDS
    398       fprintf (stderr,
    399                "### mhd_daemon_get_wait_max(daemon) -> zero "
    400                "(kqueue unmonitored connection(s) pending)\n");
    401 #  endif
    402       return 0;
    403     }
    404   }
    405 #endif /* MHD_SUPPORT_KQUEUE */
    406 
    407   ret = mhd_daemon_get_wait_erliest_timeout (d);
    408 
    409 #ifdef MHD_USE_TRACE_POLLING_FDS
    410   if (MHD_WAIT_INDEFINITELY == ret)
    411     fprintf (stderr,
    412              "### mhd_daemon_get_wait_max(daemon) -> MHD_WAIT_INDEFINITELY\n");
    413   else
    414     fprintf (stderr,
    415              "### mhd_daemon_get_wait_max(daemon) -> %lu\n",
    416              (unsigned long)ret);
    417 #endif
    418 
    419   return ret;
    420 }
    421 
    422 
    423 static MHD_FN_PAR_NONNULL_ALL_ void
    424 start_resuming_connection (struct MHD_Connection *restrict c,
    425                            struct MHD_Daemon *restrict d)
    426 {
    427   mhd_assert (c->suspended);
    428 #ifdef MHD_USE_TRACE_SUSPEND_RESUME
    429   fprintf (stderr,
    430            "%%%%%%   Resuming connection, FD: %2llu\n",
    431            (unsigned long long)c->sk.fd);
    432 #endif /* MHD_USE_TRACE_SUSPEND_RESUME */
    433   c->suspended = false;
    434   mhd_conn_init_activity_timeout (c,
    435                                   c->timeout.milsec);
    436   mhd_conn_mark_ready (c, d); /* Force processing connection in this round */
    437 }
    438 
    439 
    440 /**
    441  * Check whether any resuming connections are pending and resume them
    442  * @param d the daemon to use
    443  */
    444 static MHD_FN_PAR_NONNULL_ALL_ void
    445 daemon_resume_conns_if_needed (struct MHD_Daemon *restrict d)
    446 {
    447   struct MHD_Connection *c;
    448 
    449   if (!d->events.act_req.resume)
    450     return;
    451 
    452   d->events.act_req.resume = false; /* Reset flag before processing data */
    453 
    454   for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
    455        NULL != c;
    456        c = mhd_DLINKEDL_GET_NEXT (c, all_conn))
    457   {
    458     if (c->resuming)
    459       start_resuming_connection (c, d);
    460   }
    461 }
    462 
    463 
    464 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_EPOLL)
    465 
    466 mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
    467 
    468 static MHD_FN_PAR_NONNULL_ALL_ int
    469 get_max_wait (const struct MHD_Daemon *restrict d)
    470 {
    471   const uint_fast64_t ui64_wait = mhd_daemon_get_wait_max (d);
    472   int i_wait = (int)ui64_wait;
    473 
    474   if (MHD_WAIT_INDEFINITELY <= ui64_wait)
    475     return -1;
    476 
    477   if (mhd_COND_ALMOST_NEVER ((0 > i_wait)
    478                              || (ui64_wait != (uint_fast64_t)i_wait)))
    479     return INT_MAX;
    480 
    481   return i_wait;
    482 }
    483 
    484 
    485 mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
    486 /* End of warning-less data truncation */
    487 
    488 #endif
    489 /* MHD_SUPPORT_POLL || MHD_SUPPORT_EPOLL */
    490 
    491 
    492 MHD_FN_PAR_NONNULL_ (1) static void
    493 update_conn_net_status (struct MHD_Daemon *restrict d,
    494                         struct MHD_Connection *restrict c,
    495                         bool recv_ready,
    496                         bool send_ready,
    497                         bool err_state)
    498 {
    499   enum mhd_SocketNetState sk_state;
    500 
    501   mhd_assert (d == c->daemon);
    502   /* "resuming" must be not processed yet */
    503   mhd_assert (!c->resuming || c->suspended);
    504 
    505   dbg_print_fd_state_update ("conn", \
    506                              c->sk.fd, \
    507                              recv_ready, \
    508                              send_ready, \
    509                              err_state);
    510 
    511   sk_state = mhd_SOCKET_NET_STATE_NOTHING;
    512   if (recv_ready)
    513     sk_state = (enum mhd_SocketNetState)
    514                (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_RECV_READY);
    515   if (send_ready)
    516     sk_state = (enum mhd_SocketNetState)
    517                (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_SEND_READY);
    518   if (err_state)
    519     sk_state = (enum mhd_SocketNetState)
    520                (sk_state | (unsigned int)mhd_SOCKET_NET_STATE_ERROR_READY);
    521   c->sk.ready = sk_state;
    522 
    523   if (!c->suspended)
    524     mhd_conn_mark_ready_update3 (c, err_state, d);
    525   else
    526     mhd_assert (!c->in_proc_ready);
    527 }
    528 
    529 
    530 /**
    531  * Accept new connections on the daemon
    532  * @param d the daemon to use
    533  * @return true if all incoming connections has been accepted,
    534  *         false if some connection may still wait to be accepted
    535  */
    536 MHD_FN_PAR_NONNULL_ (1) static bool
    537 daemon_accept_new_conns (struct MHD_Daemon *restrict d)
    538 {
    539   unsigned int num_to_accept;
    540   mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd);
    541   mhd_assert (!d->net.listen.is_broken);
    542   mhd_assert (!d->conns.block_new);
    543   mhd_assert (d->conns.count < d->conns.cfg.count_limit);
    544   mhd_assert (!mhd_D_HAS_WORKERS (d));
    545 
    546   if (!d->net.listen.non_block)
    547     num_to_accept = 1; /* listen socket is blocking, only one connection can be processed */
    548   else
    549   {
    550     const unsigned int slots_left = d->conns.cfg.count_limit - d->conns.count;
    551     if (!mhd_D_HAS_MASTER (d))
    552     {
    553       /* Fill up to one quarter of allowed limit in one turn */
    554       num_to_accept = d->conns.cfg.count_limit / 4;
    555       /* Limit to a reasonable number */
    556       if (((sizeof(void *) > 4) ? 4096 : 1024) < num_to_accept)
    557         num_to_accept = ((sizeof(void *) > 4) ? 4096 : 1024);
    558       if (slots_left < num_to_accept)
    559         num_to_accept = slots_left;
    560     }
    561 #ifdef MHD_SUPPORT_THREADS
    562     else
    563     {
    564       /* Has workers thread pool. Care must be taken to evenly distribute
    565          new connections in the workers pool.
    566          At the same time, the burst of new connections should be handled as
    567          quick as possible. */
    568       const unsigned int num_conn = d->conns.count;
    569       const unsigned int limit = d->conns.cfg.count_limit;
    570       const unsigned int num_workers =
    571         d->threading.hier.master->threading.hier.pool.num;
    572       if (num_conn < limit / 16)
    573       {
    574         num_to_accept = num_conn / num_workers;
    575         if (8 > num_to_accept)
    576         {
    577           if (8 > slots_left / 16)
    578             num_to_accept = slots_left / 16;
    579           else
    580             num_to_accept = 8;
    581         }
    582         if (64 < num_to_accept)
    583           num_to_accept = 64;
    584       }
    585       else if (num_conn < limit / 8)
    586       {
    587         num_to_accept = num_conn * 2 / num_workers;
    588         if (8 > num_to_accept)
    589         {
    590           if (8 > slots_left / 8)
    591             num_to_accept = slots_left / 8;
    592           else
    593             num_to_accept = 8;
    594         }
    595         if (128 < num_to_accept)
    596           num_to_accept = 128;
    597       }
    598       else if (num_conn < limit / 4)
    599       {
    600         num_to_accept = num_conn * 4 / num_workers;
    601         if (8 > num_to_accept)
    602           num_to_accept = 8;
    603         if (slots_left / 4 < num_to_accept)
    604           num_to_accept = slots_left / 4;
    605         if (256 < num_to_accept)
    606           num_to_accept = 256;
    607       }
    608       else if (num_conn < limit / 2)
    609       {
    610         num_to_accept = num_conn * 8 / num_workers;
    611         if (16 > num_to_accept)
    612           num_to_accept = 16;
    613         if (slots_left / 4 < num_to_accept)
    614           num_to_accept = slots_left / 4;
    615         if (256 < num_to_accept)
    616           num_to_accept = 256;
    617       }
    618       else if (slots_left > limit / 4)
    619       {
    620         num_to_accept = slots_left * 4 / num_workers;
    621         if (slots_left / 8 < num_to_accept)
    622           num_to_accept = slots_left / 8;
    623         if (128 < num_to_accept)
    624           num_to_accept = 128;
    625       }
    626       else if (slots_left > limit / 8)
    627       {
    628         num_to_accept = slots_left * 2 / num_workers;
    629         if (slots_left / 16 < num_to_accept)
    630           num_to_accept = slots_left / 16;
    631         if (64 < num_to_accept)
    632           num_to_accept = 64;
    633       }
    634       else /* (slots_left <= limit / 8) */
    635         num_to_accept = slots_left / 16;
    636 
    637       if (0 == num_to_accept)
    638         num_to_accept = 1;
    639       else if (slots_left > num_to_accept)
    640         num_to_accept = slots_left;
    641     }
    642 #endif /* MHD_SUPPORT_THREADS */
    643   }
    644 
    645   while (0 != --num_to_accept)
    646   {
    647     enum mhd_DaemonAcceptResult res;
    648     res = mhd_daemon_accept_connection (d);
    649     if (mhd_DAEMON_ACCEPT_NO_MORE_PENDING == res)
    650       return true;
    651     if (mhd_DAEMON_ACCEPT_FAILED == res)
    652       return false; /* This is probably "no system resources" error.
    653                        To do try to accept more connections now. */
    654   }
    655   return false; /* More connections may need to be accepted */
    656 }
    657 
    658 
    659 /**
    660  * Check whether particular connection should be excluded from standard HTTP
    661  * communication.
    662  * @param c the connection the check
    663  * @return 'true' if connection should not be used for HTTP communication
    664  *         'false' if connection should be processed as HTTP
    665  */
    666 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ bool
    667 is_conn_excluded_from_http_comm (struct MHD_Connection *restrict c)
    668 {
    669 #ifdef MHD_SUPPORT_UPGRADE
    670   if (NULL != c->upgr.c)
    671   {
    672     mhd_assert ((mhd_HTTP_STAGE_UPGRADED == c->stage) \
    673                 || (mhd_HTTP_STAGE_UPGRADED_CLEANING == c->stage));
    674     return true;
    675   }
    676 #endif /* MHD_SUPPORT_UPGRADE */
    677 
    678   return c->suspended;
    679 }
    680 
    681 
    682 static bool
    683 daemon_process_all_active_conns (struct MHD_Daemon *restrict d)
    684 {
    685   struct MHD_Connection *c;
    686   mhd_assert (!mhd_D_HAS_WORKERS (d));
    687 
    688   c = mhd_DLINKEDL_GET_FIRST (&(d->events), proc_ready);
    689   while (NULL != c)
    690   {
    691     struct MHD_Connection *next;
    692     /* The current connection can be closed or removed from
    693        "ready" list */
    694     next = mhd_DLINKEDL_GET_NEXT (c, proc_ready);
    695     if (!mhd_conn_process_recv_send_data (c))
    696     {
    697       mhd_conn_pre_clean (c);
    698       mhd_conn_remove_from_daemon (c);
    699       mhd_conn_close_final (c);
    700     }
    701     else
    702     {
    703       mhd_assert (!c->resuming || c->suspended);
    704     }
    705 
    706     c = next;
    707   }
    708   return true;
    709 }
    710 
    711 
    712 #ifdef MHD_SUPPORT_UPGRADE
    713 /**
    714  * Clean-up all HTTP-Upgraded connections scheduled for clean-up
    715  * @param d the daemon to process
    716  */
    717 static MHD_FN_PAR_NONNULL_ALL_ void
    718 daemon_cleanup_upgraded_conns (struct MHD_Daemon *d)
    719 {
    720   volatile struct MHD_Daemon *voltl_d = d;
    721   mhd_assert (!mhd_D_HAS_WORKERS (d));
    722 
    723   if (NULL == mhd_DLINKEDL_GET_FIRST (&(voltl_d->conns.upgr), upgr_cleanup))
    724     return;
    725 
    726   while (true)
    727   {
    728     struct MHD_Connection *c;
    729 
    730     mhd_mutex_lock_chk (&(d->conns.upgr.ucu_lock));
    731     c = mhd_DLINKEDL_GET_FIRST (&(d->conns.upgr), upgr_cleanup);
    732     if (NULL != c)
    733       mhd_DLINKEDL_DEL (&(d->conns.upgr), c, upgr_cleanup);
    734     mhd_mutex_unlock_chk (&(d->conns.upgr.ucu_lock));
    735 
    736     if (NULL == c)
    737       break;
    738 
    739     mhd_assert (mhd_HTTP_STAGE_UPGRADED_CLEANING == c->stage);
    740     mhd_upgraded_deinit (c);
    741     mhd_conn_pre_clean (c);
    742     mhd_conn_remove_from_daemon (c);
    743     mhd_conn_close_final (c);
    744   }
    745 }
    746 
    747 
    748 #else  /* ! MHD_SUPPORT_UPGRADE */
    749 #  define daemon_cleanup_upgraded_conns(d) ((void) d)
    750 #endif /* ! MHD_SUPPORT_UPGRADE */
    751 
    752 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    753 mhd_daemon_close_all_conns (struct MHD_Daemon *d)
    754 {
    755   struct MHD_Connection *c;
    756   bool has_upgraded_unclosed;
    757 
    758   has_upgraded_unclosed = false;
    759   if (!mhd_D_HAS_THR_PER_CONN (d))
    760   {
    761     for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
    762          NULL != c;
    763          c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn))
    764     {
    765 #ifdef MHD_SUPPORT_UPGRADE
    766       mhd_assert (mhd_HTTP_STAGE_UPGRADING != c->stage);
    767       mhd_assert (mhd_HTTP_STAGE_UPGRADED_CLEANING != c->stage);
    768       if (NULL != c->upgr.c)
    769       {
    770         mhd_assert (c == c->upgr.c);
    771         has_upgraded_unclosed = true;
    772         mhd_upgraded_deinit (c);
    773       }
    774       else /* Combined with the next 'if' */
    775 #endif
    776       if (1)
    777       {
    778 #ifdef MHD_SUPPORT_HTTP2
    779         if (mhd_C_IS_HTTP2 (c))
    780           mhd_h2_conn_h2_deinit_start_closing (c);
    781         else
    782 #endif /* MHD_SUPPORT_HTTP2 */
    783         mhd_conn_start_closing_d_shutdown (c);
    784       }
    785       mhd_conn_pre_clean (c);
    786       mhd_conn_remove_from_daemon (c);
    787       mhd_conn_close_final (c);
    788     }
    789   }
    790   else
    791     mhd_assert (0 && "Not implemented yet");
    792 
    793   if (has_upgraded_unclosed)
    794     mhd_LOG_MSG (d, MHD_SC_DAEMON_DESTROYED_WITH_UNCLOSED_UPGRADED, \
    795                  "The daemon is being destroyed, but at least one " \
    796                  "HTTP-Upgraded connection is unclosed. Any use (including " \
    797                  "closing) of such connections is undefined behaviour.");
    798 }
    799 
    800 
    801 /**
    802  * Process all external events updated of existing connections, information
    803  * about new connections pending to be accept()'ed, presence of the events on
    804  * the daemon's ITC; resume connections.
    805  * @return 'true' if processed successfully,
    806  *         'false' is unrecoverable error occurs and the daemon must be
    807  *         closed
    808  */
    809 static MHD_FN_PAR_NONNULL_ (1) bool
    810 ext_events_process_net_updates_and_resume_conn (struct MHD_Daemon *restrict d)
    811 {
    812   struct MHD_Connection *restrict c;
    813 
    814   mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
    815   mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
    816 
    817   d->events.act_req.resume = false; /* Reset flag before processing data */
    818 
    819 #ifdef MHD_SUPPORT_THREADS
    820   if (d->events.data.extr.itc_data.is_active)
    821   {
    822     d->events.data.extr.itc_data.is_active = false;
    823     /* Clear ITC here, before other data processing.
    824      * Any external events will activate ITC again if additional data to
    825      * process is added externally. Clearing ITC early ensures that new data
    826      * (with additional ITC activation) will not be missed. */
    827     mhd_itc_clear (d->threading.itc);
    828   }
    829 #endif /* MHD_SUPPORT_THREADS */
    830 
    831   for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
    832        NULL != c;
    833        c = mhd_DLINKEDL_GET_NEXT (c, all_conn))
    834   {
    835     bool has_err_state;
    836 
    837     if (c->resuming)
    838       start_resuming_connection (c, d);
    839     else
    840     {
    841       if (is_conn_excluded_from_http_comm (c))
    842       {
    843         mhd_assert (!c->in_proc_ready);
    844         continue;
    845       }
    846 
    847       has_err_state = (0 != (((unsigned int)c->sk.ready)
    848                              & mhd_SOCKET_NET_STATE_ERROR_READY));
    849 
    850       mhd_conn_mark_ready_update3 (c,
    851                                    has_err_state,
    852                                    d);
    853     }
    854   }
    855 
    856   return true;
    857 }
    858 
    859 
    860 /**
    861  * Update all registrations of FDs for external monitoring.
    862  * @return #MHD_SC_OK on success,
    863  *         error code otherwise
    864  */
    865 static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
    866 ext_events_update_registrations (struct MHD_Daemon *restrict d)
    867 {
    868   const bool rereg_all = d->events.data.extr.reg_all;
    869   const bool edge_trigg = (mhd_WM_INT_EXTERNAL_EVENTS_EDGE == d->wmode_int);
    870   bool daemon_fds_succeed;
    871   struct MHD_Connection *c;
    872   struct MHD_Connection *c_next;
    873 
    874   mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
    875   mhd_assert (mhd_POLL_TYPE_EXT == d->events.poll_type);
    876 
    877   /* (Re-)register daemon's FDs */
    878 
    879 #ifdef MHD_SUPPORT_THREADS
    880   if (rereg_all
    881       || (NULL == d->events.data.extr.itc_data.app_cntx))
    882   {
    883     /* (Re-)register ITC FD */
    884     d->events.data.extr.itc_data.app_cntx =
    885       mhd_daemon_extr_event_reg (d,
    886                                  mhd_itc_r_fd (d->threading.itc),
    887                                  MHD_FD_STATE_RECV_EXCEPT,
    888                                  d->events.data.extr.itc_data.app_cntx,
    889                                  (struct MHD_EventUpdateContext *)
    890                                  mhd_SOCKET_REL_MARKER_ITC);
    891   }
    892   daemon_fds_succeed = (NULL != d->events.data.extr.itc_data.app_cntx);
    893 #else  /* ! MHD_SUPPORT_THREADS */
    894   daemon_fds_succeed = true;
    895 #endif /* ! MHD_SUPPORT_THREADS */
    896 
    897   if (daemon_fds_succeed)
    898   {
    899     if ((MHD_INVALID_SOCKET == d->net.listen.fd)
    900         && (NULL != d->events.data.extr.listen_data.app_cntx))
    901     {
    902       /* De-register the listen FD */
    903       d->events.data.extr.listen_data.app_cntx =
    904         mhd_daemon_extr_event_reg (d,
    905                                    d->net.listen.fd,
    906                                    MHD_FD_STATE_NONE,
    907                                    d->events.data.extr.listen_data.app_cntx,
    908                                    (struct MHD_EventUpdateContext *)
    909                                    mhd_SOCKET_REL_MARKER_LISTEN);
    910       if (NULL != d->events.data.extr.listen_data.app_cntx)
    911         mhd_log_extr_event_dereg_failed (d);
    912     }
    913     else if ((MHD_INVALID_SOCKET != d->net.listen.fd)
    914              && (rereg_all
    915                  || (NULL == d->events.data.extr.listen_data.app_cntx)))
    916     {
    917       /* (Re-)register listen FD */
    918       d->events.data.extr.listen_data.app_cntx =
    919         mhd_daemon_extr_event_reg (d,
    920                                    d->net.listen.fd,
    921                                    MHD_FD_STATE_RECV_EXCEPT,
    922                                    d->events.data.extr.listen_data.app_cntx,
    923                                    (struct MHD_EventUpdateContext *)
    924                                    mhd_SOCKET_REL_MARKER_LISTEN);
    925 
    926       daemon_fds_succeed = (NULL != d->events.data.extr.listen_data.app_cntx);
    927     }
    928   }
    929 
    930   if (!daemon_fds_succeed)
    931   {
    932     mhd_LOG_MSG (d, MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE, \
    933                  "Failed to register daemon FDs in the application "
    934                  "(external events) monitoring.");
    935     return MHD_SC_EXT_EVENT_REG_DAEMON_FDS_FAILURE;
    936   }
    937 
    938   for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
    939        NULL != c;
    940        c = c_next)
    941   {
    942     enum MHD_FdState watch_for;
    943 
    944     /* Get the next connection now, as the current connection could be removed
    945        from the daemon. */
    946     c_next = mhd_DLINKEDL_GET_NEXT (c, all_conn);
    947 
    948     mhd_assert (!c->resuming || c->suspended);
    949 
    950     if (is_conn_excluded_from_http_comm (c))
    951     {
    952       if (NULL != c->events.extrn.app_cntx)
    953       {
    954         /* De-register the connection socket FD */
    955         c->events.extrn.app_cntx =
    956           mhd_daemon_extr_event_reg (d,
    957                                      c->sk.fd,
    958                                      MHD_FD_STATE_NONE,
    959                                      c->events.extrn.app_cntx,
    960                                      (struct MHD_EventUpdateContext *)c);
    961         if (NULL != c->events.extrn.app_cntx)
    962           mhd_log_extr_event_dereg_failed (d);
    963       }
    964       continue;
    965     }
    966 
    967     watch_for =
    968       edge_trigg ?
    969       MHD_FD_STATE_RECV_SEND_EXCEPT :
    970       (enum MHD_FdState)(MHD_FD_STATE_EXCEPT
    971                          | (((unsigned int)c->event_loop_info)
    972                             & (MHD_EVENT_LOOP_INFO_RECV
    973                                | MHD_EVENT_LOOP_INFO_SEND)));
    974 
    975     mhd_assert ((!edge_trigg) \
    976                 || (MHD_FD_STATE_RECV_SEND_EXCEPT == c->events.extrn.reg_for) \
    977                 || (NULL == c->events.extrn.app_cntx));
    978 
    979     if ((NULL == c->events.extrn.app_cntx)
    980         || rereg_all
    981         || (!edge_trigg && (watch_for != c->events.extrn.reg_for)))
    982     {
    983       /* (Re-)register the connection socket FD */
    984       c->events.extrn.app_cntx =
    985         mhd_daemon_extr_event_reg (d,
    986                                    c->sk.fd,
    987                                    watch_for,
    988                                    c->events.extrn.app_cntx,
    989                                    (struct MHD_EventUpdateContext *)c);
    990       if (NULL == c->events.extrn.app_cntx)
    991       {
    992         mhd_conn_start_closing_ext_event_failed (c);
    993         mhd_conn_pre_clean (c);
    994         mhd_conn_remove_from_daemon (c);
    995         mhd_conn_close_final (c);
    996       }
    997       c->events.extrn.reg_for = watch_for;
    998     }
    999   }
   1000 
   1001   return MHD_SC_OK;
   1002 }
   1003 
   1004 
   1005 #ifdef MHD_SUPPORT_SELECT
   1006 
   1007 /**
   1008  * Add socket to the fd_set
   1009  * @param fd the socket to add
   1010  * @param fs the pointer to fd_set
   1011  * @param max the pointer to variable to be updated with maximum FD value (or
   1012  *            set to non-zero in case of WinSock)
   1013  * @param d the daemon object
   1014  */
   1015 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_
   1016 MHD_FN_PAR_INOUT_ (2)
   1017 MHD_FN_PAR_INOUT_ (3) void
   1018 fd_set_wrap (MHD_Socket fd,
   1019              fd_set *restrict fs,
   1020              int *restrict max,
   1021              struct MHD_Daemon *restrict d)
   1022 {
   1023   mhd_assert (mhd_FD_FITS_DAEMON (d, fd)); /* Must be checked for every FD before
   1024                                               it is added */
   1025   mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type);
   1026   (void)d;  /* Unused with non-debug builds */
   1027 #  if defined(MHD_SOCKETS_KIND_POSIX)
   1028   FD_SET (fd, fs);
   1029   if (*max < fd)
   1030     *max = fd;
   1031 #  elif defined(MHD_SOCKETS_KIND_WINSOCK)
   1032   /* Use custom set function to take advantage of know uniqueness of
   1033    * used sockets (to skip useless (for this function) check for duplicated
   1034    * sockets implemented in system's macro). */
   1035   mhd_assert (fs->fd_count < FD_SETSIZE - 1); /* Daemon limits set to always fit FD_SETSIZE */
   1036   mhd_assert (!FD_ISSET (fd, fs));  /* All sockets must be unique */
   1037   fs->fd_array[fs->fd_count++] = fd;
   1038   *max = 1;
   1039 #  else
   1040 #    error Unknown sockets type
   1041 #  endif
   1042 }
   1043 
   1044 
   1045 /**
   1046  * Set daemon's FD_SETs to monitor all daemon's sockets
   1047  * @param d the daemon to use
   1048  * @param listen_only set to 'true' if connections's sockets should NOT
   1049  *                    be monitored
   1050  * @return with POSIX sockets: the maximum number of the socket used in
   1051  *                             the FD_SETs;
   1052  *         with winsock: non-zero if at least one socket has been added to
   1053  *                       the FD_SETs,
   1054  *                       zero if no sockets in the FD_SETs
   1055  */
   1056 static MHD_FN_PAR_NONNULL_ (1) int
   1057 select_update_fdsets (struct MHD_Daemon *restrict d,
   1058                       bool listen_only)
   1059 {
   1060   struct MHD_Connection *c;
   1061   fd_set *const restrict rfds = d->events.data.select.rfds;
   1062   fd_set *const restrict wfds = d->events.data.select.wfds;
   1063   fd_set *const restrict efds = d->events.data.select.efds;
   1064   int ret;
   1065 
   1066   mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type);
   1067   mhd_assert (NULL != rfds);
   1068   mhd_assert (NULL != wfds);
   1069   mhd_assert (NULL != efds);
   1070   FD_ZERO (rfds);
   1071   FD_ZERO (wfds);
   1072   FD_ZERO (efds);
   1073 
   1074   ret = 0;
   1075 #  ifdef MHD_SUPPORT_THREADS
   1076   mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   1077   fd_set_wrap (mhd_itc_r_fd (d->threading.itc),
   1078                rfds,
   1079                &ret,
   1080                d);
   1081   fd_set_wrap (mhd_itc_r_fd (d->threading.itc),
   1082                efds,
   1083                &ret,
   1084                d);
   1085   mhd_dbg_print_fd_mon_req ("ITC", \
   1086                             mhd_itc_r_fd (d->threading.itc), \
   1087                             true, \
   1088                             false, \
   1089                             true);
   1090 #  endif
   1091   if ((MHD_INVALID_SOCKET != d->net.listen.fd)
   1092       && !d->conns.block_new)
   1093   {
   1094     mhd_assert (!d->net.listen.is_broken);
   1095 
   1096     fd_set_wrap (d->net.listen.fd,
   1097                  rfds,
   1098                  &ret,
   1099                  d);
   1100     fd_set_wrap (d->net.listen.fd,
   1101                  efds,
   1102                  &ret,
   1103                  d);
   1104     mhd_dbg_print_fd_mon_req ("lstn", \
   1105                               d->net.listen.fd, \
   1106                               true, \
   1107                               false, \
   1108                               true);
   1109   }
   1110   if (listen_only)
   1111     return ret;
   1112 
   1113   for (c = mhd_DLINKEDL_GET_LAST (&(d->conns), all_conn); NULL != c;
   1114        c = mhd_DLINKEDL_GET_PREV (c, all_conn))
   1115   {
   1116     mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage);
   1117     if (is_conn_excluded_from_http_comm (c))
   1118       continue;
   1119 
   1120     if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV))
   1121       fd_set_wrap (c->sk.fd,
   1122                    rfds,
   1123                    &ret,
   1124                    d);
   1125     if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND))
   1126       fd_set_wrap (c->sk.fd,
   1127                    wfds,
   1128                    &ret,
   1129                    d);
   1130     fd_set_wrap (c->sk.fd,
   1131                  efds,
   1132                  &ret,
   1133                  d);
   1134     mhd_dbg_print_fd_mon_req ("conn", \
   1135                               c->sk.fd, \
   1136                               FD_ISSET (c->sk.fd, rfds), \
   1137                               FD_ISSET (c->sk.fd, wfds), \
   1138                               true);
   1139   }
   1140 
   1141   return ret;
   1142 }
   1143 
   1144 
   1145 static MHD_FN_PAR_NONNULL_ (1) bool
   1146 select_update_statuses_from_fdsets_and_resume_conn (struct MHD_Daemon *d,
   1147                                                     int num_events)
   1148 {
   1149   struct MHD_Connection *c;
   1150   fd_set *const restrict rfds = d->events.data.select.rfds;
   1151   fd_set *const restrict wfds = d->events.data.select.wfds;
   1152   fd_set *const restrict efds = d->events.data.select.efds;
   1153   bool resuming_conn;
   1154 
   1155   mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type);
   1156   mhd_assert (0 <= num_events);
   1157   mhd_assert (((unsigned int)num_events) <= d->dbg.num_events_elements);
   1158 
   1159   resuming_conn = d->events.act_req.resume;
   1160   if (resuming_conn)
   1161   {
   1162     mhd_assert (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type));
   1163     mhd_assert (!mhd_D_HAS_THR_PER_CONN (d));
   1164     num_events = (int)-1;  /* Force process all connections */
   1165     d->events.act_req.resume = false;
   1166   }
   1167 
   1168 #  ifndef MHD_FAVOR_SMALL_CODE
   1169   if (0 == num_events)
   1170     return true;
   1171 #  endif /* MHD_FAVOR_SMALL_CODE */
   1172 
   1173 #  ifdef MHD_SUPPORT_THREADS
   1174   mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   1175   dbg_print_fd_state_update ("ITC", \
   1176                              mhd_itc_r_fd (d->threading.itc), \
   1177                              FD_ISSET (mhd_itc_r_fd (d->threading.itc), rfds), \
   1178                              FD_ISSET (mhd_itc_r_fd (d->threading.itc), wfds), \
   1179                              FD_ISSET (mhd_itc_r_fd (d->threading.itc), efds));
   1180   if (FD_ISSET (mhd_itc_r_fd (d->threading.itc), efds))
   1181   {
   1182     log_itc_broken (d);
   1183     /* ITC is broken, need to stop the daemon thread now as otherwise
   1184        application will not be able to stop the thread. */
   1185     return false;
   1186   }
   1187   if (FD_ISSET (mhd_itc_r_fd (d->threading.itc), rfds))
   1188   {
   1189     --num_events;
   1190     /* Clear ITC here, before other data processing.
   1191      * Any external events will activate ITC again if additional data to
   1192      * process is added externally. Clearing ITC early ensures that new data
   1193      * (with additional ITC activation) will not be missed. */
   1194     mhd_itc_clear (d->threading.itc);
   1195   }
   1196 
   1197 #    ifndef MHD_FAVOR_SMALL_CODE
   1198   if (0 == num_events)
   1199     return true;
   1200 #    endif /* MHD_FAVOR_SMALL_CODE */
   1201 #  endif /* MHD_SUPPORT_THREADS */
   1202 
   1203   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1204   {
   1205     mhd_assert (!d->net.listen.is_broken);
   1206     dbg_print_fd_state_update ("lstn", \
   1207                                d->net.listen.fd, \
   1208                                FD_ISSET (d->net.listen.fd, rfds), \
   1209                                FD_ISSET (d->net.listen.fd, wfds), \
   1210                                FD_ISSET (d->net.listen.fd, efds));
   1211     if (FD_ISSET (d->net.listen.fd, efds))
   1212     {
   1213       --num_events;
   1214       log_listen_broken (d);
   1215       /* Close the listening socket unless the master daemon should close it */
   1216       if (!mhd_D_HAS_MASTER (d))
   1217         mhd_socket_close (d->net.listen.fd);
   1218 
   1219       d->events.accept_pending = false;
   1220       d->net.listen.is_broken = true;
   1221       /* Stop monitoring socket to avoid spinning with busy-waiting */
   1222       d->net.listen.fd = MHD_INVALID_SOCKET;
   1223 #  ifndef MHD_FAVOR_SMALL_CODE
   1224       if (FD_ISSET (d->net.listen.fd, rfds))
   1225         --num_events;
   1226 #  endif /* MHD_FAVOR_SMALL_CODE */
   1227     }
   1228     else
   1229     {
   1230       d->events.accept_pending = FD_ISSET (d->net.listen.fd, rfds);
   1231       if (d->events.accept_pending)
   1232         --num_events;
   1233     }
   1234   }
   1235 
   1236   mhd_assert ((0 == num_events) \
   1237               || (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type)));
   1238 
   1239 #  ifdef MHD_FAVOR_SMALL_CODE
   1240   (void)num_events;
   1241   num_events = 1; /* Use static value to minimise the binary size of the next loop */
   1242 #  endif /* ! MHD_FAVOR_SMALL_CODE */
   1243 
   1244   for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
   1245        (NULL != c) && (0 != num_events);
   1246        c = mhd_DLINKEDL_GET_NEXT (c, all_conn))
   1247   {
   1248     if (c->resuming)
   1249       start_resuming_connection (c, d);
   1250     else
   1251     {
   1252       MHD_Socket sk;
   1253       bool recv_ready;
   1254       bool send_ready;
   1255       bool err_state;
   1256 
   1257       if (is_conn_excluded_from_http_comm (c))
   1258         continue;
   1259 
   1260       sk = c->sk.fd;
   1261       recv_ready = FD_ISSET (sk, rfds);
   1262       send_ready = FD_ISSET (sk, wfds);
   1263       err_state = FD_ISSET (sk, efds);
   1264 
   1265       update_conn_net_status (d,
   1266                               c,
   1267                               recv_ready,
   1268                               send_ready,
   1269                               err_state);
   1270 #  ifndef MHD_FAVOR_SMALL_CODE
   1271       num_events -=
   1272         (recv_ready ? 1 : 0) + (send_ready ? 1 : 0) + (err_state ? 1 : 0);
   1273 #  endif /* MHD_FAVOR_SMALL_CODE */
   1274     }
   1275   }
   1276 
   1277 #  ifndef MHD_FAVOR_SMALL_CODE
   1278   mhd_assert ((0 == num_events) || resuming_conn);
   1279 #  endif /* MHD_FAVOR_SMALL_CODE */
   1280   return true;
   1281 }
   1282 
   1283 
   1284 /**
   1285  * Get pointer to struct timeval for select() for polling daemon's sockets
   1286  * @param d the daemon to use
   1287  * @param[out] tmvl to pointer to the allocated struct timeval
   1288  * @return the @a tmvl pointer (with maximum wait value set)
   1289  *         or NULL if select may wait indefinitely
   1290  */
   1291 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_
   1292 MHD_FN_PAR_OUT_ (2) struct timeval *
   1293 get_timeval_for_select (const struct MHD_Daemon *restrict d,
   1294                         struct timeval *tmvl)
   1295 {
   1296   const uint_fast64_t max_wait = mhd_daemon_get_wait_max (d);
   1297 #  ifdef HAVE_TIME_T
   1298   time_t max_wait_secs = (time_t)(max_wait / 1000u);
   1299 #  else  /* ! HAVE_TIME_T */
   1300   long max_wait_secs = (long)(max_wait / 1000u);
   1301 #  endif /* ! HAVE_TIME_T */
   1302 #  ifdef HAVE_SUSECONDS_T
   1303   suseconds_t max_wait_usecs = (suseconds_t)((max_wait % 1000u) * 1000u);
   1304 #  else  /* ! HAVE_SUSECONDS_T */
   1305   long max_wait_usecs = (long)((max_wait % 1000u) * 1000u);
   1306 #  endif /* ! HAVE_SUSECONDS_T */
   1307 
   1308   if (MHD_WAIT_INDEFINITELY <= max_wait)
   1309     return NULL;
   1310 
   1311   if (0u == max_wait)
   1312   {
   1313     tmvl->tv_sec = 0;
   1314     tmvl->tv_usec = 0;
   1315 
   1316     return tmvl;
   1317   }
   1318 
   1319   if (mhd_COND_ALMOST_NEVER ((max_wait / 1000u !=
   1320                               (uint_fast64_t)max_wait_secs)
   1321                              || (max_wait_secs <= 0)))
   1322   {
   1323     /* Do not bother figuring out the real maximum 'time_t' value.
   1324        '0x7FFFFFFF' is large enough to be already unrealistic and should
   1325        fit most of signed or unsigned time_t types. */
   1326     tmvl->tv_sec = 0x7FFFFFFF;
   1327     tmvl->tv_usec = 0;
   1328 
   1329     return tmvl;
   1330   }
   1331 
   1332   tmvl->tv_sec = max_wait_secs;
   1333   tmvl->tv_usec = max_wait_usecs;
   1334 
   1335   return tmvl;
   1336 }
   1337 
   1338 
   1339 /**
   1340  * Update states of all connections, check for connection pending
   1341  * to be accept()'ed, check for the events on ITC; resume connections
   1342  * @param listen_only set to 'true' if connections's sockets should NOT
   1343  *                    be monitored
   1344  * @return 'true' if processed successfully,
   1345  *         'false' is unrecoverable error occurs and the daemon must be
   1346  *         closed
   1347  */
   1348 static MHD_FN_PAR_NONNULL_ (1) bool
   1349 get_all_net_updates_by_select_and_resume_conn (struct MHD_Daemon *restrict d,
   1350                                                bool listen_only)
   1351 {
   1352   int max_socket;
   1353   struct timeval tmvl_value;
   1354   struct timeval *tmvl_ptr;
   1355   int num_events;
   1356   mhd_assert (mhd_POLL_TYPE_SELECT == d->events.poll_type);
   1357 
   1358   max_socket = select_update_fdsets (d,
   1359                                      listen_only);
   1360 
   1361   tmvl_ptr = get_timeval_for_select (d,
   1362                                      &tmvl_value);
   1363 
   1364 #  ifdef MHD_SOCKETS_KIND_WINSOCK
   1365   if (0 == max_socket)
   1366   {
   1367     Sleep (tmvl_ptr ? tmvl_ptr->tv_sec : 600);
   1368     return true;
   1369   }
   1370 #  endif /* MHD_SOCKETS_KIND_WINSOCK */
   1371 
   1372 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1373   if (NULL != tmvl_ptr)
   1374     fprintf (stderr,
   1375              "### (Starting) select(%d, rfds, wfds, efds, [%llu, %llu])...\n",
   1376              max_socket + 1,
   1377              (unsigned long long)tmvl_ptr->tv_sec,
   1378              (unsigned long long)tmvl_ptr->tv_usec);
   1379   else
   1380     fprintf (stderr,
   1381              "### (Starting) select(%d, rfds, wfds, efds, [NULL])...\n",
   1382              max_socket + 1);
   1383 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1384   num_events = select (max_socket + 1,
   1385                        d->events.data.select.rfds,
   1386                        d->events.data.select.wfds,
   1387                        d->events.data.select.efds,
   1388                        tmvl_ptr);
   1389 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1390   if (NULL != tmvl_ptr)
   1391     fprintf (stderr,
   1392              "### (Finished) select(%d, rfds, wfds, efds, ->[%llu, %llu]) -> "
   1393              "%d\n",
   1394              max_socket + 1,
   1395              (unsigned long long)tmvl_ptr->tv_sec,
   1396              (unsigned long long)tmvl_ptr->tv_usec,
   1397              num_events);
   1398   else
   1399     fprintf (stderr,
   1400              "### (Finished) select(%d, rfds, wfds, efds, [NULL]) -> "
   1401              "%d\n",
   1402              max_socket + 1,
   1403              num_events);
   1404 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1405 
   1406   if (0 > num_events)
   1407   {
   1408     int err;
   1409     bool is_hard_error;
   1410     bool is_ignored_error;
   1411     is_hard_error = false;
   1412     is_ignored_error = false;
   1413 #  if defined(MHD_SOCKETS_KIND_POSIX)
   1414     err = errno;
   1415     if (0 != err)
   1416     {
   1417       is_hard_error =
   1418         ((mhd_EBADF_OR_ZERO == err) || (mhd_EINVAL_OR_ZERO == err));
   1419       is_ignored_error = (mhd_EINTR_OR_ZERO == err);
   1420     }
   1421 #  elif defined(MHD_SOCKETS_KIND_WINSOCK)
   1422     err = WSAGetLastError ();
   1423     is_hard_error =
   1424       ((WSAENETDOWN == err) || (WSAEFAULT == err) || (WSAEINVAL == err)
   1425        || (WSANOTINITIALISED == err));
   1426 #  endif
   1427     if (!is_ignored_error)
   1428     {
   1429       if (is_hard_error)
   1430       {
   1431         mhd_LOG_MSG (d, MHD_SC_SELECT_HARD_ERROR, \
   1432                      "The select() encountered unrecoverable error.");
   1433         return false;
   1434       }
   1435       mhd_LOG_MSG (d, MHD_SC_SELECT_SOFT_ERROR, \
   1436                    "The select() encountered error.");
   1437       return true;
   1438     }
   1439   }
   1440 
   1441   return select_update_statuses_from_fdsets_and_resume_conn (d, num_events);
   1442 }
   1443 
   1444 
   1445 #endif /* MHD_SUPPORT_SELECT */
   1446 
   1447 
   1448 #ifdef MHD_SUPPORT_POLL
   1449 
   1450 static MHD_FN_PAR_NONNULL_ (1) unsigned int
   1451 poll_update_fds (struct MHD_Daemon *restrict d,
   1452                  bool listen_only)
   1453 {
   1454   unsigned int i_s;
   1455   unsigned int i_c;
   1456   struct MHD_Connection *restrict c;
   1457 #  ifndef NDEBUG
   1458   unsigned int num_skipped = 0;
   1459 #  endif /* ! NDEBUG */
   1460 
   1461   mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type);
   1462 
   1463   i_s = 0;
   1464 #  ifdef MHD_SUPPORT_THREADS
   1465   mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   1466   mhd_assert (d->events.data.poll.fds[i_s].fd == \
   1467               mhd_itc_r_fd (d->threading.itc));
   1468   mhd_assert (mhd_SOCKET_REL_MARKER_ITC == \
   1469               d->events.data.poll.rel[i_s].fd_id);
   1470 #    ifndef HAVE_POLL_CLOBBERS_EVENTS
   1471   mhd_assert (POLLIN == d->events.data.poll.fds[i_s].events);
   1472 #    else  /* HAVE_POLL_CLOBBERS_EVENTS */
   1473   d->events.data.poll.fds[i_s].events = POLLIN;
   1474 #    endif /* HAVE_POLL_CLOBBERS_EVENTS */
   1475   mhd_dbg_print_fd_mon_req ("ITC", \
   1476                             mhd_itc_r_fd (d->threading.itc), \
   1477                             true, \
   1478                             false, \
   1479                             false);
   1480   ++i_s;
   1481 #  endif
   1482   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1483   {
   1484     mhd_assert (!d->net.listen.is_broken);
   1485     mhd_assert (d->events.data.poll.fds[i_s].fd == d->net.listen.fd);
   1486     mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN == \
   1487                 d->events.data.poll.rel[i_s].fd_id);
   1488 #  ifndef HAVE_POLL_CLOBBERS_EVENTS
   1489     mhd_assert ((POLLIN == d->events.data.poll.fds[i_s].events)
   1490                 || (0 == d->events.data.poll.fds[i_s].events));
   1491 #  endif /* ! HAVE_POLL_CLOBBERS_EVENTS */
   1492     d->events.data.poll.fds[i_s].events = d->conns.block_new ? 0 : POLLIN;
   1493     mhd_dbg_print_fd_mon_req ("lstn", \
   1494                               d->net.listen.fd, \
   1495                               POLLIN == d->events.data.poll.fds[i_s].events, \
   1496                               false, \
   1497                               false);
   1498     ++i_s;
   1499   }
   1500   if (listen_only)
   1501     return i_s;
   1502 
   1503   i_c = i_s;
   1504   for (c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn); NULL != c;
   1505        c = mhd_DLINKEDL_GET_NEXT (c, all_conn))
   1506   {
   1507     unsigned short events; /* 'unsigned' for correct bits manipulations */
   1508 
   1509     if (is_conn_excluded_from_http_comm (c))
   1510     {
   1511 #  ifndef NDEBUG
   1512       ++num_skipped;
   1513 #  endif /* ! NDEBUG */
   1514       continue;
   1515     }
   1516 
   1517     mhd_assert ((i_c - i_s) < d->conns.cfg.count_limit);
   1518     mhd_assert (i_c < d->dbg.num_events_elements);
   1519     mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage);
   1520 
   1521     d->events.data.poll.fds[i_c].fd = c->sk.fd;
   1522     d->events.data.poll.rel[i_c].connection = c;
   1523     events = 0;
   1524     if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV))
   1525       events |= MHD_POLL_IN;
   1526     if (0 != (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND))
   1527       events |= MHD_POLL_OUT;
   1528 
   1529     d->events.data.poll.fds[i_c].events = (short)events;
   1530     mhd_dbg_print_fd_mon_req ("conn", \
   1531                               c->sk.fd, \
   1532                               MHD_POLL_IN == (MHD_POLL_IN & events), \
   1533                               MHD_POLL_OUT == (MHD_POLL_OUT & events), \
   1534                               false);
   1535     ++i_c;
   1536   }
   1537   mhd_assert ((d->conns.count - num_skipped) == (i_c - i_s));
   1538   mhd_assert (i_c <= d->dbg.num_events_elements);
   1539   return i_c;
   1540 }
   1541 
   1542 
   1543 static MHD_FN_PAR_NONNULL_ (1) bool
   1544 poll_update_statuses_from_fds (struct MHD_Daemon *restrict d,
   1545                                int num_events)
   1546 {
   1547   unsigned int i_s;
   1548   unsigned int i_c;
   1549   mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type);
   1550   mhd_assert (0 <= num_events);
   1551   mhd_assert (((unsigned int)num_events) <= d->dbg.num_events_elements);
   1552 
   1553   if (0 == num_events)
   1554     return true;
   1555 
   1556   i_s = 0;
   1557 #  ifdef MHD_SUPPORT_THREADS
   1558   mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   1559   mhd_assert (d->events.data.poll.fds[i_s].fd == \
   1560               mhd_itc_r_fd (d->threading.itc));
   1561   mhd_assert (mhd_SOCKET_REL_MARKER_ITC == \
   1562               d->events.data.poll.rel[i_s].fd_id);
   1563 #    ifndef HAVE_POLL_CLOBBERS_EVENTS
   1564   mhd_assert (POLLIN == d->events.data.poll.fds[i_s].events);
   1565 #    endif /* ! HAVE_POLL_CLOBBERS_EVENTS */
   1566   dbg_print_fd_state_update ( \
   1567     "ITC", \
   1568     d->events.data.poll.fds[i_s].fd, \
   1569     0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_IN | POLLIN)), \
   1570     0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_OUT | POLLOUT)), \
   1571     0 != (d->events.data.poll.fds[i_s].revents & (POLLERR | POLLNVAL)));
   1572 
   1573   if (0 != (d->events.data.poll.fds[i_s].revents & (POLLERR | POLLNVAL)))
   1574   {
   1575     log_itc_broken (d);
   1576     /* ITC is broken, need to stop the daemon thread now as otherwise
   1577        application will not be able to stop the thread. */
   1578     return false;
   1579   }
   1580   if (0 != (d->events.data.poll.fds[i_s].revents & (MHD_POLL_IN | POLLIN)))
   1581   {
   1582     --num_events;
   1583     /* Clear ITC here, before other data processing.
   1584      * Any external events will activate ITC again if additional data to
   1585      * process is added externally. Clearing ITC early ensures that new data
   1586      * (with additional ITC activation) will not be missed. */
   1587     mhd_itc_clear (d->threading.itc);
   1588   }
   1589   ++i_s;
   1590 
   1591   if (0 == num_events)
   1592     return true;
   1593 #  endif /* MHD_SUPPORT_THREADS */
   1594 
   1595   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1596   {
   1597     const short revents = d->events.data.poll.fds[i_s].revents;
   1598 
   1599     mhd_assert (!d->net.listen.is_broken);
   1600     mhd_assert (d->events.data.poll.fds[i_s].fd == d->net.listen.fd);
   1601     mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN == \
   1602                 d->events.data.poll.rel[i_s].fd_id);
   1603 #  ifndef HAVE_POLL_CLOBBERS_EVENTS
   1604     mhd_assert ((POLLIN == d->events.data.poll.fds[i_s].events)
   1605                 || (0 == d->events.data.poll.fds[i_s].events));
   1606 #  endif /* ! HAVE_POLL_CLOBBERS_EVENTS */
   1607     dbg_print_fd_state_update ("lstn", \
   1608                                d->events.data.poll.fds[i_s].fd, \
   1609                                0 != (revents & (MHD_POLL_IN | POLLIN)), \
   1610                                0 != (revents & (MHD_POLL_OUT | POLLOUT)), \
   1611                                0 != (revents & (POLLERR | POLLNVAL | POLLHUP)));
   1612     if (0 != (revents & (POLLERR | POLLNVAL | POLLHUP)))
   1613     {
   1614       --num_events;
   1615       log_listen_broken (d);
   1616       /* Close the listening socket unless the master daemon should close it */
   1617       if (!mhd_D_HAS_MASTER (d))
   1618         mhd_socket_close (d->net.listen.fd);
   1619 
   1620       d->events.accept_pending = false;
   1621       d->net.listen.is_broken = true;
   1622       /* Stop monitoring socket to avoid spinning with busy-waiting */
   1623       d->net.listen.fd = MHD_INVALID_SOCKET;
   1624     }
   1625     else
   1626     {
   1627       const bool has_new_conns = (0 != (revents & (MHD_POLL_IN | POLLIN)));
   1628       if (has_new_conns)
   1629       {
   1630         --num_events;
   1631         d->events.accept_pending = true;
   1632       }
   1633       else
   1634       {
   1635         /* Check whether the listen socket was monitored for incoming
   1636            connections */
   1637         if (0 != (d->events.data.poll.fds[i_s].events & POLLIN))
   1638           d->events.accept_pending = false;
   1639       }
   1640     }
   1641     ++i_s;
   1642   }
   1643 
   1644   mhd_assert ((0 == num_events) \
   1645               || (!mhd_D_TYPE_IS_LISTEN_ONLY (d->threading.d_type)));
   1646 
   1647   for (i_c = i_s; (i_c < i_s + d->conns.count) && (0 < num_events); ++i_c)
   1648   {
   1649     struct MHD_Connection *restrict c;
   1650     bool recv_ready;
   1651     bool send_ready;
   1652     bool err_state;
   1653     short revents;
   1654     mhd_assert (i_c < d->dbg.num_events_elements);
   1655     mhd_assert (mhd_SOCKET_REL_MARKER_EMPTY != \
   1656                 d->events.data.poll.rel[i_c].fd_id);
   1657     mhd_assert (mhd_SOCKET_REL_MARKER_ITC != \
   1658                 d->events.data.poll.rel[i_c].fd_id);
   1659     mhd_assert (mhd_SOCKET_REL_MARKER_LISTEN != \
   1660                 d->events.data.poll.rel[i_c].fd_id);
   1661 
   1662     c = d->events.data.poll.rel[i_c].connection;
   1663     mhd_assert (!is_conn_excluded_from_http_comm (c));
   1664     mhd_assert (c->sk.fd == d->events.data.poll.fds[i_c].fd);
   1665     revents = d->events.data.poll.fds[i_c].revents;
   1666     recv_ready = (0 != (revents & (MHD_POLL_IN | POLLIN)));
   1667     send_ready = (0 != (revents & (MHD_POLL_OUT | POLLOUT)));
   1668 #  ifndef MHD_POLLHUP_ON_REM_SHUT_WR
   1669     err_state = (0 != (revents & (POLLHUP | POLLERR | POLLNVAL)));
   1670 #  else
   1671     err_state = (0 != (revents & (POLLERR | POLLNVAL)));
   1672     if (0 != (revents & POLLHUP))
   1673     { /* This can be a disconnect OR remote side set SHUT_WR */
   1674       recv_ready = true; /* Check the socket by reading */
   1675       if (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV))
   1676         err_state = true; /* The socket will not be checked by reading, the only way to avoid spinning */
   1677     }
   1678 #  endif
   1679     if (0 != (revents & (MHD_POLLPRI | MHD_POLLRDBAND)))
   1680     { /* Statuses were not requested, but returned */
   1681       if (!recv_ready
   1682           || (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_RECV)))
   1683         err_state = true; /* The socket will not be read, the only way to avoid spinning */
   1684     }
   1685     if (0 != (revents & MHD_POLLWRBAND))
   1686     { /* Status was not requested, but returned */
   1687       if (!send_ready
   1688           || (0 == (c->event_loop_info & MHD_EVENT_LOOP_INFO_SEND)))
   1689         err_state = true; /* The socket will not be written, the only way to avoid spinning */
   1690     }
   1691 
   1692     update_conn_net_status (d, c, recv_ready, send_ready, err_state);
   1693   }
   1694   mhd_assert (d->conns.count >= (i_c - i_s));
   1695   mhd_assert (i_c <= d->dbg.num_events_elements);
   1696   return true;
   1697 }
   1698 
   1699 
   1700 static MHD_FN_PAR_NONNULL_ (1) bool
   1701 get_all_net_updates_by_poll (struct MHD_Daemon *restrict d,
   1702                              bool listen_only)
   1703 {
   1704 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1705 #    ifdef MHD_SOCKETS_KIND_POSIX
   1706   static const char poll_fn_name[] = "poll";
   1707 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
   1708   static const char poll_fn_name[] = "WSAPoll";
   1709 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
   1710 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1711   unsigned int num_fds;
   1712   int max_wait;
   1713   int num_events;
   1714 
   1715   mhd_assert (mhd_POLL_TYPE_POLL == d->events.poll_type);
   1716 
   1717   num_fds = poll_update_fds (d, listen_only);
   1718 
   1719   // TODO: handle empty list situation
   1720   max_wait = get_max_wait (d);
   1721 
   1722 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1723   fprintf (stderr,
   1724            "### (Starting) %s(fds, %u, %d)...\n",
   1725            poll_fn_name,
   1726            num_fds,
   1727            max_wait);
   1728 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1729   num_events = mhd_poll (d->events.data.poll.fds,
   1730                          num_fds,
   1731                          max_wait); // TODO: use correct timeout value
   1732 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1733   fprintf (stderr,
   1734            "### (Finished) %s(fds, %u, %d) -> %d\n",
   1735            poll_fn_name,
   1736            num_fds,
   1737            max_wait,
   1738            num_events);
   1739 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1740   if (0 > num_events)
   1741   {
   1742     int err;
   1743     bool is_hard_error;
   1744     bool is_ignored_error;
   1745     is_hard_error = false;
   1746     is_ignored_error = false;
   1747 #  if defined(MHD_SOCKETS_KIND_POSIX)
   1748     err = errno;
   1749     if (0 != err)
   1750     {
   1751       is_hard_error =
   1752         ((mhd_EFAULT_OR_ZERO == err) || (mhd_EINVAL_OR_ZERO == err));
   1753       is_ignored_error = (mhd_EINTR_OR_ZERO == err);
   1754     }
   1755 #  elif defined(MHD_SOCKETS_KIND_WINSOCK)
   1756     err = WSAGetLastError ();
   1757     is_hard_error =
   1758       ((WSAENETDOWN == err) || (WSAEFAULT == err) || (WSAEINVAL == err));
   1759 #  endif
   1760     if (!is_ignored_error)
   1761     {
   1762       if (is_hard_error)
   1763       {
   1764         mhd_LOG_MSG (d, MHD_SC_POLL_HARD_ERROR, \
   1765                      "The poll() encountered unrecoverable error.");
   1766         return false;
   1767       }
   1768       mhd_LOG_MSG (d, MHD_SC_POLL_SOFT_ERROR, \
   1769                    "The poll() encountered error.");
   1770     }
   1771     return true;
   1772   }
   1773 
   1774   return poll_update_statuses_from_fds (d, num_events);
   1775 }
   1776 
   1777 
   1778 #endif /* MHD_SUPPORT_POLL */
   1779 
   1780 #ifdef MHD_SUPPORT_EPOLL
   1781 
   1782 /**
   1783  * Map events provided by epoll to connection states, ITC and
   1784  * listen socket states
   1785  */
   1786 static MHD_FN_PAR_NONNULL_ (1) bool
   1787 update_statuses_from_eevents (struct MHD_Daemon *restrict d,
   1788                               unsigned int num_events)
   1789 {
   1790   unsigned int i;
   1791   struct epoll_event *const restrict events =
   1792     d->events.data.epoll.events;
   1793   for (i = 0; num_events > i; ++i)
   1794   {
   1795     struct epoll_event *const e = events + i;
   1796 #  ifdef MHD_SUPPORT_THREADS
   1797     if (((uint64_t)mhd_SOCKET_REL_MARKER_ITC) == e->data.u64)  /* uint64_t is in the system header */
   1798     {
   1799       mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   1800       dbg_print_fd_state_update ( \
   1801         "ITC", \
   1802         mhd_itc_r_fd (d->threading.itc), \
   1803         0 != (e->events & EPOLLIN), \
   1804         0 != (e->events & EPOLLOUT), \
   1805         0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP)));
   1806 
   1807       if (0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP)))
   1808       {
   1809         log_itc_broken (d);
   1810         /* ITC is broken, need to stop the daemon thread now as otherwise
   1811            application will not be able to stop the thread. */
   1812         return false;
   1813       }
   1814       if (0 != (e->events & EPOLLIN))
   1815       {
   1816         /* Clear ITC here, before other data processing.
   1817          * Any external events will activate ITC again if additional data to
   1818          * process is added externally. Clearing ITC early ensures that new data
   1819          * (with additional ITC activation) will not be missed. */
   1820         mhd_itc_clear (d->threading.itc);
   1821       }
   1822     }
   1823     else
   1824 #  endif /* MHD_SUPPORT_THREADS */
   1825     if (((uint64_t)mhd_SOCKET_REL_MARKER_LISTEN) == e->data.u64)  /* uint64_t is in the system header */
   1826     {
   1827       mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd);
   1828       dbg_print_fd_state_update ( \
   1829         "lstn", \
   1830         d->net.listen.fd, \
   1831         0 != (e->events & EPOLLIN), \
   1832         0 != (e->events & EPOLLOUT), \
   1833         0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP)));
   1834       if (0 != (e->events & (EPOLLPRI | EPOLLERR | EPOLLHUP)))
   1835       {
   1836         log_listen_broken (d);
   1837 
   1838         /* Close the listening socket unless the master daemon should close it */
   1839         if (!mhd_D_HAS_MASTER (d))
   1840           mhd_socket_close (d->net.listen.fd);
   1841         else
   1842         {
   1843           /* Ignore possible error as the socket could be already removed
   1844              from the epoll monitoring by closing the socket */
   1845           (void)epoll_ctl (d->events.data.epoll.e_fd,
   1846                            EPOLL_CTL_DEL,
   1847                            d->net.listen.fd,
   1848                            NULL);
   1849         }
   1850 
   1851         d->events.accept_pending = false;
   1852         d->net.listen.is_broken = true;
   1853         d->net.listen.fd = MHD_INVALID_SOCKET;
   1854       }
   1855       else
   1856         d->events.accept_pending = (0 != (e->events & EPOLLIN));
   1857     }
   1858     else
   1859     {
   1860       bool recv_ready;
   1861       bool send_ready;
   1862       bool err_state;
   1863       struct MHD_Connection *const restrict c =
   1864         (struct MHD_Connection *)e->data.ptr;
   1865       mhd_assert (!is_conn_excluded_from_http_comm (c));
   1866       recv_ready = (0 != (e->events & (EPOLLIN | EPOLLERR | EPOLLHUP)));
   1867       send_ready = (0 != (e->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)));
   1868       err_state = (0 != (e->events & (EPOLLERR | EPOLLHUP)));
   1869 
   1870       update_conn_net_status (d, c, recv_ready, send_ready, err_state);
   1871     }
   1872   }
   1873   return true;
   1874 }
   1875 
   1876 
   1877 /**
   1878  * Update states of all connections, check for connection pending
   1879  * to be accept()'ed, check for the events on ITC.
   1880  */
   1881 static MHD_FN_PAR_NONNULL_ (1) bool
   1882 get_all_net_updates_by_epoll (struct MHD_Daemon *restrict d)
   1883 {
   1884   int max_events;
   1885   int num_events;
   1886   unsigned int events_processed;
   1887   int max_wait;
   1888   mhd_assert (mhd_POLL_TYPE_EPOLL == d->events.poll_type);
   1889   mhd_assert (0 < ((int)d->events.data.epoll.num_elements));
   1890   mhd_assert (0 <= ((int)d->conns.count));
   1891   mhd_assert (d->events.data.epoll.num_elements == \
   1892               (size_t)((int)d->events.data.epoll.num_elements));
   1893   mhd_assert (0 != d->events.data.epoll.num_elements);
   1894   mhd_assert (0 != d->conns.cfg.count_limit);
   1895   mhd_assert (d->events.data.epoll.num_elements == d->dbg.num_events_elements);
   1896 
   1897   // TODO: add listen socket enable/disable
   1898 
   1899   /* Minimise amount of data passed from userspace to kernel and back */
   1900   max_events = (int)d->conns.count;
   1901 #  ifdef MHD_SUPPORT_THREADS
   1902   ++max_events;
   1903 #  endif /* MHD_SUPPORT_THREADS */
   1904   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   1905     ++max_events;
   1906   /* Make sure that one extra slot used to clearly detect that all events
   1907    * were gotten. */
   1908   ++max_events;
   1909   if ((0 > max_events)
   1910       || (max_events > (int)d->events.data.epoll.num_elements))
   1911     max_events = (int)d->events.data.epoll.num_elements;
   1912 
   1913   events_processed = 0;
   1914   max_wait = get_max_wait (d);
   1915   do
   1916   {
   1917 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1918     fprintf (stderr,
   1919              "### (Starting) epoll_wait(%d, events, %d, %d)...\n",
   1920              d->events.data.epoll.e_fd,
   1921              (int)d->events.data.epoll.num_elements,
   1922              max_wait);
   1923 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1924     num_events = epoll_wait (d->events.data.epoll.e_fd,
   1925                              d->events.data.epoll.events,
   1926                              max_events,
   1927                              max_wait);
   1928 #  ifdef MHD_USE_TRACE_POLLING_FDS
   1929     fprintf (stderr,
   1930              "### (Finished) epoll_wait(%d, events, %d, %d) -> %d\n",
   1931              d->events.data.epoll.e_fd,
   1932              max_events,
   1933              max_wait,
   1934              num_events);
   1935 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   1936     max_wait = 0;
   1937     if (0 > num_events)
   1938     {
   1939       const int err = errno;
   1940       if (EINTR != err)
   1941       {
   1942         mhd_LOG_MSG (d, MHD_SC_EPOLL_HARD_ERROR, \
   1943                      "The epoll_wait() encountered unrecoverable error.");
   1944         return false;
   1945       }
   1946       return true; /* EINTR, try next time */
   1947     }
   1948     if (!update_statuses_from_eevents (d, (unsigned int)num_events))
   1949       return false;
   1950     if (max_events > num_events)
   1951       return true; /* All events have been read */
   1952 
   1953     /* Use all buffer for the next getting events round(s) */
   1954     max_events = (int)d->events.data.epoll.num_elements;
   1955     mhd_assert (0 < max_events);
   1956     mhd_assert (d->events.data.epoll.num_elements == (size_t)max_events);
   1957     max_wait = 0; /* Do not block on the next getting events rounds */
   1958 
   1959     events_processed += (unsigned int)num_events;  /* Avoid reading too many events */
   1960   } while ((events_processed < d->conns.cfg.count_limit)
   1961            || (events_processed < d->conns.cfg.count_limit + 2));
   1962 
   1963   return true;
   1964 }
   1965 
   1966 
   1967 #endif /* MHD_SUPPORT_EPOLL */
   1968 
   1969 #ifdef MHD_SUPPORT_KQUEUE
   1970 
   1971 static MHD_FN_PAR_NONNULL_ALL_
   1972 MHD_FN_PAR_IN_ (2) void
   1973 kqueue_handle_missed_change (struct MHD_Daemon *restrict d,
   1974                              const struct kevent *restrict upd_event)
   1975 {
   1976   mhd_assert (mhd_D_IS_USING_KQUEUE (d));
   1977   mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_EMPTY != mhd_KE_GET_UDATA (upd_event));
   1978   mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_ITC != mhd_KE_GET_UDATA (upd_event));
   1979 
   1980   if (mhd_SOCKET_REL_PTRMARKER_LISTEN == mhd_KE_GET_UDATA (upd_event))
   1981   {
   1982     return;
   1983   }
   1984   else
   1985   {
   1986     struct MHD_Connection *const restrict c =
   1987       (struct MHD_Connection *)mhd_KE_GET_UDATA (upd_event);
   1988 
   1989     mhd_ASSUME (d == c->daemon);
   1990 
   1991     mhd_conn_start_closing_no_sys_res (c);
   1992     mhd_conn_pre_clean (c);
   1993     mhd_conn_remove_from_daemon (c);
   1994     mhd_conn_close_final (c);
   1995   }
   1996 }
   1997 
   1998 
   1999 static MHD_FN_PAR_NONNULL_ALL_
   2000 MHD_FN_PAR_IN_SIZE_ (2, 3) void
   2001 kqueue_handle_missed_changes (struct MHD_Daemon *restrict d,
   2002                               struct kevent *restrict kes,
   2003                               int num_elements)
   2004 {
   2005   int i;
   2006 
   2007   mhd_ASSUME (0 < num_elements);
   2008 
   2009   for (i = 0; i < num_elements; ++i)
   2010     kqueue_handle_missed_change (d,
   2011                                  kes + i);
   2012 }
   2013 
   2014 
   2015 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ int
   2016 update_kqueue_monitoring (struct MHD_Daemon *restrict d)
   2017 {
   2018   struct MHD_Connection *c;
   2019   struct kevent *restrict kes = d->events.data.kq.kes;
   2020   int num_updates;
   2021   const int max_changes = (int)d->events.data.kq.num_elements;
   2022 
   2023   mhd_assert (mhd_D_IS_USING_KQUEUE (d));
   2024   mhd_assert (NULL != kes);
   2025   mhd_assert (2 <= max_changes);
   2026 
   2027   num_updates = 0;
   2028 
   2029   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2030   {
   2031     mhd_assert (!d->net.listen.is_broken);
   2032 
   2033     mhd_KE_SET (kes + num_updates,
   2034                 d->net.listen.fd,
   2035                 EVFILT_READ,
   2036                 (d->conns.block_new ? EV_DISABLE : EV_ENABLE)
   2037                 | mhd_EV_KEEPUDATA_OR_ZERO,
   2038                 mhd_SOCKET_REL_PTRMARKER_LISTEN);
   2039 
   2040     mhd_dbg_print_kevent_change ("lstn",
   2041                                  kes + num_updates);
   2042     ++num_updates;
   2043   }
   2044 
   2045   /* Process unmonitored connections starting from the earliest added
   2046      unmonitored connection */
   2047 
   2048   c = mhd_DLINKEDL_GET_FIRST (&(d->conns), all_conn);
   2049 
   2050   if ((NULL == c) || (c->events.kq.monitored))
   2051     return num_updates;
   2052 
   2053   while (1)
   2054   {
   2055     struct MHD_Connection *const next_c = mhd_DLINKEDL_GET_NEXT (c, all_conn);
   2056     if (NULL == next_c)
   2057       break; /* Found the end of the list */
   2058     if (next_c->events.kq.monitored)
   2059       break; /* Found the earliest added unmonitored connection */
   2060     c = next_c;
   2061   }
   2062 
   2063   mhd_ASSUME (NULL != c);
   2064   mhd_ASSUME (!c->events.kq.monitored);
   2065 
   2066   for ((void)c; NULL != c; c = mhd_DLINKEDL_GET_PREV (c, all_conn))
   2067   {
   2068     mhd_ASSUME (!c->events.kq.monitored);
   2069 
   2070     mhd_assert (!is_conn_excluded_from_http_comm (c));
   2071     mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage);
   2072 
   2073     /* Check for the space for two filters */
   2074     if ((max_changes - 1) <= num_updates)
   2075     {
   2076       /* Too many updates for a single kevent() call */
   2077       static const struct timespec zero_timeout = {0, 0};
   2078       int res;
   2079 
   2080 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2081       fprintf (stderr,
   2082                "### (Starting) kevent(%d, changes, %d, [NULL], "
   2083                "0, [0, 0])...\n",
   2084                d->events.data.kq.kq_fd,
   2085                num_updates);
   2086 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2087       res = mhd_kevent (d->events.data.kq.kq_fd,
   2088                         kes,
   2089                         num_updates,
   2090                         NULL,
   2091                         0,
   2092                         &zero_timeout);
   2093 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2094       fprintf (stderr,
   2095                "### (Finished) kevent(%d, changes, %d, [NULL], "
   2096                "0, [0, 0]) -> %d\n",
   2097                d->events.data.kq.kq_fd,
   2098                num_updates,
   2099                res);
   2100 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2101       if (0 > res)
   2102       {
   2103         if (EINTR != errno)
   2104           kqueue_handle_missed_changes (d,
   2105                                         kes,
   2106                                         num_updates);
   2107 
   2108       }
   2109       num_updates = 0;
   2110     }
   2111 
   2112     /* Add recv() filter */
   2113     mhd_KE_SET (kes + num_updates,
   2114                 c->sk.fd,
   2115                 EVFILT_READ,
   2116                 EV_ADD | EV_CLEAR, /* 'EV_CLEAR' means edge trigger */
   2117                 c);
   2118     mhd_dbg_print_kevent_change ("conn",
   2119                                  kes + num_updates);
   2120 
   2121     ++num_updates;
   2122 
   2123     /* Add send() filter */
   2124     mhd_KE_SET (kes + num_updates,
   2125                 c->sk.fd,
   2126                 EVFILT_WRITE,
   2127                 EV_ADD | EV_CLEAR, /* 'EV_CLEAR' means edge trigger */
   2128                 c);
   2129     mhd_dbg_print_kevent_change ("conn",
   2130                                  kes + num_updates);
   2131 
   2132     ++num_updates;
   2133 
   2134     c->events.kq.monitored = true;
   2135 
   2136     mhd_assert (0 < num_updates);
   2137   }
   2138 
   2139   mhd_assert (0 <= num_updates);
   2140   mhd_assert (num_updates <= (int)d->events.data.kq.num_elements);
   2141 
   2142   return num_updates;
   2143 }
   2144 
   2145 
   2146 /**
   2147  * Map events provided by kqueue to connection states, ITC and
   2148  * listen socket states
   2149  */
   2150 static MHD_FN_PAR_NONNULL_ (1) bool
   2151 update_statuses_from_kevents (struct MHD_Daemon *restrict d,
   2152                               unsigned int num_events)
   2153 {
   2154   unsigned int i;
   2155   struct kevent *restrict kes = d->events.data.kq.kes;
   2156 
   2157   mhd_assert (mhd_D_IS_USING_KQUEUE (d));
   2158 
   2159   for (i = 0u; num_events > i; ++i)
   2160   {
   2161     struct kevent *const e = kes + i;
   2162     bool eof_ready;
   2163 #  ifdef MHD_SUPPORT_THREADS
   2164     if (mhd_SOCKET_REL_PTRMARKER_ITC == mhd_KE_GET_UDATA (e))
   2165     {
   2166       mhd_assert (mhd_ITC_IS_VALID (d->threading.itc));
   2167       mhd_assert (mhd_itc_r_fd (d->threading.itc) == (int)e->ident);
   2168       mhd_assert (EVFILT_READ == e->filter);
   2169       mhd_assert (0 == (e->flags & EV_ERROR));
   2170 
   2171       eof_ready = (0 != (e->flags & EV_EOF));
   2172 
   2173       mhd_dbg_print_kevent_report ("ITC",
   2174                                    e);
   2175 
   2176       if (eof_ready)
   2177       {
   2178         log_itc_broken (d);
   2179         /* ITC is broken, need to stop the daemon thread now as otherwise
   2180            application will not be able to stop the thread. */
   2181         return false;
   2182       }
   2183       /* Clear ITC here, before other data processing.
   2184          Any external events will activate ITC again if additional data to
   2185          process is added externally. Clearing ITC early ensures that new data
   2186          (which followed by ITC activation) will not be missed. */
   2187       mhd_itc_clear (d->threading.itc);
   2188     }
   2189     else
   2190 #  endif /* MHD_SUPPORT_THREADS */
   2191     if (mhd_SOCKET_REL_PTRMARKER_LISTEN == mhd_KE_GET_UDATA (e))
   2192     {
   2193       bool listen_broken;
   2194       mhd_assert (MHD_INVALID_SOCKET != d->net.listen.fd);
   2195       mhd_assert (d->net.listen.fd == (int)e->ident);
   2196       mhd_assert (EVFILT_READ == e->filter);
   2197 
   2198       eof_ready = (0 != (e->flags & EV_EOF));
   2199 
   2200       mhd_dbg_print_kevent_report ("lstn",
   2201                                    e);
   2202 
   2203       listen_broken = false;
   2204       if (eof_ready)
   2205         listen_broken = true;
   2206       else if ((0 != (e->flags & EV_ERROR)))
   2207         listen_broken = true;
   2208 
   2209       if (listen_broken)
   2210       {
   2211         log_listen_broken (d);
   2212 
   2213         /* Close the listening socket unless the master daemon should close it */
   2214         if (!mhd_D_HAS_MASTER (d))
   2215           mhd_socket_close (d->net.listen.fd);
   2216         else
   2217         {
   2218           static const struct timespec zero_timeout = {0, 0};
   2219           struct kevent remove_listen;
   2220           int res;
   2221 
   2222           mhd_KE_SET (&remove_listen,
   2223                       d->net.listen.fd,
   2224                       EVFILT_READ,
   2225                       EV_DELETE,
   2226                       mhd_SOCKET_REL_PTRMARKER_LISTEN);
   2227 
   2228 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2229           fprintf (stderr,
   2230                    "### (Starting) kevent(%d, changes, 1, [NULL], "
   2231                    "0, [0, 0])...\n",
   2232                    d->events.data.kq.kq_fd);
   2233 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2234           res = mhd_kevent (d->events.data.kq.kq_fd,
   2235                             &remove_listen,
   2236                             1,
   2237                             NULL,
   2238                             0,
   2239                             &zero_timeout);
   2240 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2241           fprintf (stderr,
   2242                    "### (Finished) kevent(%d, changes, 1, [NULL], "
   2243                    "0, [0, 0]) -> %d\n",
   2244                    d->events.data.kq.kq_fd,
   2245                    res);
   2246 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2247           /* Ignore possible error as the socket could be already removed
   2248              from the kqueue monitoring by closing the socket */
   2249           (void)res;
   2250         }
   2251 
   2252         d->events.accept_pending = false;
   2253         d->net.listen.is_broken = true;
   2254         d->net.listen.fd = MHD_INVALID_SOCKET;
   2255       }
   2256       else
   2257         d->events.accept_pending = true;
   2258     }
   2259     else
   2260     {
   2261       bool err_ready;
   2262       bool recv_ready;
   2263       bool send_ready;
   2264       struct MHD_Connection *const restrict c =
   2265         (struct MHD_Connection *)mhd_KE_GET_UDATA (e);
   2266 
   2267       mhd_ASSUME (d == c->daemon);
   2268       mhd_assert (c->events.kq.monitored);
   2269       mhd_ASSUME (mhd_SOCKET_REL_PTRMARKER_EMPTY != mhd_KE_GET_UDATA (e));
   2270 
   2271       mhd_dbg_print_kevent_report ("conn",
   2272                                    e);
   2273 
   2274       if ((0 != (e->flags & EV_ERROR)))
   2275       {
   2276         /* Error adding connection to monitoring */
   2277         kqueue_handle_missed_change (d,
   2278                                      e);
   2279 
   2280         continue;
   2281       }
   2282 
   2283       eof_ready = (0 != (e->flags & EV_EOF));
   2284       err_ready = (eof_ready && (0 != e->fflags));
   2285 
   2286       if (err_ready)
   2287       {
   2288         c->sk.state.discnt_err =
   2289           mhd_socket_error_get_from_sys_err ((int)e->fflags);
   2290         mhd_assert (mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err));
   2291       }
   2292       /* This is a tricky processing as each "filter" updates only its own
   2293          side of the monitoring, not giving a picture of a complete socket
   2294          readiness. */
   2295 
   2296       if (EVFILT_READ == e->filter)
   2297       {
   2298         recv_ready = true;
   2299         send_ready = mhd_SCKT_NET_ST_HAS_FLAG_SEND (c->sk.ready);
   2300       }
   2301       else
   2302       {
   2303         mhd_assert (EVFILT_WRITE == e->filter);
   2304         recv_ready = mhd_SCKT_NET_ST_HAS_FLAG_RECV (c->sk.ready);
   2305         send_ready = true;
   2306       }
   2307 
   2308       update_conn_net_status (d,
   2309                               c,
   2310                               recv_ready,
   2311                               send_ready,
   2312                               err_ready
   2313                               || mhd_SCKT_NET_ST_HAS_FLAG_ERROR (c->sk.ready));
   2314     }
   2315   }
   2316   return true;
   2317 }
   2318 
   2319 
   2320 /**
   2321  * Update states of all connections, check for connection pending
   2322  * to be accept()'ed, check for the events on ITC.
   2323  */
   2324 static MHD_FN_PAR_NONNULL_ (1) bool
   2325 get_all_net_updates_by_kqueue (struct MHD_Daemon *restrict d)
   2326 {
   2327   int max_events;
   2328   int num_events;
   2329   int num_updates;
   2330   size_t events_processed;
   2331   uint_fast64_t max_wait;
   2332   struct timespec ke_timeout;
   2333 
   2334   mhd_assert (mhd_D_IS_USING_KQUEUE (d));
   2335   mhd_assert (0 < d->events.data.kq.kq_fd);
   2336   mhd_assert (0 < (int)(d->events.data.kq.num_elements));
   2337   mhd_assert (0 != d->events.data.kq.num_elements);
   2338   mhd_assert (0 != d->conns.cfg.count_limit);
   2339   mhd_assert (d->events.data.kq.num_elements == d->dbg.num_events_elements);
   2340 
   2341   num_updates = update_kqueue_monitoring (d);
   2342   mhd_ASSUME (0 <= num_updates);
   2343 
   2344   /* Minimise amount of data passed from userspace to kernel and back */
   2345   max_events = (int)(d->conns.count * 2);
   2346 #  ifdef MHD_SUPPORT_THREADS
   2347   ++max_events;
   2348 #  endif /* MHD_SUPPORT_THREADS */
   2349   if (MHD_INVALID_SOCKET != d->net.listen.fd)
   2350     ++max_events;
   2351   /* Make sure that one extra slot used to clearly detect that all events
   2352      were gotten (if all provided slots are used then extra event could be
   2353      pending still). */
   2354   ++max_events;
   2355   if ((0 >= max_events)
   2356       || (max_events > (int)d->events.data.kq.num_elements))
   2357     max_events = (int)d->events.data.kq.num_elements;
   2358 
   2359   max_wait = mhd_daemon_get_wait_max (d);
   2360   ke_timeout.tv_sec = (time_t)(max_wait / 1000);
   2361   ke_timeout.tv_nsec = (long)((max_wait % 1000) * 1000000L);
   2362   events_processed = 0;
   2363   do
   2364   {
   2365 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2366     if (max_wait == MHD_WAIT_INDEFINITELY)
   2367       fprintf (stderr,
   2368                "### (Starting) kevent(%d, changes, %d, events, "
   2369                "%d, [NULL])...\n",
   2370                d->events.data.kq.kq_fd,
   2371                num_updates,
   2372                max_events);
   2373     else
   2374       fprintf (stderr,
   2375                "### (Starting) kevent(%d, changes, %d, events, "
   2376                "%d, [%llu, %llu])...\n",
   2377                d->events.data.kq.kq_fd,
   2378                num_updates,
   2379                max_events,
   2380                (unsigned long long)ke_timeout.tv_sec,
   2381                (unsigned long long)ke_timeout.tv_nsec);
   2382 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2383     num_events =
   2384       kevent (d->events.data.kq.kq_fd,
   2385               d->events.data.kq.kes,
   2386               num_updates,
   2387               d->events.data.kq.kes,
   2388               max_events,
   2389               (max_wait == MHD_WAIT_INDEFINITELY) ? NULL : &ke_timeout);
   2390 #  ifdef MHD_USE_TRACE_POLLING_FDS
   2391     if (max_wait == MHD_WAIT_INDEFINITELY)
   2392       fprintf (stderr,
   2393                "### (Finished) kevent(%d, changes, %d, events, "
   2394                "%d, [NULL]) -> %d\n",
   2395                d->events.data.kq.kq_fd,
   2396                num_updates,
   2397                max_events,
   2398                num_events);
   2399     else
   2400       fprintf (stderr,
   2401                "### (Finished) kevent(%d, changes, %d, events, "
   2402                "%d, [%llu, %llu]) -> %d\n",
   2403                d->events.data.kq.kq_fd,
   2404                num_updates,
   2405                max_events,
   2406                (unsigned long long)ke_timeout.tv_sec,
   2407                (unsigned long long)ke_timeout.tv_nsec,
   2408                num_events);
   2409 #  endif /* MHD_USE_TRACE_POLLING_FDS */
   2410 
   2411     if (0 > num_events)
   2412     {
   2413       const int err = errno;
   2414       if (EINTR == err)
   2415         return true; /* EINTR, try next time */
   2416 
   2417       mhd_LOG_MSG (d, MHD_SC_KQUEUE_HARD_ERROR, \
   2418                    "The kevent() encountered unrecoverable error.");
   2419       return false;
   2420     }
   2421     if (!update_statuses_from_kevents (d,
   2422                                        (unsigned int)num_events))
   2423       return false;
   2424     if (max_events > num_events)
   2425       return true; /* All events have been read */
   2426 
   2427     /* Use all slots for the next round(s) of getting events  */
   2428     max_events = (int)d->events.data.kq.num_elements;
   2429     max_wait = 0; /* Do not block on the next getting events rounds */
   2430     ke_timeout.tv_sec = 0;
   2431     ke_timeout.tv_nsec = 0;
   2432 
   2433     mhd_assert (0 < max_events);
   2434 
   2435     /* If too many events are coming - process events that have been read already */
   2436     events_processed += (size_t)num_events;
   2437   } while ((events_processed < (d->conns.cfg.count_limit * 2))
   2438            || (events_processed < (d->conns.cfg.count_limit * 2) + 2));
   2439 
   2440   return true;
   2441 }
   2442 
   2443 
   2444 #endif /* MHD_SUPPORT_KQUEUE */
   2445 
   2446 
   2447 /**
   2448  * Close timed-out connections (if any)
   2449  * @param d the daemon to use
   2450  */
   2451 static MHD_FN_PAR_NONNULL_ALL_ void
   2452 daemon_close_timedout_conns (struct MHD_Daemon *restrict d)
   2453 {
   2454   struct MHD_Connection *c;
   2455   struct MHD_Connection *prev_c;
   2456 
   2457 #if defined(MHD_SUPPORT_THREADS)
   2458   mhd_assert (!mhd_D_HAS_WORKERS (d));
   2459   mhd_assert (!mhd_D_HAS_THR_PER_CONN (d));
   2460 #endif /* MHD_SUPPORT_THREADS */
   2461 
   2462   /* Check "normal" timeouts list */
   2463   c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout));
   2464 
   2465   while (NULL != c)
   2466   {
   2467     mhd_assert (!c->timeout.in_cstm_tmout_list);
   2468     mhd_assert (0u != d->conns.cfg.timeout_milsec);
   2469 
   2470     if (mhd_conn_is_timeout_expired (c))
   2471     {
   2472       prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout),
   2473                                       tmout_list);
   2474       mhd_conn_start_closing_timedout (c);
   2475       mhd_conn_pre_clean (c);
   2476       mhd_conn_remove_from_daemon (c);
   2477       mhd_conn_close_final (c);
   2478 
   2479       c = prev_c;
   2480     }
   2481     else
   2482       break; /* DL-list is sorted, no need to check the rest of the list */
   2483   }
   2484 
   2485   /* Check "custom" timeouts list */
   2486   c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout));
   2487 
   2488   while (NULL != c)
   2489   {
   2490     mhd_assert (c->timeout.in_cstm_tmout_list);
   2491 
   2492     prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout),
   2493                                     tmout_list);
   2494 
   2495     if (mhd_conn_is_timeout_expired (c))
   2496     {
   2497       mhd_conn_start_closing_timedout (c);
   2498       mhd_conn_pre_clean (c);
   2499       mhd_conn_remove_from_daemon (c);
   2500       mhd_conn_close_final (c);
   2501     }
   2502 
   2503     /* "Custom" timeouts list is not sorted, check all members */
   2504     c = prev_c;
   2505   }
   2506 }
   2507 
   2508 
   2509 /**
   2510  * Prepare daemon's data for the new round of connections processing
   2511  * @param d the daemon to use
   2512  */
   2513 static MHD_FN_PAR_NONNULL_ALL_ void
   2514 daemon_reset_per_round_data (struct MHD_Daemon *restrict d)
   2515 {
   2516   d->events.time.is_set = false;
   2517 }
   2518 
   2519 
   2520 /**
   2521  * Perform one round of daemon connection and data processing.
   2522  *
   2523  * This function do the following:
   2524  * + poll all connections and daemon FDs (if internal polling is used);
   2525  * + resume connections pending to be resumed;
   2526  * + update connection statuses based on socket states (recv/send ready or
   2527  *   disconnect detection);
   2528  * + receive, send and/or parse connections data as needed, including call of
   2529  *   callbacks for processing requests and response generation;
   2530  * + close broken connections;
   2531  * + accept new connection (if needed);
   2532  * + cleanup closed "upgraded" connections.
   2533  * @param d the daemon to use
   2534  * @return 'true' on success,
   2535  *         'false' if daemon is broken
   2536  */
   2537 static MHD_FN_PAR_NONNULL_ (1) bool
   2538 process_all_events_and_data (struct MHD_Daemon *restrict d)
   2539 {
   2540   daemon_reset_per_round_data (d);
   2541 
   2542   switch (d->events.poll_type)
   2543   {
   2544   case mhd_POLL_TYPE_EXT:
   2545     mhd_assert (mhd_WM_INT_HAS_EXT_EVENTS (d->wmode_int));
   2546     if (!ext_events_process_net_updates_and_resume_conn (d))
   2547       return false;
   2548     break;
   2549 #ifdef MHD_SUPPORT_SELECT
   2550   case mhd_POLL_TYPE_SELECT:
   2551     if (!get_all_net_updates_by_select_and_resume_conn (d, false))
   2552       return false;
   2553     break;
   2554 #endif /* MHD_SUPPORT_SELECT */
   2555 #ifdef MHD_SUPPORT_POLL
   2556   case mhd_POLL_TYPE_POLL:
   2557     if (!get_all_net_updates_by_poll (d, false))
   2558       return false;
   2559     daemon_resume_conns_if_needed (d);
   2560     break;
   2561 #endif /* MHD_SUPPORT_POLL */
   2562 #ifdef MHD_SUPPORT_EPOLL
   2563   case mhd_POLL_TYPE_EPOLL:
   2564     if (!get_all_net_updates_by_epoll (d))
   2565       return false;
   2566     daemon_resume_conns_if_needed (d);
   2567     break;
   2568 #endif /* MHD_SUPPORT_EPOLL */
   2569 #ifdef MHD_SUPPORT_KQUEUE
   2570   case mhd_POLL_TYPE_KQUEUE:
   2571     if (!get_all_net_updates_by_kqueue (d))
   2572       return false;
   2573     daemon_resume_conns_if_needed (d);
   2574     break;
   2575 #endif /* MHD_SUPPORT_KQUEUE */
   2576 #ifndef MHD_SUPPORT_SELECT
   2577   case mhd_POLL_TYPE_SELECT:
   2578 #endif /* ! MHD_SUPPORT_SELECT */
   2579 #ifndef MHD_SUPPORT_POLL
   2580   case mhd_POLL_TYPE_POLL:
   2581 #endif /* ! MHD_SUPPORT_POLL */
   2582   case mhd_POLL_TYPE_NOT_SET_YET:
   2583   default:
   2584     mhd_UNREACHABLE ();
   2585     MHD_PANIC ("Daemon data integrity broken");
   2586     break;
   2587   }
   2588 
   2589   mhd_daemon_process_ext_added_conns (d);
   2590 
   2591   if (d->events.accept_pending && !d->conns.block_new)
   2592     d->events.accept_pending = !daemon_accept_new_conns (d);
   2593 
   2594   daemon_process_all_active_conns (d);
   2595   daemon_close_timedout_conns (d);
   2596   daemon_cleanup_upgraded_conns (d);
   2597   return !mhd_D_HAS_STOP_REQ (d);
   2598 }
   2599 
   2600 
   2601 static
   2602 MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
   2603 process_reg_events_int (struct MHD_Daemon *MHD_RESTRICT daemon,
   2604                         uint_fast64_t *MHD_RESTRICT next_max_wait)
   2605 {
   2606   enum MHD_StatusCode res;
   2607 
   2608   if (mhd_DAEMON_STATE_STARTED > daemon->state)
   2609     return MHD_SC_TOO_EARLY;
   2610   if (!mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int))
   2611     return MHD_SC_EXTERNAL_EVENT_ONLY;
   2612   if (mhd_DAEMON_STATE_STARTED < daemon->state)
   2613     return MHD_SC_TOO_LATE;
   2614 
   2615 #ifdef MHD_SUPPORT_THREADS
   2616   if (daemon->events.data.extr.itc_data.is_broken)
   2617     return MHD_SC_DAEMON_SYS_DATA_BROKEN;
   2618 #endif /* MHD_SUPPORT_THREADS */
   2619 
   2620   if (daemon->net.listen.is_broken)
   2621     return MHD_SC_DAEMON_SYS_DATA_BROKEN;
   2622 
   2623   /* Ignore returned value */
   2624   (void)process_all_events_and_data (daemon);
   2625 
   2626   if (NULL != next_max_wait)
   2627     *next_max_wait = MHD_WAIT_INDEFINITELY;
   2628 
   2629   res = ext_events_update_registrations (daemon);
   2630   if (MHD_SC_OK != res)
   2631     return res;
   2632 
   2633 #ifdef MHD_SUPPORT_THREADS
   2634   if (daemon->events.data.extr.itc_data.is_broken)
   2635   {
   2636     log_itc_broken (daemon);
   2637     return MHD_SC_DAEMON_SYS_DATA_BROKEN;
   2638   }
   2639 #endif /* MHD_SUPPORT_THREADS */
   2640 
   2641   if (daemon->net.listen.is_broken)
   2642   {
   2643     log_listen_broken (daemon);
   2644     return MHD_SC_DAEMON_SYS_DATA_BROKEN;
   2645   }
   2646 
   2647   if (NULL != next_max_wait)
   2648     *next_max_wait = mhd_daemon_get_wait_max (daemon);
   2649 
   2650   return MHD_SC_OK;
   2651 }
   2652 
   2653 
   2654 MHD_EXTERN_
   2655 MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
   2656 MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon,
   2657                                uint_fast64_t *MHD_RESTRICT next_max_wait)
   2658 {
   2659   enum MHD_StatusCode res;
   2660 #ifdef MHD_USE_TRACE_POLLING_FDS
   2661   fprintf (stderr,
   2662            "### (Starting) MHD_daemon_process_reg_events(daemon, [%s])...\n",
   2663            (NULL != next_max_wait) ? "non-NULL" : "NULL");
   2664 #endif
   2665   res = process_reg_events_int (daemon,
   2666                                 next_max_wait);
   2667 #ifdef MHD_USE_TRACE_POLLING_FDS
   2668   if (NULL == next_max_wait)
   2669     fprintf (stderr,
   2670              "### (Finished) MHD_daemon_process_reg_events(daemon, [NULL]) ->"
   2671              "%u\n",
   2672              (unsigned int)res);
   2673   else if (MHD_WAIT_INDEFINITELY == *next_max_wait)
   2674     fprintf (stderr,
   2675              "### (Finished) MHD_daemon_process_reg_events(daemon, "
   2676              "->MHD_WAIT_INDEFINITELY) ->%u\n",
   2677              (unsigned int)res);
   2678   else
   2679     fprintf (stderr,
   2680              "### (Finished) MHD_daemon_process_reg_events(daemon, ->%llu) "
   2681              "->%u\n",
   2682              (unsigned long long)*next_max_wait,
   2683              (unsigned int)res);
   2684 #endif
   2685   return res;
   2686 }
   2687 
   2688 
   2689 #ifdef MHD_SUPPORT_THREADS
   2690 
   2691 /**
   2692  * The entry point for the daemon worker thread
   2693  * @param cls the closure
   2694  */
   2695 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC
   2696 mhd_worker_all_events (void *cls)
   2697 {
   2698   struct MHD_Daemon *const restrict d = (struct MHD_Daemon *)cls;
   2699   mhd_thread_handle_ID_set_current_thread_ID (&(d->threading.tid));
   2700   mhd_assert (d->dbg.net_inited);
   2701   mhd_assert (!d->dbg.net_deinited);
   2702   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
   2703   mhd_assert (mhd_D_TYPE_HAS_EVENTS_PROCESSING (d->threading.d_type));
   2704   mhd_assert (mhd_DAEMON_TYPE_LISTEN_ONLY != d->threading.d_type);
   2705   mhd_assert (!mhd_D_TYPE_HAS_WORKERS (d->threading.d_type));
   2706   mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION != d->wmode_int);
   2707   mhd_assert (d->dbg.events_fully_inited);
   2708   mhd_assert (d->dbg.connections_inited);
   2709 
   2710 #  ifdef mhd_HAVE_MHD_THREAD_BLOCK_SIGPIPE
   2711   // TODO: store and use the result
   2712   (void)mhd_thread_block_sigpipe ();
   2713 #  endif
   2714 
   2715   while (!d->threading.stop_requested)
   2716   {
   2717     if (!process_all_events_and_data (d))
   2718       break;
   2719   }
   2720   if (!d->threading.stop_requested)
   2721   {
   2722     mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED, \
   2723                  "The daemon thread is stopping, but termination has not " \
   2724                  "been requested for the daemon.");
   2725   }
   2726   mhd_daemon_close_all_conns (d);
   2727 
   2728 #  ifdef MHD_SUPPORT_HTTPS
   2729   if (mhd_D_HAS_TLS (d))
   2730     mhd_tls_thread_cleanup (d->tls);
   2731 #  endif /* MHD_SUPPORT_HTTPS */
   2732 
   2733   return (mhd_THRD_RTRN_TYPE)0;
   2734 }
   2735 
   2736 
   2737 static MHD_FN_PAR_NONNULL_ (1) bool
   2738 process_listening_and_itc_only (struct MHD_Daemon *restrict d)
   2739 {
   2740   if (false)
   2741     (void)0;
   2742 #  ifdef MHD_SUPPORT_SELECT
   2743   else if (mhd_POLL_TYPE_SELECT == d->events.poll_type)
   2744   {
   2745     return false; // TODO: implement
   2746   }
   2747 #  endif /* MHD_SUPPORT_SELECT */
   2748 #  ifdef MHD_SUPPORT_POLL
   2749   else if (mhd_POLL_TYPE_POLL == d->events.poll_type)
   2750   {
   2751     if (!get_all_net_updates_by_poll (d, true))
   2752       return false;
   2753   }
   2754 #  endif /* MHD_SUPPORT_POLL */
   2755   else
   2756   {
   2757     (void)d;  /* Mute compiler warning */
   2758     mhd_assert (0 && "Impossible value");
   2759     mhd_UNREACHABLE ();
   2760     MHD_PANIC ("Daemon data integrity broken");
   2761   }
   2762   // TODO: Accept connections
   2763   return false;
   2764 }
   2765 
   2766 
   2767 /**
   2768  * The entry point for the daemon listening thread
   2769  * @param cls the closure
   2770  */
   2771 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC
   2772 mhd_worker_listening_only (void *cls)
   2773 {
   2774   struct MHD_Daemon *const restrict d = (struct MHD_Daemon *)cls;
   2775   mhd_thread_handle_ID_set_current_thread_ID (&(d->threading.tid));
   2776 
   2777   mhd_assert (d->dbg.net_inited);
   2778   mhd_assert (!d->dbg.net_deinited);
   2779   mhd_assert (mhd_DAEMON_TYPE_LISTEN_ONLY == d->threading.d_type);
   2780   mhd_assert (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION == d->wmode_int);
   2781   mhd_assert (d->dbg.events_fully_inited);
   2782   mhd_assert (d->dbg.connections_inited);
   2783 
   2784 #  ifdef mhd_HAVE_MHD_THREAD_BLOCK_SIGPIPE
   2785   // TODO: store and use the result
   2786   (void)mhd_thread_block_sigpipe ();
   2787 #  endif
   2788 
   2789   while (!d->threading.stop_requested)
   2790   {
   2791     if (!process_listening_and_itc_only (d))
   2792       break;
   2793   }
   2794   if (!d->threading.stop_requested)
   2795   {
   2796     mhd_LOG_MSG (d, MHD_SC_DAEMON_THREAD_STOP_UNEXPECTED, \
   2797                  "The daemon thread is stopping, but termination has " \
   2798                  "not been requested by the daemon.");
   2799   }
   2800 
   2801 #  ifdef MHD_SUPPORT_HTTPS
   2802   if (mhd_D_HAS_TLS (d))
   2803     mhd_tls_thread_cleanup (d->tls);
   2804 #  endif /* MHD_SUPPORT_HTTPS */
   2805 
   2806   return (mhd_THRD_RTRN_TYPE)0;
   2807 }
   2808 
   2809 
   2810 mhd_THRD_RTRN_TYPE mhd_THRD_CALL_SPEC
   2811 mhd_worker_connection (void *cls)
   2812 {
   2813   if (cls) // TODO: Implement
   2814     MHD_PANIC ("Not yet implemented");
   2815 
   2816 #  if 0 // def MHD_SUPPORT_HTTPS
   2817   if (mhd_D_HAS_TLS (d))
   2818     mhd_tls_thread_cleanup (d->tls);
   2819 #  endif /* MHD_SUPPORT_HTTPS */
   2820 
   2821   return (mhd_THRD_RTRN_TYPE)0;
   2822 }
   2823 
   2824 
   2825 #endif /* MHD_SUPPORT_THREADS */