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_ci#if defined(LWS_WITH_CLIENT) 28d4afb5ceSopenharmony_cistatic int 29d4afb5ceSopenharmony_cilws_close_trans_q_leader(struct lws_dll2 *d, void *user) 30d4afb5ceSopenharmony_ci{ 31d4afb5ceSopenharmony_ci struct lws *w = lws_container_of(d, struct lws, dll2_cli_txn_queue); 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci __lws_close_free_wsi(w, (enum lws_close_status)-1, "trans q leader closing"); 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci return 0; 36d4afb5ceSopenharmony_ci} 37d4afb5ceSopenharmony_ci#endif 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_civoid 40d4afb5ceSopenharmony_ci__lws_reset_wsi(struct lws *wsi) 41d4afb5ceSopenharmony_ci{ 42d4afb5ceSopenharmony_ci if (!wsi) 43d4afb5ceSopenharmony_ci return; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->cli_hostname_copy); 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON) 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci if (wsi->conmon.dns_results_copy) { 52d4afb5ceSopenharmony_ci lws_conmon_addrinfo_destroy(wsi->conmon.dns_results_copy); 53d4afb5ceSopenharmony_ci wsi->conmon.dns_results_copy = NULL; 54d4afb5ceSopenharmony_ci } 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_ci wsi->conmon.ciu_dns = 57d4afb5ceSopenharmony_ci wsi->conmon.ciu_sockconn = 58d4afb5ceSopenharmony_ci wsi->conmon.ciu_tls = 59d4afb5ceSopenharmony_ci wsi->conmon.ciu_txn_resp = 0; 60d4afb5ceSopenharmony_ci#endif 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci /* 63d4afb5ceSopenharmony_ci * if we have wsi in our transaction queue, if we are closing we 64d4afb5ceSopenharmony_ci * must go through and close all those first 65d4afb5ceSopenharmony_ci */ 66d4afb5ceSopenharmony_ci if (wsi->a.vhost) { 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci /* we are no longer an active client connection that can piggyback */ 69d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_cli_active_conns); 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&wsi->dll2_cli_txn_queue_owner, NULL, 72d4afb5ceSopenharmony_ci lws_close_trans_q_leader); 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci /* 75d4afb5ceSopenharmony_ci * !!! If we are closing, but we have pending pipelined 76d4afb5ceSopenharmony_ci * transaction results we already sent headers for, that's going 77d4afb5ceSopenharmony_ci * to destroy sync for HTTP/1 and leave H2 stream with no live 78d4afb5ceSopenharmony_ci * swsi.` 79d4afb5ceSopenharmony_ci * 80d4afb5ceSopenharmony_ci * However this is normal if we are being closed because the 81d4afb5ceSopenharmony_ci * transaction queue leader is closing. 82d4afb5ceSopenharmony_ci */ 83d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll2_cli_txn_queue); 84d4afb5ceSopenharmony_ci } 85d4afb5ceSopenharmony_ci#endif 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci if (wsi->a.vhost) { 88d4afb5ceSopenharmony_ci lws_vhost_lock(wsi->a.vhost); 89d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->vh_awaiting_socket); 90d4afb5ceSopenharmony_ci lws_vhost_unlock(wsi->a.vhost); 91d4afb5ceSopenharmony_ci } 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci /* 94d4afb5ceSopenharmony_ci * Protocol user data may be allocated either internally by lws 95d4afb5ceSopenharmony_ci * or by specified the user. We should only free what we allocated. 96d4afb5ceSopenharmony_ci */ 97d4afb5ceSopenharmony_ci if (wsi->a.protocol && wsi->a.protocol->per_session_data_size && 98d4afb5ceSopenharmony_ci wsi->user_space && !wsi->user_space_externally_allocated) { 99d4afb5ceSopenharmony_ci /* confirm no sul left scheduled in user data itself */ 100d4afb5ceSopenharmony_ci lws_sul_debug_zombies(wsi->a.context, wsi->user_space, 101d4afb5ceSopenharmony_ci wsi->a.protocol->per_session_data_size, __func__); 102d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->user_space); 103d4afb5ceSopenharmony_ci } 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci /* 106d4afb5ceSopenharmony_ci * Don't let buflist content or state from the wsi's previous life 107d4afb5ceSopenharmony_ci * carry over to the new life 108d4afb5ceSopenharmony_ci */ 109d4afb5ceSopenharmony_ci 110d4afb5ceSopenharmony_ci lws_buflist_destroy_all_segments(&wsi->buflist); 111d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_buflist); 112d4afb5ceSopenharmony_ci lws_buflist_destroy_all_segments(&wsi->buflist_out); 113d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UDP) 114d4afb5ceSopenharmony_ci if (wsi->udp) { 115d4afb5ceSopenharmony_ci /* confirm no sul left scheduled in wsi->udp itself */ 116d4afb5ceSopenharmony_ci lws_sul_debug_zombies(wsi->a.context, wsi->udp, 117d4afb5ceSopenharmony_ci sizeof(*wsi->udp), "close udp wsi"); 118d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->udp); 119d4afb5ceSopenharmony_ci } 120d4afb5ceSopenharmony_ci#endif 121d4afb5ceSopenharmony_ci wsi->retry = 0; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 124d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll2_cli_txn_queue); 125d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_cli_active_conns); 126d4afb5ceSopenharmony_ci if (wsi->cli_hostname_copy) 127d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->cli_hostname_copy); 128d4afb5ceSopenharmony_ci#endif 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 131d4afb5ceSopenharmony_ci lws_async_dns_cancel(wsi); 132d4afb5ceSopenharmony_ci#endif 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 135d4afb5ceSopenharmony_ci if (wsi->http.buflist_post_body) 136d4afb5ceSopenharmony_ci lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body); 137d4afb5ceSopenharmony_ci#endif 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 140d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->listen_list); 141d4afb5ceSopenharmony_ci#endif 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 144d4afb5ceSopenharmony_ci if (wsi->a.vhost) 145d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_cli_active_conns); 146d4afb5ceSopenharmony_ci#endif 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci __lws_same_vh_protocol_remove(wsi); 149d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 150d4afb5ceSopenharmony_ci //lws_free_set_NULL(wsi->stash); 151d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->cli_hostname_copy); 152d4afb5ceSopenharmony_ci#endif 153d4afb5ceSopenharmony_ci 154d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 155d4afb5ceSopenharmony_ci lws_peer_track_wsi_close(wsi->a.context, wsi->peer); 156d4afb5ceSopenharmony_ci wsi->peer = NULL; 157d4afb5ceSopenharmony_ci#endif 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci /* since we will destroy the wsi, make absolutely sure now */ 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci#if defined(LWS_WITH_OPENSSL) 162d4afb5ceSopenharmony_ci __lws_ssl_remove_wsi_from_buffered_list(wsi); 163d4afb5ceSopenharmony_ci#endif 164d4afb5ceSopenharmony_ci __lws_wsi_remove_from_sul(wsi); 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_destroy_role)) 167d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, 168d4afb5ceSopenharmony_ci LWS_ROPS_destroy_role).destroy_role(wsi); 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 171d4afb5ceSopenharmony_ci __lws_header_table_detach(wsi, 0); 172d4afb5ceSopenharmony_ci#endif 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 175d4afb5ceSopenharmony_ci /* 176d4afb5ceSopenharmony_ci * Let's try to clean out the h2-ness of the wsi 177d4afb5ceSopenharmony_ci */ 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci memset(&wsi->h2, 0, sizeof(wsi->h2)); 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed = wsi->mux_substream = 182d4afb5ceSopenharmony_ci wsi->upgraded_to_http2 = wsi->mux_stream_immortal = 183d4afb5ceSopenharmony_ci wsi->h2_acked_settings = wsi->seen_nonpseudoheader = 184d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = wsi->favoured_pollin = 185d4afb5ceSopenharmony_ci wsi->already_did_cce = wsi->told_user_closed = 186d4afb5ceSopenharmony_ci wsi->waiting_to_send_close_frame = wsi->close_needs_ack = 187d4afb5ceSopenharmony_ci wsi->parent_pending_cb_on_writable = wsi->seen_zero_length_recv = 188d4afb5ceSopenharmony_ci wsi->close_when_buffered_out_drained = wsi->could_have_pending = 0; 189d4afb5ceSopenharmony_ci#endif 190d4afb5ceSopenharmony_ci 191d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 192d4afb5ceSopenharmony_ci wsi->do_ws = wsi->chunked = wsi->client_rx_avail = 193d4afb5ceSopenharmony_ci wsi->client_http_body_pending = wsi->transaction_from_pipeline_queue = 194d4afb5ceSopenharmony_ci wsi->keepalive_active = wsi->keepalive_rejected = 195d4afb5ceSopenharmony_ci wsi->redirected_to_get = wsi->client_pipeline = wsi->client_h2_alpn = 196d4afb5ceSopenharmony_ci wsi->client_mux_substream = wsi->client_mux_migrated = 197d4afb5ceSopenharmony_ci wsi->tls_session_reused = wsi->perf_done = 0; 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci wsi->immortal_substream_count = 0; 200d4afb5ceSopenharmony_ci#endif 201d4afb5ceSopenharmony_ci} 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci/* req cx lock */ 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_civoid 206d4afb5ceSopenharmony_ci__lws_free_wsi(struct lws *wsi) 207d4afb5ceSopenharmony_ci{ 208d4afb5ceSopenharmony_ci struct lws_vhost *vh; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci if (!wsi) 211d4afb5ceSopenharmony_ci return; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci lws_context_assert_lock_held(wsi->a.context); 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS) 216d4afb5ceSopenharmony_ci if (wsi->for_ss) { 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 219d4afb5ceSopenharmony_ci if (wsi->client_bound_sspc) { 220d4afb5ceSopenharmony_ci lws_sspc_handle_t *h = (lws_sspc_handle_t *) 221d4afb5ceSopenharmony_ci wsi->a.opaque_user_data; 222d4afb5ceSopenharmony_ci if (h) { 223d4afb5ceSopenharmony_ci h->cwsi = NULL; 224d4afb5ceSopenharmony_ci wsi->a.opaque_user_data = NULL; 225d4afb5ceSopenharmony_ci } 226d4afb5ceSopenharmony_ci } else 227d4afb5ceSopenharmony_ci#endif 228d4afb5ceSopenharmony_ci { 229d4afb5ceSopenharmony_ci /* 230d4afb5ceSopenharmony_ci * Make certain it is disconnected from the ss by now 231d4afb5ceSopenharmony_ci */ 232d4afb5ceSopenharmony_ci lws_ss_handle_t *h = (lws_ss_handle_t *) 233d4afb5ceSopenharmony_ci wsi->a.opaque_user_data; 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ci if (h) { 236d4afb5ceSopenharmony_ci h->wsi = NULL; 237d4afb5ceSopenharmony_ci wsi->a.opaque_user_data = NULL; 238d4afb5ceSopenharmony_ci } 239d4afb5ceSopenharmony_ci } 240d4afb5ceSopenharmony_ci } 241d4afb5ceSopenharmony_ci#endif 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci vh = wsi->a.vhost; 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci __lws_reset_wsi(wsi); 246d4afb5ceSopenharmony_ci __lws_wsi_remove_from_sul(wsi); 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci if (vh) 249d4afb5ceSopenharmony_ci /* this may destroy vh */ 250d4afb5ceSopenharmony_ci __lws_vhost_unbind_wsi(wsi); /* req cx + vh lock */ 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 253d4afb5ceSopenharmony_ci if (wsi->stash) 254d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 255d4afb5ceSopenharmony_ci#endif 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci if (wsi->a.context->event_loop_ops->destroy_wsi) 258d4afb5ceSopenharmony_ci wsi->a.context->event_loop_ops->destroy_wsi(wsi); 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "tsi fds count %d\n", 261d4afb5ceSopenharmony_ci wsi->a.context->pt[(int)wsi->tsi].fds_count); 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci /* confirm no sul left scheduled in wsi itself */ 264d4afb5ceSopenharmony_ci lws_sul_debug_zombies(wsi->a.context, wsi, sizeof(*wsi), __func__); 265d4afb5ceSopenharmony_ci 266d4afb5ceSopenharmony_ci __lws_lc_untag(wsi->a.context, &wsi->lc); 267d4afb5ceSopenharmony_ci lws_free(wsi); 268d4afb5ceSopenharmony_ci} 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_civoid 272d4afb5ceSopenharmony_cilws_remove_child_from_any_parent(struct lws *wsi) 273d4afb5ceSopenharmony_ci{ 274d4afb5ceSopenharmony_ci struct lws **pwsi; 275d4afb5ceSopenharmony_ci int seen = 0; 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci if (!wsi->parent) 278d4afb5ceSopenharmony_ci return; 279d4afb5ceSopenharmony_ci 280d4afb5ceSopenharmony_ci /* detach ourselves from parent's child list */ 281d4afb5ceSopenharmony_ci pwsi = &wsi->parent->child_list; 282d4afb5ceSopenharmony_ci while (*pwsi) { 283d4afb5ceSopenharmony_ci if (*pwsi == wsi) { 284d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "detach from parent %s", 285d4afb5ceSopenharmony_ci lws_wsi_tag(wsi->parent)); 286d4afb5ceSopenharmony_ci 287d4afb5ceSopenharmony_ci if (wsi->parent->a.protocol) 288d4afb5ceSopenharmony_ci wsi->parent->a.protocol->callback(wsi, 289d4afb5ceSopenharmony_ci LWS_CALLBACK_CHILD_CLOSING, 290d4afb5ceSopenharmony_ci wsi->parent->user_space, wsi, 0); 291d4afb5ceSopenharmony_ci 292d4afb5ceSopenharmony_ci *pwsi = wsi->sibling_list; 293d4afb5ceSopenharmony_ci seen = 1; 294d4afb5ceSopenharmony_ci break; 295d4afb5ceSopenharmony_ci } 296d4afb5ceSopenharmony_ci pwsi = &(*pwsi)->sibling_list; 297d4afb5ceSopenharmony_ci } 298d4afb5ceSopenharmony_ci if (!seen) 299d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "failed to detach from parent"); 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci wsi->parent = NULL; 302d4afb5ceSopenharmony_ci} 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 305d4afb5ceSopenharmony_civoid 306d4afb5ceSopenharmony_cilws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len) 307d4afb5ceSopenharmony_ci{ 308d4afb5ceSopenharmony_ci lws_addrinfo_clean(wsi); 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci if (wsi->already_did_cce) 311d4afb5ceSopenharmony_ci return; 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_ci wsi->already_did_cce = 1; 314d4afb5ceSopenharmony_ci 315d4afb5ceSopenharmony_ci if (!wsi->a.protocol) 316d4afb5ceSopenharmony_ci return; 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci if (!wsi->client_suppress_CONNECTION_ERROR) 319d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, 320d4afb5ceSopenharmony_ci LWS_CALLBACK_CLIENT_CONNECTION_ERROR, 321d4afb5ceSopenharmony_ci wsi->user_space, arg, len); 322d4afb5ceSopenharmony_ci} 323d4afb5ceSopenharmony_ci#endif 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_civoid 326d4afb5ceSopenharmony_cilws_addrinfo_clean(struct lws *wsi) 327d4afb5ceSopenharmony_ci{ 328d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 329d4afb5ceSopenharmony_ci struct lws_dll2 *d = lws_dll2_get_head(&wsi->dns_sorted_list), *d1; 330d4afb5ceSopenharmony_ci 331d4afb5ceSopenharmony_ci while (d) { 332d4afb5ceSopenharmony_ci lws_dns_sort_t *r = lws_container_of(d, lws_dns_sort_t, list); 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci d1 = d->next; 335d4afb5ceSopenharmony_ci lws_dll2_remove(d); 336d4afb5ceSopenharmony_ci lws_free(r); 337d4afb5ceSopenharmony_ci 338d4afb5ceSopenharmony_ci d = d1; 339d4afb5ceSopenharmony_ci } 340d4afb5ceSopenharmony_ci#endif 341d4afb5ceSopenharmony_ci} 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_ci/* requires cx and pt lock */ 344d4afb5ceSopenharmony_ci 345d4afb5ceSopenharmony_civoid 346d4afb5ceSopenharmony_ci__lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, 347d4afb5ceSopenharmony_ci const char *caller) 348d4afb5ceSopenharmony_ci{ 349d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 350d4afb5ceSopenharmony_ci const struct lws_protocols *pro; 351d4afb5ceSopenharmony_ci struct lws_context *context; 352d4afb5ceSopenharmony_ci struct lws *wsi1, *wsi2; 353d4afb5ceSopenharmony_ci int n, ccb; 354d4afb5ceSopenharmony_ci 355d4afb5ceSopenharmony_ci if (!wsi) 356d4afb5ceSopenharmony_ci return; 357d4afb5ceSopenharmony_ci 358d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "caller: %s", caller); 359d4afb5ceSopenharmony_ci 360d4afb5ceSopenharmony_ci lws_access_log(wsi); 361d4afb5ceSopenharmony_ci 362d4afb5ceSopenharmony_ci if (!lws_dll2_is_detached(&wsi->dll_buflist)) 363d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "going down with stuff in buflist"); 364d4afb5ceSopenharmony_ci 365d4afb5ceSopenharmony_ci context = wsi->a.context; 366d4afb5ceSopenharmony_ci pt = &context->pt[(int)wsi->tsi]; 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ci if (pt->pipe_wsi == wsi) 369d4afb5ceSopenharmony_ci pt->pipe_wsi = NULL; 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) && \ 372d4afb5ceSopenharmony_ci (defined(LWS_WITH_CLIENT) || defined(LWS_WITH_SERVER)) 373d4afb5ceSopenharmony_ci /* wsi level: only reports if dangling caliper */ 374d4afb5ceSopenharmony_ci if (wsi->cal_conn.mt && wsi->cal_conn.us_start) { 375d4afb5ceSopenharmony_ci if ((lws_metrics_priv_to_pub(wsi->cal_conn.mt)->flags) & LWSMTFL_REPORT_HIST) { 376d4afb5ceSopenharmony_ci lws_metrics_caliper_report_hist(wsi->cal_conn, (struct lws *)NULL); 377d4afb5ceSopenharmony_ci } else { 378d4afb5ceSopenharmony_ci lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO); 379d4afb5ceSopenharmony_ci lws_metrics_caliper_done(wsi->cal_conn); 380d4afb5ceSopenharmony_ci } 381d4afb5ceSopenharmony_ci } else 382d4afb5ceSopenharmony_ci lws_metrics_caliper_done(wsi->cal_conn); 383d4afb5ceSopenharmony_ci#endif 384d4afb5ceSopenharmony_ci 385d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 386d4afb5ceSopenharmony_ci if (wsi == context->async_dns.wsi) 387d4afb5ceSopenharmony_ci context->async_dns.wsi = NULL; 388d4afb5ceSopenharmony_ci#endif 389d4afb5ceSopenharmony_ci 390d4afb5ceSopenharmony_ci lws_pt_assert_lock_held(pt); 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->cli_hostname_copy); 395d4afb5ceSopenharmony_ci wsi->client_mux_substream_was = wsi->client_mux_substream; 396d4afb5ceSopenharmony_ci 397d4afb5ceSopenharmony_ci lws_addrinfo_clean(wsi); 398d4afb5ceSopenharmony_ci#endif 399d4afb5ceSopenharmony_ci 400d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 401d4afb5ceSopenharmony_ci if (wsi->mux_stream_immortal) 402d4afb5ceSopenharmony_ci lws_http_close_immortal(wsi); 403d4afb5ceSopenharmony_ci#endif 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ci /* if we have children, close them first */ 406d4afb5ceSopenharmony_ci if (wsi->child_list) { 407d4afb5ceSopenharmony_ci wsi2 = wsi->child_list; 408d4afb5ceSopenharmony_ci while (wsi2) { 409d4afb5ceSopenharmony_ci wsi1 = wsi2->sibling_list; 410d4afb5ceSopenharmony_ci// wsi2->parent = NULL; 411d4afb5ceSopenharmony_ci /* stop it doing shutdown processing */ 412d4afb5ceSopenharmony_ci wsi2->socket_is_permanently_unusable = 1; 413d4afb5ceSopenharmony_ci __lws_close_free_wsi(wsi2, reason, 414d4afb5ceSopenharmony_ci "general child recurse"); 415d4afb5ceSopenharmony_ci wsi2 = wsi1; 416d4afb5ceSopenharmony_ci } 417d4afb5ceSopenharmony_ci wsi->child_list = NULL; 418d4afb5ceSopenharmony_ci } 419d4afb5ceSopenharmony_ci 420d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_RAW_FILE) 421d4afb5ceSopenharmony_ci if (wsi->role_ops == &role_ops_raw_file) { 422d4afb5ceSopenharmony_ci lws_remove_child_from_any_parent(wsi); 423d4afb5ceSopenharmony_ci __remove_wsi_socket_from_fds(wsi); 424d4afb5ceSopenharmony_ci if (wsi->a.protocol) 425d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, wsi->role_ops->close_cb[0], 426d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0); 427d4afb5ceSopenharmony_ci goto async_close; 428d4afb5ceSopenharmony_ci } 429d4afb5ceSopenharmony_ci#endif 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci wsi->wsistate_pre_close = wsi->wsistate; 432d4afb5ceSopenharmony_ci 433d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 434d4afb5ceSopenharmony_ci if (wsi->role_ops == &role_ops_cgi) { 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci // lwsl_debug("%s: closing stdwsi index %d\n", __func__, (int)wsi->lsp_channel); 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci /* we are not a network connection, but a handler for CGI io */ 439d4afb5ceSopenharmony_ci if (wsi->parent && wsi->parent->http.cgi) { 440d4afb5ceSopenharmony_ci 441d4afb5ceSopenharmony_ci /* 442d4afb5ceSopenharmony_ci * We need to keep the logical cgi around so we can 443d4afb5ceSopenharmony_ci * drain it 444d4afb5ceSopenharmony_ci */ 445d4afb5ceSopenharmony_ci 446d4afb5ceSopenharmony_ci// if (wsi->parent->child_list == wsi && !wsi->sibling_list) 447d4afb5ceSopenharmony_ci// lws_cgi_remove_and_kill(wsi->parent); 448d4afb5ceSopenharmony_ci 449d4afb5ceSopenharmony_ci /* end the binding between us and network connection */ 450d4afb5ceSopenharmony_ci if (wsi->parent->http.cgi && wsi->parent->http.cgi->lsp) 451d4afb5ceSopenharmony_ci wsi->parent->http.cgi->lsp->stdwsi[(int)wsi->lsp_channel] = 452d4afb5ceSopenharmony_ci NULL; 453d4afb5ceSopenharmony_ci } 454d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci goto just_kill_connection; 457d4afb5ceSopenharmony_ci } 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci if (wsi->http.cgi) 460d4afb5ceSopenharmony_ci lws_cgi_remove_and_kill(wsi); 461d4afb5ceSopenharmony_ci#endif 462d4afb5ceSopenharmony_ci 463d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 464d4afb5ceSopenharmony_ci if (!wsi->close_is_redirect) 465d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 466d4afb5ceSopenharmony_ci#endif 467d4afb5ceSopenharmony_ci 468d4afb5ceSopenharmony_ci if (wsi->role_ops == &role_ops_raw_skt) { 469d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 470d4afb5ceSopenharmony_ci goto just_kill_connection; 471d4afb5ceSopenharmony_ci } 472d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)) 473d4afb5ceSopenharmony_ci if (lwsi_role_http(wsi) && lwsi_role_server(wsi) && 474d4afb5ceSopenharmony_ci wsi->http.fop_fd != NULL) 475d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 476d4afb5ceSopenharmony_ci#endif 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_DEAD_SOCKET) 479d4afb5ceSopenharmony_ci return; 480d4afb5ceSopenharmony_ci 481d4afb5ceSopenharmony_ci if (wsi->socket_is_permanently_unusable || 482d4afb5ceSopenharmony_ci reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY || 483d4afb5ceSopenharmony_ci lwsi_state(wsi) == LRS_SHUTDOWN) 484d4afb5ceSopenharmony_ci goto just_kill_connection; 485d4afb5ceSopenharmony_ci 486d4afb5ceSopenharmony_ci switch (lwsi_state_PRE_CLOSE(wsi)) { 487d4afb5ceSopenharmony_ci case LRS_DEAD_SOCKET: 488d4afb5ceSopenharmony_ci return; 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci /* we tried the polite way... */ 491d4afb5ceSopenharmony_ci case LRS_WAITING_TO_SEND_CLOSE: 492d4afb5ceSopenharmony_ci case LRS_AWAITING_CLOSE_ACK: 493d4afb5ceSopenharmony_ci case LRS_RETURNED_CLOSE: 494d4afb5ceSopenharmony_ci goto just_kill_connection; 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ci case LRS_FLUSHING_BEFORE_CLOSE: 497d4afb5ceSopenharmony_ci if (lws_has_buffered_out(wsi) 498d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 499d4afb5ceSopenharmony_ci || wsi->http.comp_ctx.buflist_comp || 500d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more 501d4afb5ceSopenharmony_ci#endif 502d4afb5ceSopenharmony_ci ) { 503d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 504d4afb5ceSopenharmony_ci return; 505d4afb5ceSopenharmony_ci } 506d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, " end LRS_FLUSHING_BEFORE_CLOSE"); 507d4afb5ceSopenharmony_ci goto just_kill_connection; 508d4afb5ceSopenharmony_ci default: 509d4afb5ceSopenharmony_ci if (lws_has_buffered_out(wsi) 510d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 511d4afb5ceSopenharmony_ci || wsi->http.comp_ctx.buflist_comp || 512d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more 513d4afb5ceSopenharmony_ci#endif 514d4afb5ceSopenharmony_ci ) { 515d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "LRS_FLUSHING_BEFORE_CLOSE"); 516d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE); 517d4afb5ceSopenharmony_ci __lws_set_timeout(wsi, 518d4afb5ceSopenharmony_ci PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5); 519d4afb5ceSopenharmony_ci return; 520d4afb5ceSopenharmony_ci } 521d4afb5ceSopenharmony_ci break; 522d4afb5ceSopenharmony_ci } 523d4afb5ceSopenharmony_ci 524d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_WAITING_CONNECT || 525d4afb5ceSopenharmony_ci lwsi_state(wsi) == LRS_WAITING_DNS || 526d4afb5ceSopenharmony_ci lwsi_state(wsi) == LRS_H1C_ISSUE_HANDSHAKE) 527d4afb5ceSopenharmony_ci goto just_kill_connection; 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_ci if (!wsi->told_user_closed && wsi->user_space && wsi->a.protocol && 530d4afb5ceSopenharmony_ci wsi->protocol_bind_balance) { 531d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, 532d4afb5ceSopenharmony_ci wsi->role_ops->protocol_unbind_cb[ 533d4afb5ceSopenharmony_ci !!lwsi_role_server(wsi)], 534d4afb5ceSopenharmony_ci wsi->user_space, (void *)__func__, 0); 535d4afb5ceSopenharmony_ci wsi->protocol_bind_balance = 0; 536d4afb5ceSopenharmony_ci } 537d4afb5ceSopenharmony_ci 538d4afb5ceSopenharmony_ci /* 539d4afb5ceSopenharmony_ci * signal we are closing, lws_write will 540d4afb5ceSopenharmony_ci * add any necessary version-specific stuff. If the write fails, 541d4afb5ceSopenharmony_ci * no worries we are closing anyway. If we didn't initiate this 542d4afb5ceSopenharmony_ci * close, then our state has been changed to 543d4afb5ceSopenharmony_ci * LRS_RETURNED_CLOSE and we will skip this. 544d4afb5ceSopenharmony_ci * 545d4afb5ceSopenharmony_ci * Likewise if it's a second call to close this connection after we 546d4afb5ceSopenharmony_ci * sent the close indication to the peer already, we are in state 547d4afb5ceSopenharmony_ci * LRS_AWAITING_CLOSE_ACK and will skip doing this a second time. 548d4afb5ceSopenharmony_ci */ 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_via_role_protocol) && 551d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_close_via_role_protocol). 552d4afb5ceSopenharmony_ci close_via_role_protocol(wsi, reason)) { 553d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "close_via_role took over (sockfd %d)", 554d4afb5ceSopenharmony_ci wsi->desc.sockfd); 555d4afb5ceSopenharmony_ci return; 556d4afb5ceSopenharmony_ci } 557d4afb5ceSopenharmony_ci 558d4afb5ceSopenharmony_cijust_kill_connection: 559d4afb5ceSopenharmony_ci 560d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "real just_kill_connection A: (sockfd %d)", 561d4afb5ceSopenharmony_ci wsi->desc.sockfd); 562d4afb5ceSopenharmony_ci 563d4afb5ceSopenharmony_ci#if defined(LWS_WITH_THREADPOOL) && defined(LWS_HAVE_PTHREAD_H) 564d4afb5ceSopenharmony_ci lws_threadpool_wsi_closing(wsi); 565d4afb5ceSopenharmony_ci#endif 566d4afb5ceSopenharmony_ci 567d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)) 568d4afb5ceSopenharmony_ci if (lwsi_role_http(wsi) && lwsi_role_server(wsi) && 569d4afb5ceSopenharmony_ci wsi->http.fop_fd != NULL) 570d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 571d4afb5ceSopenharmony_ci#endif 572d4afb5ceSopenharmony_ci 573d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->sul_connect_timeout); 574d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 575d4afb5ceSopenharmony_ci lws_async_dns_cancel(wsi); 576d4afb5ceSopenharmony_ci#endif 577d4afb5ceSopenharmony_ci 578d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 579d4afb5ceSopenharmony_ci if (wsi->http.buflist_post_body) 580d4afb5ceSopenharmony_ci lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body); 581d4afb5ceSopenharmony_ci#endif 582d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UDP) 583d4afb5ceSopenharmony_ci if (wsi->udp) { 584d4afb5ceSopenharmony_ci /* confirm no sul left scheduled in wsi->udp itself */ 585d4afb5ceSopenharmony_ci lws_sul_debug_zombies(wsi->a.context, wsi->udp, 586d4afb5ceSopenharmony_ci sizeof(*wsi->udp), "close udp wsi"); 587d4afb5ceSopenharmony_ci 588d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->udp); 589d4afb5ceSopenharmony_ci } 590d4afb5ceSopenharmony_ci#endif 591d4afb5ceSopenharmony_ci 592d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_kill_connection)) 593d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, 594d4afb5ceSopenharmony_ci LWS_ROPS_close_kill_connection). 595d4afb5ceSopenharmony_ci close_kill_connection(wsi, reason); 596d4afb5ceSopenharmony_ci 597d4afb5ceSopenharmony_ci n = 0; 598d4afb5ceSopenharmony_ci 599d4afb5ceSopenharmony_ci if (!wsi->told_user_closed && wsi->user_space && 600d4afb5ceSopenharmony_ci wsi->protocol_bind_balance && wsi->a.protocol) { 601d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: DROP_PROTOCOL %s\n", __func__, lws_wsi_tag(wsi), 602d4afb5ceSopenharmony_ci wsi->a.protocol ? wsi->a.protocol->name: "NULL"); 603d4afb5ceSopenharmony_ci if (wsi->a.protocol) 604d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, 605d4afb5ceSopenharmony_ci wsi->role_ops->protocol_unbind_cb[ 606d4afb5ceSopenharmony_ci !!lwsi_role_server(wsi)], 607d4afb5ceSopenharmony_ci wsi->user_space, (void *)__func__, 0); 608d4afb5ceSopenharmony_ci wsi->protocol_bind_balance = 0; 609d4afb5ceSopenharmony_ci } 610d4afb5ceSopenharmony_ci 611d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 612d4afb5ceSopenharmony_ci if (( 613d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 614d4afb5ceSopenharmony_ci /* 615d4afb5ceSopenharmony_ci * If our goal is a ws upgrade, effectively we did not reach 616d4afb5ceSopenharmony_ci * ESTABLISHED if we did not get the upgrade server reply 617d4afb5ceSopenharmony_ci */ 618d4afb5ceSopenharmony_ci (lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY && 619d4afb5ceSopenharmony_ci wsi->role_ops == &role_ops_ws) || 620d4afb5ceSopenharmony_ci#endif 621d4afb5ceSopenharmony_ci lwsi_state(wsi) == LRS_WAITING_DNS || 622d4afb5ceSopenharmony_ci lwsi_state(wsi) == LRS_WAITING_CONNECT) && 623d4afb5ceSopenharmony_ci !wsi->already_did_cce && wsi->a.protocol && 624d4afb5ceSopenharmony_ci !wsi->close_is_redirect) { 625d4afb5ceSopenharmony_ci static const char _reason[] = "closed before established"; 626d4afb5ceSopenharmony_ci 627d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "closing in unestablished state 0x%x", 628d4afb5ceSopenharmony_ci lwsi_state(wsi)); 629d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 630d4afb5ceSopenharmony_ci 631d4afb5ceSopenharmony_ci lws_inform_client_conn_fail(wsi, 632d4afb5ceSopenharmony_ci (void *)_reason, sizeof(_reason)); 633d4afb5ceSopenharmony_ci } 634d4afb5ceSopenharmony_ci#endif 635d4afb5ceSopenharmony_ci 636d4afb5ceSopenharmony_ci /* 637d4afb5ceSopenharmony_ci * Testing with ab shows that we have to stage the socket close when 638d4afb5ceSopenharmony_ci * the system is under stress... shutdown any further TX, change the 639d4afb5ceSopenharmony_ci * state to one that won't emit anything more, and wait with a timeout 640d4afb5ceSopenharmony_ci * for the POLLIN to show a zero-size rx before coming back and doing 641d4afb5ceSopenharmony_ci * the actual close. 642d4afb5ceSopenharmony_ci */ 643d4afb5ceSopenharmony_ci if (wsi->role_ops != &role_ops_raw_skt && !lwsi_role_client(wsi) && 644d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_SHUTDOWN && 645d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_UNCONNECTED && 646d4afb5ceSopenharmony_ci reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY && 647d4afb5ceSopenharmony_ci !wsi->socket_is_permanently_unusable) { 648d4afb5ceSopenharmony_ci 649d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 650d4afb5ceSopenharmony_ci if (lws_is_ssl(wsi) && wsi->tls.ssl) { 651d4afb5ceSopenharmony_ci n = 0; 652d4afb5ceSopenharmony_ci switch (__lws_tls_shutdown(wsi)) { 653d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_DONE: 654d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_ERROR: 655d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE_READ: 656d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE: 657d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE: 658d4afb5ceSopenharmony_ci break; 659d4afb5ceSopenharmony_ci } 660d4afb5ceSopenharmony_ci } else 661d4afb5ceSopenharmony_ci#endif 662d4afb5ceSopenharmony_ci { 663d4afb5ceSopenharmony_ci lwsl_info("%s: shutdown conn: %s (sk %d, state 0x%x)\n", 664d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi), (int)(lws_intptr_t)wsi->desc.sockfd, 665d4afb5ceSopenharmony_ci lwsi_state(wsi)); 666d4afb5ceSopenharmony_ci if (!wsi->socket_is_permanently_unusable && 667d4afb5ceSopenharmony_ci lws_socket_is_valid(wsi->desc.sockfd)) { 668d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 669d4afb5ceSopenharmony_ci n = shutdown(wsi->desc.sockfd, SHUT_WR); 670d4afb5ceSopenharmony_ci } 671d4afb5ceSopenharmony_ci } 672d4afb5ceSopenharmony_ci if (n) 673d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "closing: shutdown (state 0x%x) ret %d", 674d4afb5ceSopenharmony_ci lwsi_state(wsi), LWS_ERRNO); 675d4afb5ceSopenharmony_ci 676d4afb5ceSopenharmony_ci /* 677d4afb5ceSopenharmony_ci * This causes problems on WINCE / ESP32 with disconnection 678d4afb5ceSopenharmony_ci * when the events are half closing connection 679d4afb5ceSopenharmony_ci */ 680d4afb5ceSopenharmony_ci#if !defined(_WIN32_WCE) && !defined(LWS_PLAT_FREERTOS) 681d4afb5ceSopenharmony_ci /* libuv: no event available to guarantee completion */ 682d4afb5ceSopenharmony_ci if (!wsi->socket_is_permanently_unusable && 683d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 684d4afb5ceSopenharmony_ci !wsi->close_is_redirect && 685d4afb5ceSopenharmony_ci#endif 686d4afb5ceSopenharmony_ci lws_socket_is_valid(wsi->desc.sockfd) && 687d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_SHUTDOWN && 688d4afb5ceSopenharmony_ci (context->event_loop_ops->flags & LELOF_ISPOLL)) { 689d4afb5ceSopenharmony_ci __lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN); 690d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_SHUTDOWN); 691d4afb5ceSopenharmony_ci __lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH, 692d4afb5ceSopenharmony_ci (int)context->timeout_secs); 693d4afb5ceSopenharmony_ci 694d4afb5ceSopenharmony_ci return; 695d4afb5ceSopenharmony_ci } 696d4afb5ceSopenharmony_ci#endif 697d4afb5ceSopenharmony_ci } 698d4afb5ceSopenharmony_ci 699d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "real just_kill_connection: sockfd %d\n", 700d4afb5ceSopenharmony_ci wsi->desc.sockfd); 701d4afb5ceSopenharmony_ci 702d4afb5ceSopenharmony_ci#ifdef LWS_WITH_HUBBUB 703d4afb5ceSopenharmony_ci if (wsi->http.rw) { 704d4afb5ceSopenharmony_ci lws_rewrite_destroy(wsi->http.rw); 705d4afb5ceSopenharmony_ci wsi->http.rw = NULL; 706d4afb5ceSopenharmony_ci } 707d4afb5ceSopenharmony_ci#endif 708d4afb5ceSopenharmony_ci 709d4afb5ceSopenharmony_ci if (wsi->http.pending_return_headers) 710d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.pending_return_headers); 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ci /* 713d4afb5ceSopenharmony_ci * we won't be servicing or receiving anything further from this guy 714d4afb5ceSopenharmony_ci * delete socket from the internal poll list if still present 715d4afb5ceSopenharmony_ci */ 716d4afb5ceSopenharmony_ci __lws_ssl_remove_wsi_from_buffered_list(wsi); 717d4afb5ceSopenharmony_ci __lws_wsi_remove_from_sul(wsi); 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci //if (wsi->told_event_loop_closed) // cgi std close case (dummy-callback) 720d4afb5ceSopenharmony_ci // return; 721d4afb5ceSopenharmony_ci 722d4afb5ceSopenharmony_ci /* checking return redundant since we anyway close */ 723d4afb5ceSopenharmony_ci __remove_wsi_socket_from_fds(wsi); 724d4afb5ceSopenharmony_ci 725d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_DEAD_SOCKET); 726d4afb5ceSopenharmony_ci lws_buflist_destroy_all_segments(&wsi->buflist); 727d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_buflist); 728d4afb5ceSopenharmony_ci 729d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_role)) 730d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_close_role). 731d4afb5ceSopenharmony_ci close_role(pt, wsi); 732d4afb5ceSopenharmony_ci 733d4afb5ceSopenharmony_ci /* tell the user it's all over for this guy */ 734d4afb5ceSopenharmony_ci 735d4afb5ceSopenharmony_ci ccb = 0; 736d4afb5ceSopenharmony_ci if ((lwsi_state_est_PRE_CLOSE(wsi) || 737d4afb5ceSopenharmony_ci /* raw skt adopted but didn't complete tls hs should CLOSE */ 738d4afb5ceSopenharmony_ci (wsi->role_ops == &role_ops_raw_skt && !lwsi_role_client(wsi)) || 739d4afb5ceSopenharmony_ci lwsi_state_PRE_CLOSE(wsi) == LRS_WAITING_SERVER_REPLY) && 740d4afb5ceSopenharmony_ci !wsi->told_user_closed && 741d4afb5ceSopenharmony_ci wsi->role_ops->close_cb[lwsi_role_server(wsi)]) { 742d4afb5ceSopenharmony_ci if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi)) 743d4afb5ceSopenharmony_ci ccb = 1; 744d4afb5ceSopenharmony_ci /* 745d4afb5ceSopenharmony_ci * The network wsi for a client h2 connection shouldn't 746d4afb5ceSopenharmony_ci * call back for its role: the child stream connections 747d4afb5ceSopenharmony_ci * own the role. Otherwise h2 will call back closed 748d4afb5ceSopenharmony_ci * one too many times as the children do it and then 749d4afb5ceSopenharmony_ci * the closing network stream. 750d4afb5ceSopenharmony_ci */ 751d4afb5ceSopenharmony_ci } 752d4afb5ceSopenharmony_ci 753d4afb5ceSopenharmony_ci if (!wsi->told_user_closed && 754d4afb5ceSopenharmony_ci !lws_dll2_is_detached(&wsi->vh_awaiting_socket)) 755d4afb5ceSopenharmony_ci /* 756d4afb5ceSopenharmony_ci * He's a guy who go started with dns, but failed or is 757d4afb5ceSopenharmony_ci * caught with a shutdown before he got the result. We have 758d4afb5ceSopenharmony_ci * to issclient_mux_substream_wasue him a close cb 759d4afb5ceSopenharmony_ci */ 760d4afb5ceSopenharmony_ci ccb = 1; 761d4afb5ceSopenharmony_ci 762d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "cce=%d", ccb); 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci pro = wsi->a.protocol; 765d4afb5ceSopenharmony_ci 766d4afb5ceSopenharmony_ci if (wsi->already_did_cce) 767d4afb5ceSopenharmony_ci /* 768d4afb5ceSopenharmony_ci * If we handled this by CLIENT_CONNECTION_ERROR, it's 769d4afb5ceSopenharmony_ci * mutually exclusive with CLOSE 770d4afb5ceSopenharmony_ci */ 771d4afb5ceSopenharmony_ci ccb = 0; 772d4afb5ceSopenharmony_ci 773d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 774d4afb5ceSopenharmony_ci if (!wsi->close_is_redirect && !ccb && 775d4afb5ceSopenharmony_ci (lwsi_state_PRE_CLOSE(wsi) & LWSIFS_NOT_EST) && 776d4afb5ceSopenharmony_ci lwsi_role_client(wsi)) { 777d4afb5ceSopenharmony_ci lws_inform_client_conn_fail(wsi, "Closed before conn", 18); 778d4afb5ceSopenharmony_ci } 779d4afb5ceSopenharmony_ci#endif 780d4afb5ceSopenharmony_ci if (ccb 781d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 782d4afb5ceSopenharmony_ci && !wsi->close_is_redirect 783d4afb5ceSopenharmony_ci#endif 784d4afb5ceSopenharmony_ci ) { 785d4afb5ceSopenharmony_ci 786d4afb5ceSopenharmony_ci if (!wsi->a.protocol && wsi->a.vhost && wsi->a.vhost->protocols) 787d4afb5ceSopenharmony_ci pro = &wsi->a.vhost->protocols[0]; 788d4afb5ceSopenharmony_ci 789d4afb5ceSopenharmony_ci if (pro) 790d4afb5ceSopenharmony_ci pro->callback(wsi, 791d4afb5ceSopenharmony_ci wsi->role_ops->close_cb[lwsi_role_server(wsi)], 792d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0); 793d4afb5ceSopenharmony_ci wsi->told_user_closed = 1; 794d4afb5ceSopenharmony_ci } 795d4afb5ceSopenharmony_ci 796d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_RAW_FILE) 797d4afb5ceSopenharmony_ciasync_close: 798d4afb5ceSopenharmony_ci#endif 799d4afb5ceSopenharmony_ci 800d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS) 801d4afb5ceSopenharmony_ci if (wsi->for_ss) { 802d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "for_ss"); 803d4afb5ceSopenharmony_ci /* 804d4afb5ceSopenharmony_ci * We were adopted for a particular ss, but, eg, we may not 805d4afb5ceSopenharmony_ci * have succeeded with the connection... we are closing which is 806d4afb5ceSopenharmony_ci * good, but we have to invalidate any pointer the related ss 807d4afb5ceSopenharmony_ci * handle may be holding on us 808d4afb5ceSopenharmony_ci */ 809d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 810d4afb5ceSopenharmony_ci 811d4afb5ceSopenharmony_ci if (wsi->client_proxy_onward) { 812d4afb5ceSopenharmony_ci /* 813d4afb5ceSopenharmony_ci * We are an onward proxied wsi at the proxy, 814d4afb5ceSopenharmony_ci * opaque is proxing "conn", we must remove its pointer 815d4afb5ceSopenharmony_ci * to us since we are destroying 816d4afb5ceSopenharmony_ci */ 817d4afb5ceSopenharmony_ci lws_proxy_clean_conn_ss(wsi); 818d4afb5ceSopenharmony_ci } else 819d4afb5ceSopenharmony_ci 820d4afb5ceSopenharmony_ci if (wsi->client_bound_sspc) { 821d4afb5ceSopenharmony_ci lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data; 822d4afb5ceSopenharmony_ci 823d4afb5ceSopenharmony_ci if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) { 824d4afb5ceSopenharmony_ci 825d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 826d4afb5ceSopenharmony_ci /* 827d4afb5ceSopenharmony_ci * If any hanging caliper measurement, dump it, and free any tags 828d4afb5ceSopenharmony_ci */ 829d4afb5ceSopenharmony_ci lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL); 830d4afb5ceSopenharmony_ci#endif 831d4afb5ceSopenharmony_ci 832d4afb5ceSopenharmony_ci h->cwsi = NULL; 833d4afb5ceSopenharmony_ci //wsi->a.opaque_user_data = NULL; 834d4afb5ceSopenharmony_ci } 835d4afb5ceSopenharmony_ci } else 836d4afb5ceSopenharmony_ci#endif 837d4afb5ceSopenharmony_ci { 838d4afb5ceSopenharmony_ci lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data; 839d4afb5ceSopenharmony_ci 840d4afb5ceSopenharmony_ci if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) { 841d4afb5ceSopenharmony_ci 842d4afb5ceSopenharmony_ci /* 843d4afb5ceSopenharmony_ci * ss level: only reports if dangling caliper 844d4afb5ceSopenharmony_ci * not already reported 845d4afb5ceSopenharmony_ci */ 846d4afb5ceSopenharmony_ci lws_metrics_caliper_report_hist(h->cal_txn, wsi); 847d4afb5ceSopenharmony_ci 848d4afb5ceSopenharmony_ci h->wsi = NULL; 849d4afb5ceSopenharmony_ci wsi->a.opaque_user_data = NULL; 850d4afb5ceSopenharmony_ci 851d4afb5ceSopenharmony_ci if (h->ss_dangling_connected && 852d4afb5ceSopenharmony_ci lws_ss_event_helper(h, LWSSSCS_DISCONNECTED) == 853d4afb5ceSopenharmony_ci LWSSSSRET_DESTROY_ME) { 854d4afb5ceSopenharmony_ci 855d4afb5ceSopenharmony_ci lws_ss_destroy(&h); 856d4afb5ceSopenharmony_ci } 857d4afb5ceSopenharmony_ci } 858d4afb5ceSopenharmony_ci } 859d4afb5ceSopenharmony_ci } 860d4afb5ceSopenharmony_ci#endif 861d4afb5ceSopenharmony_ci 862d4afb5ceSopenharmony_ci 863d4afb5ceSopenharmony_ci lws_remove_child_from_any_parent(wsi); 864d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 865d4afb5ceSopenharmony_ci 866d4afb5ceSopenharmony_ci if (wsi->a.context->event_loop_ops->wsi_logical_close) 867d4afb5ceSopenharmony_ci if (wsi->a.context->event_loop_ops->wsi_logical_close(wsi)) 868d4afb5ceSopenharmony_ci return; 869d4afb5ceSopenharmony_ci 870d4afb5ceSopenharmony_ci __lws_close_free_wsi_final(wsi); 871d4afb5ceSopenharmony_ci} 872d4afb5ceSopenharmony_ci 873d4afb5ceSopenharmony_ci 874d4afb5ceSopenharmony_ci/* cx + vh lock */ 875d4afb5ceSopenharmony_ci 876d4afb5ceSopenharmony_civoid 877d4afb5ceSopenharmony_ci__lws_close_free_wsi_final(struct lws *wsi) 878d4afb5ceSopenharmony_ci{ 879d4afb5ceSopenharmony_ci int n; 880d4afb5ceSopenharmony_ci 881d4afb5ceSopenharmony_ci if (!wsi->shadow && 882d4afb5ceSopenharmony_ci lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) { 883d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "fd %d", wsi->desc.sockfd); 884d4afb5ceSopenharmony_ci n = compatible_close(wsi->desc.sockfd); 885d4afb5ceSopenharmony_ci if (n) 886d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "closing: close ret %d", LWS_ERRNO); 887d4afb5ceSopenharmony_ci 888d4afb5ceSopenharmony_ci __remove_wsi_socket_from_fds(wsi); 889d4afb5ceSopenharmony_ci if (lws_socket_is_valid(wsi->desc.sockfd)) 890d4afb5ceSopenharmony_ci delete_from_fd(wsi->a.context, wsi->desc.sockfd); 891d4afb5ceSopenharmony_ci 892d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(WIN32) && !defined(LWS_PLAT_OPTEE) 893d4afb5ceSopenharmony_ci delete_from_fdwsi(wsi->a.context, wsi); 894d4afb5ceSopenharmony_ci#endif 895d4afb5ceSopenharmony_ci 896d4afb5ceSopenharmony_ci sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd); 897d4afb5ceSopenharmony_ci } 898d4afb5ceSopenharmony_ci 899d4afb5ceSopenharmony_ci /* ... if we're closing the cancel pipe, account for it */ 900d4afb5ceSopenharmony_ci 901d4afb5ceSopenharmony_ci { 902d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = 903d4afb5ceSopenharmony_ci &wsi->a.context->pt[(int)wsi->tsi]; 904d4afb5ceSopenharmony_ci 905d4afb5ceSopenharmony_ci if (pt->pipe_wsi == wsi) 906d4afb5ceSopenharmony_ci pt->pipe_wsi = NULL; 907d4afb5ceSopenharmony_ci if (pt->dummy_pipe_fds[0] == wsi->desc.sockfd) 908d4afb5ceSopenharmony_ci pt->dummy_pipe_fds[0] = LWS_SOCK_INVALID; 909d4afb5ceSopenharmony_ci } 910d4afb5ceSopenharmony_ci 911d4afb5ceSopenharmony_ci wsi->desc.sockfd = LWS_SOCK_INVALID; 912d4afb5ceSopenharmony_ci 913d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 914d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->cli_hostname_copy); 915d4afb5ceSopenharmony_ci if (wsi->close_is_redirect) { 916d4afb5ceSopenharmony_ci 917d4afb5ceSopenharmony_ci wsi->close_is_redirect = 0; 918d4afb5ceSopenharmony_ci 919d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "picking up redirection"); 920d4afb5ceSopenharmony_ci 921d4afb5ceSopenharmony_ci lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, 922d4afb5ceSopenharmony_ci &role_ops_h1); 923d4afb5ceSopenharmony_ci 924d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 925d4afb5ceSopenharmony_ci if (wsi->client_mux_substream_was) 926d4afb5ceSopenharmony_ci wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0; 927d4afb5ceSopenharmony_ci#endif 928d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) 929d4afb5ceSopenharmony_ci if (wsi->mux.parent_wsi) { 930d4afb5ceSopenharmony_ci lws_wsi_mux_sibling_disconnect(wsi); 931d4afb5ceSopenharmony_ci wsi->mux.parent_wsi = NULL; 932d4afb5ceSopenharmony_ci } 933d4afb5ceSopenharmony_ci#endif 934d4afb5ceSopenharmony_ci 935d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 936d4afb5ceSopenharmony_ci memset(&wsi->tls, 0, sizeof(wsi->tls)); 937d4afb5ceSopenharmony_ci#endif 938d4afb5ceSopenharmony_ci 939d4afb5ceSopenharmony_ci // wsi->a.protocol = NULL; 940d4afb5ceSopenharmony_ci if (wsi->a.protocol) 941d4afb5ceSopenharmony_ci lws_bind_protocol(wsi, wsi->a.protocol, "client_reset"); 942d4afb5ceSopenharmony_ci wsi->pending_timeout = NO_PENDING_TIMEOUT; 943d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed = 0; 944d4afb5ceSopenharmony_ci 945d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 946d4afb5ceSopenharmony_ci if (wsi->stash->cis[CIS_ALPN]) 947d4afb5ceSopenharmony_ci lws_strncpy(wsi->alpn, wsi->stash->cis[CIS_ALPN], 948d4afb5ceSopenharmony_ci sizeof(wsi->alpn)); 949d4afb5ceSopenharmony_ci#endif 950d4afb5ceSopenharmony_ci 951d4afb5ceSopenharmony_ci if (lws_header_table_attach(wsi, 0)) { 952d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "failed to get ah"); 953d4afb5ceSopenharmony_ci return; 954d4afb5ceSopenharmony_ci } 955d4afb5ceSopenharmony_ci// } 956d4afb5ceSopenharmony_ci //_lws_header_table_reset(wsi->http.ah); 957d4afb5ceSopenharmony_ci 958d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 959d4afb5ceSopenharmony_ci wsi->tls.use_ssl = (unsigned int)wsi->flags; 960d4afb5ceSopenharmony_ci#endif 961d4afb5ceSopenharmony_ci 962d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 963d4afb5ceSopenharmony_ci if (wsi->stash && wsi->stash->cis[CIS_ADDRESS]) { 964d4afb5ceSopenharmony_ci struct lws_vhost *vh = NULL; 965d4afb5ceSopenharmony_ci lws_tls_jit_trust_vhost_bind(wsi->a.context, 966d4afb5ceSopenharmony_ci wsi->stash->cis[CIS_ADDRESS], 967d4afb5ceSopenharmony_ci &vh); 968d4afb5ceSopenharmony_ci if (vh) { 969d4afb5ceSopenharmony_ci if (!vh->count_bound_wsi && vh->grace_after_unref) { 970d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "%s in use\n", 971d4afb5ceSopenharmony_ci vh->lc.gutag); 972d4afb5ceSopenharmony_ci lws_sul_cancel(&vh->sul_unref); 973d4afb5ceSopenharmony_ci } 974d4afb5ceSopenharmony_ci vh->count_bound_wsi++; 975d4afb5ceSopenharmony_ci wsi->a.vhost = vh; 976d4afb5ceSopenharmony_ci } 977d4afb5ceSopenharmony_ci } 978d4afb5ceSopenharmony_ci#endif 979d4afb5ceSopenharmony_ci 980d4afb5ceSopenharmony_ci return; 981d4afb5ceSopenharmony_ci } 982d4afb5ceSopenharmony_ci#endif 983d4afb5ceSopenharmony_ci 984d4afb5ceSopenharmony_ci /* outermost destroy notification for wsi (user_space still intact) */ 985d4afb5ceSopenharmony_ci if (wsi->a.vhost) 986d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, 987d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0); 988d4afb5ceSopenharmony_ci 989d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 990d4afb5ceSopenharmony_ci if (wsi->http.cgi) { 991d4afb5ceSopenharmony_ci lws_spawn_piped_destroy(&wsi->http.cgi->lsp); 992d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->http.cgi->sul_grace); 993d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.cgi); 994d4afb5ceSopenharmony_ci } 995d4afb5ceSopenharmony_ci#endif 996d4afb5ceSopenharmony_ci 997d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION) 998d4afb5ceSopenharmony_ci lws_fi_destroy(&wsi->fic); 999d4afb5ceSopenharmony_ci#endif 1000d4afb5ceSopenharmony_ci 1001d4afb5ceSopenharmony_ci __lws_wsi_remove_from_sul(wsi); 1002d4afb5ceSopenharmony_ci sanity_assert_no_wsi_traces(wsi->a.context, wsi); 1003d4afb5ceSopenharmony_ci __lws_free_wsi(wsi); 1004d4afb5ceSopenharmony_ci} 1005d4afb5ceSopenharmony_ci 1006d4afb5ceSopenharmony_ci 1007d4afb5ceSopenharmony_civoid 1008d4afb5ceSopenharmony_cilws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *caller) 1009d4afb5ceSopenharmony_ci{ 1010d4afb5ceSopenharmony_ci struct lws_context *cx = wsi->a.context; 1011d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 1012d4afb5ceSopenharmony_ci 1013d4afb5ceSopenharmony_ci lws_context_lock(cx, __func__); 1014d4afb5ceSopenharmony_ci 1015d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 1016d4afb5ceSopenharmony_ci /* may destroy vhost, cannot hold vhost lock outside it */ 1017d4afb5ceSopenharmony_ci __lws_close_free_wsi(wsi, reason, caller); 1018d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 1019d4afb5ceSopenharmony_ci 1020d4afb5ceSopenharmony_ci lws_context_unlock(cx); 1021d4afb5ceSopenharmony_ci} 1022d4afb5ceSopenharmony_ci 1023d4afb5ceSopenharmony_ci 1024