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