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 }