1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_civoid 28d4afb5ceSopenharmony_ci__lws_wsi_remove_from_sul(struct lws *wsi) 29d4afb5ceSopenharmony_ci{ 30d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->sul_timeout); 31d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->sul_hrtimer); 32d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->sul_validity); 33d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION) 34d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->sul_fault_timedclose); 35d4afb5ceSopenharmony_ci#endif 36d4afb5ceSopenharmony_ci} 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci/* 39d4afb5ceSopenharmony_ci * hrtimer 40d4afb5ceSopenharmony_ci */ 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_cistatic void 43d4afb5ceSopenharmony_cilws_sul_hrtimer_cb(lws_sorted_usec_list_t *sul) 44d4afb5ceSopenharmony_ci{ 45d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(sul, struct lws, sul_hrtimer); 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_ci if (wsi->a.protocol && 48d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, LWS_CALLBACK_TIMER, 49d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0)) 50d4afb5ceSopenharmony_ci __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 51d4afb5ceSopenharmony_ci "hrtimer cb errored"); 52d4afb5ceSopenharmony_ci} 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_civoid 55d4afb5ceSopenharmony_ci__lws_set_timer_usecs(struct lws *wsi, lws_usec_t us) 56d4afb5ceSopenharmony_ci{ 57d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 58d4afb5ceSopenharmony_ci 59d4afb5ceSopenharmony_ci wsi->sul_hrtimer.cb = lws_sul_hrtimer_cb; 60d4afb5ceSopenharmony_ci __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], 61d4afb5ceSopenharmony_ci &wsi->sul_hrtimer, us); 62d4afb5ceSopenharmony_ci} 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_civoid 65d4afb5ceSopenharmony_cilws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs) 66d4afb5ceSopenharmony_ci{ 67d4afb5ceSopenharmony_ci __lws_set_timer_usecs(wsi, usecs); 68d4afb5ceSopenharmony_ci} 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci/* 71d4afb5ceSopenharmony_ci * wsi timeout 72d4afb5ceSopenharmony_ci */ 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_cistatic void 75d4afb5ceSopenharmony_cilws_sul_wsitimeout_cb(lws_sorted_usec_list_t *sul) 76d4afb5ceSopenharmony_ci{ 77d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(sul, struct lws, sul_timeout); 78d4afb5ceSopenharmony_ci struct lws_context *cx = wsi->a.context; 79d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &cx->pt[(int)wsi->tsi]; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci /* no need to log normal idle keepalive timeout */ 82d4afb5ceSopenharmony_ci// if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE) 83d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 84d4afb5ceSopenharmony_ci if (wsi->pending_timeout != PENDING_TIMEOUT_USER_OK) 85d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "TIMEDOUT WAITING %d, dhdr %d, ah %p, wl %d", 86d4afb5ceSopenharmony_ci wsi->pending_timeout, 87d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed, wsi->http.ah, 88d4afb5ceSopenharmony_ci pt->http.ah_wait_list_length); 89d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) 90d4afb5ceSopenharmony_ci if (wsi->http.cgi) 91d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "CGI timeout: %s", wsi->http.cgi->summary); 92d4afb5ceSopenharmony_ci#endif 93d4afb5ceSopenharmony_ci#else 94d4afb5ceSopenharmony_ci if (wsi->pending_timeout != PENDING_TIMEOUT_USER_OK) 95d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "TIMEDOUT WAITING on %d ", 96d4afb5ceSopenharmony_ci wsi->pending_timeout); 97d4afb5ceSopenharmony_ci#endif 98d4afb5ceSopenharmony_ci /* cgi timeout */ 99d4afb5ceSopenharmony_ci if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE) 100d4afb5ceSopenharmony_ci /* 101d4afb5ceSopenharmony_ci * Since he failed a timeout, he already had a chance to 102d4afb5ceSopenharmony_ci * do something and was unable to... that includes 103d4afb5ceSopenharmony_ci * situations like half closed connections. So process 104d4afb5ceSopenharmony_ci * this "failed timeout" close as a violent death and 105d4afb5ceSopenharmony_ci * don't try to do protocol cleanup like flush partials. 106d4afb5ceSopenharmony_ci */ 107d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 108d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 109d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_WAITING_SSL) 110d4afb5ceSopenharmony_ci lws_inform_client_conn_fail(wsi, 111d4afb5ceSopenharmony_ci (void *)"Timed out waiting SSL", 21); 112d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY) 113d4afb5ceSopenharmony_ci lws_inform_client_conn_fail(wsi, 114d4afb5ceSopenharmony_ci (void *)"Timed out waiting server reply", 30); 115d4afb5ceSopenharmony_ci#endif 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci lws_context_lock(cx, __func__); 118d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 119d4afb5ceSopenharmony_ci __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "timeout"); 120d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 121d4afb5ceSopenharmony_ci lws_context_unlock(cx); 122d4afb5ceSopenharmony_ci} 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_civoid 125d4afb5ceSopenharmony_ci__lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) 126d4afb5ceSopenharmony_ci{ 127d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci wsi->sul_timeout.cb = lws_sul_wsitimeout_cb; 130d4afb5ceSopenharmony_ci __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], 131d4afb5ceSopenharmony_ci &wsi->sul_timeout, 132d4afb5ceSopenharmony_ci ((lws_usec_t)secs) * LWS_US_PER_SEC); 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "%d secs, reason %d\n", secs, reason); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci wsi->pending_timeout = (char)reason; 137d4afb5ceSopenharmony_ci} 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_civoid 140d4afb5ceSopenharmony_cilws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) 141d4afb5ceSopenharmony_ci{ 142d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci lws_context_lock(pt->context, __func__); 145d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 146d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->sul_timeout.list); 147d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci if (!secs) 150d4afb5ceSopenharmony_ci goto bail; 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci if (secs == LWS_TO_KILL_SYNC) { 153d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "TO_KILL_SYNC"); 154d4afb5ceSopenharmony_ci lws_context_unlock(pt->context); 155d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 156d4afb5ceSopenharmony_ci "to sync kill"); 157d4afb5ceSopenharmony_ci return; 158d4afb5ceSopenharmony_ci } 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci if (secs == LWS_TO_KILL_ASYNC) 161d4afb5ceSopenharmony_ci secs = 0; 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci // assert(!secs || !wsi->mux_stream_immortal); 164d4afb5ceSopenharmony_ci if (secs && wsi->mux_stream_immortal) 165d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "on immortal stream %d %d", reason, secs); 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 168d4afb5ceSopenharmony_ci __lws_set_timeout(wsi, reason, secs); 169d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_cibail: 172d4afb5ceSopenharmony_ci lws_context_unlock(pt->context); 173d4afb5ceSopenharmony_ci} 174d4afb5ceSopenharmony_ci 175d4afb5ceSopenharmony_civoid 176d4afb5ceSopenharmony_cilws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us) 177d4afb5ceSopenharmony_ci{ 178d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 181d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->sul_timeout.list); 182d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci if (!us) 185d4afb5ceSopenharmony_ci return; 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 188d4afb5ceSopenharmony_ci __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], 189d4afb5ceSopenharmony_ci &wsi->sul_timeout, us); 190d4afb5ceSopenharmony_ci 191d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "%llu us, reason %d", 192d4afb5ceSopenharmony_ci (unsigned long long)us, reason); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci wsi->pending_timeout = (char)reason; 195d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 196d4afb5ceSopenharmony_ci} 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_cistatic void 199d4afb5ceSopenharmony_cilws_validity_cb(lws_sorted_usec_list_t *sul) 200d4afb5ceSopenharmony_ci{ 201d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(sul, struct lws, sul_validity); 202d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 203d4afb5ceSopenharmony_ci const lws_retry_bo_t *rbo = wsi->retry_policy; 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci /* one of either the ping or hangup validity threshold was crossed */ 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci if (wsi->validity_hup) { 208d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "validity too old"); 209d4afb5ceSopenharmony_ci struct lws_context *cx = wsi->a.context; 210d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &cx->pt[(int)wsi->tsi]; 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci lws_context_lock(cx, __func__); 213d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 214d4afb5ceSopenharmony_ci __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 215d4afb5ceSopenharmony_ci "validity timeout"); 216d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 217d4afb5ceSopenharmony_ci lws_context_unlock(cx); 218d4afb5ceSopenharmony_ci return; 219d4afb5ceSopenharmony_ci } 220d4afb5ceSopenharmony_ci 221d4afb5ceSopenharmony_ci /* schedule a protocol-dependent ping */ 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "scheduling validity check"); 224d4afb5ceSopenharmony_ci 225d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive)) 226d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive). 227d4afb5ceSopenharmony_ci issue_keepalive(wsi, 0); 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci /* 230d4afb5ceSopenharmony_ci * We arrange to come back here after the additional ping to hangup time 231d4afb5ceSopenharmony_ci * and do the hangup, unless we get validated (by, eg, a PONG) and 232d4afb5ceSopenharmony_ci * reset the timer 233d4afb5ceSopenharmony_ci */ 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ci assert(rbo->secs_since_valid_hangup > rbo->secs_since_valid_ping); 236d4afb5ceSopenharmony_ci 237d4afb5ceSopenharmony_ci wsi->validity_hup = 1; 238d4afb5ceSopenharmony_ci __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend], 239d4afb5ceSopenharmony_ci &wsi->sul_validity, 240d4afb5ceSopenharmony_ci ((uint64_t)rbo->secs_since_valid_hangup - 241d4afb5ceSopenharmony_ci rbo->secs_since_valid_ping) * LWS_US_PER_SEC); 242d4afb5ceSopenharmony_ci} 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci/* 245d4afb5ceSopenharmony_ci * The role calls this back to actually confirm validity on a particular wsi 246d4afb5ceSopenharmony_ci * (which may not be the original wsi) 247d4afb5ceSopenharmony_ci */ 248d4afb5ceSopenharmony_ci 249d4afb5ceSopenharmony_civoid 250d4afb5ceSopenharmony_ci_lws_validity_confirmed_role(struct lws *wsi) 251d4afb5ceSopenharmony_ci{ 252d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 253d4afb5ceSopenharmony_ci const lws_retry_bo_t *rbo = wsi->retry_policy; 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci if (!rbo || !rbo->secs_since_valid_hangup) 256d4afb5ceSopenharmony_ci return; 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci wsi->validity_hup = 0; 259d4afb5ceSopenharmony_ci wsi->sul_validity.cb = lws_validity_cb; 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci wsi->validity_hup = rbo->secs_since_valid_ping >= 262d4afb5ceSopenharmony_ci rbo->secs_since_valid_hangup; 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "setting validity timer %ds (hup %d)", 265d4afb5ceSopenharmony_ci wsi->validity_hup ? rbo->secs_since_valid_hangup : 266d4afb5ceSopenharmony_ci rbo->secs_since_valid_ping, 267d4afb5ceSopenharmony_ci wsi->validity_hup); 268d4afb5ceSopenharmony_ci 269d4afb5ceSopenharmony_ci __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend], 270d4afb5ceSopenharmony_ci &wsi->sul_validity, 271d4afb5ceSopenharmony_ci ((uint64_t)(wsi->validity_hup ? 272d4afb5ceSopenharmony_ci rbo->secs_since_valid_hangup : 273d4afb5ceSopenharmony_ci rbo->secs_since_valid_ping)) * LWS_US_PER_SEC); 274d4afb5ceSopenharmony_ci} 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_civoid 277d4afb5ceSopenharmony_cilws_validity_confirmed(struct lws *wsi) 278d4afb5ceSopenharmony_ci{ 279d4afb5ceSopenharmony_ci /* 280d4afb5ceSopenharmony_ci * This may be a stream inside a muxed network connection... leave it 281d4afb5ceSopenharmony_ci * to the role to figure out who actually needs to understand their 282d4afb5ceSopenharmony_ci * validity was confirmed. 283d4afb5ceSopenharmony_ci */ 284d4afb5ceSopenharmony_ci if (!wsi->h2_stream_carries_ws && /* only if not encapsulated */ 285d4afb5ceSopenharmony_ci wsi->role_ops && 286d4afb5ceSopenharmony_ci lws_rops_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive)) 287d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive). 288d4afb5ceSopenharmony_ci issue_keepalive(wsi, 1); 289d4afb5ceSopenharmony_ci} 290