libmicrohttpd2

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

conn_timeout.c (6620B)


      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) 2025 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/conn_timeout.c
     41  * @brief  The definitions of connection timeout handling functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "sys_bool_type.h"
     48 
     49 #include "mhd_assert.h"
     50 
     51 #include "mhd_constexpr.h"
     52 
     53 #include "mhd_dlinked_list.h"
     54 
     55 #include "mhd_daemon.h"
     56 #include "mhd_connection.h"
     57 
     58 #include "daemon_funcs.h"
     59 
     60 #include "conn_timeout.h"
     61 
     62 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t
     63 mhd_conn_get_timeout_left (const struct MHD_Connection *restrict c,
     64                            uint_fast64_t cur_milsec)
     65 {
     66   mhd_constexpr uint_fast64_t uifast64_hibit =
     67     (uint_fast64_t) (~(((uint_fast64_t) (~((uint_fast64_t) 0))) >> 1u));
     68   const uint_fast64_t timeout = c->timeout.milsec;
     69   uint_fast64_t timedout_time;
     70   uint_fast64_t timeout_left;
     71 
     72   mhd_assert (! c->suspended);
     73 
     74   if (0u == timeout)
     75     return (uint_fast64_t) 0xFFFFFFFFFFFFFFFFu;
     76 
     77   /* The logic used in these calculations allows values wrap over the maximum
     78      value (taking into account that maximum timeout time is limited) */
     79   timedout_time =
     80     c->timeout.last_act + c->timeout.milsec + 1u; /* '+1' to not expire at exactly 'timeout' milliseconds */
     81   /* Time before timed out moment */
     82   timeout_left = timedout_time - cur_milsec;
     83 
     84   if (0u == (timeout_left & uifast64_hibit))
     85   {
     86     /* "Timeout left" must be always less or equal the timeout value (plus one)
     87        unless the system clock jumped back. */
     88     mhd_assert ((timeout_left <= (c->timeout.milsec + 1u)) ||
     89                 ((cur_milsec - c->timeout.last_act)
     90                  > (c->timeout.last_act - cur_milsec)));
     91 
     92     return timeout_left;
     93   }
     94 
     95   return 0u; /* Already timed out */
     96 }
     97 
     98 
     99 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
    100 mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c)
    101 {
    102   struct MHD_Daemon *const restrict d = c->daemon;
    103 
    104   return (0u == mhd_conn_get_timeout_left (c,
    105                                            mhd_daemon_get_milsec_counter (d)));
    106 }
    107 
    108 
    109 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    110 mhd_conn_init_activity_timeout (struct MHD_Connection *restrict c,
    111                                 uint_fast32_t timeout)
    112 {
    113   struct MHD_Daemon *const restrict d = c->daemon;
    114 
    115 #if defined(MHD_SUPPORT_THREADS)
    116   mhd_assert (! mhd_D_HAS_WORKERS (d));
    117 #endif /* MHD_SUPPORT_THREADS */
    118 
    119   mhd_assert (! c->suspended);
    120   mhd_assert (! c->timeout.in_cstm_tmout_list);
    121 
    122   c->timeout.milsec = timeout;
    123 
    124   if (0u == timeout)
    125     return;
    126 
    127   c->timeout.last_act = mhd_daemon_get_milsec_counter (d);
    128 
    129   if (mhd_D_HAS_THR_PER_CONN (d))
    130     return;
    131 
    132   if (timeout == d->conns.cfg.timeout_milsec)
    133   {
    134     mhd_DLINKEDL_INS_FIRST_D (&(d->conns.def_timeout),
    135                               c,
    136                               timeout.tmout_list);
    137   }
    138   else
    139   {
    140     mhd_DLINKEDL_INS_FIRST_D (&(d->conns.cust_timeout),
    141                               c,
    142                               timeout.tmout_list);
    143     c->timeout.in_cstm_tmout_list = true;
    144   }
    145 }
    146 
    147 
    148 MHD_INTERNAL
    149 MHD_FN_PAR_NONNULL_ALL_ void
    150 mhd_conn_deinit_activity_timeout (struct MHD_Connection *restrict c)
    151 {
    152   struct MHD_Daemon *const restrict d = c->daemon;
    153 
    154 #if defined(MHD_SUPPORT_THREADS)
    155   mhd_assert (! mhd_D_HAS_WORKERS (d));
    156 #endif /* MHD_SUPPORT_THREADS */
    157 
    158   if (0u == c->timeout.milsec)
    159   {
    160     mhd_assert (! c->timeout.in_cstm_tmout_list);
    161     return;
    162   }
    163 
    164   if (mhd_D_HAS_THR_PER_CONN (d))
    165   {
    166     mhd_assert (! c->timeout.in_cstm_tmout_list);
    167     return;
    168   }
    169 
    170   if (! c->timeout.in_cstm_tmout_list)
    171     mhd_DLINKEDL_DEL_D (&(d->conns.def_timeout),
    172                         c,
    173                         timeout.tmout_list);
    174   else
    175     mhd_DLINKEDL_DEL_D (&(d->conns.cust_timeout), \
    176                         c,
    177                         timeout.tmout_list);
    178 
    179   c->timeout.in_cstm_tmout_list = false;
    180 }
    181 
    182 
    183 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    184 mhd_conn_update_activity_mark (struct MHD_Connection *restrict c)
    185 {
    186   struct MHD_Daemon *const restrict d = c->daemon;
    187   uint_fast64_t prev_mark;
    188 
    189 #if defined(MHD_SUPPORT_THREADS)
    190   mhd_assert (! mhd_D_HAS_WORKERS (d));
    191 #endif /* MHD_SUPPORT_THREADS */
    192 
    193   mhd_assert (! c->suspended);
    194 
    195   if (0u == c->timeout.milsec)
    196   {
    197     mhd_assert (! c->timeout.in_cstm_tmout_list);
    198     return;
    199   }
    200 
    201   prev_mark = c->timeout.last_act;
    202   c->timeout.last_act = mhd_daemon_get_milsec_counter (d);
    203 
    204   if (c->timeout.last_act == prev_mark)
    205     return; /* Nothing to update */
    206 
    207   if (mhd_D_HAS_THR_PER_CONN (d))
    208   {
    209     mhd_assert (! c->timeout.in_cstm_tmout_list);
    210     return; /* each connection has personal timeout */
    211   }
    212 
    213   if (c->timeout.in_cstm_tmout_list)
    214     return; /* custom timeout, no need to move it in "normal" DLL */
    215 
    216   /* move connection to head of timeout list */
    217   mhd_DLINKEDL_MOVE_TO_FIRST_D (&(d->conns.def_timeout),
    218                                 c,
    219                                 timeout.tmout_list);
    220 }