1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 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 const uint8_t hnames[] = {
28d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_PEER_ADDRESS,
29d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_URI,
30d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_HOST,
31d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_ORIGIN,
32d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
33d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_METHOD,
34d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_IFACE,
35d4afb5ceSopenharmony_ci	_WSI_TOKEN_CLIENT_ALPN
36d4afb5ceSopenharmony_ci};
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_cistruct lws *
39d4afb5ceSopenharmony_cilws_http_client_connect_via_info2(struct lws *wsi)
40d4afb5ceSopenharmony_ci{
41d4afb5ceSopenharmony_ci	struct client_info_stash *stash = wsi->stash;
42d4afb5ceSopenharmony_ci	int n;
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	lwsl_wsi_debug(wsi, "stash %p", stash);
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	if (!stash)
47d4afb5ceSopenharmony_ci		return wsi;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	wsi->a.opaque_user_data = wsi->stash->opaque_user_data;
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	if (stash->cis[CIS_METHOD] && (!strcmp(stash->cis[CIS_METHOD], "RAW") ||
52d4afb5ceSopenharmony_ci				      !strcmp(stash->cis[CIS_METHOD], "MQTT")))
53d4afb5ceSopenharmony_ci		goto no_ah;
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci	/*
56d4afb5ceSopenharmony_ci	 * we're not necessarily in a position to action these right away,
57d4afb5ceSopenharmony_ci	 * stash them... we only need during connect phase so into a temp
58d4afb5ceSopenharmony_ci	 * allocated stash
59d4afb5ceSopenharmony_ci	 */
60d4afb5ceSopenharmony_ci	for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames); n++)
61d4afb5ceSopenharmony_ci		if (hnames[n] && stash->cis[n] &&
62d4afb5ceSopenharmony_ci		    lws_hdr_simple_create(wsi, hnames[n], stash->cis[n]))
63d4afb5ceSopenharmony_ci			goto bail;
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SOCKS5)
66d4afb5ceSopenharmony_ci	if (!wsi->a.vhost->socks_proxy_port)
67d4afb5ceSopenharmony_ci		lws_free_set_NULL(wsi->stash);
68d4afb5ceSopenharmony_ci#endif
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_cino_ah:
71d4afb5ceSopenharmony_ci	return lws_client_connect_2_dnsreq(wsi);
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_cibail:
74d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SOCKS5)
75d4afb5ceSopenharmony_ci	if (!wsi->a.vhost->socks_proxy_port)
76d4afb5ceSopenharmony_ci		lws_free_set_NULL(wsi->stash);
77d4afb5ceSopenharmony_ci#endif
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci	lws_free_set_NULL(wsi->stash);
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci	return NULL;
82d4afb5ceSopenharmony_ci}
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ciint
85d4afb5ceSopenharmony_cilws_client_stash_create(struct lws *wsi, const char **cisin)
86d4afb5ceSopenharmony_ci{
87d4afb5ceSopenharmony_ci	size_t size;
88d4afb5ceSopenharmony_ci	char *pc;
89d4afb5ceSopenharmony_ci	int n;
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	size = sizeof(*wsi->stash) + 1;
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci	/*
94d4afb5ceSopenharmony_ci	 * Let's overallocate the stash object with space for all the args
95d4afb5ceSopenharmony_ci	 * in one hit.
96d4afb5ceSopenharmony_ci	 */
97d4afb5ceSopenharmony_ci	for (n = 0; n < CIS_COUNT; n++)
98d4afb5ceSopenharmony_ci		if (cisin[n])
99d4afb5ceSopenharmony_ci			size += strlen(cisin[n]) + 1;
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci	if (wsi->stash)
102d4afb5ceSopenharmony_ci		lws_free_set_NULL(wsi->stash);
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	wsi->stash = lws_malloc(size, "client stash");
105d4afb5ceSopenharmony_ci	if (!wsi->stash)
106d4afb5ceSopenharmony_ci		return 1;
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	/* all the pointers default to NULL, but no need to zero the args */
109d4afb5ceSopenharmony_ci	memset(wsi->stash, 0, sizeof(*wsi->stash));
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci	pc = (char *)&wsi->stash[1];
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci	for (n = 0; n < CIS_COUNT; n++)
114d4afb5ceSopenharmony_ci		if (cisin[n]) {
115d4afb5ceSopenharmony_ci			size_t mm;
116d4afb5ceSopenharmony_ci			wsi->stash->cis[n] = pc;
117d4afb5ceSopenharmony_ci			if (n == CIS_PATH && cisin[n][0] != '/')
118d4afb5ceSopenharmony_ci				*pc++ = '/';
119d4afb5ceSopenharmony_ci			mm = strlen(cisin[n]) + 1;
120d4afb5ceSopenharmony_ci			memcpy(pc, cisin[n], mm);
121d4afb5ceSopenharmony_ci			pc += mm;
122d4afb5ceSopenharmony_ci		}
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_ci	return 0;
125d4afb5ceSopenharmony_ci}
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_cistruct lws *
128d4afb5ceSopenharmony_cilws_client_connect_via_info(const struct lws_client_connect_info *i)
129d4afb5ceSopenharmony_ci{
130d4afb5ceSopenharmony_ci	const char *local = i->protocol;
131d4afb5ceSopenharmony_ci	struct lws *wsi, *safe = NULL;
132d4afb5ceSopenharmony_ci	const struct lws_protocols *p;
133d4afb5ceSopenharmony_ci	const char *cisin[CIS_COUNT];
134d4afb5ceSopenharmony_ci	struct lws_vhost *vh;
135d4afb5ceSopenharmony_ci	int tsi;
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	if (i->context->requested_stop_internal_loops)
138d4afb5ceSopenharmony_ci		return NULL;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	if (!i->context->protocol_init_done)
141d4afb5ceSopenharmony_ci		if (lws_protocol_init(i->context))
142d4afb5ceSopenharmony_ci			return NULL;
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	/*
145d4afb5ceSopenharmony_ci	 * If we have .local_protocol_name, use it to select the local protocol
146d4afb5ceSopenharmony_ci	 * handler to bind to.  Otherwise use .protocol if http[s].
147d4afb5ceSopenharmony_ci	 */
148d4afb5ceSopenharmony_ci	if (i->local_protocol_name)
149d4afb5ceSopenharmony_ci		local = i->local_protocol_name;
150d4afb5ceSopenharmony_ci
151d4afb5ceSopenharmony_ci	lws_context_lock(i->context, __func__);
152d4afb5ceSopenharmony_ci	/*
153d4afb5ceSopenharmony_ci	 * PHASE 1: if SMP, find out the tsi related to current service thread
154d4afb5ceSopenharmony_ci	 */
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	tsi = lws_pthread_self_to_tsi(i->context);
157d4afb5ceSopenharmony_ci	assert(tsi >= 0);
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci	/* PHASE 2: create a bare wsi */
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	wsi = __lws_wsi_create_with_role(i->context, tsi, NULL, i->log_cx);
162d4afb5ceSopenharmony_ci	lws_context_unlock(i->context);
163d4afb5ceSopenharmony_ci	if (wsi == NULL)
164d4afb5ceSopenharmony_ci		return NULL;
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci	vh = i->vhost;
167d4afb5ceSopenharmony_ci	if (!vh) {
168d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
169d4afb5ceSopenharmony_ci		if (lws_tls_jit_trust_vhost_bind(i->context, i->address, &vh))
170d4afb5ceSopenharmony_ci#endif
171d4afb5ceSopenharmony_ci		{
172d4afb5ceSopenharmony_ci			vh = lws_get_vhost_by_name(i->context, "default");
173d4afb5ceSopenharmony_ci			if (!vh) {
174d4afb5ceSopenharmony_ci
175d4afb5ceSopenharmony_ci				vh = i->context->vhost_list;
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci				if (!vh) { /* coverity */
178d4afb5ceSopenharmony_ci					lwsl_cx_err(i->context, "no vhost");
179d4afb5ceSopenharmony_ci					goto bail;
180d4afb5ceSopenharmony_ci				}
181d4afb5ceSopenharmony_ci				if (!strcmp(vh->name, "system"))
182d4afb5ceSopenharmony_ci					vh = vh->vhost_next;
183d4afb5ceSopenharmony_ci			}
184d4afb5ceSopenharmony_ci		}
185d4afb5ceSopenharmony_ci	}
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS)
188d4afb5ceSopenharmony_ci	/* any of these imply we are a client wsi bound to an SS, which
189d4afb5ceSopenharmony_ci	 * implies our opaque user ptr is the ss (or sspc if PROXY_LINK) handle
190d4afb5ceSopenharmony_ci	 */
191d4afb5ceSopenharmony_ci	wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD));
192d4afb5ceSopenharmony_ci	wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */
193d4afb5ceSopenharmony_ci	wsi->client_proxy_onward = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD);
194d4afb5ceSopenharmony_ci#endif
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
197d4afb5ceSopenharmony_ci	wsi->fic.name = "wsi";
198d4afb5ceSopenharmony_ci	if (i->fic.fi_owner.count)
199d4afb5ceSopenharmony_ci		/*
200d4afb5ceSopenharmony_ci		 * This moves all the lws_fi_t from i->fi to the vhost fi,
201d4afb5ceSopenharmony_ci		 * leaving it empty
202d4afb5ceSopenharmony_ci		 */
203d4afb5ceSopenharmony_ci		lws_fi_import(&wsi->fic, &i->fic);
204d4afb5ceSopenharmony_ci
205d4afb5ceSopenharmony_ci	lws_fi_inherit_copy(&wsi->fic, &i->context->fic, "wsi", i->fi_wsi_name);
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci	if (lws_fi(&wsi->fic, "createfail"))
208d4afb5ceSopenharmony_ci		goto bail;
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS)
211d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
212d4afb5ceSopenharmony_ci	if (wsi->client_bound_sspc) {
213d4afb5ceSopenharmony_ci		lws_sspc_handle_t *fih = (lws_sspc_handle_t *)i->opaque_user_data;
214d4afb5ceSopenharmony_ci		lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
215d4afb5ceSopenharmony_ci	}
216d4afb5ceSopenharmony_ci#endif
217d4afb5ceSopenharmony_ci	if (wsi->for_ss) {
218d4afb5ceSopenharmony_ci		lws_ss_handle_t *fih = (lws_ss_handle_t *)i->opaque_user_data;
219d4afb5ceSopenharmony_ci		lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
220d4afb5ceSopenharmony_ci	}
221d4afb5ceSopenharmony_ci#endif
222d4afb5ceSopenharmony_ci#endif
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci	lws_wsi_fault_timedclose(wsi);
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	/*
227d4afb5ceSopenharmony_ci	 * Until we exit, we can report connection failure directly to the
228d4afb5ceSopenharmony_ci	 * caller without needing to call through to protocol CONNECTION_ERROR.
229d4afb5ceSopenharmony_ci	 */
230d4afb5ceSopenharmony_ci	wsi->client_suppress_CONNECTION_ERROR = 1;
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_ci	if (i->keep_warm_secs)
233d4afb5ceSopenharmony_ci		wsi->keep_warm_secs = i->keep_warm_secs;
234d4afb5ceSopenharmony_ci	else
235d4afb5ceSopenharmony_ci		wsi->keep_warm_secs = 5;
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ci	wsi->seq = i->seq;
238d4afb5ceSopenharmony_ci	wsi->flags = i->ssl_connection;
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci	wsi->c_pri = i->priority;
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci	if (i->retry_and_idle_policy)
243d4afb5ceSopenharmony_ci		wsi->retry_policy = i->retry_and_idle_policy;
244d4afb5ceSopenharmony_ci	else
245d4afb5ceSopenharmony_ci		wsi->retry_policy = &i->context->default_retry;
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ci	if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY)
248d4afb5ceSopenharmony_ci		wsi->conn_validity_wakesuspend = 1;
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ci	lws_vhost_bind_wsi(vh, wsi);
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
253d4afb5ceSopenharmony_ci	/* additionally inerit from vhost we bound to */
254d4afb5ceSopenharmony_ci	lws_fi_inherit_copy(&wsi->fic, &vh->fic, "wsi", i->fi_wsi_name);
255d4afb5ceSopenharmony_ci#endif
256d4afb5ceSopenharmony_ci
257d4afb5ceSopenharmony_ci	if (!wsi->a.vhost) {
258d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "No vhost in the context");
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci		goto bail;
261d4afb5ceSopenharmony_ci	}
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci	/*
264d4afb5ceSopenharmony_ci	 * PHASE 3: Choose an initial role for the wsi and do role-specific init
265d4afb5ceSopenharmony_ci	 *
266d4afb5ceSopenharmony_ci	 * Note the initial role may not reflect the final role, eg,
267d4afb5ceSopenharmony_ci	 * we may want ws, but first we have to go through h1 to get that
268d4afb5ceSopenharmony_ci	 */
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci	if (lws_role_call_client_bind(wsi, i) < 0) {
271d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "unable to bind to role");
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci		goto bail;
274d4afb5ceSopenharmony_ci	}
275d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "role binding to %s", wsi->role_ops->name);
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci	/*
278d4afb5ceSopenharmony_ci	 * PHASE 4: fill up the wsi with stuff from the connect_info as far as
279d4afb5ceSopenharmony_ci	 * it can go.  It's uncertain because not only is our connection
280d4afb5ceSopenharmony_ci	 * going to complete asynchronously, we might have bound to h1 and not
281d4afb5ceSopenharmony_ci	 * even be able to get ahold of an ah immediately.
282d4afb5ceSopenharmony_ci	 */
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci	wsi->user_space = NULL;
285d4afb5ceSopenharmony_ci	wsi->pending_timeout = NO_PENDING_TIMEOUT;
286d4afb5ceSopenharmony_ci	wsi->position_in_fds_table = LWS_NO_FDS_POS;
287d4afb5ceSopenharmony_ci	wsi->ocport = wsi->c_port = (uint16_t)(unsigned int)i->port;
288d4afb5ceSopenharmony_ci	wsi->sys_tls_client_cert = i->sys_tls_client_cert;
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
291d4afb5ceSopenharmony_ci	wsi->txc.manual_initial_tx_credit =
292d4afb5ceSopenharmony_ci			(int32_t)i->manual_initial_tx_credit;
293d4afb5ceSopenharmony_ci#endif
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ci	wsi->a.protocol = &wsi->a.vhost->protocols[0];
296d4afb5ceSopenharmony_ci	wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
297d4afb5ceSopenharmony_ci	wsi->client_no_follow_redirect = !!(i->ssl_connection &
298d4afb5ceSopenharmony_ci					    LCCSCF_HTTP_NO_FOLLOW_REDIRECT);
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	/*
301d4afb5ceSopenharmony_ci	 * PHASE 5: handle external user_space now, generic alloc is done in
302d4afb5ceSopenharmony_ci	 * role finalization
303d4afb5ceSopenharmony_ci	 */
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci	if (i->userdata) {
306d4afb5ceSopenharmony_ci		wsi->user_space_externally_allocated = 1;
307d4afb5ceSopenharmony_ci		wsi->user_space = i->userdata;
308d4afb5ceSopenharmony_ci	}
309d4afb5ceSopenharmony_ci
310d4afb5ceSopenharmony_ci	if (local) {
311d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "vh %s protocol binding to %s\n",
312d4afb5ceSopenharmony_ci				wsi->a.vhost->name, local);
313d4afb5ceSopenharmony_ci		p = lws_vhost_name_to_protocol(wsi->a.vhost, local);
314d4afb5ceSopenharmony_ci		if (p)
315d4afb5ceSopenharmony_ci			lws_bind_protocol(wsi, p, __func__);
316d4afb5ceSopenharmony_ci		else
317d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "unknown protocol %s", local);
318d4afb5ceSopenharmony_ci
319d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "%s: %s %s entry",
320d4afb5ceSopenharmony_ci			    lws_wsi_tag(wsi), wsi->role_ops->name,
321d4afb5ceSopenharmony_ci			    wsi->a.protocol ? wsi->a.protocol->name : "none");
322d4afb5ceSopenharmony_ci	}
323d4afb5ceSopenharmony_ci
324d4afb5ceSopenharmony_ci	/*
325d4afb5ceSopenharmony_ci	 * PHASE 5: handle external user_space now, generic alloc is done in
326d4afb5ceSopenharmony_ci	 * role finalization
327d4afb5ceSopenharmony_ci	 */
328d4afb5ceSopenharmony_ci
329d4afb5ceSopenharmony_ci	if (!wsi->user_space && i->userdata) {
330d4afb5ceSopenharmony_ci		wsi->user_space_externally_allocated = 1;
331d4afb5ceSopenharmony_ci		wsi->user_space = i->userdata;
332d4afb5ceSopenharmony_ci	}
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
335d4afb5ceSopenharmony_ci	wsi->tls.use_ssl = (unsigned int)i->ssl_connection;
336d4afb5ceSopenharmony_ci#else
337d4afb5ceSopenharmony_ci	if (i->ssl_connection & LCCSCF_USE_SSL) {
338d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "lws not configured for tls");
339d4afb5ceSopenharmony_ci		goto bail;
340d4afb5ceSopenharmony_ci	}
341d4afb5ceSopenharmony_ci#endif
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci	/*
344d4afb5ceSopenharmony_ci	 * PHASE 6: stash the things from connect_info that we can't process
345d4afb5ceSopenharmony_ci	 * right now, eg, if http binding, without an ah.  If h1 and no ah, we
346d4afb5ceSopenharmony_ci	 * will go on the ah waiting list and process those things later (after
347d4afb5ceSopenharmony_ci	 * the connect_info and maybe the things pointed to have gone out of
348d4afb5ceSopenharmony_ci	 * scope)
349d4afb5ceSopenharmony_ci	 *
350d4afb5ceSopenharmony_ci	 * However these things are stashed in a generic way at this point,
351d4afb5ceSopenharmony_ci	 * with no relationship to http or ah
352d4afb5ceSopenharmony_ci	 */
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	cisin[CIS_ADDRESS]	= i->address;
355d4afb5ceSopenharmony_ci	cisin[CIS_PATH]		= i->path;
356d4afb5ceSopenharmony_ci	cisin[CIS_HOST]		= i->host;
357d4afb5ceSopenharmony_ci	cisin[CIS_ORIGIN]	= i->origin;
358d4afb5ceSopenharmony_ci	cisin[CIS_PROTOCOL]	= i->protocol;
359d4afb5ceSopenharmony_ci	cisin[CIS_METHOD]	= i->method;
360d4afb5ceSopenharmony_ci	cisin[CIS_IFACE]	= i->iface;
361d4afb5ceSopenharmony_ci	cisin[CIS_ALPN]		= i->alpn;
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci	if (lws_client_stash_create(wsi, cisin))
364d4afb5ceSopenharmony_ci		goto bail;
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
367d4afb5ceSopenharmony_ci	if (i->alpn)
368d4afb5ceSopenharmony_ci		lws_strncpy(wsi->alpn, i->alpn, sizeof(wsi->alpn));
369d4afb5ceSopenharmony_ci#endif
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci	wsi->a.opaque_user_data = wsi->stash->opaque_user_data =
372d4afb5ceSopenharmony_ci		i->opaque_user_data;
373d4afb5ceSopenharmony_ci
374d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS)
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci	if (wsi->for_ss) {
377d4afb5ceSopenharmony_ci		/* it's related to ss... the options are
378d4afb5ceSopenharmony_ci		 *
379d4afb5ceSopenharmony_ci		 * LCCSCF_SECSTREAM_PROXY_LINK  : client SSPC link to proxy
380d4afb5ceSopenharmony_ci		 * LCCSCF_SECSTREAM_PROXY_ONWARD: proxy's onward connection
381d4afb5ceSopenharmony_ci		 */
382d4afb5ceSopenharmony_ci		__lws_lc_tag(i->context, &i->context->lcg[
383d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
384d4afb5ceSopenharmony_ci		         i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK ? LWSLCG_WSI_SSP_CLIENT :
385d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
386d4afb5ceSopenharmony_ci		         (i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD ? LWSLCG_WSI_SSP_ONWARD :
387d4afb5ceSopenharmony_ci#endif
388d4afb5ceSopenharmony_ci			  LWSLCG_WSI_CLIENT
389d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
390d4afb5ceSopenharmony_ci			  )
391d4afb5ceSopenharmony_ci#endif
392d4afb5ceSopenharmony_ci		],
393d4afb5ceSopenharmony_ci#else
394d4afb5ceSopenharmony_ci				LWSLCG_WSI_CLIENT],
395d4afb5ceSopenharmony_ci#endif
396d4afb5ceSopenharmony_ci			&wsi->lc, "%s/%s/%s/(%s)", i->method ? i->method : "WS",
397d4afb5ceSopenharmony_ci			wsi->role_ops->name, i->address,
398d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
399d4afb5ceSopenharmony_ci			wsi->client_bound_sspc ?
400d4afb5ceSopenharmony_ci				lws_sspc_tag((lws_sspc_handle_t *)i->opaque_user_data) :
401d4afb5ceSopenharmony_ci#endif
402d4afb5ceSopenharmony_ci			lws_ss_tag(((lws_ss_handle_t *)i->opaque_user_data)));
403d4afb5ceSopenharmony_ci	} else
404d4afb5ceSopenharmony_ci#endif
405d4afb5ceSopenharmony_ci		__lws_lc_tag(i->context, &i->context->lcg[LWSLCG_WSI_CLIENT], &wsi->lc,
406d4afb5ceSopenharmony_ci			     "%s/%s/%s/%s", i->method ? i->method : "WS",
407d4afb5ceSopenharmony_ci			     wsi->role_ops->name ? wsi->role_ops->name : "novh", vh->name, i->address);
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	/*
412d4afb5ceSopenharmony_ci	 * at this point user callbacks like
413d4afb5ceSopenharmony_ci	 * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
414d4afb5ceSopenharmony_ci	 * know the parent... eg for proxying we can grab extra headers from
415d4afb5ceSopenharmony_ci	 * the parent's incoming ah and add them to the child client handshake
416d4afb5ceSopenharmony_ci	 */
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci	if (i->parent_wsi) {
419d4afb5ceSopenharmony_ci		lwsl_wsi_info(wsi, "created as child %s",
420d4afb5ceSopenharmony_ci			      lws_wsi_tag(i->parent_wsi));
421d4afb5ceSopenharmony_ci		wsi->parent = i->parent_wsi;
422d4afb5ceSopenharmony_ci		safe = wsi->sibling_list = i->parent_wsi->child_list;
423d4afb5ceSopenharmony_ci		i->parent_wsi->child_list = wsi;
424d4afb5ceSopenharmony_ci	}
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	/*
427d4afb5ceSopenharmony_ci	 * PHASE 7: Do any role-specific finalization processing.  We can still
428d4afb5ceSopenharmony_ci	 * see important info things via wsi->stash
429d4afb5ceSopenharmony_ci	 */
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ci	if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_client_bind)) {
432d4afb5ceSopenharmony_ci
433d4afb5ceSopenharmony_ci		int n = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_client_bind).
434d4afb5ceSopenharmony_ci							client_bind(wsi, NULL);
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci		if (n && i->parent_wsi)
437d4afb5ceSopenharmony_ci			/* unpick from parent */
438d4afb5ceSopenharmony_ci			i->parent_wsi->child_list = safe;
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci		if (n < 0)
441d4afb5ceSopenharmony_ci			/* we didn't survive, wsi is freed */
442d4afb5ceSopenharmony_ci			goto bail2;
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci		if (n)
445d4afb5ceSopenharmony_ci			/* something else failed, wsi needs freeing */
446d4afb5ceSopenharmony_ci			goto bail;
447d4afb5ceSopenharmony_ci	}
448d4afb5ceSopenharmony_ci
449d4afb5ceSopenharmony_ci	/* let the caller's optional wsi storage have the wsi we created */
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci	if (i->pwsi)
452d4afb5ceSopenharmony_ci		*i->pwsi = wsi;
453d4afb5ceSopenharmony_ci
454d4afb5ceSopenharmony_ci	if (!wsi->a.protocol)
455d4afb5ceSopenharmony_ci		/* we must have one protocol or another bound by this point */
456d4afb5ceSopenharmony_ci		goto bail;
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci	/* PHASE 8: notify protocol with role-specific connected callback */
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci	/* raw socket per se doesn't want this... raw socket proxy wants it... */
461d4afb5ceSopenharmony_ci
462d4afb5ceSopenharmony_ci	if (wsi->role_ops != &role_ops_raw_skt ||
463d4afb5ceSopenharmony_ci	    (i->local_protocol_name &&
464d4afb5ceSopenharmony_ci	     !strcmp(i->local_protocol_name, "raw-proxy"))) {
465d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "adoption cb %d to %s %s",
466d4afb5ceSopenharmony_ci			   wsi->role_ops->adoption_cb[0],
467d4afb5ceSopenharmony_ci			   wsi->role_ops->name, wsi->a.protocol->name);
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci		wsi->a.protocol->callback(wsi, wsi->role_ops->adoption_cb[0],
470d4afb5ceSopenharmony_ci				wsi->user_space, NULL, 0);
471d4afb5ceSopenharmony_ci	}
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HUBBUB)
474d4afb5ceSopenharmony_ci	if (i->uri_replace_to)
475d4afb5ceSopenharmony_ci		wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
476d4afb5ceSopenharmony_ci					     i->uri_replace_from,
477d4afb5ceSopenharmony_ci					     i->uri_replace_to);
478d4afb5ceSopenharmony_ci#endif
479d4afb5ceSopenharmony_ci
480d4afb5ceSopenharmony_ci	if (i->method && (!strcmp(i->method, "RAW") // ||
481d4afb5ceSopenharmony_ci//			  !strcmp(i->method, "MQTT")
482d4afb5ceSopenharmony_ci	)) {
483d4afb5ceSopenharmony_ci
484d4afb5ceSopenharmony_ci		/*
485d4afb5ceSopenharmony_ci		 * Not for MQTT here, since we don't know if we will
486d4afb5ceSopenharmony_ci		 * pipeline it or not...
487d4afb5ceSopenharmony_ci		 */
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci		wsi->tls.ssl = NULL;
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
494d4afb5ceSopenharmony_ci			const char *cce = NULL;
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci			switch (
497d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS)
498d4afb5ceSopenharmony_ci			lws_client_create_tls(wsi, &cce, 1)
499d4afb5ceSopenharmony_ci#else
500d4afb5ceSopenharmony_ci			lws_client_create_tls(wsi, &cce, 0)
501d4afb5ceSopenharmony_ci#endif
502d4afb5ceSopenharmony_ci			) {
503d4afb5ceSopenharmony_ci			case 1:
504d4afb5ceSopenharmony_ci				return wsi;
505d4afb5ceSopenharmony_ci			case 0:
506d4afb5ceSopenharmony_ci				break;
507d4afb5ceSopenharmony_ci			default:
508d4afb5ceSopenharmony_ci				goto bail3;
509d4afb5ceSopenharmony_ci			}
510d4afb5ceSopenharmony_ci		}
511d4afb5ceSopenharmony_ci#endif
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci		/* fallthru */
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci		wsi = lws_http_client_connect_via_info2(wsi);
517d4afb5ceSopenharmony_ci	}
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci	if (wsi)
520d4afb5ceSopenharmony_ci		/*
521d4afb5ceSopenharmony_ci		 * If it subsequently fails, report CONNECTION_ERROR,
522d4afb5ceSopenharmony_ci		 * because we're going to return a non-error return now.
523d4afb5ceSopenharmony_ci		 */
524d4afb5ceSopenharmony_ci		wsi->client_suppress_CONNECTION_ERROR = 0;
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	return wsi;
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
529d4afb5ceSopenharmony_cibail3:
530d4afb5ceSopenharmony_ci	lwsl_wsi_info(wsi, "tls start fail");
531d4afb5ceSopenharmony_ci	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail");
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci	if (i->pwsi)
534d4afb5ceSopenharmony_ci		*i->pwsi = NULL;
535d4afb5ceSopenharmony_ci
536d4afb5ceSopenharmony_ci	return NULL;
537d4afb5ceSopenharmony_ci#endif
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_cibail:
540d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
541d4afb5ceSopenharmony_ci	if (wsi->tls.ssl)
542d4afb5ceSopenharmony_ci		lws_tls_restrict_return(wsi);
543d4afb5ceSopenharmony_ci#endif
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci	lws_free_set_NULL(wsi->stash);
546d4afb5ceSopenharmony_ci	lws_fi_destroy(&wsi->fic);
547d4afb5ceSopenharmony_ci	lws_free(wsi);
548d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
549d4afb5ceSopenharmony_cibail2:
550d4afb5ceSopenharmony_ci#endif
551d4afb5ceSopenharmony_ci
552d4afb5ceSopenharmony_ci	if (i->pwsi)
553d4afb5ceSopenharmony_ci		*i->pwsi = NULL;
554d4afb5ceSopenharmony_ci
555d4afb5ceSopenharmony_ci	return NULL;
556d4afb5ceSopenharmony_ci}
557