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_cistatic int
28d4afb5ceSopenharmony_cilws_get_idlest_tsi(struct lws_context *context)
29d4afb5ceSopenharmony_ci{
30d4afb5ceSopenharmony_ci	unsigned int lowest = ~0u;
31d4afb5ceSopenharmony_ci	int n = 0, hit = -1;
32d4afb5ceSopenharmony_ci
33d4afb5ceSopenharmony_ci	for (; n < context->count_threads; n++) {
34d4afb5ceSopenharmony_ci		lwsl_cx_debug(context, "%d %d\n", context->pt[n].fds_count,
35d4afb5ceSopenharmony_ci				context->fd_limit_per_thread - 1);
36d4afb5ceSopenharmony_ci		if ((unsigned int)context->pt[n].fds_count !=
37d4afb5ceSopenharmony_ci		    context->fd_limit_per_thread - 1 &&
38d4afb5ceSopenharmony_ci		    (unsigned int)context->pt[n].fds_count < lowest) {
39d4afb5ceSopenharmony_ci			lowest = context->pt[n].fds_count;
40d4afb5ceSopenharmony_ci			hit = n;
41d4afb5ceSopenharmony_ci		}
42d4afb5ceSopenharmony_ci	}
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	return hit;
45d4afb5ceSopenharmony_ci}
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_cistruct lws *
48d4afb5ceSopenharmony_cilws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *desc)
49d4afb5ceSopenharmony_ci{
50d4afb5ceSopenharmony_ci	struct lws *new_wsi;
51d4afb5ceSopenharmony_ci	int n = fixed_tsi;
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci	if (n < 0)
54d4afb5ceSopenharmony_ci		n = lws_get_idlest_tsi(vhost->context);
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci	if (n < 0) {
57d4afb5ceSopenharmony_ci		lwsl_vhost_err(vhost, "no space for new conn");
58d4afb5ceSopenharmony_ci		return NULL;
59d4afb5ceSopenharmony_ci	}
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_ci	lws_context_lock(vhost->context, __func__);
62d4afb5ceSopenharmony_ci	new_wsi = __lws_wsi_create_with_role(vhost->context, n, NULL,
63d4afb5ceSopenharmony_ci					     vhost->lc.log_cx);
64d4afb5ceSopenharmony_ci	lws_context_unlock(vhost->context);
65d4afb5ceSopenharmony_ci	if (new_wsi == NULL) {
66d4afb5ceSopenharmony_ci		lwsl_vhost_err(vhost, "OOM");
67d4afb5ceSopenharmony_ci		return NULL;
68d4afb5ceSopenharmony_ci	}
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci	lws_wsi_fault_timedclose(new_wsi);
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci	__lws_lc_tag(vhost->context, &vhost->context->lcg[
73d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
74d4afb5ceSopenharmony_ci	strcmp(desc, "adopted") ? LWSLCG_WSI_MUX :
75d4afb5ceSopenharmony_ci#endif
76d4afb5ceSopenharmony_ci	LWSLCG_WSI_SERVER], &new_wsi->lc, desc);
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	new_wsi->wsistate |= LWSIFR_SERVER;
79d4afb5ceSopenharmony_ci	new_wsi->tsi = (char)n;
80d4afb5ceSopenharmony_ci	lwsl_wsi_debug(new_wsi, "joining vh %s, tsi %d",
81d4afb5ceSopenharmony_ci			vhost->name, new_wsi->tsi);
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci	lws_vhost_bind_wsi(vhost, new_wsi);
84d4afb5ceSopenharmony_ci	new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
85d4afb5ceSopenharmony_ci	new_wsi->retry_policy = vhost->retry_policy;
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	/* initialize the instance struct */
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	lwsi_set_state(new_wsi, LRS_UNCONNECTED);
90d4afb5ceSopenharmony_ci	new_wsi->hdr_parsing_completed = 0;
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci#ifdef LWS_WITH_TLS
93d4afb5ceSopenharmony_ci	new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost);
94d4afb5ceSopenharmony_ci#endif
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci	/*
97d4afb5ceSopenharmony_ci	 * these can only be set once the protocol is known
98d4afb5ceSopenharmony_ci	 * we set an un-established connection's protocol pointer
99d4afb5ceSopenharmony_ci	 * to the start of the supported list, so it can look
100d4afb5ceSopenharmony_ci	 * for matching ones during the handshake
101d4afb5ceSopenharmony_ci	 */
102d4afb5ceSopenharmony_ci	new_wsi->a.protocol = vhost->protocols;
103d4afb5ceSopenharmony_ci	new_wsi->user_space = NULL;
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci	/*
106d4afb5ceSopenharmony_ci	 * outermost create notification for wsi
107d4afb5ceSopenharmony_ci	 * no user_space because no protocol selection
108d4afb5ceSopenharmony_ci	 */
109d4afb5ceSopenharmony_ci	vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL,
110d4afb5ceSopenharmony_ci				     NULL, 0);
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci	return new_wsi;
113d4afb5ceSopenharmony_ci}
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci/* if not a socket, it's a raw, non-ssl file descriptor
117d4afb5ceSopenharmony_ci * req cx lock, acq pt lock, acq vh lock
118d4afb5ceSopenharmony_ci */
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_cistatic struct lws *
121d4afb5ceSopenharmony_ci__lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
122d4afb5ceSopenharmony_ci			    const char *vh_prot_name, struct lws *parent,
123d4afb5ceSopenharmony_ci			    void *opaque, const char *fi_wsi_name)
124d4afb5ceSopenharmony_ci{
125d4afb5ceSopenharmony_ci	struct lws_context *context;
126d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
127d4afb5ceSopenharmony_ci	struct lws *new_wsi;
128d4afb5ceSopenharmony_ci	int n;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci	/*
131d4afb5ceSopenharmony_ci	 * Notice that in SMP case, the wsi may be being created on an
132d4afb5ceSopenharmony_ci	 * entirely different pt / tsi for load balancing.  In that case as
133d4afb5ceSopenharmony_ci	 * we initialize it, it may become "live" concurrently unexpectedly...
134d4afb5ceSopenharmony_ci	 */
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci	if (!vh)
137d4afb5ceSopenharmony_ci		return NULL;
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci	context = vh->context;
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	lws_context_assert_lock_held(vh->context);
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	n = -1;
144d4afb5ceSopenharmony_ci	if (parent)
145d4afb5ceSopenharmony_ci		n = parent->tsi;
146d4afb5ceSopenharmony_ci	new_wsi = lws_create_new_server_wsi(vh, n, "adopted");
147d4afb5ceSopenharmony_ci	if (!new_wsi)
148d4afb5ceSopenharmony_ci		return NULL;
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	/* bring in specific fault injection rules early */
151d4afb5ceSopenharmony_ci	lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name);
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	if (lws_fi(&new_wsi->fic, "createfail")) {
154d4afb5ceSopenharmony_ci		lws_fi_destroy(&new_wsi->fic);
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci		return NULL;
157d4afb5ceSopenharmony_ci	}
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci	new_wsi->a.opaque_user_data = opaque;
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	pt = &context->pt[(int)new_wsi->tsi];
162d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci	if (parent) {
165d4afb5ceSopenharmony_ci		new_wsi->parent = parent;
166d4afb5ceSopenharmony_ci		new_wsi->sibling_list = parent->child_list;
167d4afb5ceSopenharmony_ci		parent->child_list = new_wsi;
168d4afb5ceSopenharmony_ci	}
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci	if (vh_prot_name) {
171d4afb5ceSopenharmony_ci		new_wsi->a.protocol = lws_vhost_name_to_protocol(new_wsi->a.vhost,
172d4afb5ceSopenharmony_ci							       vh_prot_name);
173d4afb5ceSopenharmony_ci		if (!new_wsi->a.protocol) {
174d4afb5ceSopenharmony_ci			lwsl_vhost_err(new_wsi->a.vhost, "Protocol %s not enabled",
175d4afb5ceSopenharmony_ci						      vh_prot_name);
176d4afb5ceSopenharmony_ci			goto bail;
177d4afb5ceSopenharmony_ci		}
178d4afb5ceSopenharmony_ci		if (lws_ensure_user_space(new_wsi)) {
179d4afb5ceSopenharmony_ci			lwsl_wsi_notice(new_wsi, "OOM");
180d4afb5ceSopenharmony_ci			goto bail;
181d4afb5ceSopenharmony_ci		}
182d4afb5ceSopenharmony_ci	}
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
185d4afb5ceSopenharmony_ci	    !(type & LWS_ADOPT_SOCKET))
186d4afb5ceSopenharmony_ci		type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci	if (lws_role_call_adoption_bind(new_wsi, (int)type, vh_prot_name)) {
189d4afb5ceSopenharmony_ci		lwsl_wsi_err(new_wsi, "no role for desc type 0x%x", type);
190d4afb5ceSopenharmony_ci		goto bail;
191d4afb5ceSopenharmony_ci	}
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
194d4afb5ceSopenharmony_ci	if (new_wsi->role_ops) {
195d4afb5ceSopenharmony_ci		lws_metrics_tag_wsi_add(new_wsi, "role", new_wsi->role_ops->name);
196d4afb5ceSopenharmony_ci	}
197d4afb5ceSopenharmony_ci#endif
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	/*
202d4afb5ceSopenharmony_ci	 * he's an allocated wsi, but he's not on any fds list or child list,
203d4afb5ceSopenharmony_ci	 * join him to the vhost's list of these kinds of incomplete wsi until
204d4afb5ceSopenharmony_ci	 * he gets another identity (he may do async dns now...)
205d4afb5ceSopenharmony_ci	 */
206d4afb5ceSopenharmony_ci	lws_vhost_lock(new_wsi->a.vhost);
207d4afb5ceSopenharmony_ci	lws_dll2_add_head(&new_wsi->vh_awaiting_socket,
208d4afb5ceSopenharmony_ci			  &new_wsi->a.vhost->vh_awaiting_socket_owner);
209d4afb5ceSopenharmony_ci	lws_vhost_unlock(new_wsi->a.vhost);
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_ci	return new_wsi;
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_cibail:
214d4afb5ceSopenharmony_ci	lwsl_wsi_notice(new_wsi, "exiting on bail");
215d4afb5ceSopenharmony_ci	if (parent)
216d4afb5ceSopenharmony_ci		parent->child_list = new_wsi->sibling_list;
217d4afb5ceSopenharmony_ci	if (new_wsi->user_space)
218d4afb5ceSopenharmony_ci		lws_free(new_wsi->user_space);
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	lws_fi_destroy(&new_wsi->fic);
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
223d4afb5ceSopenharmony_ci	__lws_vhost_unbind_wsi(new_wsi); /* req cx, acq vh lock */
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	lws_free(new_wsi);
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_ci	return NULL;
228d4afb5ceSopenharmony_ci}
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_ci/*
233d4afb5ceSopenharmony_ci * If the incoming wsi is bound to a vhost that is a ss server, this creates
234d4afb5ceSopenharmony_ci * an accepted ss bound to the wsi.
235d4afb5ceSopenharmony_ci *
236d4afb5ceSopenharmony_ci * For h1 or raw, we can do the binding here, but for muxed protocols like h2
237d4afb5ceSopenharmony_ci * or mqtt we have to do it not on the nwsi but on the stream.  And for h2 we
238d4afb5ceSopenharmony_ci * start off bound to h1 role, since we don't know if we will upgrade to h2
239d4afb5ceSopenharmony_ci * until we meet the server.
240d4afb5ceSopenharmony_ci *
241d4afb5ceSopenharmony_ci * 1) No tls is assumed to mean no muxed protocol so can do it at adopt.
242d4afb5ceSopenharmony_ci *
243d4afb5ceSopenharmony_ci * 2) After alpn if not muxed we can do it.
244d4afb5ceSopenharmony_ci *
245d4afb5ceSopenharmony_ci * 3) For muxed, do it at the nwsi migration and on new stream
246d4afb5ceSopenharmony_ci */
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ciint
249d4afb5ceSopenharmony_cilws_adopt_ss_server_accept(struct lws *new_wsi)
250d4afb5ceSopenharmony_ci{
251d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt =
252d4afb5ceSopenharmony_ci			&new_wsi->a.context->pt[(int)new_wsi->tsi];
253d4afb5ceSopenharmony_ci	lws_ss_handle_t *h;
254d4afb5ceSopenharmony_ci	void *pv, **ppv;
255d4afb5ceSopenharmony_ci
256d4afb5ceSopenharmony_ci	if (!new_wsi->a.vhost->ss_handle)
257d4afb5ceSopenharmony_ci		return 0;
258d4afb5ceSopenharmony_ci
259d4afb5ceSopenharmony_ci	pv = (char *)&new_wsi->a.vhost->ss_handle[1];
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci	/*
262d4afb5ceSopenharmony_ci	 * Yes... the vhost is pointing to its secure stream representing the
263d4afb5ceSopenharmony_ci	 * server... we want to create an accepted SS and bind it to new_wsi,
264d4afb5ceSopenharmony_ci	 * the info/ssi from the server SS (so the SS callbacks defined there),
265d4afb5ceSopenharmony_ci	 * the opaque_user_data of the server object and the policy of it.
266d4afb5ceSopenharmony_ci	 */
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci	ppv = (void **)((char *)pv +
269d4afb5ceSopenharmony_ci	      new_wsi->a.vhost->ss_handle->info.opaque_user_data_offset);
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	/*
272d4afb5ceSopenharmony_ci	 * indicate we are an accepted connection referencing the
273d4afb5ceSopenharmony_ci	 * server object
274d4afb5ceSopenharmony_ci	 */
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci	new_wsi->a.vhost->ss_handle->info.flags |= LWSSSINFLAGS_SERVER;
277d4afb5ceSopenharmony_ci
278d4afb5ceSopenharmony_ci	if (lws_ss_create(new_wsi->a.context, new_wsi->tsi,
279d4afb5ceSopenharmony_ci			  &new_wsi->a.vhost->ss_handle->info,
280d4afb5ceSopenharmony_ci			  *ppv, &h, NULL, NULL)) {
281d4afb5ceSopenharmony_ci		lwsl_wsi_err(new_wsi, "accept ss creation failed");
282d4afb5ceSopenharmony_ci		goto fail1;
283d4afb5ceSopenharmony_ci	}
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	/*
286d4afb5ceSopenharmony_ci	 * We made a fresh accepted SS conn from the server pieces,
287d4afb5ceSopenharmony_ci	 * now bind the wsi... the problem is, this is the nwsi if it's
288d4afb5ceSopenharmony_ci	 * h2.
289d4afb5ceSopenharmony_ci	 */
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci	h->wsi = new_wsi;
292d4afb5ceSopenharmony_ci	new_wsi->a.opaque_user_data = h;
293d4afb5ceSopenharmony_ci	h->info.flags |= LWSSSINFLAGS_ACCEPTED;
294d4afb5ceSopenharmony_ci	/* indicate wsi should invalidate any ss link to it on close */
295d4afb5ceSopenharmony_ci	new_wsi->for_ss = 1;
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ci	// lwsl_wsi_notice(new_wsi, "%s: opaq %p, role %s",
298d4afb5ceSopenharmony_ci	//			     new_wsi->a.opaque_user_data,
299d4afb5ceSopenharmony_ci	//			     new_wsi->role_ops->name);
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci	h->policy = new_wsi->a.vhost->ss_handle->policy;
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci	/* apply requested socket options */
304d4afb5ceSopenharmony_ci	if (lws_plat_set_socket_options_ip(new_wsi->desc.sockfd,
305d4afb5ceSopenharmony_ci					   h->policy->priority,
306d4afb5ceSopenharmony_ci		      (LCCSCF_IP_LOW_LATENCY *
307d4afb5ceSopenharmony_ci		       !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)) |
308d4afb5ceSopenharmony_ci		      (LCCSCF_IP_HIGH_THROUGHPUT *
309d4afb5ceSopenharmony_ci		       !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)) |
310d4afb5ceSopenharmony_ci		      (LCCSCF_IP_HIGH_RELIABILITY *
311d4afb5ceSopenharmony_ci		       !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)) |
312d4afb5ceSopenharmony_ci		      (LCCSCF_IP_LOW_COST *
313d4afb5ceSopenharmony_ci		       !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_COST))))
314d4afb5ceSopenharmony_ci		lwsl_wsi_warn(new_wsi, "unable to set ip options");
315d4afb5ceSopenharmony_ci
316d4afb5ceSopenharmony_ci	/*
317d4afb5ceSopenharmony_ci	 * add us to the list of clients that came in from the server
318d4afb5ceSopenharmony_ci	 */
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
321d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&h->cli_list, &new_wsi->a.vhost->ss_handle->src_list);
322d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
323d4afb5ceSopenharmony_ci
324d4afb5ceSopenharmony_ci	/*
325d4afb5ceSopenharmony_ci	 * Let's give it appropriate state notifications
326d4afb5ceSopenharmony_ci	 */
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci	if (lws_ss_event_helper(h, LWSSSCS_CREATING))
329d4afb5ceSopenharmony_ci		goto fail;
330d4afb5ceSopenharmony_ci	if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
331d4afb5ceSopenharmony_ci		goto fail;
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci	/* defer CONNECTED until we see if he is upgrading */
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci//	if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
336d4afb5ceSopenharmony_ci//		goto fail;
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci	// lwsl_notice("%s: accepted ss complete, pcol %s\n", __func__,
339d4afb5ceSopenharmony_ci	//		new_wsi->a.protocol->name);
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	return 0;
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_cifail:
344d4afb5ceSopenharmony_ci	lws_ss_destroy(&h);
345d4afb5ceSopenharmony_cifail1:
346d4afb5ceSopenharmony_ci	return 1;
347d4afb5ceSopenharmony_ci}
348d4afb5ceSopenharmony_ci
349d4afb5ceSopenharmony_ci#endif
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_cistatic struct lws *
353d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type,
354d4afb5ceSopenharmony_ci			    lws_sock_file_fd_type fd)
355d4afb5ceSopenharmony_ci{
356d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt =
357d4afb5ceSopenharmony_ci			&new_wsi->a.context->pt[(int)new_wsi->tsi];
358d4afb5ceSopenharmony_ci	int n;
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	/* enforce that every fd is nonblocking */
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci	if (type & LWS_ADOPT_SOCKET) {
363d4afb5ceSopenharmony_ci		if (lws_plat_set_nonblocking(fd.sockfd)) {
364d4afb5ceSopenharmony_ci			lwsl_wsi_err(new_wsi, "unable to set sockfd %d nonblocking",
365d4afb5ceSopenharmony_ci				     fd.sockfd);
366d4afb5ceSopenharmony_ci			goto fail;
367d4afb5ceSopenharmony_ci		}
368d4afb5ceSopenharmony_ci	}
369d4afb5ceSopenharmony_ci#if !defined(WIN32)
370d4afb5ceSopenharmony_ci	else
371d4afb5ceSopenharmony_ci		if (lws_plat_set_nonblocking(fd.filefd)) {
372d4afb5ceSopenharmony_ci			lwsl_wsi_err(new_wsi, "unable to set filefd nonblocking");
373d4afb5ceSopenharmony_ci			goto fail;
374d4afb5ceSopenharmony_ci		}
375d4afb5ceSopenharmony_ci#endif
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci	new_wsi->desc = fd;
378d4afb5ceSopenharmony_ci
379d4afb5ceSopenharmony_ci	if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
380d4afb5ceSopenharmony_ci	    !(type & LWS_ADOPT_SOCKET))
381d4afb5ceSopenharmony_ci		type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci	/*
384d4afb5ceSopenharmony_ci	 * A new connection was accepted. Give the user a chance to
385d4afb5ceSopenharmony_ci	 * set properties of the newly created wsi. There's no protocol
386d4afb5ceSopenharmony_ci	 * selected yet so we issue this to the vhosts's default protocol,
387d4afb5ceSopenharmony_ci	 * itself by default protocols[0]
388d4afb5ceSopenharmony_ci	 */
389d4afb5ceSopenharmony_ci	new_wsi->wsistate |= LWSIFR_SERVER;
390d4afb5ceSopenharmony_ci	n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
391d4afb5ceSopenharmony_ci	if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
392d4afb5ceSopenharmony_ci		n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci	if (new_wsi->a.context->event_loop_ops->sock_accept)
395d4afb5ceSopenharmony_ci		if (new_wsi->a.context->event_loop_ops->sock_accept(new_wsi))
396d4afb5ceSopenharmony_ci			goto fail;
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
399d4afb5ceSopenharmony_ci	/*
400d4afb5ceSopenharmony_ci	 * Caution: after this point the wsi is live on its service thread
401d4afb5ceSopenharmony_ci	 * which may be concurrent to this.  We mark the wsi as still undergoing
402d4afb5ceSopenharmony_ci	 * init in another pt so the assigned pt leaves it alone.
403d4afb5ceSopenharmony_ci	 */
404d4afb5ceSopenharmony_ci	new_wsi->undergoing_init_from_other_pt = 1;
405d4afb5ceSopenharmony_ci#endif
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	if (!(type & LWS_ADOPT_ALLOW_SSL)) {
408d4afb5ceSopenharmony_ci		lws_pt_lock(pt, __func__);
409d4afb5ceSopenharmony_ci		if (__insert_wsi_socket_into_fds(new_wsi->a.context, new_wsi)) {
410d4afb5ceSopenharmony_ci			lws_pt_unlock(pt);
411d4afb5ceSopenharmony_ci			lwsl_wsi_err(new_wsi, "fail inserting socket");
412d4afb5ceSopenharmony_ci			goto fail;
413d4afb5ceSopenharmony_ci		}
414d4afb5ceSopenharmony_ci		lws_pt_unlock(pt);
415d4afb5ceSopenharmony_ci	}
416d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
417d4afb5ceSopenharmony_ci	 else
418d4afb5ceSopenharmony_ci		if (lws_server_socket_service_ssl(new_wsi, fd.sockfd, 0)) {
419d4afb5ceSopenharmony_ci			lwsl_wsi_info(new_wsi, "fail ssl negotiation");
420d4afb5ceSopenharmony_ci
421d4afb5ceSopenharmony_ci			goto fail;
422d4afb5ceSopenharmony_ci		}
423d4afb5ceSopenharmony_ci#endif
424d4afb5ceSopenharmony_ci
425d4afb5ceSopenharmony_ci	lws_vhost_lock(new_wsi->a.vhost);
426d4afb5ceSopenharmony_ci	/* he has fds visibility now, remove from vhost orphan list */
427d4afb5ceSopenharmony_ci	lws_dll2_remove(&new_wsi->vh_awaiting_socket);
428d4afb5ceSopenharmony_ci	lws_vhost_unlock(new_wsi->a.vhost);
429d4afb5ceSopenharmony_ci
430d4afb5ceSopenharmony_ci	/*
431d4afb5ceSopenharmony_ci	 *  by deferring callback to this point, after insertion to fds,
432d4afb5ceSopenharmony_ci	 * lws_callback_on_writable() can work from the callback
433d4afb5ceSopenharmony_ci	 */
434d4afb5ceSopenharmony_ci	if ((new_wsi->a.protocol->callback)(new_wsi, (enum lws_callback_reasons)n, new_wsi->user_space,
435d4afb5ceSopenharmony_ci					  NULL, 0))
436d4afb5ceSopenharmony_ci		goto fail;
437d4afb5ceSopenharmony_ci
438d4afb5ceSopenharmony_ci	/* role may need to do something after all adoption completed */
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	lws_role_call_adoption_bind(new_wsi, (int)type | _LWS_ADOPT_FINISH,
441d4afb5ceSopenharmony_ci				    new_wsi->a.protocol->name);
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
444d4afb5ceSopenharmony_ci	/*
445d4afb5ceSopenharmony_ci	 * Did we come from an accepted client connection to a ss server?
446d4afb5ceSopenharmony_ci	 *
447d4afb5ceSopenharmony_ci	 * !!! For mux protocols, this will cause an additional inactive ss
448d4afb5ceSopenharmony_ci	 * representing the nwsi.  Doing that allows us to support both h1
449d4afb5ceSopenharmony_ci	 * (here) and h2 (at __lws_wsi_server_new())
450d4afb5ceSopenharmony_ci	 */
451d4afb5ceSopenharmony_ci
452d4afb5ceSopenharmony_ci	lwsl_wsi_info(new_wsi, "vhost %s", new_wsi->a.vhost->lc.gutag);
453d4afb5ceSopenharmony_ci
454d4afb5ceSopenharmony_ci	if (lws_adopt_ss_server_accept(new_wsi))
455d4afb5ceSopenharmony_ci		goto fail;
456d4afb5ceSopenharmony_ci#endif
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
459d4afb5ceSopenharmony_ci	/* its actual pt can service it now */
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci	new_wsi->undergoing_init_from_other_pt = 0;
462d4afb5ceSopenharmony_ci#endif
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ci	lws_cancel_service_pt(new_wsi);
465d4afb5ceSopenharmony_ci
466d4afb5ceSopenharmony_ci	return new_wsi;
467d4afb5ceSopenharmony_ci
468d4afb5ceSopenharmony_cifail:
469d4afb5ceSopenharmony_ci	if (type & LWS_ADOPT_SOCKET)
470d4afb5ceSopenharmony_ci		lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS,
471d4afb5ceSopenharmony_ci				   "adopt skt fail");
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci	return NULL;
474d4afb5ceSopenharmony_ci}
475d4afb5ceSopenharmony_ci
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci/* if not a socket, it's a raw, non-ssl file descriptor */
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_cistruct lws *
480d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
481d4afb5ceSopenharmony_ci			   lws_sock_file_fd_type fd, const char *vh_prot_name,
482d4afb5ceSopenharmony_ci			   struct lws *parent)
483d4afb5ceSopenharmony_ci{
484d4afb5ceSopenharmony_ci	lws_adopt_desc_t info;
485d4afb5ceSopenharmony_ci
486d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof(info));
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	info.vh = vh;
489d4afb5ceSopenharmony_ci	info.type = type;
490d4afb5ceSopenharmony_ci	info.fd = fd;
491d4afb5ceSopenharmony_ci	info.vh_prot_name = vh_prot_name;
492d4afb5ceSopenharmony_ci	info.parent = parent;
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_ci	return lws_adopt_descriptor_vhost_via_info(&info);
495d4afb5ceSopenharmony_ci}
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_cistruct lws *
498d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
499d4afb5ceSopenharmony_ci{
500d4afb5ceSopenharmony_ci	socklen_t slen = sizeof(lws_sockaddr46);
501d4afb5ceSopenharmony_ci	struct lws *new_wsi;
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS)
504d4afb5ceSopenharmony_ci	struct lws_peer *peer = NULL;
505d4afb5ceSopenharmony_ci
506d4afb5ceSopenharmony_ci	if (info->type & LWS_ADOPT_SOCKET) {
507d4afb5ceSopenharmony_ci		peer = lws_get_or_create_peer(info->vh, info->fd.sockfd);
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci		if (peer && info->vh->context->ip_limit_wsi &&
510d4afb5ceSopenharmony_ci		    peer->count_wsi >= info->vh->context->ip_limit_wsi) {
511d4afb5ceSopenharmony_ci			lwsl_info("Peer reached wsi limit %d\n",
512d4afb5ceSopenharmony_ci					info->vh->context->ip_limit_wsi);
513d4afb5ceSopenharmony_ci			if (info->vh->context->pl_notify_cb)
514d4afb5ceSopenharmony_ci				info->vh->context->pl_notify_cb(
515d4afb5ceSopenharmony_ci							info->vh->context,
516d4afb5ceSopenharmony_ci							info->fd.sockfd,
517d4afb5ceSopenharmony_ci							&peer->sa46);
518d4afb5ceSopenharmony_ci			compatible_close(info->fd.sockfd);
519d4afb5ceSopenharmony_ci			return NULL;
520d4afb5ceSopenharmony_ci		}
521d4afb5ceSopenharmony_ci	}
522d4afb5ceSopenharmony_ci#endif
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci	lws_context_lock(info->vh->context, __func__);
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	new_wsi = __lws_adopt_descriptor_vhost1(info->vh, info->type,
527d4afb5ceSopenharmony_ci					      info->vh_prot_name, info->parent,
528d4afb5ceSopenharmony_ci					      info->opaque, info->fi_wsi_name);
529d4afb5ceSopenharmony_ci	if (!new_wsi) {
530d4afb5ceSopenharmony_ci		if (info->type & LWS_ADOPT_SOCKET)
531d4afb5ceSopenharmony_ci			compatible_close(info->fd.sockfd);
532d4afb5ceSopenharmony_ci		goto bail;
533d4afb5ceSopenharmony_ci	}
534d4afb5ceSopenharmony_ci
535d4afb5ceSopenharmony_ci	if (info->type & LWS_ADOPT_SOCKET &&
536d4afb5ceSopenharmony_ci	    getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer,
537d4afb5ceSopenharmony_ci								    &slen) < 0)
538d4afb5ceSopenharmony_ci		lwsl_info("%s: getpeername failed\n", __func__);
539d4afb5ceSopenharmony_ci
540d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS)
541d4afb5ceSopenharmony_ci	if (peer)
542d4afb5ceSopenharmony_ci		lws_peer_add_wsi(info->vh->context, peer, new_wsi);
543d4afb5ceSopenharmony_ci#endif
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci	new_wsi = lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_cibail:
548d4afb5ceSopenharmony_ci	lws_context_unlock(info->vh->context);
549d4afb5ceSopenharmony_ci
550d4afb5ceSopenharmony_ci	return new_wsi;
551d4afb5ceSopenharmony_ci}
552d4afb5ceSopenharmony_ci
553d4afb5ceSopenharmony_cistruct lws *
554d4afb5ceSopenharmony_cilws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
555d4afb5ceSopenharmony_ci{
556d4afb5ceSopenharmony_ci	lws_sock_file_fd_type fd;
557d4afb5ceSopenharmony_ci
558d4afb5ceSopenharmony_ci	fd.sockfd = accept_fd;
559d4afb5ceSopenharmony_ci	return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
560d4afb5ceSopenharmony_ci			LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
561d4afb5ceSopenharmony_ci}
562d4afb5ceSopenharmony_ci
563d4afb5ceSopenharmony_cistruct lws *
564d4afb5ceSopenharmony_cilws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
565d4afb5ceSopenharmony_ci{
566d4afb5ceSopenharmony_ci	return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
567d4afb5ceSopenharmony_ci}
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci/* Common read-buffer adoption for lws_adopt_*_readbuf */
570d4afb5ceSopenharmony_cistatic struct lws*
571d4afb5ceSopenharmony_ciadopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
572d4afb5ceSopenharmony_ci{
573d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
574d4afb5ceSopenharmony_ci	struct lws_pollfd *pfd;
575d4afb5ceSopenharmony_ci	int n;
576d4afb5ceSopenharmony_ci
577d4afb5ceSopenharmony_ci	if (!wsi)
578d4afb5ceSopenharmony_ci		return NULL;
579d4afb5ceSopenharmony_ci
580d4afb5ceSopenharmony_ci	if (!readbuf || len == 0)
581d4afb5ceSopenharmony_ci		return wsi;
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci	if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
584d4afb5ceSopenharmony_ci		return wsi;
585d4afb5ceSopenharmony_ci
586d4afb5ceSopenharmony_ci	pt = &wsi->a.context->pt[(int)wsi->tsi];
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_ci	n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
589d4afb5ceSopenharmony_ci				       len);
590d4afb5ceSopenharmony_ci	if (n < 0)
591d4afb5ceSopenharmony_ci		goto bail;
592d4afb5ceSopenharmony_ci	if (n)
593d4afb5ceSopenharmony_ci		lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
594d4afb5ceSopenharmony_ci
595d4afb5ceSopenharmony_ci	/*
596d4afb5ceSopenharmony_ci	 * we can't process the initial read data until we can attach an ah.
597d4afb5ceSopenharmony_ci	 *
598d4afb5ceSopenharmony_ci	 * if one is available, get it and place the data in his ah rxbuf...
599d4afb5ceSopenharmony_ci	 * wsi with ah that have pending rxbuf get auto-POLLIN service.
600d4afb5ceSopenharmony_ci	 *
601d4afb5ceSopenharmony_ci	 * no autoservice because we didn't get a chance to attach the
602d4afb5ceSopenharmony_ci	 * readbuf data to wsi or ah yet, and we will do it next if we get
603d4afb5ceSopenharmony_ci	 * the ah.
604d4afb5ceSopenharmony_ci	 */
605d4afb5ceSopenharmony_ci	if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
606d4afb5ceSopenharmony_ci
607d4afb5ceSopenharmony_ci		lwsl_notice("%s: calling service on readbuf ah\n", __func__);
608d4afb5ceSopenharmony_ci
609d4afb5ceSopenharmony_ci		/*
610d4afb5ceSopenharmony_ci		 * unlike a normal connect, we have the headers already
611d4afb5ceSopenharmony_ci		 * (or the first part of them anyway).
612d4afb5ceSopenharmony_ci		 * libuv won't come back and service us without a network
613d4afb5ceSopenharmony_ci		 * event, so we need to do the header service right here.
614d4afb5ceSopenharmony_ci		 */
615d4afb5ceSopenharmony_ci		pfd = &pt->fds[wsi->position_in_fds_table];
616d4afb5ceSopenharmony_ci		pfd->revents |= LWS_POLLIN;
617d4afb5ceSopenharmony_ci		lwsl_err("%s: calling service\n", __func__);
618d4afb5ceSopenharmony_ci		if (lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi))
619d4afb5ceSopenharmony_ci			/* service closed us */
620d4afb5ceSopenharmony_ci			return NULL;
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci		return wsi;
623d4afb5ceSopenharmony_ci	}
624d4afb5ceSopenharmony_ci	lwsl_err("%s: deferring handling ah\n", __func__);
625d4afb5ceSopenharmony_ci
626d4afb5ceSopenharmony_ci	return wsi;
627d4afb5ceSopenharmony_ci
628d4afb5ceSopenharmony_cibail:
629d4afb5ceSopenharmony_ci	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
630d4afb5ceSopenharmony_ci			   "adopt skt readbuf fail");
631d4afb5ceSopenharmony_ci
632d4afb5ceSopenharmony_ci	return NULL;
633d4afb5ceSopenharmony_ci}
634d4afb5ceSopenharmony_ci
635d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UDP)
636d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
637d4afb5ceSopenharmony_ci
638d4afb5ceSopenharmony_ci/*
639d4afb5ceSopenharmony_ci * This is the ASYNC_DNS callback target for udp client, it's analogous to
640d4afb5ceSopenharmony_ci * connect3()
641d4afb5ceSopenharmony_ci */
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_cistatic struct lws *
644d4afb5ceSopenharmony_cilws_create_adopt_udp2(struct lws *wsi, const char *ads,
645d4afb5ceSopenharmony_ci		      const struct addrinfo *r, int n, void *opaque)
646d4afb5ceSopenharmony_ci{
647d4afb5ceSopenharmony_ci	lws_sock_file_fd_type sock;
648d4afb5ceSopenharmony_ci	int bc = 1, m;
649d4afb5ceSopenharmony_ci
650d4afb5ceSopenharmony_ci	assert(wsi);
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci	if (ads && (n < 0 || !r)) {
653d4afb5ceSopenharmony_ci		/*
654d4afb5ceSopenharmony_ci		 * DNS lookup failed: there are no usable results.  Fail the
655d4afb5ceSopenharmony_ci		 * overall connection request.
656d4afb5ceSopenharmony_ci		 */
657d4afb5ceSopenharmony_ci		lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
658d4afb5ceSopenharmony_ci
659d4afb5ceSopenharmony_ci		goto bail;
660d4afb5ceSopenharmony_ci	}
661d4afb5ceSopenharmony_ci
662d4afb5ceSopenharmony_ci	m = lws_sort_dns(wsi, r);
663d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS)
664d4afb5ceSopenharmony_ci	lws_async_dns_freeaddrinfo(&r);
665d4afb5ceSopenharmony_ci#else
666d4afb5ceSopenharmony_ci	freeaddrinfo((struct addrinfo *)r);
667d4afb5ceSopenharmony_ci#endif
668d4afb5ceSopenharmony_ci	if (m)
669d4afb5ceSopenharmony_ci		goto bail;
670d4afb5ceSopenharmony_ci
671d4afb5ceSopenharmony_ci	while (lws_dll2_get_head(&wsi->dns_sorted_list)) {
672d4afb5ceSopenharmony_ci		lws_dns_sort_t *s = lws_container_of(
673d4afb5ceSopenharmony_ci				lws_dll2_get_head(&wsi->dns_sorted_list),
674d4afb5ceSopenharmony_ci				lws_dns_sort_t, list);
675d4afb5ceSopenharmony_ci
676d4afb5ceSopenharmony_ci		/*
677d4afb5ceSopenharmony_ci		 * Remove it from the head, but don't free it yet... we are
678d4afb5ceSopenharmony_ci		 * taking responsibility to free it
679d4afb5ceSopenharmony_ci		 */
680d4afb5ceSopenharmony_ci		lws_dll2_remove(&s->list);
681d4afb5ceSopenharmony_ci
682d4afb5ceSopenharmony_ci		/*
683d4afb5ceSopenharmony_ci		 * We have done the dns lookup, identify the result we want
684d4afb5ceSopenharmony_ci		 * if any, and then complete the adoption by binding wsi to
685d4afb5ceSopenharmony_ci		 * socket opened on it.
686d4afb5ceSopenharmony_ci		 *
687d4afb5ceSopenharmony_ci		 * Ignore the weak assumptions about protocol driven by port
688d4afb5ceSopenharmony_ci		 * number and force to DGRAM / UDP since that's what this
689d4afb5ceSopenharmony_ci		 * function is for.
690d4afb5ceSopenharmony_ci		 */
691d4afb5ceSopenharmony_ci
692d4afb5ceSopenharmony_ci#if !defined(__linux__)
693d4afb5ceSopenharmony_ci		sock.sockfd = socket(s->dest.sa4.sin_family,
694d4afb5ceSopenharmony_ci				     SOCK_DGRAM, IPPROTO_UDP);
695d4afb5ceSopenharmony_ci#else
696d4afb5ceSopenharmony_ci		/* PF_PACKET is linux-only */
697d4afb5ceSopenharmony_ci		sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
698d4afb5ceSopenharmony_ci						s->dest.sa4.sin_family,
699d4afb5ceSopenharmony_ci				     SOCK_DGRAM, wsi->pf_packet ?
700d4afb5ceSopenharmony_ci					htons(0x800) : IPPROTO_UDP);
701d4afb5ceSopenharmony_ci#endif
702d4afb5ceSopenharmony_ci		if (sock.sockfd == LWS_SOCK_INVALID)
703d4afb5ceSopenharmony_ci			goto resume;
704d4afb5ceSopenharmony_ci
705d4afb5ceSopenharmony_ci		/* ipv6 udp!!! */
706d4afb5ceSopenharmony_ci
707d4afb5ceSopenharmony_ci		if (s->af == AF_INET)
708d4afb5ceSopenharmony_ci			s->dest.sa4.sin_port = htons(wsi->c_port);
709d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
710d4afb5ceSopenharmony_ci		else
711d4afb5ceSopenharmony_ci			s->dest.sa6.sin6_port = htons(wsi->c_port);
712d4afb5ceSopenharmony_ci#endif
713d4afb5ceSopenharmony_ci
714d4afb5ceSopenharmony_ci		if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR,
715d4afb5ceSopenharmony_ci			       (const char *)&bc, sizeof(bc)) < 0)
716d4afb5ceSopenharmony_ci			lwsl_err("%s: failed to set reuse\n", __func__);
717d4afb5ceSopenharmony_ci
718d4afb5ceSopenharmony_ci		if (wsi->do_broadcast &&
719d4afb5ceSopenharmony_ci		    setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST,
720d4afb5ceSopenharmony_ci			       (const char *)&bc, sizeof(bc)) < 0)
721d4afb5ceSopenharmony_ci			lwsl_err("%s: failed to set broadcast\n", __func__);
722d4afb5ceSopenharmony_ci
723d4afb5ceSopenharmony_ci		/* Bind the udp socket to a particular network interface */
724d4afb5ceSopenharmony_ci
725d4afb5ceSopenharmony_ci		if (opaque &&
726d4afb5ceSopenharmony_ci		    lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
727d4afb5ceSopenharmony_ci			goto resume;
728d4afb5ceSopenharmony_ci
729d4afb5ceSopenharmony_ci		if (wsi->do_bind &&
730d4afb5ceSopenharmony_ci		    bind(sock.sockfd, sa46_sockaddr(&s->dest),
731d4afb5ceSopenharmony_ci#if defined(_WIN32)
732d4afb5ceSopenharmony_ci			 (int)sa46_socklen(&s->dest)
733d4afb5ceSopenharmony_ci#else
734d4afb5ceSopenharmony_ci			 sizeof(struct sockaddr)
735d4afb5ceSopenharmony_ci#endif
736d4afb5ceSopenharmony_ci		) == -1) {
737d4afb5ceSopenharmony_ci			lwsl_err("%s: bind failed\n", __func__);
738d4afb5ceSopenharmony_ci			goto resume;
739d4afb5ceSopenharmony_ci		}
740d4afb5ceSopenharmony_ci
741d4afb5ceSopenharmony_ci		if (!wsi->do_bind && !wsi->pf_packet) {
742d4afb5ceSopenharmony_ci#if !defined(__APPLE__)
743d4afb5ceSopenharmony_ci			if (connect(sock.sockfd, sa46_sockaddr(&s->dest),
744d4afb5ceSopenharmony_ci				    sa46_socklen(&s->dest)) == -1 &&
745d4afb5ceSopenharmony_ci			    errno != EADDRNOTAVAIL /* openbsd */ ) {
746d4afb5ceSopenharmony_ci				lwsl_err("%s: conn fd %d fam %d %s:%u failed "
747d4afb5ceSopenharmony_ci					 "errno %d\n", __func__, sock.sockfd,
748d4afb5ceSopenharmony_ci					 s->dest.sa4.sin_family,
749d4afb5ceSopenharmony_ci					 ads ? ads : "null", wsi->c_port,
750d4afb5ceSopenharmony_ci					 LWS_ERRNO);
751d4afb5ceSopenharmony_ci				compatible_close(sock.sockfd);
752d4afb5ceSopenharmony_ci				goto resume;
753d4afb5ceSopenharmony_ci			}
754d4afb5ceSopenharmony_ci#endif
755d4afb5ceSopenharmony_ci		}
756d4afb5ceSopenharmony_ci
757d4afb5ceSopenharmony_ci		if (wsi->udp)
758d4afb5ceSopenharmony_ci			wsi->udp->sa46 = s->dest;
759d4afb5ceSopenharmony_ci		wsi->sa46_peer = s->dest;
760d4afb5ceSopenharmony_ci
761d4afb5ceSopenharmony_ci		/* we connected: complete the udp socket adoption flow */
762d4afb5ceSopenharmony_ci
763d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS)
764d4afb5ceSopenharmony_ci	if (wsi->a.context->async_dns.wsi == wsi)
765d4afb5ceSopenharmony_ci		wsi->a.context->async_dns.dns_server_connected = 1;
766d4afb5ceSopenharmony_ci#endif
767d4afb5ceSopenharmony_ci
768d4afb5ceSopenharmony_ci		lws_free(s);
769d4afb5ceSopenharmony_ci		lws_addrinfo_clean(wsi);
770d4afb5ceSopenharmony_ci		return lws_adopt_descriptor_vhost2(wsi,
771d4afb5ceSopenharmony_ci						LWS_ADOPT_RAW_SOCKET_UDP, sock);
772d4afb5ceSopenharmony_ci
773d4afb5ceSopenharmony_ciresume:
774d4afb5ceSopenharmony_ci		lws_free(s);
775d4afb5ceSopenharmony_ci	}
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci	lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
778d4afb5ceSopenharmony_ci	lws_addrinfo_clean(wsi);
779d4afb5ceSopenharmony_ci
780d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS)
781d4afb5ceSopenharmony_ci	if (wsi->a.context->async_dns.wsi == wsi)
782d4afb5ceSopenharmony_ci		lws_async_dns_drop_server(wsi->a.context);
783d4afb5ceSopenharmony_ci#endif
784d4afb5ceSopenharmony_ci
785d4afb5ceSopenharmony_cibail:
786d4afb5ceSopenharmony_ci
787d4afb5ceSopenharmony_ci	/* caller must close */
788d4afb5ceSopenharmony_ci
789d4afb5ceSopenharmony_ci	return NULL;
790d4afb5ceSopenharmony_ci}
791d4afb5ceSopenharmony_ci
792d4afb5ceSopenharmony_cistruct lws *
793d4afb5ceSopenharmony_cilws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
794d4afb5ceSopenharmony_ci		     int flags, const char *protocol_name, const char *ifname,
795d4afb5ceSopenharmony_ci		     struct lws *parent_wsi, void *opaque,
796d4afb5ceSopenharmony_ci		     const lws_retry_bo_t *retry_policy, const char *fi_wsi_name)
797d4afb5ceSopenharmony_ci{
798d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE)
799d4afb5ceSopenharmony_ci	struct lws *wsi;
800d4afb5ceSopenharmony_ci	int n;
801d4afb5ceSopenharmony_ci
802d4afb5ceSopenharmony_ci	lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
803d4afb5ceSopenharmony_ci
804d4afb5ceSopenharmony_ci	/* create the logical wsi without any valid fd */
805d4afb5ceSopenharmony_ci
806d4afb5ceSopenharmony_ci	lws_context_lock(vhost->context, __func__);
807d4afb5ceSopenharmony_ci
808d4afb5ceSopenharmony_ci	wsi = __lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET |
809d4afb5ceSopenharmony_ci						 LWS_ADOPT_RAW_SOCKET_UDP,
810d4afb5ceSopenharmony_ci					  protocol_name, parent_wsi, opaque,
811d4afb5ceSopenharmony_ci					  fi_wsi_name);
812d4afb5ceSopenharmony_ci
813d4afb5ceSopenharmony_ci	lws_context_unlock(vhost->context);
814d4afb5ceSopenharmony_ci	if (!wsi) {
815d4afb5ceSopenharmony_ci		lwsl_err("%s: udp wsi creation failed\n", __func__);
816d4afb5ceSopenharmony_ci		goto bail;
817d4afb5ceSopenharmony_ci	}
818d4afb5ceSopenharmony_ci
819d4afb5ceSopenharmony_ci	// lwsl_notice("%s: role %s\n", __func__, wsi->role_ops->name);
820d4afb5ceSopenharmony_ci
821d4afb5ceSopenharmony_ci	wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
822d4afb5ceSopenharmony_ci	wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
823d4afb5ceSopenharmony_ci	wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
824d4afb5ceSopenharmony_ci	wsi->c_port = (uint16_t)(unsigned int)port;
825d4afb5ceSopenharmony_ci	if (retry_policy)
826d4afb5ceSopenharmony_ci		wsi->retry_policy = retry_policy;
827d4afb5ceSopenharmony_ci	else
828d4afb5ceSopenharmony_ci		wsi->retry_policy = vhost->retry_policy;
829d4afb5ceSopenharmony_ci
830d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS)
831d4afb5ceSopenharmony_ci	{
832d4afb5ceSopenharmony_ci		struct addrinfo *r, h;
833d4afb5ceSopenharmony_ci		char buf[16];
834d4afb5ceSopenharmony_ci
835d4afb5ceSopenharmony_ci		memset(&h, 0, sizeof(h));
836d4afb5ceSopenharmony_ci		h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
837d4afb5ceSopenharmony_ci		h.ai_socktype = SOCK_DGRAM;
838d4afb5ceSopenharmony_ci		h.ai_protocol = IPPROTO_UDP;
839d4afb5ceSopenharmony_ci#if defined(AI_PASSIVE)
840d4afb5ceSopenharmony_ci		h.ai_flags = AI_PASSIVE;
841d4afb5ceSopenharmony_ci#endif
842d4afb5ceSopenharmony_ci#ifdef AI_ADDRCONFIG
843d4afb5ceSopenharmony_ci		h.ai_flags |= AI_ADDRCONFIG;
844d4afb5ceSopenharmony_ci#endif
845d4afb5ceSopenharmony_ci
846d4afb5ceSopenharmony_ci		/* if the dns lookup is synchronous, do the whole thing now */
847d4afb5ceSopenharmony_ci		lws_snprintf(buf, sizeof(buf), "%u", port);
848d4afb5ceSopenharmony_ci		n = getaddrinfo(ads, buf, &h, &r);
849d4afb5ceSopenharmony_ci		if (n) {
850d4afb5ceSopenharmony_ci
851d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & LLL_INFO)
852d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS)
853d4afb5ceSopenharmony_ci			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
854d4afb5ceSopenharmony_ci				  gai_strerror(n));
855d4afb5ceSopenharmony_ci#else
856d4afb5ceSopenharmony_ci
857d4afb5ceSopenharmony_ci			lwsl_info("%s: getaddrinfo error: %s\n", __func__,
858d4afb5ceSopenharmony_ci					strerror(n));
859d4afb5ceSopenharmony_ci#endif
860d4afb5ceSopenharmony_ci#endif
861d4afb5ceSopenharmony_ci			//freeaddrinfo(r);
862d4afb5ceSopenharmony_ci			goto bail1;
863d4afb5ceSopenharmony_ci		}
864d4afb5ceSopenharmony_ci		/*
865d4afb5ceSopenharmony_ci		 * With synchronous dns, complete it immediately after the
866d4afb5ceSopenharmony_ci		 * blocking dns lookup finished... free r when connect either
867d4afb5ceSopenharmony_ci		 * completed or failed
868d4afb5ceSopenharmony_ci		 */
869d4afb5ceSopenharmony_ci		wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
870d4afb5ceSopenharmony_ci
871d4afb5ceSopenharmony_ci		return wsi;
872d4afb5ceSopenharmony_ci	}
873d4afb5ceSopenharmony_ci#else
874d4afb5ceSopenharmony_ci	if (ads) {
875d4afb5ceSopenharmony_ci		/*
876d4afb5ceSopenharmony_ci		 * with async dns, use the wsi as the point about which to do
877d4afb5ceSopenharmony_ci		 * the dns lookup and have it call the second part when it's
878d4afb5ceSopenharmony_ci		 * done.
879d4afb5ceSopenharmony_ci		 *
880d4afb5ceSopenharmony_ci		 * Keep a refcount on the results and free it when we connected
881d4afb5ceSopenharmony_ci		 * or definitively failed.
882d4afb5ceSopenharmony_ci		 *
883d4afb5ceSopenharmony_ci		 * Notice wsi has no socket at this point (we don't know what
884d4afb5ceSopenharmony_ci		 * kind to ask for until we get the dns back).  But it is bound
885d4afb5ceSopenharmony_ci		 * to a vhost and can be cleaned up from that at vhost destroy.
886d4afb5ceSopenharmony_ci		 */
887d4afb5ceSopenharmony_ci		n = lws_async_dns_query(vhost->context, 0, ads,
888d4afb5ceSopenharmony_ci					LWS_ADNS_RECORD_A,
889d4afb5ceSopenharmony_ci					lws_create_adopt_udp2, wsi,
890d4afb5ceSopenharmony_ci					(void *)ifname);
891d4afb5ceSopenharmony_ci		// lwsl_notice("%s: dns query returned %d\n", __func__, n);
892d4afb5ceSopenharmony_ci		if (n == LADNS_RET_FAILED) {
893d4afb5ceSopenharmony_ci			lwsl_err("%s: async dns failed\n", __func__);
894d4afb5ceSopenharmony_ci			wsi = NULL;
895d4afb5ceSopenharmony_ci			/*
896d4afb5ceSopenharmony_ci			 * It was already closed by calling callback with error
897d4afb5ceSopenharmony_ci			 * from lws_async_dns_query()
898d4afb5ceSopenharmony_ci			 */
899d4afb5ceSopenharmony_ci			goto bail;
900d4afb5ceSopenharmony_ci		}
901d4afb5ceSopenharmony_ci	} else {
902d4afb5ceSopenharmony_ci		lwsl_debug("%s: udp adopt has no ads\n", __func__);
903d4afb5ceSopenharmony_ci		wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
904d4afb5ceSopenharmony_ci	}
905d4afb5ceSopenharmony_ci
906d4afb5ceSopenharmony_ci	/* dns lookup is happening asynchronously */
907d4afb5ceSopenharmony_ci
908d4afb5ceSopenharmony_ci	// lwsl_notice("%s: returning wsi %p\n", __func__, wsi);
909d4afb5ceSopenharmony_ci
910d4afb5ceSopenharmony_ci	return wsi;
911d4afb5ceSopenharmony_ci#endif
912d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS)
913d4afb5ceSopenharmony_cibail1:
914d4afb5ceSopenharmony_ci	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
915d4afb5ceSopenharmony_ci	wsi = NULL;
916d4afb5ceSopenharmony_ci#endif
917d4afb5ceSopenharmony_cibail:
918d4afb5ceSopenharmony_ci	return wsi;
919d4afb5ceSopenharmony_ci#else
920d4afb5ceSopenharmony_ci	return NULL;
921d4afb5ceSopenharmony_ci#endif
922d4afb5ceSopenharmony_ci}
923d4afb5ceSopenharmony_ci#endif
924d4afb5ceSopenharmony_ci#endif
925d4afb5ceSopenharmony_ci
926d4afb5ceSopenharmony_cistruct lws *
927d4afb5ceSopenharmony_cilws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
928d4afb5ceSopenharmony_ci			 const char *readbuf, size_t len)
929d4afb5ceSopenharmony_ci{
930d4afb5ceSopenharmony_ci        return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
931d4afb5ceSopenharmony_ci				    readbuf, len);
932d4afb5ceSopenharmony_ci}
933d4afb5ceSopenharmony_ci
934d4afb5ceSopenharmony_cistruct lws *
935d4afb5ceSopenharmony_cilws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
936d4afb5ceSopenharmony_ci			       lws_sockfd_type accept_fd,
937d4afb5ceSopenharmony_ci			       const char *readbuf, size_t len)
938d4afb5ceSopenharmony_ci{
939d4afb5ceSopenharmony_ci        return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
940d4afb5ceSopenharmony_ci				    readbuf, len);
941d4afb5ceSopenharmony_ci}
942