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_ciconst char *
28d4afb5ceSopenharmony_cilws_wsi_tag(struct lws *wsi)
29d4afb5ceSopenharmony_ci{
30d4afb5ceSopenharmony_ci	if (!wsi)
31d4afb5ceSopenharmony_ci		return "[null wsi]";
32d4afb5ceSopenharmony_ci	return lws_lc_tag(&wsi->lc);
33d4afb5ceSopenharmony_ci}
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci#if defined (_DEBUG)
36d4afb5ceSopenharmony_civoid lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
37d4afb5ceSopenharmony_ci{
38d4afb5ceSopenharmony_ci	wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "state 0x%lx", (unsigned long)wsi->wsistate);
41d4afb5ceSopenharmony_ci}
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_civoid lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
44d4afb5ceSopenharmony_ci{
45d4afb5ceSopenharmony_ci	lws_wsi_state_t old = wsi->wsistate;
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_ci	wsi->wsistate = (old & (unsigned int)(~LRS_MASK)) | lrs;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "lwsi_set_state 0x%lx -> 0x%lx",
50d4afb5ceSopenharmony_ci			(unsigned long)old, (unsigned long)wsi->wsistate);
51d4afb5ceSopenharmony_ci}
52d4afb5ceSopenharmony_ci#endif
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_civoid
56d4afb5ceSopenharmony_cilws_log_prepend_wsi(struct lws_log_cx *cx, void *obj, char **p, char *e)
57d4afb5ceSopenharmony_ci{
58d4afb5ceSopenharmony_ci	struct lws *wsi = (struct lws *)obj;
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci	*p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
61d4afb5ceSopenharmony_ci							lws_wsi_tag(wsi));
62d4afb5ceSopenharmony_ci}
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_civoid
65d4afb5ceSopenharmony_cilws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
66d4afb5ceSopenharmony_ci{
67d4afb5ceSopenharmony_ci	if (wsi->a.vhost == vh)
68d4afb5ceSopenharmony_ci		return;
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci	lws_context_lock(vh->context, __func__); /* ---------- context { */
71d4afb5ceSopenharmony_ci	wsi->a.vhost = vh;
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
74d4afb5ceSopenharmony_ci	if (!vh->count_bound_wsi && vh->grace_after_unref) {
75d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "in use");
76d4afb5ceSopenharmony_ci		lws_sul_cancel(&vh->sul_unref);
77d4afb5ceSopenharmony_ci	}
78d4afb5ceSopenharmony_ci#endif
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci	vh->count_bound_wsi++;
81d4afb5ceSopenharmony_ci	lws_context_unlock(vh->context); /* } context ---------- */
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "vh %s: wsi %s/%s, count_bound_wsi %d\n",
84d4afb5ceSopenharmony_ci		   vh->name, wsi->role_ops ? wsi->role_ops->name : "none",
85d4afb5ceSopenharmony_ci		   wsi->a.protocol ? wsi->a.protocol->name : "none",
86d4afb5ceSopenharmony_ci		   vh->count_bound_wsi);
87d4afb5ceSopenharmony_ci	assert(wsi->a.vhost->count_bound_wsi > 0);
88d4afb5ceSopenharmony_ci}
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci/* req cx lock... acquires vh lock */
92d4afb5ceSopenharmony_civoid
93d4afb5ceSopenharmony_ci__lws_vhost_unbind_wsi(struct lws *wsi)
94d4afb5ceSopenharmony_ci{
95d4afb5ceSopenharmony_ci        struct lws_vhost *vh = wsi->a.vhost;
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci        if (!vh)
98d4afb5ceSopenharmony_ci                return;
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci	lws_context_assert_lock_held(wsi->a.context);
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci	lws_vhost_lock(vh);
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	assert(vh->count_bound_wsi > 0);
105d4afb5ceSopenharmony_ci	vh->count_bound_wsi--;
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
108d4afb5ceSopenharmony_ci	if (!vh->count_bound_wsi && vh->grace_after_unref)
109d4afb5ceSopenharmony_ci		lws_tls_jit_trust_vh_start_grace(vh);
110d4afb5ceSopenharmony_ci#endif
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "vh %s: count_bound_wsi %d",
113d4afb5ceSopenharmony_ci		   vh->name, vh->count_bound_wsi);
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	lws_vhost_unlock(vh);
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_ci	if (!vh->count_bound_wsi && vh->being_destroyed)
118d4afb5ceSopenharmony_ci		/*
119d4afb5ceSopenharmony_ci		 * We have closed all wsi that were bound to this vhost
120d4afb5ceSopenharmony_ci		 * by any pt: nothing can be servicing any wsi belonging
121d4afb5ceSopenharmony_ci		 * to it any more.
122d4afb5ceSopenharmony_ci		 *
123d4afb5ceSopenharmony_ci		 * Finalize the vh destruction... must drop vh lock
124d4afb5ceSopenharmony_ci		 */
125d4afb5ceSopenharmony_ci		__lws_vhost_destroy2(vh);
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci	wsi->a.vhost = NULL;
128d4afb5ceSopenharmony_ci}
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_cistruct lws *
131d4afb5ceSopenharmony_cilws_get_network_wsi(struct lws *wsi)
132d4afb5ceSopenharmony_ci{
133d4afb5ceSopenharmony_ci	if (!wsi)
134d4afb5ceSopenharmony_ci		return NULL;
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) || defined(LWS_ROLE_MQTT)
137d4afb5ceSopenharmony_ci	if (!wsi->mux_substream
138d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
139d4afb5ceSopenharmony_ci			&& !wsi->client_mux_substream
140d4afb5ceSopenharmony_ci#endif
141d4afb5ceSopenharmony_ci	)
142d4afb5ceSopenharmony_ci		return wsi;
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	while (wsi->mux.parent_wsi)
145d4afb5ceSopenharmony_ci		wsi = wsi->mux.parent_wsi;
146d4afb5ceSopenharmony_ci#endif
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci	return wsi;
149d4afb5ceSopenharmony_ci}
150d4afb5ceSopenharmony_ci
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ciconst struct lws_protocols *
153d4afb5ceSopenharmony_cilws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
154d4afb5ceSopenharmony_ci{
155d4afb5ceSopenharmony_ci	int n;
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	for (n = 0; n < vh->count_protocols; n++)
158d4afb5ceSopenharmony_ci		if (vh->protocols[n].name && !strcmp(name, vh->protocols[n].name))
159d4afb5ceSopenharmony_ci			return &vh->protocols[n];
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	return NULL;
162d4afb5ceSopenharmony_ci}
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ciint
165d4afb5ceSopenharmony_cilws_callback_all_protocol(struct lws_context *context,
166d4afb5ceSopenharmony_ci			  const struct lws_protocols *protocol, int reason)
167d4afb5ceSopenharmony_ci{
168d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[0];
169d4afb5ceSopenharmony_ci	unsigned int n, m = context->count_threads;
170d4afb5ceSopenharmony_ci	struct lws *wsi;
171d4afb5ceSopenharmony_ci
172d4afb5ceSopenharmony_ci	while (m--) {
173d4afb5ceSopenharmony_ci		for (n = 0; n < pt->fds_count; n++) {
174d4afb5ceSopenharmony_ci			wsi = wsi_from_fd(context, pt->fds[n].fd);
175d4afb5ceSopenharmony_ci			if (!wsi)
176d4afb5ceSopenharmony_ci				continue;
177d4afb5ceSopenharmony_ci			if (wsi->a.protocol == protocol)
178d4afb5ceSopenharmony_ci				protocol->callback(wsi,
179d4afb5ceSopenharmony_ci					(enum lws_callback_reasons)reason,
180d4afb5ceSopenharmony_ci					wsi->user_space, NULL, 0);
181d4afb5ceSopenharmony_ci		}
182d4afb5ceSopenharmony_ci		pt++;
183d4afb5ceSopenharmony_ci	}
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci	return 0;
186d4afb5ceSopenharmony_ci}
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_civoid *
189d4afb5ceSopenharmony_cilws_evlib_wsi_to_evlib_pt(struct lws *wsi)
190d4afb5ceSopenharmony_ci{
191d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci	return pt->evlib_pt;
194d4afb5ceSopenharmony_ci}
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_civoid *
197d4afb5ceSopenharmony_cilws_evlib_tsi_to_evlib_pt(struct lws_context *cx, int tsi)
198d4afb5ceSopenharmony_ci{
199d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &cx->pt[tsi];
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	return pt->evlib_pt;
202d4afb5ceSopenharmony_ci}
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ciint
205d4afb5ceSopenharmony_cilws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
206d4afb5ceSopenharmony_ci			  const struct lws_protocols *protocol, int reason,
207d4afb5ceSopenharmony_ci			  void *argp, size_t len)
208d4afb5ceSopenharmony_ci{
209d4afb5ceSopenharmony_ci	struct lws_context *context = vh->context;
210d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[0];
211d4afb5ceSopenharmony_ci	unsigned int n, m = context->count_threads;
212d4afb5ceSopenharmony_ci	struct lws *wsi;
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci	while (m--) {
215d4afb5ceSopenharmony_ci		for (n = 0; n < pt->fds_count; n++) {
216d4afb5ceSopenharmony_ci			wsi = wsi_from_fd(context, pt->fds[n].fd);
217d4afb5ceSopenharmony_ci			if (!wsi)
218d4afb5ceSopenharmony_ci				continue;
219d4afb5ceSopenharmony_ci			if (wsi->a.vhost == vh && (wsi->a.protocol == protocol ||
220d4afb5ceSopenharmony_ci						 !protocol))
221d4afb5ceSopenharmony_ci				wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason,
222d4afb5ceSopenharmony_ci						wsi->user_space, argp, len);
223d4afb5ceSopenharmony_ci		}
224d4afb5ceSopenharmony_ci		pt++;
225d4afb5ceSopenharmony_ci	}
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_ci	return 0;
228d4afb5ceSopenharmony_ci}
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ciint
231d4afb5ceSopenharmony_cilws_callback_all_protocol_vhost(struct lws_vhost *vh,
232d4afb5ceSopenharmony_ci			  const struct lws_protocols *protocol, int reason)
233d4afb5ceSopenharmony_ci{
234d4afb5ceSopenharmony_ci	return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
235d4afb5ceSopenharmony_ci}
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ciint
238d4afb5ceSopenharmony_cilws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, size_t len)
239d4afb5ceSopenharmony_ci{
240d4afb5ceSopenharmony_ci	int n;
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci	for (n = 0; n < wsi->a.vhost->count_protocols; n++)
243d4afb5ceSopenharmony_ci		if (wsi->a.vhost->protocols[n].callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len))
244d4afb5ceSopenharmony_ci			return 1;
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	return 0;
247d4afb5ceSopenharmony_ci}
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
250d4afb5ceSopenharmony_ci/*
251d4afb5ceSopenharmony_ci * We want to inject a fault that makes it feel like the peer hung up on us,
252d4afb5ceSopenharmony_ci * or we were otherwise cut off.
253d4afb5ceSopenharmony_ci */
254d4afb5ceSopenharmony_civoid
255d4afb5ceSopenharmony_cilws_wsi_fault_timedclose_cb(lws_sorted_usec_list_t *s)
256d4afb5ceSopenharmony_ci{
257d4afb5ceSopenharmony_ci	struct lws *wsi = lws_container_of(s, struct lws, sul_fault_timedclose);
258d4afb5ceSopenharmony_ci
259d4afb5ceSopenharmony_ci	lwsl_wsi_warn(wsi, "force-closing");
260d4afb5ceSopenharmony_ci	lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
261d4afb5ceSopenharmony_ci}
262d4afb5ceSopenharmony_ci#endif
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
265d4afb5ceSopenharmony_civoid
266d4afb5ceSopenharmony_cilws_wsi_fault_timedclose(struct lws *wsi)
267d4afb5ceSopenharmony_ci{
268d4afb5ceSopenharmony_ci	uint64_t u;
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci	if (!lws_fi(&wsi->fic, "timedclose"))
271d4afb5ceSopenharmony_ci		return;
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci	if (lws_fi_range(&wsi->fic, "timedclose_ms", &u))
274d4afb5ceSopenharmony_ci		return;
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci	lwsl_wsi_warn(wsi, "injecting close in %ums", (unsigned int)u);
277d4afb5ceSopenharmony_ci	lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->sul_fault_timedclose,
278d4afb5ceSopenharmony_ci			 lws_wsi_fault_timedclose_cb,
279d4afb5ceSopenharmony_ci			 (lws_usec_t)(u * 1000ull));
280d4afb5ceSopenharmony_ci}
281d4afb5ceSopenharmony_ci#endif
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci/*
285d4afb5ceSopenharmony_ci * We need the context lock
286d4afb5ceSopenharmony_ci */
287d4afb5ceSopenharmony_ci
288d4afb5ceSopenharmony_cistruct lws *
289d4afb5ceSopenharmony_ci__lws_wsi_create_with_role(struct lws_context *context, int tsi,
290d4afb5ceSopenharmony_ci			   const struct lws_role_ops *ops,
291d4afb5ceSopenharmony_ci			   lws_log_cx_t *log_cx_template)
292d4afb5ceSopenharmony_ci{
293d4afb5ceSopenharmony_ci	size_t s = sizeof(struct lws);
294d4afb5ceSopenharmony_ci	struct lws *wsi;
295d4afb5ceSopenharmony_ci
296d4afb5ceSopenharmony_ci	assert(tsi >= 0 && tsi < LWS_MAX_SMP);
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci	lws_context_assert_lock_held(context);
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EVENT_LIBS)
301d4afb5ceSopenharmony_ci	s += context->event_loop_ops->evlib_size_wsi;
302d4afb5ceSopenharmony_ci#endif
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_ci	wsi = lws_zalloc(s, __func__);
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ci	if (!wsi) {
307d4afb5ceSopenharmony_ci		lwsl_cx_err(context, "OOM");
308d4afb5ceSopenharmony_ci		return NULL;
309d4afb5ceSopenharmony_ci	}
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci	if (log_cx_template)
312d4afb5ceSopenharmony_ci		wsi->lc.log_cx = log_cx_template;
313d4afb5ceSopenharmony_ci	else
314d4afb5ceSopenharmony_ci		wsi->lc.log_cx = context->log_cx;
315d4afb5ceSopenharmony_ci
316d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EVENT_LIBS)
317d4afb5ceSopenharmony_ci	wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi);
318d4afb5ceSopenharmony_ci#endif
319d4afb5ceSopenharmony_ci	wsi->a.context = context;
320d4afb5ceSopenharmony_ci	lws_role_transition(wsi, 0, LRS_UNCONNECTED, ops);
321d4afb5ceSopenharmony_ci	wsi->pending_timeout = NO_PENDING_TIMEOUT;
322d4afb5ceSopenharmony_ci	wsi->a.protocol = NULL;
323d4afb5ceSopenharmony_ci	wsi->tsi = (char)tsi;
324d4afb5ceSopenharmony_ci	wsi->a.vhost = NULL;
325d4afb5ceSopenharmony_ci	wsi->desc.sockfd = LWS_SOCK_INVALID;
326d4afb5ceSopenharmony_ci	wsi->position_in_fds_table = LWS_NO_FDS_POS;
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
329d4afb5ceSopenharmony_ci	lws_xos_init(&wsi->fic.xos, lws_xos(&context->fic.xos));
330d4afb5ceSopenharmony_ci#endif
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci	lws_fi_inherit_copy(&wsi->fic, &context->fic, "wsi", NULL);
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci	if (lws_fi(&wsi->fic, "createfail")) {
335d4afb5ceSopenharmony_ci		lws_fi_destroy(&wsi->fic);
336d4afb5ceSopenharmony_ci		lws_free(wsi);
337d4afb5ceSopenharmony_ci		return NULL;
338d4afb5ceSopenharmony_ci	}
339d4afb5ceSopenharmony_ci
340d4afb5ceSopenharmony_ci	return wsi;
341d4afb5ceSopenharmony_ci}
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ciint
344d4afb5ceSopenharmony_cilws_wsi_inject_to_loop(struct lws_context_per_thread *pt, struct lws *wsi)
345d4afb5ceSopenharmony_ci{
346d4afb5ceSopenharmony_ci	int ret = 1;
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__); /* -------------- pt { */
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci	if (pt->context->event_loop_ops->sock_accept)
351d4afb5ceSopenharmony_ci		if (pt->context->event_loop_ops->sock_accept(wsi))
352d4afb5ceSopenharmony_ci			goto bail;
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	if (__insert_wsi_socket_into_fds(pt->context, wsi))
355d4afb5ceSopenharmony_ci		goto bail;
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci	ret = 0;
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_cibail:
360d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci	return ret;
363d4afb5ceSopenharmony_ci}
364d4afb5ceSopenharmony_ci
365d4afb5ceSopenharmony_ci/*
366d4afb5ceSopenharmony_ci * Take a copy of wsi->desc.sockfd before calling this, then close it
367d4afb5ceSopenharmony_ci * afterwards
368d4afb5ceSopenharmony_ci */
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ciint
371d4afb5ceSopenharmony_cilws_wsi_extract_from_loop(struct lws *wsi)
372d4afb5ceSopenharmony_ci{
373d4afb5ceSopenharmony_ci	if (lws_socket_is_valid(wsi->desc.sockfd))
374d4afb5ceSopenharmony_ci		__remove_wsi_socket_from_fds(wsi);
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci	if (!wsi->a.context->event_loop_ops->destroy_wsi &&
377d4afb5ceSopenharmony_ci	    wsi->a.context->event_loop_ops->wsi_logical_close) {
378d4afb5ceSopenharmony_ci		wsi->a.context->event_loop_ops->wsi_logical_close(wsi);
379d4afb5ceSopenharmony_ci		return 1; /* close / destroy continues async */
380d4afb5ceSopenharmony_ci	}
381d4afb5ceSopenharmony_ci
382d4afb5ceSopenharmony_ci	if (wsi->a.context->event_loop_ops->destroy_wsi)
383d4afb5ceSopenharmony_ci		wsi->a.context->event_loop_ops->destroy_wsi(wsi);
384d4afb5ceSopenharmony_ci
385d4afb5ceSopenharmony_ci	return 0; /* he is destroyed */
386d4afb5ceSopenharmony_ci}
387d4afb5ceSopenharmony_ci
388d4afb5ceSopenharmony_ciint
389d4afb5ceSopenharmony_cilws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
390d4afb5ceSopenharmony_ci				   size_t len)
391d4afb5ceSopenharmony_ci{
392d4afb5ceSopenharmony_ci	int n;
393d4afb5ceSopenharmony_ci	struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi");
394d4afb5ceSopenharmony_ci
395d4afb5ceSopenharmony_ci	if (!wsi)
396d4afb5ceSopenharmony_ci		return 1;
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci	wsi->a.context = vh->context;
399d4afb5ceSopenharmony_ci	lws_vhost_bind_wsi(vh, wsi);
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci	for (n = 0; n < wsi->a.vhost->count_protocols; n++) {
402d4afb5ceSopenharmony_ci		wsi->a.protocol = &vh->protocols[n];
403d4afb5ceSopenharmony_ci		if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len)) {
404d4afb5ceSopenharmony_ci			lws_free(wsi);
405d4afb5ceSopenharmony_ci			return 1;
406d4afb5ceSopenharmony_ci		}
407d4afb5ceSopenharmony_ci	}
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	lws_free(wsi);
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	return 0;
412d4afb5ceSopenharmony_ci}
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ciint
416d4afb5ceSopenharmony_cilws_rx_flow_control(struct lws *wsi, int _enable)
417d4afb5ceSopenharmony_ci{
418d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
419d4afb5ceSopenharmony_ci	int en = _enable;
420d4afb5ceSopenharmony_ci
421d4afb5ceSopenharmony_ci	// h2 ignores rx flow control atm
422d4afb5ceSopenharmony_ci	if (lwsi_role_h2(wsi) || wsi->mux_substream ||
423d4afb5ceSopenharmony_ci	    lwsi_role_h2_ENCAPSULATION(wsi))
424d4afb5ceSopenharmony_ci		return 0; // !!!
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "0x%x", _enable);
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci	if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) {
429d4afb5ceSopenharmony_ci		/*
430d4afb5ceSopenharmony_ci		 * convert user bool style to bitmap style... in user simple
431d4afb5ceSopenharmony_ci		 * bool style _enable = 0 = flow control it, = 1 = allow rx
432d4afb5ceSopenharmony_ci		 */
433d4afb5ceSopenharmony_ci		en = LWS_RXFLOW_REASON_APPLIES | LWS_RXFLOW_REASON_USER_BOOL;
434d4afb5ceSopenharmony_ci		if (_enable & 1)
435d4afb5ceSopenharmony_ci			en |= LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT;
436d4afb5ceSopenharmony_ci	}
437d4afb5ceSopenharmony_ci
438d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	/* any bit set in rxflow_bitmap DISABLEs rxflow control */
441d4afb5ceSopenharmony_ci	if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT)
442d4afb5ceSopenharmony_ci		wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap & ~(en & 0xff));
443d4afb5ceSopenharmony_ci	else
444d4afb5ceSopenharmony_ci		wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap | (en & 0xff));
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) ==
447d4afb5ceSopenharmony_ci	    wsi->rxflow_change_to)
448d4afb5ceSopenharmony_ci		goto skip;
449d4afb5ceSopenharmony_ci
450d4afb5ceSopenharmony_ci	wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE |
451d4afb5ceSopenharmony_ci				(!wsi->rxflow_bitmap);
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "bitmap 0x%x: en 0x%x, ch 0x%x",
454d4afb5ceSopenharmony_ci			   wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci	if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW ||
457d4afb5ceSopenharmony_ci	    !wsi->rxflow_will_be_applied) {
458d4afb5ceSopenharmony_ci		en = __lws_rx_flow_control(wsi);
459d4afb5ceSopenharmony_ci		lws_pt_unlock(pt);
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci		return en;
462d4afb5ceSopenharmony_ci	}
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ciskip:
465d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci	return 0;
468d4afb5ceSopenharmony_ci}
469d4afb5ceSopenharmony_ci
470d4afb5ceSopenharmony_civoid
471d4afb5ceSopenharmony_cilws_rx_flow_allow_all_protocol(const struct lws_context *context,
472d4afb5ceSopenharmony_ci			       const struct lws_protocols *protocol)
473d4afb5ceSopenharmony_ci{
474d4afb5ceSopenharmony_ci	const struct lws_context_per_thread *pt = &context->pt[0];
475d4afb5ceSopenharmony_ci	struct lws *wsi;
476d4afb5ceSopenharmony_ci	unsigned int n, m = context->count_threads;
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ci	while (m--) {
479d4afb5ceSopenharmony_ci		for (n = 0; n < pt->fds_count; n++) {
480d4afb5ceSopenharmony_ci			wsi = wsi_from_fd(context, pt->fds[n].fd);
481d4afb5ceSopenharmony_ci			if (!wsi)
482d4afb5ceSopenharmony_ci				continue;
483d4afb5ceSopenharmony_ci			if (wsi->a.protocol == protocol)
484d4afb5ceSopenharmony_ci				lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
485d4afb5ceSopenharmony_ci		}
486d4afb5ceSopenharmony_ci		pt++;
487d4afb5ceSopenharmony_ci	}
488d4afb5ceSopenharmony_ci}
489d4afb5ceSopenharmony_ci
490d4afb5ceSopenharmony_ciint user_callback_handle_rxflow(lws_callback_function callback_function,
491d4afb5ceSopenharmony_ci				struct lws *wsi,
492d4afb5ceSopenharmony_ci				enum lws_callback_reasons reason, void *user,
493d4afb5ceSopenharmony_ci				void *in, size_t len)
494d4afb5ceSopenharmony_ci{
495d4afb5ceSopenharmony_ci	int n;
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci	wsi->rxflow_will_be_applied = 1;
498d4afb5ceSopenharmony_ci	n = callback_function(wsi, reason, user, in, len);
499d4afb5ceSopenharmony_ci	wsi->rxflow_will_be_applied = 0;
500d4afb5ceSopenharmony_ci	if (!n)
501d4afb5ceSopenharmony_ci		n = __lws_rx_flow_control(wsi);
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci	return n;
504d4afb5ceSopenharmony_ci}
505d4afb5ceSopenharmony_ci
506d4afb5ceSopenharmony_ciint
507d4afb5ceSopenharmony_ci__lws_rx_flow_control(struct lws *wsi)
508d4afb5ceSopenharmony_ci{
509d4afb5ceSopenharmony_ci	struct lws *wsic = wsi->child_list;
510d4afb5ceSopenharmony_ci
511d4afb5ceSopenharmony_ci	// h2 ignores rx flow control atm
512d4afb5ceSopenharmony_ci	if (lwsi_role_h2(wsi) || wsi->mux_substream ||
513d4afb5ceSopenharmony_ci	    lwsi_role_h2_ENCAPSULATION(wsi))
514d4afb5ceSopenharmony_ci		return 0; // !!!
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci	/* if he has children, do those if they were changed */
517d4afb5ceSopenharmony_ci	while (wsic) {
518d4afb5ceSopenharmony_ci		if (wsic->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)
519d4afb5ceSopenharmony_ci			__lws_rx_flow_control(wsic);
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci		wsic = wsic->sibling_list;
522d4afb5ceSopenharmony_ci	}
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci	/* there is no pending change */
525d4afb5ceSopenharmony_ci	if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
526d4afb5ceSopenharmony_ci		return 0;
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci	/* stuff is still buffered, not ready to really accept new input */
529d4afb5ceSopenharmony_ci	if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
530d4afb5ceSopenharmony_ci		/* get ourselves called back to deal with stashed buffer */
531d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi);
532d4afb5ceSopenharmony_ci		// return 0;
533d4afb5ceSopenharmony_ci	}
534d4afb5ceSopenharmony_ci
535d4afb5ceSopenharmony_ci	/* now the pending is cleared, we can change rxflow state */
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci	wsi->rxflow_change_to &= (~LWS_RXFLOW_PENDING_CHANGE) & 3;
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "rxflow: change_to %d",
540d4afb5ceSopenharmony_ci		      wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_ci	/* adjust the pollfd for this wsi */
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
545d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "reenable POLLIN");
546d4afb5ceSopenharmony_ci		// lws_buflist_describe(&wsi->buflist, NULL, __func__);
547d4afb5ceSopenharmony_ci		if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
548d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "fail");
549d4afb5ceSopenharmony_ci			return -1;
550d4afb5ceSopenharmony_ci		}
551d4afb5ceSopenharmony_ci	} else
552d4afb5ceSopenharmony_ci		if (__lws_change_pollfd(wsi, LWS_POLLIN, 0))
553d4afb5ceSopenharmony_ci			return -1;
554d4afb5ceSopenharmony_ci
555d4afb5ceSopenharmony_ci	return 0;
556d4afb5ceSopenharmony_ci}
557d4afb5ceSopenharmony_ci
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ciconst struct lws_protocols *
560d4afb5ceSopenharmony_cilws_get_protocol(struct lws *wsi)
561d4afb5ceSopenharmony_ci{
562d4afb5ceSopenharmony_ci	return wsi->a.protocol;
563d4afb5ceSopenharmony_ci}
564d4afb5ceSopenharmony_ci
565d4afb5ceSopenharmony_ci
566d4afb5ceSopenharmony_ciint
567d4afb5ceSopenharmony_cilws_ensure_user_space(struct lws *wsi)
568d4afb5ceSopenharmony_ci{
569d4afb5ceSopenharmony_ci	if (!wsi->a.protocol)
570d4afb5ceSopenharmony_ci		return 0;
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci	/* allocate the per-connection user memory (if any) */
573d4afb5ceSopenharmony_ci
574d4afb5ceSopenharmony_ci	if (wsi->a.protocol->per_session_data_size && !wsi->user_space) {
575d4afb5ceSopenharmony_ci		wsi->user_space = lws_zalloc(
576d4afb5ceSopenharmony_ci			    wsi->a.protocol->per_session_data_size, "user space");
577d4afb5ceSopenharmony_ci		if (wsi->user_space == NULL) {
578d4afb5ceSopenharmony_ci			lwsl_wsi_err(wsi, "OOM");
579d4afb5ceSopenharmony_ci			return 1;
580d4afb5ceSopenharmony_ci		}
581d4afb5ceSopenharmony_ci	} else
582d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "protocol pss %lu, user_space=%p",
583d4afb5ceSopenharmony_ci				    (long)wsi->a.protocol->per_session_data_size,
584d4afb5ceSopenharmony_ci				    wsi->user_space);
585d4afb5ceSopenharmony_ci	return 0;
586d4afb5ceSopenharmony_ci}
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_civoid *
589d4afb5ceSopenharmony_cilws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
590d4afb5ceSopenharmony_ci{
591d4afb5ceSopenharmony_ci	((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size =
592d4afb5ceSopenharmony_ci		new_size;
593d4afb5ceSopenharmony_ci
594d4afb5ceSopenharmony_ci	if (lws_ensure_user_space(wsi))
595d4afb5ceSopenharmony_ci			return NULL;
596d4afb5ceSopenharmony_ci
597d4afb5ceSopenharmony_ci	return wsi->user_space;
598d4afb5ceSopenharmony_ci}
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ciint
601d4afb5ceSopenharmony_cilws_get_tsi(struct lws *wsi)
602d4afb5ceSopenharmony_ci{
603d4afb5ceSopenharmony_ci        return (int)wsi->tsi;
604d4afb5ceSopenharmony_ci}
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ciint
607d4afb5ceSopenharmony_cilws_is_ssl(struct lws *wsi)
608d4afb5ceSopenharmony_ci{
609d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
610d4afb5ceSopenharmony_ci	return wsi->tls.use_ssl & LCCSCF_USE_SSL;
611d4afb5ceSopenharmony_ci#else
612d4afb5ceSopenharmony_ci	(void)wsi;
613d4afb5ceSopenharmony_ci	return 0;
614d4afb5ceSopenharmony_ci#endif
615d4afb5ceSopenharmony_ci}
616d4afb5ceSopenharmony_ci
617d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
618d4afb5ceSopenharmony_cilws_tls_conn*
619d4afb5ceSopenharmony_cilws_get_ssl(struct lws *wsi)
620d4afb5ceSopenharmony_ci{
621d4afb5ceSopenharmony_ci	return wsi->tls.ssl;
622d4afb5ceSopenharmony_ci}
623d4afb5ceSopenharmony_ci#endif
624d4afb5ceSopenharmony_ci
625d4afb5ceSopenharmony_ciint
626d4afb5ceSopenharmony_cilws_has_buffered_out(struct lws *wsi)
627d4afb5ceSopenharmony_ci{
628d4afb5ceSopenharmony_ci	if (wsi->buflist_out)
629d4afb5ceSopenharmony_ci		return 1;
630d4afb5ceSopenharmony_ci
631d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
632d4afb5ceSopenharmony_ci	{
633d4afb5ceSopenharmony_ci		struct lws *nwsi = lws_get_network_wsi(wsi);
634d4afb5ceSopenharmony_ci
635d4afb5ceSopenharmony_ci		if (nwsi->buflist_out)
636d4afb5ceSopenharmony_ci			return 1;
637d4afb5ceSopenharmony_ci	}
638d4afb5ceSopenharmony_ci#endif
639d4afb5ceSopenharmony_ci
640d4afb5ceSopenharmony_ci	return 0;
641d4afb5ceSopenharmony_ci}
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_ciint
644d4afb5ceSopenharmony_cilws_partial_buffered(struct lws *wsi)
645d4afb5ceSopenharmony_ci{
646d4afb5ceSopenharmony_ci	return lws_has_buffered_out(wsi);
647d4afb5ceSopenharmony_ci}
648d4afb5ceSopenharmony_ci
649d4afb5ceSopenharmony_cilws_fileofs_t
650d4afb5ceSopenharmony_cilws_get_peer_write_allowance(struct lws *wsi)
651d4afb5ceSopenharmony_ci{
652d4afb5ceSopenharmony_ci	if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit))
653d4afb5ceSopenharmony_ci		return -1;
654d4afb5ceSopenharmony_ci
655d4afb5ceSopenharmony_ci	return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit).
656d4afb5ceSopenharmony_ci				   tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
657d4afb5ceSopenharmony_ci}
658d4afb5ceSopenharmony_ci
659d4afb5ceSopenharmony_civoid
660d4afb5ceSopenharmony_cilws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
661d4afb5ceSopenharmony_ci		    const struct lws_role_ops *ops)
662d4afb5ceSopenharmony_ci{
663d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
664d4afb5ceSopenharmony_ci	const char *name = "(unset)";
665d4afb5ceSopenharmony_ci#endif
666d4afb5ceSopenharmony_ci	wsi->wsistate = (unsigned int)role | (unsigned int)state;
667d4afb5ceSopenharmony_ci	if (ops)
668d4afb5ceSopenharmony_ci		wsi->role_ops = ops;
669d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
670d4afb5ceSopenharmony_ci	if (wsi->role_ops)
671d4afb5ceSopenharmony_ci		name = wsi->role_ops->name;
672d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "wsistate 0x%lx, ops %s",
673d4afb5ceSopenharmony_ci			    (unsigned long)wsi->wsistate, name);
674d4afb5ceSopenharmony_ci#endif
675d4afb5ceSopenharmony_ci}
676d4afb5ceSopenharmony_ci
677d4afb5ceSopenharmony_ciint
678d4afb5ceSopenharmony_cilws_parse_uri(char *p, const char **prot, const char **ads, int *port,
679d4afb5ceSopenharmony_ci	      const char **path)
680d4afb5ceSopenharmony_ci{
681d4afb5ceSopenharmony_ci	const char *end;
682d4afb5ceSopenharmony_ci	char unix_skt = 0;
683d4afb5ceSopenharmony_ci
684d4afb5ceSopenharmony_ci	/* cut up the location into address, port and path */
685d4afb5ceSopenharmony_ci	*prot = p;
686d4afb5ceSopenharmony_ci	while (*p && (*p != ':' || p[1] != '/' || p[2] != '/'))
687d4afb5ceSopenharmony_ci		p++;
688d4afb5ceSopenharmony_ci	if (!*p) {
689d4afb5ceSopenharmony_ci		end = p;
690d4afb5ceSopenharmony_ci		p = (char *)*prot;
691d4afb5ceSopenharmony_ci		*prot = end;
692d4afb5ceSopenharmony_ci	} else {
693d4afb5ceSopenharmony_ci		*p = '\0';
694d4afb5ceSopenharmony_ci		p += 3;
695d4afb5ceSopenharmony_ci	}
696d4afb5ceSopenharmony_ci	if (*p == '+') /* unix skt */
697d4afb5ceSopenharmony_ci		unix_skt = 1;
698d4afb5ceSopenharmony_ci
699d4afb5ceSopenharmony_ci	*ads = p;
700d4afb5ceSopenharmony_ci	if (!strcmp(*prot, "http") || !strcmp(*prot, "ws"))
701d4afb5ceSopenharmony_ci		*port = 80;
702d4afb5ceSopenharmony_ci	else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
703d4afb5ceSopenharmony_ci		*port = 443;
704d4afb5ceSopenharmony_ci
705d4afb5ceSopenharmony_ci	if (*p == '[') {
706d4afb5ceSopenharmony_ci		++(*ads);
707d4afb5ceSopenharmony_ci		while (*p && *p != ']')
708d4afb5ceSopenharmony_ci			p++;
709d4afb5ceSopenharmony_ci		if (*p)
710d4afb5ceSopenharmony_ci			*p++ = '\0';
711d4afb5ceSopenharmony_ci	} else
712d4afb5ceSopenharmony_ci		while (*p && *p != ':' && (unix_skt || *p != '/'))
713d4afb5ceSopenharmony_ci			p++;
714d4afb5ceSopenharmony_ci
715d4afb5ceSopenharmony_ci	if (*p == ':') {
716d4afb5ceSopenharmony_ci		*p++ = '\0';
717d4afb5ceSopenharmony_ci		*port = atoi(p);
718d4afb5ceSopenharmony_ci		while (*p && *p != '/')
719d4afb5ceSopenharmony_ci			p++;
720d4afb5ceSopenharmony_ci	}
721d4afb5ceSopenharmony_ci	*path = "/";
722d4afb5ceSopenharmony_ci	if (*p) {
723d4afb5ceSopenharmony_ci		*p++ = '\0';
724d4afb5ceSopenharmony_ci		if (*p)
725d4afb5ceSopenharmony_ci			*path = p;
726d4afb5ceSopenharmony_ci	}
727d4afb5ceSopenharmony_ci
728d4afb5ceSopenharmony_ci	return 0;
729d4afb5ceSopenharmony_ci}
730d4afb5ceSopenharmony_ci
731d4afb5ceSopenharmony_ci/* ... */
732d4afb5ceSopenharmony_ci
733d4afb5ceSopenharmony_ciint
734d4afb5ceSopenharmony_cilws_get_urlarg_by_name_safe(struct lws *wsi, const char *name, char *buf, int len)
735d4afb5ceSopenharmony_ci{
736d4afb5ceSopenharmony_ci	int n = 0, fraglen, sl = (int)strlen(name);
737d4afb5ceSopenharmony_ci
738d4afb5ceSopenharmony_ci	do {
739d4afb5ceSopenharmony_ci		fraglen = lws_hdr_copy_fragment(wsi, buf, len,
740d4afb5ceSopenharmony_ci						WSI_TOKEN_HTTP_URI_ARGS, n);
741d4afb5ceSopenharmony_ci
742d4afb5ceSopenharmony_ci		if (fraglen < 0)
743d4afb5ceSopenharmony_ci			break;
744d4afb5ceSopenharmony_ci
745d4afb5ceSopenharmony_ci		if (fraglen + 1 < len &&
746d4afb5ceSopenharmony_ci		    fraglen >= sl &&
747d4afb5ceSopenharmony_ci		    !strncmp(buf, name, (size_t)sl)) {
748d4afb5ceSopenharmony_ci			/*
749d4afb5ceSopenharmony_ci			 * If he left off the trailing =, trim it from the
750d4afb5ceSopenharmony_ci			 * result
751d4afb5ceSopenharmony_ci			 */
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci			if (name[sl - 1] != '=' &&
754d4afb5ceSopenharmony_ci			    sl < fraglen &&
755d4afb5ceSopenharmony_ci			    buf[sl] == '=')
756d4afb5ceSopenharmony_ci				sl++;
757d4afb5ceSopenharmony_ci
758d4afb5ceSopenharmony_ci			memmove(buf, buf + sl, (size_t)(fraglen - sl));
759d4afb5ceSopenharmony_ci			buf[fraglen - sl] = '\0';
760d4afb5ceSopenharmony_ci
761d4afb5ceSopenharmony_ci			return fraglen - sl;
762d4afb5ceSopenharmony_ci		}
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci		n++;
765d4afb5ceSopenharmony_ci	} while (1);
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ci	return -1;
768d4afb5ceSopenharmony_ci}
769d4afb5ceSopenharmony_ci
770d4afb5ceSopenharmony_ciconst char *
771d4afb5ceSopenharmony_cilws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
772d4afb5ceSopenharmony_ci{
773d4afb5ceSopenharmony_ci	int n = lws_get_urlarg_by_name_safe(wsi, name, buf, len);
774d4afb5ceSopenharmony_ci
775d4afb5ceSopenharmony_ci	return n < 0 ? NULL : buf;
776d4afb5ceSopenharmony_ci}
777d4afb5ceSopenharmony_ci
778d4afb5ceSopenharmony_ci
779d4afb5ceSopenharmony_ci#if defined(LWS_WITHOUT_EXTENSIONS)
780d4afb5ceSopenharmony_ci
781d4afb5ceSopenharmony_ci/* we need to provide dummy callbacks for internal exts
782d4afb5ceSopenharmony_ci * so user code runs when faced with a lib compiled with
783d4afb5ceSopenharmony_ci * extensions disabled.
784d4afb5ceSopenharmony_ci */
785d4afb5ceSopenharmony_ci
786d4afb5ceSopenharmony_ciint
787d4afb5ceSopenharmony_cilws_extension_callback_pm_deflate(struct lws_context *context,
788d4afb5ceSopenharmony_ci                                  const struct lws_extension *ext,
789d4afb5ceSopenharmony_ci                                  struct lws *wsi,
790d4afb5ceSopenharmony_ci                                  enum lws_extension_callback_reasons reason,
791d4afb5ceSopenharmony_ci                                  void *user, void *in, size_t len)
792d4afb5ceSopenharmony_ci{
793d4afb5ceSopenharmony_ci	(void)context;
794d4afb5ceSopenharmony_ci	(void)ext;
795d4afb5ceSopenharmony_ci	(void)wsi;
796d4afb5ceSopenharmony_ci	(void)reason;
797d4afb5ceSopenharmony_ci	(void)user;
798d4afb5ceSopenharmony_ci	(void)in;
799d4afb5ceSopenharmony_ci	(void)len;
800d4afb5ceSopenharmony_ci
801d4afb5ceSopenharmony_ci	return 0;
802d4afb5ceSopenharmony_ci}
803d4afb5ceSopenharmony_ci
804d4afb5ceSopenharmony_ciint
805d4afb5ceSopenharmony_cilws_set_extension_option(struct lws *wsi, const char *ext_name,
806d4afb5ceSopenharmony_ci			 const char *opt_name, const char *opt_val)
807d4afb5ceSopenharmony_ci{
808d4afb5ceSopenharmony_ci	return -1;
809d4afb5ceSopenharmony_ci}
810d4afb5ceSopenharmony_ci#endif
811d4afb5ceSopenharmony_ci
812d4afb5ceSopenharmony_ciint
813d4afb5ceSopenharmony_cilws_is_cgi(struct lws *wsi) {
814d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI
815d4afb5ceSopenharmony_ci	return !!wsi->http.cgi;
816d4afb5ceSopenharmony_ci#else
817d4afb5ceSopenharmony_ci	return 0;
818d4afb5ceSopenharmony_ci#endif
819d4afb5ceSopenharmony_ci}
820d4afb5ceSopenharmony_ci
821d4afb5ceSopenharmony_ciconst struct lws_protocol_vhost_options *
822d4afb5ceSopenharmony_cilws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name)
823d4afb5ceSopenharmony_ci{
824d4afb5ceSopenharmony_ci	while (pvo) {
825d4afb5ceSopenharmony_ci		if (!strcmp(pvo->name, name))
826d4afb5ceSopenharmony_ci			break;
827d4afb5ceSopenharmony_ci
828d4afb5ceSopenharmony_ci		pvo = pvo->next;
829d4afb5ceSopenharmony_ci	}
830d4afb5ceSopenharmony_ci
831d4afb5ceSopenharmony_ci	return pvo;
832d4afb5ceSopenharmony_ci}
833d4afb5ceSopenharmony_ci
834d4afb5ceSopenharmony_ciint
835d4afb5ceSopenharmony_cilws_pvo_get_str(void *in, const char *name, const char **result)
836d4afb5ceSopenharmony_ci{
837d4afb5ceSopenharmony_ci	const struct lws_protocol_vhost_options *pv =
838d4afb5ceSopenharmony_ci		lws_pvo_search((const struct lws_protocol_vhost_options *)in,
839d4afb5ceSopenharmony_ci				name);
840d4afb5ceSopenharmony_ci
841d4afb5ceSopenharmony_ci	if (!pv)
842d4afb5ceSopenharmony_ci		return 1;
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci	*result = (const char *)pv->value;
845d4afb5ceSopenharmony_ci
846d4afb5ceSopenharmony_ci	return 0;
847d4afb5ceSopenharmony_ci}
848d4afb5ceSopenharmony_ci
849d4afb5ceSopenharmony_ciint
850d4afb5ceSopenharmony_cilws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len)
851d4afb5ceSopenharmony_ci{
852d4afb5ceSopenharmony_ci	struct lws_vhost *v = pt->context->vhost_list;
853d4afb5ceSopenharmony_ci	lws_fakewsi_def_plwsa(pt);
854d4afb5ceSopenharmony_ci	int n, ret = 0;
855d4afb5ceSopenharmony_ci
856d4afb5ceSopenharmony_ci	lws_fakewsi_prep_plwsa_ctx(pt->context);
857d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && LWS_MAX_SMP > 1
858d4afb5ceSopenharmony_ci	((struct lws *)plwsa)->tsi = (char)(int)(pt - &pt->context->pt[0]);
859d4afb5ceSopenharmony_ci#endif
860d4afb5ceSopenharmony_ci
861d4afb5ceSopenharmony_ci	while (v) {
862d4afb5ceSopenharmony_ci		const struct lws_protocols *p = v->protocols;
863d4afb5ceSopenharmony_ci
864d4afb5ceSopenharmony_ci		plwsa->vhost = v; /* not a real bound wsi */
865d4afb5ceSopenharmony_ci
866d4afb5ceSopenharmony_ci		for (n = 0; n < v->count_protocols; n++) {
867d4afb5ceSopenharmony_ci			plwsa->protocol = p;
868d4afb5ceSopenharmony_ci			if (p->callback &&
869d4afb5ceSopenharmony_ci			    p->callback((struct lws *)plwsa, (enum lws_callback_reasons)reason, NULL, in, len))
870d4afb5ceSopenharmony_ci				ret |= 1;
871d4afb5ceSopenharmony_ci			p++;
872d4afb5ceSopenharmony_ci		}
873d4afb5ceSopenharmony_ci
874d4afb5ceSopenharmony_ci		v = v->vhost_next;
875d4afb5ceSopenharmony_ci	}
876d4afb5ceSopenharmony_ci
877d4afb5ceSopenharmony_ci	return ret;
878d4afb5ceSopenharmony_ci}
879d4afb5ceSopenharmony_ci
880d4afb5ceSopenharmony_civoid *
881d4afb5ceSopenharmony_cilws_wsi_user(struct lws *wsi)
882d4afb5ceSopenharmony_ci{
883d4afb5ceSopenharmony_ci	return wsi->user_space;
884d4afb5ceSopenharmony_ci}
885d4afb5ceSopenharmony_ci
886d4afb5ceSopenharmony_ciint
887d4afb5ceSopenharmony_cilws_wsi_tsi(struct lws *wsi)
888d4afb5ceSopenharmony_ci{
889d4afb5ceSopenharmony_ci	return wsi->tsi;
890d4afb5ceSopenharmony_ci}
891d4afb5ceSopenharmony_ci
892d4afb5ceSopenharmony_ci
893d4afb5ceSopenharmony_civoid
894d4afb5ceSopenharmony_cilws_set_wsi_user(struct lws *wsi, void *data)
895d4afb5ceSopenharmony_ci{
896d4afb5ceSopenharmony_ci	if (!wsi->user_space_externally_allocated && wsi->user_space)
897d4afb5ceSopenharmony_ci		lws_free(wsi->user_space);
898d4afb5ceSopenharmony_ci
899d4afb5ceSopenharmony_ci	wsi->user_space_externally_allocated = 1;
900d4afb5ceSopenharmony_ci	wsi->user_space = data;
901d4afb5ceSopenharmony_ci}
902d4afb5ceSopenharmony_ci
903d4afb5ceSopenharmony_cistruct lws *
904d4afb5ceSopenharmony_cilws_get_parent(const struct lws *wsi)
905d4afb5ceSopenharmony_ci{
906d4afb5ceSopenharmony_ci	return wsi->parent;
907d4afb5ceSopenharmony_ci}
908d4afb5ceSopenharmony_ci
909d4afb5ceSopenharmony_cistruct lws *
910d4afb5ceSopenharmony_cilws_get_child(const struct lws *wsi)
911d4afb5ceSopenharmony_ci{
912d4afb5ceSopenharmony_ci	return wsi->child_list;
913d4afb5ceSopenharmony_ci}
914d4afb5ceSopenharmony_ci
915d4afb5ceSopenharmony_civoid *
916d4afb5ceSopenharmony_cilws_get_opaque_parent_data(const struct lws *wsi)
917d4afb5ceSopenharmony_ci{
918d4afb5ceSopenharmony_ci	return wsi->opaque_parent_data;
919d4afb5ceSopenharmony_ci}
920d4afb5ceSopenharmony_ci
921d4afb5ceSopenharmony_civoid
922d4afb5ceSopenharmony_cilws_set_opaque_parent_data(struct lws *wsi, void *data)
923d4afb5ceSopenharmony_ci{
924d4afb5ceSopenharmony_ci	wsi->opaque_parent_data = data;
925d4afb5ceSopenharmony_ci}
926d4afb5ceSopenharmony_ci
927d4afb5ceSopenharmony_civoid *
928d4afb5ceSopenharmony_cilws_get_opaque_user_data(const struct lws *wsi)
929d4afb5ceSopenharmony_ci{
930d4afb5ceSopenharmony_ci	return wsi->a.opaque_user_data;
931d4afb5ceSopenharmony_ci}
932d4afb5ceSopenharmony_ci
933d4afb5ceSopenharmony_civoid
934d4afb5ceSopenharmony_cilws_set_opaque_user_data(struct lws *wsi, void *data)
935d4afb5ceSopenharmony_ci{
936d4afb5ceSopenharmony_ci	wsi->a.opaque_user_data = data;
937d4afb5ceSopenharmony_ci}
938d4afb5ceSopenharmony_ci
939d4afb5ceSopenharmony_ciint
940d4afb5ceSopenharmony_cilws_get_child_pending_on_writable(const struct lws *wsi)
941d4afb5ceSopenharmony_ci{
942d4afb5ceSopenharmony_ci	return wsi->parent_pending_cb_on_writable;
943d4afb5ceSopenharmony_ci}
944d4afb5ceSopenharmony_ci
945d4afb5ceSopenharmony_civoid
946d4afb5ceSopenharmony_cilws_clear_child_pending_on_writable(struct lws *wsi)
947d4afb5ceSopenharmony_ci{
948d4afb5ceSopenharmony_ci	wsi->parent_pending_cb_on_writable = 0;
949d4afb5ceSopenharmony_ci}
950d4afb5ceSopenharmony_ci
951d4afb5ceSopenharmony_ci
952d4afb5ceSopenharmony_ci
953d4afb5ceSopenharmony_ciconst char *
954d4afb5ceSopenharmony_cilws_get_vhost_name(struct lws_vhost *vhost)
955d4afb5ceSopenharmony_ci{
956d4afb5ceSopenharmony_ci	return vhost->name;
957d4afb5ceSopenharmony_ci}
958d4afb5ceSopenharmony_ci
959d4afb5ceSopenharmony_ciint
960d4afb5ceSopenharmony_cilws_get_vhost_port(struct lws_vhost *vhost)
961d4afb5ceSopenharmony_ci{
962d4afb5ceSopenharmony_ci	return vhost->listen_port;
963d4afb5ceSopenharmony_ci}
964d4afb5ceSopenharmony_ci
965d4afb5ceSopenharmony_civoid *
966d4afb5ceSopenharmony_cilws_get_vhost_user(struct lws_vhost *vhost)
967d4afb5ceSopenharmony_ci{
968d4afb5ceSopenharmony_ci	return vhost->user;
969d4afb5ceSopenharmony_ci}
970d4afb5ceSopenharmony_ci
971d4afb5ceSopenharmony_ciconst char *
972d4afb5ceSopenharmony_cilws_get_vhost_iface(struct lws_vhost *vhost)
973d4afb5ceSopenharmony_ci{
974d4afb5ceSopenharmony_ci	return vhost->iface;
975d4afb5ceSopenharmony_ci}
976d4afb5ceSopenharmony_ci
977d4afb5ceSopenharmony_cilws_sockfd_type
978d4afb5ceSopenharmony_cilws_get_socket_fd(struct lws *wsi)
979d4afb5ceSopenharmony_ci{
980d4afb5ceSopenharmony_ci	if (!wsi)
981d4afb5ceSopenharmony_ci		return -1;
982d4afb5ceSopenharmony_ci	return wsi->desc.sockfd;
983d4afb5ceSopenharmony_ci}
984d4afb5ceSopenharmony_ci
985d4afb5ceSopenharmony_ci
986d4afb5ceSopenharmony_cistruct lws_vhost *
987d4afb5ceSopenharmony_cilws_vhost_get(struct lws *wsi)
988d4afb5ceSopenharmony_ci{
989d4afb5ceSopenharmony_ci	return wsi->a.vhost;
990d4afb5ceSopenharmony_ci}
991d4afb5ceSopenharmony_ci
992d4afb5ceSopenharmony_cistruct lws_vhost *
993d4afb5ceSopenharmony_cilws_get_vhost(struct lws *wsi)
994d4afb5ceSopenharmony_ci{
995d4afb5ceSopenharmony_ci	return wsi->a.vhost;
996d4afb5ceSopenharmony_ci}
997d4afb5ceSopenharmony_ci
998d4afb5ceSopenharmony_ciconst struct lws_protocols *
999d4afb5ceSopenharmony_cilws_protocol_get(struct lws *wsi)
1000d4afb5ceSopenharmony_ci{
1001d4afb5ceSopenharmony_ci	return wsi->a.protocol;
1002d4afb5ceSopenharmony_ci}
1003d4afb5ceSopenharmony_ci
1004d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UDP)
1005d4afb5ceSopenharmony_ciconst struct lws_udp *
1006d4afb5ceSopenharmony_cilws_get_udp(const struct lws *wsi)
1007d4afb5ceSopenharmony_ci{
1008d4afb5ceSopenharmony_ci	return wsi->udp;
1009d4afb5ceSopenharmony_ci}
1010d4afb5ceSopenharmony_ci#endif
1011d4afb5ceSopenharmony_ci
1012d4afb5ceSopenharmony_cistruct lws_context *
1013d4afb5ceSopenharmony_cilws_get_context(const struct lws *wsi)
1014d4afb5ceSopenharmony_ci{
1015d4afb5ceSopenharmony_ci	return wsi->a.context;
1016d4afb5ceSopenharmony_ci}
1017d4afb5ceSopenharmony_ci
1018d4afb5ceSopenharmony_cistruct lws_log_cx *
1019d4afb5ceSopenharmony_cilwsl_wsi_get_cx(struct lws *wsi)
1020d4afb5ceSopenharmony_ci{
1021d4afb5ceSopenharmony_ci	if (!wsi)
1022d4afb5ceSopenharmony_ci		return NULL;
1023d4afb5ceSopenharmony_ci
1024d4afb5ceSopenharmony_ci	return wsi->lc.log_cx;
1025d4afb5ceSopenharmony_ci}
1026d4afb5ceSopenharmony_ci
1027d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1028d4afb5ceSopenharmony_ciint
1029d4afb5ceSopenharmony_ci_lws_generic_transaction_completed_active_conn(struct lws **_wsi, char take_vh_lock)
1030d4afb5ceSopenharmony_ci{
1031d4afb5ceSopenharmony_ci	struct lws *wnew, *wsi = *_wsi;
1032d4afb5ceSopenharmony_ci
1033d4afb5ceSopenharmony_ci	/*
1034d4afb5ceSopenharmony_ci	 * Are we constitutionally capable of having a queue, ie, we are on
1035d4afb5ceSopenharmony_ci	 * the "active client connections" list?
1036d4afb5ceSopenharmony_ci	 *
1037d4afb5ceSopenharmony_ci	 * If not, that's it for us.
1038d4afb5ceSopenharmony_ci	 */
1039d4afb5ceSopenharmony_ci
1040d4afb5ceSopenharmony_ci	if (lws_dll2_is_detached(&wsi->dll_cli_active_conns))
1041d4afb5ceSopenharmony_ci		return 0; /* no new transaction */
1042d4afb5ceSopenharmony_ci
1043d4afb5ceSopenharmony_ci	/*
1044d4afb5ceSopenharmony_ci	 * With h1 queuing, the original "active client" moves his attributes
1045d4afb5ceSopenharmony_ci	 * like fd, ssl, queue and active client list entry to the next guy in
1046d4afb5ceSopenharmony_ci	 * the queue before closing... it's because the user code knows the
1047d4afb5ceSopenharmony_ci	 * individual wsi and the action must take place in the correct wsi
1048d4afb5ceSopenharmony_ci	 * context.  Note this means we don't truly pipeline headers.
1049d4afb5ceSopenharmony_ci	 *
1050d4afb5ceSopenharmony_ci	 * Trying to keep the original "active client" in place to do the work
1051d4afb5ceSopenharmony_ci	 * of the wsi breaks down when dealing with queued POSTs otherwise; it's
1052d4afb5ceSopenharmony_ci	 * also competing with the real mux child arrangements and complicating
1053d4afb5ceSopenharmony_ci	 * the code.
1054d4afb5ceSopenharmony_ci	 *
1055d4afb5ceSopenharmony_ci	 * For that reason, see if we have any queued child now...
1056d4afb5ceSopenharmony_ci	 */
1057d4afb5ceSopenharmony_ci
1058d4afb5ceSopenharmony_ci	if (!wsi->dll2_cli_txn_queue_owner.head) {
1059d4afb5ceSopenharmony_ci		/*
1060d4afb5ceSopenharmony_ci		 * Nothing pipelined... we should hang around a bit
1061d4afb5ceSopenharmony_ci		 * in case something turns up... otherwise we'll close
1062d4afb5ceSopenharmony_ci		 */
1063d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "nothing pipelined waiting");
1064d4afb5ceSopenharmony_ci		lwsi_set_state(wsi, LRS_IDLING);
1065d4afb5ceSopenharmony_ci
1066d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE,
1067d4afb5ceSopenharmony_ci				wsi->keep_warm_secs);
1068d4afb5ceSopenharmony_ci
1069d4afb5ceSopenharmony_ci		return 0; /* no new transaction right now */
1070d4afb5ceSopenharmony_ci	}
1071d4afb5ceSopenharmony_ci
1072d4afb5ceSopenharmony_ci	/*
1073d4afb5ceSopenharmony_ci	 * We have a queued child wsi we should bequeath our assets to, before
1074d4afb5ceSopenharmony_ci	 * closing ourself
1075d4afb5ceSopenharmony_ci	 */
1076d4afb5ceSopenharmony_ci
1077d4afb5ceSopenharmony_ci	if (take_vh_lock)
1078d4afb5ceSopenharmony_ci		lws_vhost_lock(wsi->a.vhost);
1079d4afb5ceSopenharmony_ci
1080d4afb5ceSopenharmony_ci	wnew = lws_container_of(wsi->dll2_cli_txn_queue_owner.head, struct lws,
1081d4afb5ceSopenharmony_ci				dll2_cli_txn_queue);
1082d4afb5ceSopenharmony_ci
1083d4afb5ceSopenharmony_ci	assert(wsi != wnew);
1084d4afb5ceSopenharmony_ci
1085d4afb5ceSopenharmony_ci	lws_dll2_remove(&wnew->dll2_cli_txn_queue);
1086d4afb5ceSopenharmony_ci
1087d4afb5ceSopenharmony_ci	assert(lws_socket_is_valid(wsi->desc.sockfd));
1088d4afb5ceSopenharmony_ci
1089d4afb5ceSopenharmony_ci	__lws_change_pollfd(wsi, LWS_POLLOUT | LWS_POLLIN, 0);
1090d4afb5ceSopenharmony_ci
1091d4afb5ceSopenharmony_ci	/* copy the fd */
1092d4afb5ceSopenharmony_ci	wnew->desc = wsi->desc;
1093d4afb5ceSopenharmony_ci
1094d4afb5ceSopenharmony_ci	assert(lws_socket_is_valid(wnew->desc.sockfd));
1095d4afb5ceSopenharmony_ci
1096d4afb5ceSopenharmony_ci	/* disconnect the fd from association with old wsi */
1097d4afb5ceSopenharmony_ci
1098d4afb5ceSopenharmony_ci	if (__remove_wsi_socket_from_fds(wsi))
1099d4afb5ceSopenharmony_ci		return -1;
1100d4afb5ceSopenharmony_ci
1101d4afb5ceSopenharmony_ci	sanity_assert_no_wsi_traces(wsi->a.context, wsi);
1102d4afb5ceSopenharmony_ci	sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd);
1103d4afb5ceSopenharmony_ci	wsi->desc.sockfd = LWS_SOCK_INVALID;
1104d4afb5ceSopenharmony_ci
1105d4afb5ceSopenharmony_ci	__lws_wsi_remove_from_sul(wsi);
1106d4afb5ceSopenharmony_ci
1107d4afb5ceSopenharmony_ci	/*
1108d4afb5ceSopenharmony_ci	 * ... we're doing some magic here in terms of handing off the socket
1109d4afb5ceSopenharmony_ci	 * that has been active to a wsi that has not yet itself been active...
1110d4afb5ceSopenharmony_ci	 * depending on the event lib we may need to give a magic spark to the
1111d4afb5ceSopenharmony_ci	 * new guy and snuff out the old guy's magic spark at that level as well
1112d4afb5ceSopenharmony_ci	 */
1113d4afb5ceSopenharmony_ci
1114d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EVENT_LIBS)
1115d4afb5ceSopenharmony_ci	if (wsi->a.context->event_loop_ops->destroy_wsi)
1116d4afb5ceSopenharmony_ci		wsi->a.context->event_loop_ops->destroy_wsi(wsi);
1117d4afb5ceSopenharmony_ci	if (wsi->a.context->event_loop_ops->sock_accept)
1118d4afb5ceSopenharmony_ci		wsi->a.context->event_loop_ops->sock_accept(wnew);
1119d4afb5ceSopenharmony_ci#endif
1120d4afb5ceSopenharmony_ci
1121d4afb5ceSopenharmony_ci	/* point the fd table entry to new guy */
1122d4afb5ceSopenharmony_ci
1123d4afb5ceSopenharmony_ci	assert(lws_socket_is_valid(wnew->desc.sockfd));
1124d4afb5ceSopenharmony_ci
1125d4afb5ceSopenharmony_ci	if (__insert_wsi_socket_into_fds(wsi->a.context, wnew))
1126d4afb5ceSopenharmony_ci		return -1;
1127d4afb5ceSopenharmony_ci
1128d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
1129d4afb5ceSopenharmony_ci	/* pass on the tls */
1130d4afb5ceSopenharmony_ci
1131d4afb5ceSopenharmony_ci	wnew->tls = wsi->tls;
1132d4afb5ceSopenharmony_ci	wsi->tls.client_bio = NULL;
1133d4afb5ceSopenharmony_ci	wsi->tls.ssl = NULL;
1134d4afb5ceSopenharmony_ci	wsi->tls.use_ssl = 0;
1135d4afb5ceSopenharmony_ci#endif
1136d4afb5ceSopenharmony_ci
1137d4afb5ceSopenharmony_ci	/* take over his copy of his endpoint as an active connection */
1138d4afb5ceSopenharmony_ci
1139d4afb5ceSopenharmony_ci	if (!wnew->cli_hostname_copy && wsi->cli_hostname_copy) {
1140d4afb5ceSopenharmony_ci		wnew->cli_hostname_copy = wsi->cli_hostname_copy;
1141d4afb5ceSopenharmony_ci		wsi->cli_hostname_copy = NULL;
1142d4afb5ceSopenharmony_ci	}
1143d4afb5ceSopenharmony_ci	wnew->keep_warm_secs = wsi->keep_warm_secs;
1144d4afb5ceSopenharmony_ci
1145d4afb5ceSopenharmony_ci	/*
1146d4afb5ceSopenharmony_ci	 * selected queued guy now replaces the original leader on the
1147d4afb5ceSopenharmony_ci	 * active client conn list
1148d4afb5ceSopenharmony_ci	 */
1149d4afb5ceSopenharmony_ci
1150d4afb5ceSopenharmony_ci	lws_dll2_remove(&wsi->dll_cli_active_conns);
1151d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&wnew->dll_cli_active_conns,
1152d4afb5ceSopenharmony_ci			  &wsi->a.vhost->dll_cli_active_conns_owner);
1153d4afb5ceSopenharmony_ci
1154d4afb5ceSopenharmony_ci	/* move any queued guys to queue on new active conn */
1155d4afb5ceSopenharmony_ci
1156d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1157d4afb5ceSopenharmony_ci				   wsi->dll2_cli_txn_queue_owner.head) {
1158d4afb5ceSopenharmony_ci		struct lws *ww = lws_container_of(d, struct lws,
1159d4afb5ceSopenharmony_ci					  dll2_cli_txn_queue);
1160d4afb5ceSopenharmony_ci
1161d4afb5ceSopenharmony_ci		lws_dll2_remove(&ww->dll2_cli_txn_queue);
1162d4afb5ceSopenharmony_ci		lws_dll2_add_tail(&ww->dll2_cli_txn_queue,
1163d4afb5ceSopenharmony_ci				  &wnew->dll2_cli_txn_queue_owner);
1164d4afb5ceSopenharmony_ci
1165d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(d, d1);
1166d4afb5ceSopenharmony_ci
1167d4afb5ceSopenharmony_ci	if (take_vh_lock)
1168d4afb5ceSopenharmony_ci		lws_vhost_unlock(wsi->a.vhost);
1169d4afb5ceSopenharmony_ci
1170d4afb5ceSopenharmony_ci	/*
1171d4afb5ceSopenharmony_ci	 * The original leader who passed on all his powers already can die...
1172d4afb5ceSopenharmony_ci	 * in the call stack above us there are guys who still want to touch
1173d4afb5ceSopenharmony_ci	 * him, so have him die next time around the event loop, not now.
1174d4afb5ceSopenharmony_ci	 */
1175d4afb5ceSopenharmony_ci
1176d4afb5ceSopenharmony_ci	wsi->already_did_cce = 1; /* so the close doesn't trigger a CCE */
1177d4afb5ceSopenharmony_ci	lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
1178d4afb5ceSopenharmony_ci
1179d4afb5ceSopenharmony_ci	/* after the first one, they can only be coming from the queue */
1180d4afb5ceSopenharmony_ci	wnew->transaction_from_pipeline_queue = 1;
1181d4afb5ceSopenharmony_ci
1182d4afb5ceSopenharmony_ci	lwsl_wsi_notice(wsi, " pipeline queue passed -> %s", lws_wsi_tag(wnew));
1183d4afb5ceSopenharmony_ci
1184d4afb5ceSopenharmony_ci	*_wsi = wnew; /* inform caller we swapped */
1185d4afb5ceSopenharmony_ci
1186d4afb5ceSopenharmony_ci	return 1; /* new transaction */
1187d4afb5ceSopenharmony_ci}
1188d4afb5ceSopenharmony_ci#endif
1189d4afb5ceSopenharmony_ci
1190d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT
1191d4afb5ceSopenharmony_cilws_raw_transaction_completed(struct lws *wsi)
1192d4afb5ceSopenharmony_ci{
1193d4afb5ceSopenharmony_ci	if (lws_has_buffered_out(wsi)) {
1194d4afb5ceSopenharmony_ci		/*
1195d4afb5ceSopenharmony_ci		 * ...so he tried to send something large, but it went out
1196d4afb5ceSopenharmony_ci		 * as a partial, but he immediately called us to say he wants
1197d4afb5ceSopenharmony_ci		 * to close the connection.
1198d4afb5ceSopenharmony_ci		 *
1199d4afb5ceSopenharmony_ci		 * Defer the close until the last part of the partial is sent.
1200d4afb5ceSopenharmony_ci		 *
1201d4afb5ceSopenharmony_ci		 */
1202d4afb5ceSopenharmony_ci
1203d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "deferring due to partial");
1204d4afb5ceSopenharmony_ci		wsi->close_when_buffered_out_drained = 1;
1205d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi);
1206d4afb5ceSopenharmony_ci
1207d4afb5ceSopenharmony_ci		return 0;
1208d4afb5ceSopenharmony_ci	}
1209d4afb5ceSopenharmony_ci
1210d4afb5ceSopenharmony_ci	return -1;
1211d4afb5ceSopenharmony_ci}
1212d4afb5ceSopenharmony_ci
1213d4afb5ceSopenharmony_ciint
1214d4afb5ceSopenharmony_cilws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
1215d4afb5ceSopenharmony_ci		  const char *reason)
1216d4afb5ceSopenharmony_ci{
1217d4afb5ceSopenharmony_ci//	if (wsi->a.protocol == p)
1218d4afb5ceSopenharmony_ci//		return 0;
1219d4afb5ceSopenharmony_ci	const struct lws_protocols *vp = wsi->a.vhost->protocols, *vpo;
1220d4afb5ceSopenharmony_ci
1221d4afb5ceSopenharmony_ci	if (wsi->a.protocol && wsi->protocol_bind_balance) {
1222d4afb5ceSopenharmony_ci		wsi->a.protocol->callback(wsi,
1223d4afb5ceSopenharmony_ci		       wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)],
1224d4afb5ceSopenharmony_ci					wsi->user_space, (void *)reason, 0);
1225d4afb5ceSopenharmony_ci		wsi->protocol_bind_balance = 0;
1226d4afb5ceSopenharmony_ci	}
1227d4afb5ceSopenharmony_ci	if (!wsi->user_space_externally_allocated)
1228d4afb5ceSopenharmony_ci		lws_free_set_NULL(wsi->user_space);
1229d4afb5ceSopenharmony_ci
1230d4afb5ceSopenharmony_ci	lws_same_vh_protocol_remove(wsi);
1231d4afb5ceSopenharmony_ci
1232d4afb5ceSopenharmony_ci	wsi->a.protocol = p;
1233d4afb5ceSopenharmony_ci	if (!p)
1234d4afb5ceSopenharmony_ci		return 0;
1235d4afb5ceSopenharmony_ci
1236d4afb5ceSopenharmony_ci	if (lws_ensure_user_space(wsi))
1237d4afb5ceSopenharmony_ci		return 1;
1238d4afb5ceSopenharmony_ci
1239d4afb5ceSopenharmony_ci	if (p > vp && p < &vp[wsi->a.vhost->count_protocols])
1240d4afb5ceSopenharmony_ci		lws_same_vh_protocol_insert(wsi, (int)(p - vp));
1241d4afb5ceSopenharmony_ci	else {
1242d4afb5ceSopenharmony_ci		int n = wsi->a.vhost->count_protocols;
1243d4afb5ceSopenharmony_ci		int hit = 0;
1244d4afb5ceSopenharmony_ci
1245d4afb5ceSopenharmony_ci		vpo = vp;
1246d4afb5ceSopenharmony_ci
1247d4afb5ceSopenharmony_ci		while (n--) {
1248d4afb5ceSopenharmony_ci			if (p->name && vp->name && !strcmp(p->name, vp->name)) {
1249d4afb5ceSopenharmony_ci				hit = 1;
1250d4afb5ceSopenharmony_ci				lws_same_vh_protocol_insert(wsi, (int)(vp - vpo));
1251d4afb5ceSopenharmony_ci				break;
1252d4afb5ceSopenharmony_ci			}
1253d4afb5ceSopenharmony_ci			vp++;
1254d4afb5ceSopenharmony_ci		}
1255d4afb5ceSopenharmony_ci		if (!hit)
1256d4afb5ceSopenharmony_ci			lwsl_err("%s: %p is not in vhost '%s' protocols list\n",
1257d4afb5ceSopenharmony_ci				 __func__, p, wsi->a.vhost->name);
1258d4afb5ceSopenharmony_ci	}
1259d4afb5ceSopenharmony_ci
1260d4afb5ceSopenharmony_ci	if (wsi->a.protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
1261d4afb5ceSopenharmony_ci				    !!lwsi_role_server(wsi)],
1262d4afb5ceSopenharmony_ci				    wsi->user_space, NULL, 0))
1263d4afb5ceSopenharmony_ci		return 1;
1264d4afb5ceSopenharmony_ci
1265d4afb5ceSopenharmony_ci	wsi->protocol_bind_balance = 1;
1266d4afb5ceSopenharmony_ci
1267d4afb5ceSopenharmony_ci	return 0;
1268d4afb5ceSopenharmony_ci}
1269d4afb5ceSopenharmony_ci
1270d4afb5ceSopenharmony_civoid
1271d4afb5ceSopenharmony_cilws_http_close_immortal(struct lws *wsi)
1272d4afb5ceSopenharmony_ci{
1273d4afb5ceSopenharmony_ci	struct lws *nwsi;
1274d4afb5ceSopenharmony_ci
1275d4afb5ceSopenharmony_ci	if (!wsi->mux_substream)
1276d4afb5ceSopenharmony_ci		return;
1277d4afb5ceSopenharmony_ci
1278d4afb5ceSopenharmony_ci	assert(wsi->mux_stream_immortal);
1279d4afb5ceSopenharmony_ci	wsi->mux_stream_immortal = 0;
1280d4afb5ceSopenharmony_ci
1281d4afb5ceSopenharmony_ci	nwsi = lws_get_network_wsi(wsi);
1282d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "%s (%d)", lws_wsi_tag(nwsi),
1283d4afb5ceSopenharmony_ci				       nwsi->immortal_substream_count);
1284d4afb5ceSopenharmony_ci	assert(nwsi->immortal_substream_count);
1285d4afb5ceSopenharmony_ci	nwsi->immortal_substream_count--;
1286d4afb5ceSopenharmony_ci	if (!nwsi->immortal_substream_count)
1287d4afb5ceSopenharmony_ci		/*
1288d4afb5ceSopenharmony_ci		 * since we closed the only immortal stream on this nwsi, we
1289d4afb5ceSopenharmony_ci		 * need to reapply a normal timeout regime to the nwsi
1290d4afb5ceSopenharmony_ci		 */
1291d4afb5ceSopenharmony_ci		lws_set_timeout(nwsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
1292d4afb5ceSopenharmony_ci				wsi->a.vhost->keepalive_timeout ?
1293d4afb5ceSopenharmony_ci				    wsi->a.vhost->keepalive_timeout : 31);
1294d4afb5ceSopenharmony_ci}
1295d4afb5ceSopenharmony_ci
1296d4afb5ceSopenharmony_civoid
1297d4afb5ceSopenharmony_cilws_mux_mark_immortal(struct lws *wsi)
1298d4afb5ceSopenharmony_ci{
1299d4afb5ceSopenharmony_ci	struct lws *nwsi;
1300d4afb5ceSopenharmony_ci
1301d4afb5ceSopenharmony_ci	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1302d4afb5ceSopenharmony_ci
1303d4afb5ceSopenharmony_ci	if (!wsi->mux_substream
1304d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1305d4afb5ceSopenharmony_ci			&& !wsi->client_mux_substream
1306d4afb5ceSopenharmony_ci#endif
1307d4afb5ceSopenharmony_ci	) {
1308d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "not mux substream");
1309d4afb5ceSopenharmony_ci		return;
1310d4afb5ceSopenharmony_ci	}
1311d4afb5ceSopenharmony_ci
1312d4afb5ceSopenharmony_ci	if (wsi->mux_stream_immortal)
1313d4afb5ceSopenharmony_ci		/* only need to handle it once per child wsi */
1314d4afb5ceSopenharmony_ci		return;
1315d4afb5ceSopenharmony_ci
1316d4afb5ceSopenharmony_ci	nwsi = lws_get_network_wsi(wsi);
1317d4afb5ceSopenharmony_ci	if (!nwsi)
1318d4afb5ceSopenharmony_ci		return;
1319d4afb5ceSopenharmony_ci
1320d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "%s (%d)\n", lws_wsi_tag(nwsi),
1321d4afb5ceSopenharmony_ci				    nwsi->immortal_substream_count);
1322d4afb5ceSopenharmony_ci
1323d4afb5ceSopenharmony_ci	wsi->mux_stream_immortal = 1;
1324d4afb5ceSopenharmony_ci	assert(nwsi->immortal_substream_count < 255); /* largest count */
1325d4afb5ceSopenharmony_ci	nwsi->immortal_substream_count++;
1326d4afb5ceSopenharmony_ci	if (nwsi->immortal_substream_count == 1)
1327d4afb5ceSopenharmony_ci		lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
1328d4afb5ceSopenharmony_ci}
1329d4afb5ceSopenharmony_ci
1330d4afb5ceSopenharmony_ciint
1331d4afb5ceSopenharmony_cilws_http_mark_sse(struct lws *wsi)
1332d4afb5ceSopenharmony_ci{
1333d4afb5ceSopenharmony_ci	if (!wsi)
1334d4afb5ceSopenharmony_ci		return 0;
1335d4afb5ceSopenharmony_ci
1336d4afb5ceSopenharmony_ci	lws_http_headers_detach(wsi);
1337d4afb5ceSopenharmony_ci	lws_mux_mark_immortal(wsi);
1338d4afb5ceSopenharmony_ci
1339d4afb5ceSopenharmony_ci	if (wsi->mux_substream)
1340d4afb5ceSopenharmony_ci		wsi->h2_stream_carries_sse = 1;
1341d4afb5ceSopenharmony_ci
1342d4afb5ceSopenharmony_ci	return 0;
1343d4afb5ceSopenharmony_ci}
1344d4afb5ceSopenharmony_ci
1345d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1346d4afb5ceSopenharmony_ci
1347d4afb5ceSopenharmony_ciconst char *
1348d4afb5ceSopenharmony_cilws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx)
1349d4afb5ceSopenharmony_ci{
1350d4afb5ceSopenharmony_ci	/* try the generic client stash */
1351d4afb5ceSopenharmony_ci	if (wsi->stash)
1352d4afb5ceSopenharmony_ci		return wsi->stash->cis[stash_idx];
1353d4afb5ceSopenharmony_ci
1354d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1355d4afb5ceSopenharmony_ci	/* if not, use the ah stash if applicable */
1356d4afb5ceSopenharmony_ci	return lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)hdr_idx);
1357d4afb5ceSopenharmony_ci#else
1358d4afb5ceSopenharmony_ci	return NULL;
1359d4afb5ceSopenharmony_ci#endif
1360d4afb5ceSopenharmony_ci}
1361d4afb5ceSopenharmony_ci#endif
1362d4afb5ceSopenharmony_ci
1363d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
1364d4afb5ceSopenharmony_ci
1365d4afb5ceSopenharmony_civoid
1366d4afb5ceSopenharmony_cilws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, unsigned int sid)
1367d4afb5ceSopenharmony_ci{
1368d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "par %s: assign sid %d (curr %d)",
1369d4afb5ceSopenharmony_ci			lws_wsi_tag(parent_wsi), sid, wsi->mux.my_sid);
1370d4afb5ceSopenharmony_ci
1371d4afb5ceSopenharmony_ci	if (wsi->mux.my_sid && wsi->mux.my_sid != (unsigned int)sid)
1372d4afb5ceSopenharmony_ci		assert(0);
1373d4afb5ceSopenharmony_ci
1374d4afb5ceSopenharmony_ci	wsi->mux.my_sid = sid;
1375d4afb5ceSopenharmony_ci	wsi->mux.parent_wsi = parent_wsi;
1376d4afb5ceSopenharmony_ci	wsi->role_ops = parent_wsi->role_ops;
1377d4afb5ceSopenharmony_ci
1378d4afb5ceSopenharmony_ci	/* new guy's sibling is whoever was the first child before */
1379d4afb5ceSopenharmony_ci	wsi->mux.sibling_list = parent_wsi->mux.child_list;
1380d4afb5ceSopenharmony_ci
1381d4afb5ceSopenharmony_ci	/* first child is now the new guy */
1382d4afb5ceSopenharmony_ci	parent_wsi->mux.child_list = wsi;
1383d4afb5ceSopenharmony_ci
1384d4afb5ceSopenharmony_ci	parent_wsi->mux.child_count++;
1385d4afb5ceSopenharmony_ci}
1386d4afb5ceSopenharmony_ci
1387d4afb5ceSopenharmony_cistruct lws *
1388d4afb5ceSopenharmony_cilws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid)
1389d4afb5ceSopenharmony_ci{
1390d4afb5ceSopenharmony_ci	lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) {
1391d4afb5ceSopenharmony_ci		if (wsi->mux.my_sid == sid)
1392d4afb5ceSopenharmony_ci			return wsi;
1393d4afb5ceSopenharmony_ci	} lws_end_foreach_ll(wsi, mux.sibling_list);
1394d4afb5ceSopenharmony_ci
1395d4afb5ceSopenharmony_ci	return NULL;
1396d4afb5ceSopenharmony_ci}
1397d4afb5ceSopenharmony_ci
1398d4afb5ceSopenharmony_civoid
1399d4afb5ceSopenharmony_cilws_wsi_mux_dump_children(struct lws *wsi)
1400d4afb5ceSopenharmony_ci{
1401d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1402d4afb5ceSopenharmony_ci	if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO))
1403d4afb5ceSopenharmony_ci		return;
1404d4afb5ceSopenharmony_ci
1405d4afb5ceSopenharmony_ci	lws_start_foreach_llp(struct lws **, w,
1406d4afb5ceSopenharmony_ci			      wsi->mux.parent_wsi->mux.child_list) {
1407d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "   \\---- child %s %s\n",
1408d4afb5ceSopenharmony_ci				   (*w)->role_ops ? (*w)->role_ops->name : "?",
1409d4afb5ceSopenharmony_ci							   lws_wsi_tag(*w));
1410d4afb5ceSopenharmony_ci		assert(*w != (*w)->mux.sibling_list);
1411d4afb5ceSopenharmony_ci	} lws_end_foreach_llp(w, mux.sibling_list);
1412d4afb5ceSopenharmony_ci#endif
1413d4afb5ceSopenharmony_ci}
1414d4afb5ceSopenharmony_ci
1415d4afb5ceSopenharmony_civoid
1416d4afb5ceSopenharmony_cilws_wsi_mux_close_children(struct lws *wsi, int reason)
1417d4afb5ceSopenharmony_ci{
1418d4afb5ceSopenharmony_ci	struct lws *wsi2;
1419d4afb5ceSopenharmony_ci	struct lws **w;
1420d4afb5ceSopenharmony_ci
1421d4afb5ceSopenharmony_ci	if (!wsi->mux.child_list)
1422d4afb5ceSopenharmony_ci		return;
1423d4afb5ceSopenharmony_ci
1424d4afb5ceSopenharmony_ci	w = &wsi->mux.child_list;
1425d4afb5ceSopenharmony_ci	while (*w) {
1426d4afb5ceSopenharmony_ci		lwsl_wsi_info((*w), "   closing child");
1427d4afb5ceSopenharmony_ci		/* disconnect from siblings */
1428d4afb5ceSopenharmony_ci		wsi2 = (*w)->mux.sibling_list;
1429d4afb5ceSopenharmony_ci		assert (wsi2 != *w);
1430d4afb5ceSopenharmony_ci		(*w)->mux.sibling_list = NULL;
1431d4afb5ceSopenharmony_ci		(*w)->socket_is_permanently_unusable = 1;
1432d4afb5ceSopenharmony_ci		__lws_close_free_wsi(*w, (enum lws_close_status)reason, "mux child recurse");
1433d4afb5ceSopenharmony_ci		*w = wsi2;
1434d4afb5ceSopenharmony_ci	}
1435d4afb5ceSopenharmony_ci}
1436d4afb5ceSopenharmony_ci
1437d4afb5ceSopenharmony_ci
1438d4afb5ceSopenharmony_civoid
1439d4afb5ceSopenharmony_cilws_wsi_mux_sibling_disconnect(struct lws *wsi)
1440d4afb5ceSopenharmony_ci{
1441d4afb5ceSopenharmony_ci	struct lws *wsi2;
1442d4afb5ceSopenharmony_ci
1443d4afb5ceSopenharmony_ci	lws_start_foreach_llp(struct lws **, w,
1444d4afb5ceSopenharmony_ci			      wsi->mux.parent_wsi->mux.child_list) {
1445d4afb5ceSopenharmony_ci
1446d4afb5ceSopenharmony_ci		/* disconnect from siblings */
1447d4afb5ceSopenharmony_ci		if (*w == wsi) {
1448d4afb5ceSopenharmony_ci			wsi2 = (*w)->mux.sibling_list;
1449d4afb5ceSopenharmony_ci			(*w)->mux.sibling_list = NULL;
1450d4afb5ceSopenharmony_ci			*w = wsi2;
1451d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, " disentangled from sibling %s",
1452d4afb5ceSopenharmony_ci					    lws_wsi_tag(wsi2));
1453d4afb5ceSopenharmony_ci			break;
1454d4afb5ceSopenharmony_ci		}
1455d4afb5ceSopenharmony_ci	} lws_end_foreach_llp(w, mux.sibling_list);
1456d4afb5ceSopenharmony_ci	wsi->mux.parent_wsi->mux.child_count--;
1457d4afb5ceSopenharmony_ci
1458d4afb5ceSopenharmony_ci	wsi->mux.parent_wsi = NULL;
1459d4afb5ceSopenharmony_ci}
1460d4afb5ceSopenharmony_ci
1461d4afb5ceSopenharmony_civoid
1462d4afb5ceSopenharmony_cilws_wsi_mux_dump_waiting_children(struct lws *wsi)
1463d4afb5ceSopenharmony_ci{
1464d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1465d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: children waiting for POLLOUT service:\n",
1466d4afb5ceSopenharmony_ci		  __func__, lws_wsi_tag(wsi));
1467d4afb5ceSopenharmony_ci
1468d4afb5ceSopenharmony_ci	wsi = wsi->mux.child_list;
1469d4afb5ceSopenharmony_ci	while (wsi) {
1470d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "  %c sid %u: 0x%x %s %s",
1471d4afb5ceSopenharmony_ci			  wsi->mux.requested_POLLOUT ? '*' : ' ',
1472d4afb5ceSopenharmony_ci			  wsi->mux.my_sid, lwsi_state(wsi),
1473d4afb5ceSopenharmony_ci			  wsi->role_ops->name,
1474d4afb5ceSopenharmony_ci			  wsi->a.protocol ? wsi->a.protocol->name : "noprotocol");
1475d4afb5ceSopenharmony_ci
1476d4afb5ceSopenharmony_ci		wsi = wsi->mux.sibling_list;
1477d4afb5ceSopenharmony_ci	}
1478d4afb5ceSopenharmony_ci#endif
1479d4afb5ceSopenharmony_ci}
1480d4afb5ceSopenharmony_ci
1481d4afb5ceSopenharmony_ciint
1482d4afb5ceSopenharmony_cilws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi)
1483d4afb5ceSopenharmony_ci{
1484d4afb5ceSopenharmony_ci	struct lws /* *network_wsi = lws_get_network_wsi(wsi), */ *wsi2;
1485d4afb5ceSopenharmony_ci	//int already = network_wsi->mux.requested_POLLOUT;
1486d4afb5ceSopenharmony_ci
1487d4afb5ceSopenharmony_ci	/* mark everybody above him as requesting pollout */
1488d4afb5ceSopenharmony_ci
1489d4afb5ceSopenharmony_ci	wsi2 = wsi;
1490d4afb5ceSopenharmony_ci	while (wsi2) {
1491d4afb5ceSopenharmony_ci		wsi2->mux.requested_POLLOUT = 1;
1492d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi2, "sid %u, pending writable",
1493d4afb5ceSopenharmony_ci							wsi2->mux.my_sid);
1494d4afb5ceSopenharmony_ci		wsi2 = wsi2->mux.parent_wsi;
1495d4afb5ceSopenharmony_ci	}
1496d4afb5ceSopenharmony_ci
1497d4afb5ceSopenharmony_ci	return 0; // already;
1498d4afb5ceSopenharmony_ci}
1499d4afb5ceSopenharmony_ci
1500d4afb5ceSopenharmony_cistruct lws *
1501d4afb5ceSopenharmony_cilws_wsi_mux_move_child_to_tail(struct lws **wsi2)
1502d4afb5ceSopenharmony_ci{
1503d4afb5ceSopenharmony_ci	struct lws *w = *wsi2;
1504d4afb5ceSopenharmony_ci
1505d4afb5ceSopenharmony_ci	while (w) {
1506d4afb5ceSopenharmony_ci		if (!w->mux.sibling_list) { /* w is the current last */
1507d4afb5ceSopenharmony_ci			lwsl_wsi_debug(w, "*wsi2 = %s\n", lws_wsi_tag(*wsi2));
1508d4afb5ceSopenharmony_ci
1509d4afb5ceSopenharmony_ci			if (w == *wsi2) /* we are already last */
1510d4afb5ceSopenharmony_ci				break;
1511d4afb5ceSopenharmony_ci
1512d4afb5ceSopenharmony_ci			/* last points to us as new last */
1513d4afb5ceSopenharmony_ci			w->mux.sibling_list = *wsi2;
1514d4afb5ceSopenharmony_ci
1515d4afb5ceSopenharmony_ci			/* guy pointing to us until now points to
1516d4afb5ceSopenharmony_ci			 * our old next */
1517d4afb5ceSopenharmony_ci			*wsi2 = (*wsi2)->mux.sibling_list;
1518d4afb5ceSopenharmony_ci
1519d4afb5ceSopenharmony_ci			/* we point to nothing because we are last */
1520d4afb5ceSopenharmony_ci			w->mux.sibling_list->mux.sibling_list = NULL;
1521d4afb5ceSopenharmony_ci
1522d4afb5ceSopenharmony_ci			/* w becomes us */
1523d4afb5ceSopenharmony_ci			w = w->mux.sibling_list;
1524d4afb5ceSopenharmony_ci			break;
1525d4afb5ceSopenharmony_ci		}
1526d4afb5ceSopenharmony_ci		w = w->mux.sibling_list;
1527d4afb5ceSopenharmony_ci	}
1528d4afb5ceSopenharmony_ci
1529d4afb5ceSopenharmony_ci	/* clear the waiting for POLLOUT on the guy that was chosen */
1530d4afb5ceSopenharmony_ci
1531d4afb5ceSopenharmony_ci	if (w)
1532d4afb5ceSopenharmony_ci		w->mux.requested_POLLOUT = 0;
1533d4afb5ceSopenharmony_ci
1534d4afb5ceSopenharmony_ci	return w;
1535d4afb5ceSopenharmony_ci}
1536d4afb5ceSopenharmony_ci
1537d4afb5ceSopenharmony_ciint
1538d4afb5ceSopenharmony_cilws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi)
1539d4afb5ceSopenharmony_ci{
1540d4afb5ceSopenharmony_ci	struct lws *w = wsi->mux.child_list;
1541d4afb5ceSopenharmony_ci
1542d4afb5ceSopenharmony_ci	while (w) {
1543d4afb5ceSopenharmony_ci		if (w->mux.requested_POLLOUT) {
1544d4afb5ceSopenharmony_ci			if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
1545d4afb5ceSopenharmony_ci				return -1;
1546d4afb5ceSopenharmony_ci			return 0;
1547d4afb5ceSopenharmony_ci		}
1548d4afb5ceSopenharmony_ci		w = w->mux.sibling_list;
1549d4afb5ceSopenharmony_ci	}
1550d4afb5ceSopenharmony_ci
1551d4afb5ceSopenharmony_ci	if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
1552d4afb5ceSopenharmony_ci		return -1;
1553d4afb5ceSopenharmony_ci
1554d4afb5ceSopenharmony_ci	return 0;
1555d4afb5ceSopenharmony_ci}
1556d4afb5ceSopenharmony_ci
1557d4afb5ceSopenharmony_ciint
1558d4afb5ceSopenharmony_cilws_wsi_txc_check_skint(struct lws_tx_credit *txc, int32_t tx_cr)
1559d4afb5ceSopenharmony_ci{
1560d4afb5ceSopenharmony_ci	if (txc->tx_cr <= 0) {
1561d4afb5ceSopenharmony_ci		/*
1562d4afb5ceSopenharmony_ci		 * If other side is not able to cope with us sending any DATA
1563d4afb5ceSopenharmony_ci		 * so no matter if we have POLLOUT on our side if it's DATA we
1564d4afb5ceSopenharmony_ci		 * want to send.
1565d4afb5ceSopenharmony_ci		 */
1566d4afb5ceSopenharmony_ci
1567d4afb5ceSopenharmony_ci		if (!txc->skint)
1568d4afb5ceSopenharmony_ci			lwsl_info("%s: %p: skint (%d)\n", __func__, txc,
1569d4afb5ceSopenharmony_ci				  (int)txc->tx_cr);
1570d4afb5ceSopenharmony_ci
1571d4afb5ceSopenharmony_ci		txc->skint = 1;
1572d4afb5ceSopenharmony_ci
1573d4afb5ceSopenharmony_ci		return 1;
1574d4afb5ceSopenharmony_ci	}
1575d4afb5ceSopenharmony_ci
1576d4afb5ceSopenharmony_ci	if (txc->skint)
1577d4afb5ceSopenharmony_ci		lwsl_info("%s: %p: unskint (%d)\n", __func__, txc,
1578d4afb5ceSopenharmony_ci			  (int)txc->tx_cr);
1579d4afb5ceSopenharmony_ci
1580d4afb5ceSopenharmony_ci	txc->skint = 0;
1581d4afb5ceSopenharmony_ci
1582d4afb5ceSopenharmony_ci	return 0;
1583d4afb5ceSopenharmony_ci}
1584d4afb5ceSopenharmony_ci
1585d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1586d4afb5ceSopenharmony_civoid
1587d4afb5ceSopenharmony_cilws_wsi_txc_describe(struct lws_tx_credit *txc, const char *at, uint32_t sid)
1588d4afb5ceSopenharmony_ci{
1589d4afb5ceSopenharmony_ci	lwsl_info("%s: %p: %s: sid %d: %speer-to-us: %d, us-to-peer: %d\n",
1590d4afb5ceSopenharmony_ci		  __func__, txc, at, (int)sid, txc->skint ? "SKINT, " : "",
1591d4afb5ceSopenharmony_ci		  (int)txc->peer_tx_cr_est, (int)txc->tx_cr);
1592d4afb5ceSopenharmony_ci}
1593d4afb5ceSopenharmony_ci#endif
1594d4afb5ceSopenharmony_ci
1595d4afb5ceSopenharmony_ciint
1596d4afb5ceSopenharmony_cilws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add)
1597d4afb5ceSopenharmony_ci{
1598d4afb5ceSopenharmony_ci	if (wsi->role_ops && lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit))
1599d4afb5ceSopenharmony_ci		return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit).
1600d4afb5ceSopenharmony_ci				   tx_credit(wsi, peer_to_us, add);
1601d4afb5ceSopenharmony_ci
1602d4afb5ceSopenharmony_ci	return 0;
1603d4afb5ceSopenharmony_ci}
1604d4afb5ceSopenharmony_ci
1605d4afb5ceSopenharmony_ci/*
1606d4afb5ceSopenharmony_ci * Let the protocol know about incoming tx credit window updates if it's
1607d4afb5ceSopenharmony_ci * managing the flow control manually (it may want to proxy this information)
1608d4afb5ceSopenharmony_ci */
1609d4afb5ceSopenharmony_ci
1610d4afb5ceSopenharmony_ciint
1611d4afb5ceSopenharmony_cilws_wsi_txc_report_manual_txcr_in(struct lws *wsi, int32_t bump)
1612d4afb5ceSopenharmony_ci{
1613d4afb5ceSopenharmony_ci	if (!wsi->txc.manual)
1614d4afb5ceSopenharmony_ci		/*
1615d4afb5ceSopenharmony_ci		 * If we don't care about managing it manually, no need to
1616d4afb5ceSopenharmony_ci		 * report it
1617d4afb5ceSopenharmony_ci		 */
1618d4afb5ceSopenharmony_ci		return 0;
1619d4afb5ceSopenharmony_ci
1620d4afb5ceSopenharmony_ci	return user_callback_handle_rxflow(wsi->a.protocol->callback,
1621d4afb5ceSopenharmony_ci					   wsi, LWS_CALLBACK_WSI_TX_CREDIT_GET,
1622d4afb5ceSopenharmony_ci					   wsi->user_space, NULL, (size_t)bump);
1623d4afb5ceSopenharmony_ci}
1624d4afb5ceSopenharmony_ci
1625d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1626d4afb5ceSopenharmony_ci
1627d4afb5ceSopenharmony_ciint
1628d4afb5ceSopenharmony_cilws_wsi_mux_apply_queue(struct lws *wsi)
1629d4afb5ceSopenharmony_ci{
1630d4afb5ceSopenharmony_ci	/* we have a transaction queue that wants to pipeline */
1631d4afb5ceSopenharmony_ci
1632d4afb5ceSopenharmony_ci	lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
1633d4afb5ceSopenharmony_ci	lws_vhost_lock(wsi->a.vhost);
1634d4afb5ceSopenharmony_ci
1635d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1636d4afb5ceSopenharmony_ci				   wsi->dll2_cli_txn_queue_owner.head) {
1637d4afb5ceSopenharmony_ci		struct lws *w = lws_container_of(d, struct lws,
1638d4afb5ceSopenharmony_ci						 dll2_cli_txn_queue);
1639d4afb5ceSopenharmony_ci
1640d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
1641d4afb5ceSopenharmony_ci		if (lwsi_role_http(wsi) &&
1642d4afb5ceSopenharmony_ci		    lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
1643d4afb5ceSopenharmony_ci			lwsl_wsi_info(w, "cli pipeq to be h2");
1644d4afb5ceSopenharmony_ci
1645d4afb5ceSopenharmony_ci			lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
1646d4afb5ceSopenharmony_ci
1647d4afb5ceSopenharmony_ci			/* remove ourselves from client queue */
1648d4afb5ceSopenharmony_ci			lws_dll2_remove(&w->dll2_cli_txn_queue);
1649d4afb5ceSopenharmony_ci
1650d4afb5ceSopenharmony_ci			/* attach ourselves as an h2 stream */
1651d4afb5ceSopenharmony_ci			lws_wsi_h2_adopt(wsi, w);
1652d4afb5ceSopenharmony_ci		}
1653d4afb5ceSopenharmony_ci#endif
1654d4afb5ceSopenharmony_ci
1655d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
1656d4afb5ceSopenharmony_ci		if (lwsi_role_mqtt(wsi) &&
1657d4afb5ceSopenharmony_ci		    lwsi_state(wsi) == LRS_ESTABLISHED) {
1658d4afb5ceSopenharmony_ci			lwsl_wsi_info(w, "cli pipeq to be mqtt\n");
1659d4afb5ceSopenharmony_ci
1660d4afb5ceSopenharmony_ci			/* remove ourselves from client queue */
1661d4afb5ceSopenharmony_ci			lws_dll2_remove(&w->dll2_cli_txn_queue);
1662d4afb5ceSopenharmony_ci
1663d4afb5ceSopenharmony_ci			/* attach ourselves as an h2 stream */
1664d4afb5ceSopenharmony_ci			lws_wsi_mqtt_adopt(wsi, w);
1665d4afb5ceSopenharmony_ci		}
1666d4afb5ceSopenharmony_ci#endif
1667d4afb5ceSopenharmony_ci
1668d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(d, d1);
1669d4afb5ceSopenharmony_ci
1670d4afb5ceSopenharmony_ci	lws_vhost_unlock(wsi->a.vhost);
1671d4afb5ceSopenharmony_ci	lws_context_unlock(wsi->a.context); /* } cx --------------  */
1672d4afb5ceSopenharmony_ci
1673d4afb5ceSopenharmony_ci	return 0;
1674d4afb5ceSopenharmony_ci}
1675d4afb5ceSopenharmony_ci
1676d4afb5ceSopenharmony_ci#endif
1677d4afb5ceSopenharmony_ci
1678d4afb5ceSopenharmony_ci#endif
1679