1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 2021 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 struct ss_pcols *ss_pcols[] = {
28d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1)
29d4afb5ceSopenharmony_ci	&ss_pcol_h1,		/* LWSSSP_H1 */
30d4afb5ceSopenharmony_ci#else
31d4afb5ceSopenharmony_ci	NULL,
32d4afb5ceSopenharmony_ci#endif
33d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
34d4afb5ceSopenharmony_ci	&ss_pcol_h2,		/* LWSSSP_H2 */
35d4afb5ceSopenharmony_ci#else
36d4afb5ceSopenharmony_ci	NULL,
37d4afb5ceSopenharmony_ci#endif
38d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
39d4afb5ceSopenharmony_ci	&ss_pcol_ws,		/* LWSSSP_WS */
40d4afb5ceSopenharmony_ci#else
41d4afb5ceSopenharmony_ci	NULL,
42d4afb5ceSopenharmony_ci#endif
43d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
44d4afb5ceSopenharmony_ci	&ss_pcol_mqtt,		/* LWSSSP_MQTT */
45d4afb5ceSopenharmony_ci#else
46d4afb5ceSopenharmony_ci	NULL,
47d4afb5ceSopenharmony_ci#endif
48d4afb5ceSopenharmony_ci	&ss_pcol_raw,		/* LWSSSP_RAW */
49d4afb5ceSopenharmony_ci	NULL,
50d4afb5ceSopenharmony_ci};
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_cistatic const char *state_names[] = {
53d4afb5ceSopenharmony_ci	"(unset)",
54d4afb5ceSopenharmony_ci	"LWSSSCS_CREATING",
55d4afb5ceSopenharmony_ci	"LWSSSCS_DISCONNECTED",
56d4afb5ceSopenharmony_ci	"LWSSSCS_UNREACHABLE",
57d4afb5ceSopenharmony_ci	"LWSSSCS_AUTH_FAILED",
58d4afb5ceSopenharmony_ci	"LWSSSCS_CONNECTED",
59d4afb5ceSopenharmony_ci	"LWSSSCS_CONNECTING",
60d4afb5ceSopenharmony_ci	"LWSSSCS_DESTROYING",
61d4afb5ceSopenharmony_ci	"LWSSSCS_POLL",
62d4afb5ceSopenharmony_ci	"LWSSSCS_ALL_RETRIES_FAILED",
63d4afb5ceSopenharmony_ci	"LWSSSCS_QOS_ACK_REMOTE",
64d4afb5ceSopenharmony_ci	"LWSSSCS_QOS_NACK_REMOTE",
65d4afb5ceSopenharmony_ci	"LWSSSCS_QOS_ACK_LOCAL",
66d4afb5ceSopenharmony_ci	"LWSSSCS_QOS_NACK_LOCAL",
67d4afb5ceSopenharmony_ci	"LWSSSCS_TIMEOUT",
68d4afb5ceSopenharmony_ci	"LWSSSCS_SERVER_TXN",
69d4afb5ceSopenharmony_ci	"LWSSSCS_SERVER_UPGRADE",
70d4afb5ceSopenharmony_ci	"LWSSSCS_EVENT_WAIT_CANCELLED",
71d4afb5ceSopenharmony_ci	"LWSSSCS_UPSTREAM_LINK_RETRY",
72d4afb5ceSopenharmony_ci};
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci/*
75d4afb5ceSopenharmony_ci * For each "current state", set bit offsets for valid "next states".
76d4afb5ceSopenharmony_ci *
77d4afb5ceSopenharmony_ci * Since there are complicated ways to arrive at state transitions like proxying
78d4afb5ceSopenharmony_ci * and asynchronous destruction etc, so we monitor the state transitions we are
79d4afb5ceSopenharmony_ci * giving the ss user code to ensure we never deliver illegal state transitions
80d4afb5ceSopenharmony_ci * (because we will assert if we have bugs that do it)
81d4afb5ceSopenharmony_ci */
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ciconst uint32_t ss_state_txn_validity[] = {
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	/* if we was last in this state...  we can legally go to these states */
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	[0]				= (1 << LWSSSCS_CREATING) |
88d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ci	[LWSSSCS_CREATING]		= (1 << LWSSSCS_CONNECTING) |
91d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
92d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) |
93d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_SERVER_UPGRADE) |
94d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci	[LWSSSCS_DISCONNECTED]		= (1 << LWSSSCS_CONNECTING) |
97d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
98d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) |
99d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci	[LWSSSCS_UNREACHABLE]		= (1 << LWSSSCS_ALL_RETRIES_FAILED) |
102d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
103d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) |
104d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTING) |
105d4afb5ceSopenharmony_ci					  /* win conn failure > retry > succ */
106d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTED) |
107d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_ci	[LWSSSCS_AUTH_FAILED]		= (1 << LWSSSCS_ALL_RETRIES_FAILED) |
110d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
111d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTING) |
112d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci	[LWSSSCS_CONNECTED]		= (1 << LWSSSCS_SERVER_UPGRADE) |
115d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_SERVER_TXN) |
116d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_AUTH_FAILED) |
117d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_ACK_REMOTE) |
118d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_NACK_REMOTE) |
119d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_ACK_LOCAL) |
120d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_NACK_LOCAL) |
121d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DISCONNECTED) |
122d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
123d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) | /* proxy retry */
124d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	[LWSSSCS_CONNECTING]		= (1 << LWSSSCS_UNREACHABLE) |
127d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_AUTH_FAILED) |
128d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTING) |
129d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTED) |
130d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
131d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) |
132d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DISCONNECTED) | /* proxy retry */
133d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_ci	[LWSSSCS_DESTROYING]		= 0,
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	[LWSSSCS_POLL]			= (1 << LWSSSCS_CONNECTING) |
138d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
139d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_ALL_RETRIES_FAILED) |
140d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
141d4afb5ceSopenharmony_ci
142d4afb5ceSopenharmony_ci	[LWSSSCS_ALL_RETRIES_FAILED]	= (1 << LWSSSCS_CONNECTING) |
143d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
144d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	[LWSSSCS_QOS_ACK_REMOTE]	= (1 << LWSSSCS_DISCONNECTED) |
147d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
148d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
149d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_ACK_REMOTE) |
150d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_NACK_REMOTE) |
151d4afb5ceSopenharmony_ci#endif
152d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
153d4afb5ceSopenharmony_ci
154d4afb5ceSopenharmony_ci	[LWSSSCS_QOS_NACK_REMOTE]	= (1 << LWSSSCS_DISCONNECTED) |
155d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
156d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT)
157d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_ACK_REMOTE) |
158d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_NACK_REMOTE) |
159d4afb5ceSopenharmony_ci#endif
160d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ci	[LWSSSCS_QOS_ACK_LOCAL]		= (1 << LWSSSCS_DISCONNECTED) |
163d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
164d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci	[LWSSSCS_QOS_NACK_LOCAL]	= (1 << LWSSSCS_DESTROYING) |
167d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT),
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci	/* he can get the timeout at any point and take no action... */
170d4afb5ceSopenharmony_ci	[LWSSSCS_TIMEOUT]		= (1 << LWSSSCS_CONNECTING) |
171d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_CONNECTED) |
172d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_ACK_REMOTE) |
173d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_QOS_NACK_REMOTE) |
174d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_POLL) |
175d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
176d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DISCONNECTED) |
177d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_UNREACHABLE) |
178d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci	[LWSSSCS_SERVER_TXN]		= (1 << LWSSSCS_DISCONNECTED) |
181d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
182d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	[LWSSSCS_SERVER_UPGRADE]	= (1 << LWSSSCS_SERVER_TXN) |
185d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_TIMEOUT) |
186d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DISCONNECTED) |
187d4afb5ceSopenharmony_ci					  (1 << LWSSSCS_DESTROYING),
188d4afb5ceSopenharmony_ci};
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci/*
193d4afb5ceSopenharmony_ci * Convert any conmon data to JSON and attach to the ss handle.
194d4afb5ceSopenharmony_ci */
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_cilws_ss_state_return_t
197d4afb5ceSopenharmony_cilws_conmon_ss_json(lws_ss_handle_t *h)
198d4afb5ceSopenharmony_ci{
199d4afb5ceSopenharmony_ci	char ads[48], *end, *buf, *obuf;
200d4afb5ceSopenharmony_ci	const struct addrinfo *ai;
201d4afb5ceSopenharmony_ci	lws_ss_state_return_t ret = LWSSSSRET_OK;
202d4afb5ceSopenharmony_ci	struct lws_conmon cm;
203d4afb5ceSopenharmony_ci	size_t len = 500;
204d4afb5ceSopenharmony_ci
205d4afb5ceSopenharmony_ci	if (!h->policy || !(h->policy->flags & LWSSSPOLF_PERF) || !h->wsi ||
206d4afb5ceSopenharmony_ci	    h->wsi->perf_done)
207d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	if (h->conmon_json)
210d4afb5ceSopenharmony_ci		lws_free_set_NULL(h->conmon_json);
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	h->conmon_json = lws_malloc(len, __func__);
213d4afb5ceSopenharmony_ci	if (!h->conmon_json)
214d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci	obuf = buf = h->conmon_json;
217d4afb5ceSopenharmony_ci	end = buf + len - 1;
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	lws_conmon_wsi_take(h->wsi, &cm);
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci	lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
222d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
223d4afb5ceSopenharmony_ci		     "{\"peer\":\"%s\","
224d4afb5ceSopenharmony_ci		      "\"dns_us\":%u,"
225d4afb5ceSopenharmony_ci		      "\"dns_disp\":%u,"
226d4afb5ceSopenharmony_ci		      "\"sockconn_us\":%u,"
227d4afb5ceSopenharmony_ci		      "\"tls_us\":%u,"
228d4afb5ceSopenharmony_ci		      "\"txn_resp_us\":%u,"
229d4afb5ceSopenharmony_ci		      "\"dns\":[",
230d4afb5ceSopenharmony_ci		    ads,
231d4afb5ceSopenharmony_ci		    (unsigned int)cm.ciu_dns,
232d4afb5ceSopenharmony_ci		    (unsigned int)cm.dns_disposition,
233d4afb5ceSopenharmony_ci		    (unsigned int)cm.ciu_sockconn,
234d4afb5ceSopenharmony_ci		    (unsigned int)cm.ciu_tls,
235d4afb5ceSopenharmony_ci		    (unsigned int)cm.ciu_txn_resp);
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ci	ai = cm.dns_results_copy;
238d4afb5ceSopenharmony_ci	while (ai) {
239d4afb5ceSopenharmony_ci		lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
240d4afb5ceSopenharmony_ci		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "\"%s\"", ads);
241d4afb5ceSopenharmony_ci		if (ai->ai_next && buf < end - 2)
242d4afb5ceSopenharmony_ci			*buf++ = ',';
243d4afb5ceSopenharmony_ci		ai = ai->ai_next;
244d4afb5ceSopenharmony_ci	}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "]");
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	switch (cm.pcol) {
249d4afb5ceSopenharmony_ci	case LWSCONMON_PCOL_HTTP:
250d4afb5ceSopenharmony_ci		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
251d4afb5ceSopenharmony_ci			   ",\"prot_specific\":{\"protocol\":\"http\",\"resp\":%u}",
252d4afb5ceSopenharmony_ci			   (unsigned int)cm.protocol_specific.http.response);
253d4afb5ceSopenharmony_ci		break;
254d4afb5ceSopenharmony_ci	default:
255d4afb5ceSopenharmony_ci		break;
256d4afb5ceSopenharmony_ci	}
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "}");
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci	/*
261d4afb5ceSopenharmony_ci	 * This destroys the DNS list in the lws_conmon that we took
262d4afb5ceSopenharmony_ci	 * responsibility for when we used lws_conmon_wsi_take()
263d4afb5ceSopenharmony_ci	 */
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci	lws_conmon_release(&cm);
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci	h->conmon_len = (uint16_t)lws_ptr_diff(buf, obuf);
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
270d4afb5ceSopenharmony_ci	if (h->proxy_onward) {
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci		/*
273d4afb5ceSopenharmony_ci		 * ask to forward it on the proxy link
274d4afb5ceSopenharmony_ci		 */
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci		ss_proxy_onward_link_req_writeable(h);
277d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
278d4afb5ceSopenharmony_ci	}
279d4afb5ceSopenharmony_ci#endif
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci	/*
282d4afb5ceSopenharmony_ci	 * We can deliver it directly
283d4afb5ceSopenharmony_ci	 */
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	if (h->info.rx)
286d4afb5ceSopenharmony_ci		ret = h->info.rx(ss_to_userobj(h), (uint8_t *)h->conmon_json,
287d4afb5ceSopenharmony_ci				 (unsigned int)h->conmon_len,
288d4afb5ceSopenharmony_ci				 (int)(LWSSS_FLAG_SOM | LWSSS_FLAG_EOM |
289d4afb5ceSopenharmony_ci						 LWSSS_FLAG_PERF_JSON));
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci	lws_free_set_NULL(h->conmon_json);
292d4afb5ceSopenharmony_ci
293d4afb5ceSopenharmony_ci	return ret;
294d4afb5ceSopenharmony_ci}
295d4afb5ceSopenharmony_ci#endif
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ciint
298d4afb5ceSopenharmony_cilws_ss_check_next_state(lws_lifecycle_t *lc, uint8_t *prevstate,
299d4afb5ceSopenharmony_ci			lws_ss_constate_t cs)
300d4afb5ceSopenharmony_ci{
301d4afb5ceSopenharmony_ci	if (cs >= LWSSSCS_USER_BASE ||
302d4afb5ceSopenharmony_ci	    cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
303d4afb5ceSopenharmony_ci	    cs == LWSSSCS_SERVER_TXN ||
304d4afb5ceSopenharmony_ci	    cs == LWSSSCS_UPSTREAM_LINK_RETRY)
305d4afb5ceSopenharmony_ci		/*
306d4afb5ceSopenharmony_ci		 * we can't judge user or transient states, leave the old state
307d4afb5ceSopenharmony_ci		 * and just wave them through
308d4afb5ceSopenharmony_ci		 */
309d4afb5ceSopenharmony_ci		return 0;
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci	if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
312d4afb5ceSopenharmony_ci		/* we don't recognize this state as usable */
313d4afb5ceSopenharmony_ci		lwsl_err("%s: %s: bad new state %u\n", __func__, lc->gutag, cs);
314d4afb5ceSopenharmony_ci		assert(0);
315d4afb5ceSopenharmony_ci		return 1;
316d4afb5ceSopenharmony_ci	}
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci	if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
319d4afb5ceSopenharmony_ci		/* existing state is broken */
320d4afb5ceSopenharmony_ci		lwsl_err("%s: %s: bad existing state %u\n", __func__,
321d4afb5ceSopenharmony_ci			 lc->gutag, (unsigned int)*prevstate);
322d4afb5ceSopenharmony_ci		assert(0);
323d4afb5ceSopenharmony_ci		return 1;
324d4afb5ceSopenharmony_ci	}
325d4afb5ceSopenharmony_ci
326d4afb5ceSopenharmony_ci	if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci		lwsl_notice("%s: %s: %s -> %s\n", __func__, lc->gutag,
329d4afb5ceSopenharmony_ci			    lws_ss_state_name((int)*prevstate),
330d4afb5ceSopenharmony_ci			    lws_ss_state_name((int)cs));
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci		/* this is explicitly allowed, update old state to new */
333d4afb5ceSopenharmony_ci		*prevstate = (uint8_t)cs;
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci		return 0;
336d4afb5ceSopenharmony_ci	}
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci	lwsl_err("%s: %s: transition from %s -> %s is illegal\n", __func__,
339d4afb5ceSopenharmony_ci		 lc->gutag, lws_ss_state_name((int)*prevstate),
340d4afb5ceSopenharmony_ci		 lws_ss_state_name((int)cs));
341d4afb5ceSopenharmony_ci
342d4afb5ceSopenharmony_ci	assert(0);
343d4afb5ceSopenharmony_ci
344d4afb5ceSopenharmony_ci	return 1;
345d4afb5ceSopenharmony_ci}
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ciint
348d4afb5ceSopenharmony_cilws_ss_check_next_state_ss(lws_ss_handle_t *ss, uint8_t *prevstate,
349d4afb5ceSopenharmony_ci			   lws_ss_constate_t cs)
350d4afb5ceSopenharmony_ci{
351d4afb5ceSopenharmony_ci	if (cs >= LWSSSCS_USER_BASE ||
352d4afb5ceSopenharmony_ci	    cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
353d4afb5ceSopenharmony_ci	    cs == LWSSSCS_UPSTREAM_LINK_RETRY)
354d4afb5ceSopenharmony_ci		/*
355d4afb5ceSopenharmony_ci		 * we can't judge user or transient states, leave the old state
356d4afb5ceSopenharmony_ci		 * and just wave them through
357d4afb5ceSopenharmony_ci		 */
358d4afb5ceSopenharmony_ci		return 0;
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
361d4afb5ceSopenharmony_ci		/* we don't recognize this state as usable */
362d4afb5ceSopenharmony_ci		lwsl_ss_err(ss, "bad new state %u", cs);
363d4afb5ceSopenharmony_ci		assert(0);
364d4afb5ceSopenharmony_ci		return 1;
365d4afb5ceSopenharmony_ci	}
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci	if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
368d4afb5ceSopenharmony_ci		/* existing state is broken */
369d4afb5ceSopenharmony_ci		lwsl_ss_err(ss, "bad existing state %u",
370d4afb5ceSopenharmony_ci				(unsigned int)*prevstate);
371d4afb5ceSopenharmony_ci		assert(0);
372d4afb5ceSopenharmony_ci		return 1;
373d4afb5ceSopenharmony_ci	}
374d4afb5ceSopenharmony_ci
375d4afb5ceSopenharmony_ci	if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci		lwsl_ss_notice(ss, "%s -> %s",
378d4afb5ceSopenharmony_ci			       lws_ss_state_name((int)*prevstate),
379d4afb5ceSopenharmony_ci			       lws_ss_state_name((int)cs));
380d4afb5ceSopenharmony_ci
381d4afb5ceSopenharmony_ci		/* this is explicitly allowed, update old state to new */
382d4afb5ceSopenharmony_ci		*prevstate = (uint8_t)cs;
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci		return 0;
385d4afb5ceSopenharmony_ci	}
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	lwsl_ss_err(ss, "transition from %s -> %s is illegal",
388d4afb5ceSopenharmony_ci		    lws_ss_state_name((int)*prevstate),
389d4afb5ceSopenharmony_ci		    lws_ss_state_name((int)cs));
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_ci	assert(0);
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_ci	return 1;
394d4afb5ceSopenharmony_ci}
395d4afb5ceSopenharmony_ci
396d4afb5ceSopenharmony_ciconst char *
397d4afb5ceSopenharmony_cilws_ss_state_name(int state)
398d4afb5ceSopenharmony_ci{
399d4afb5ceSopenharmony_ci	if (state >= LWSSSCS_USER_BASE)
400d4afb5ceSopenharmony_ci		return "user state";
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci	if (state >= (int)LWS_ARRAY_SIZE(state_names))
403d4afb5ceSopenharmony_ci		return "unknown";
404d4afb5ceSopenharmony_ci
405d4afb5ceSopenharmony_ci	return state_names[state];
406d4afb5ceSopenharmony_ci}
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_cilws_ss_state_return_t
409d4afb5ceSopenharmony_cilws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs)
410d4afb5ceSopenharmony_ci{
411d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
412d4afb5ceSopenharmony_ci
413d4afb5ceSopenharmony_ci	if (!h)
414d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
415d4afb5ceSopenharmony_ci
416d4afb5ceSopenharmony_ci	if (lws_ss_check_next_state_ss(h, &h->prev_ss_state, cs))
417d4afb5ceSopenharmony_ci		return LWSSSSRET_DESTROY_ME;
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	if (cs == LWSSSCS_CONNECTED)
420d4afb5ceSopenharmony_ci		h->ss_dangling_connected = 1;
421d4afb5ceSopenharmony_ci	if (cs == LWSSSCS_DISCONNECTED)
422d4afb5ceSopenharmony_ci		h->ss_dangling_connected = 0;
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SEQUENCER)
425d4afb5ceSopenharmony_ci	/*
426d4afb5ceSopenharmony_ci	 * A parent sequencer for the ss is optional, if we have one, keep it
427d4afb5ceSopenharmony_ci	 * informed of state changes on the ss connection
428d4afb5ceSopenharmony_ci	 */
429d4afb5ceSopenharmony_ci	if (h->seq && cs != LWSSSCS_DESTROYING)
430d4afb5ceSopenharmony_ci		lws_seq_queue_event(h->seq, LWSSEQ_SS_STATE_BASE + cs,
431d4afb5ceSopenharmony_ci				    (void *)h, NULL);
432d4afb5ceSopenharmony_ci#endif
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci	if (h->info.state) {
435d4afb5ceSopenharmony_ci		h->h_in_svc = h;
436d4afb5ceSopenharmony_ci		r = h->info.state(ss_to_userobj(h), NULL, cs,
437d4afb5ceSopenharmony_ci			cs == LWSSSCS_UNREACHABLE &&
438d4afb5ceSopenharmony_ci			h->wsi && h->wsi->dns_reachability);
439d4afb5ceSopenharmony_ci		h->h_in_svc = NULL;
440d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
441d4afb5ceSopenharmony_ci		if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) &&
442d4afb5ceSopenharmony_ci		    cs == LWSSSCS_DISCONNECTED)
443d4afb5ceSopenharmony_ci			r = LWSSSSRET_DESTROY_ME;
444d4afb5ceSopenharmony_ci#endif
445d4afb5ceSopenharmony_ci		return r;
446d4afb5ceSopenharmony_ci	}
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci	return LWSSSSRET_OK;
449d4afb5ceSopenharmony_ci}
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ciint
452d4afb5ceSopenharmony_ci_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(lws_ss_state_return_t r, struct lws *wsi,
453d4afb5ceSopenharmony_ci			 lws_ss_handle_t **ph)
454d4afb5ceSopenharmony_ci{
455d4afb5ceSopenharmony_ci	if (r == LWSSSSRET_DESTROY_ME) {
456d4afb5ceSopenharmony_ci		lwsl_info("%s: DESTROY ME: %s, %s\n", __func__,
457d4afb5ceSopenharmony_ci				lws_wsi_tag(wsi), lws_ss_tag(*ph));
458d4afb5ceSopenharmony_ci		if (wsi) {
459d4afb5ceSopenharmony_ci			lws_set_opaque_user_data(wsi, NULL);
460d4afb5ceSopenharmony_ci			lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
461d4afb5ceSopenharmony_ci		} else {
462d4afb5ceSopenharmony_ci			if ((*ph)->wsi) {
463d4afb5ceSopenharmony_ci				lws_set_opaque_user_data((*ph)->wsi, NULL);
464d4afb5ceSopenharmony_ci				lws_set_timeout((*ph)->wsi, 1, LWS_TO_KILL_ASYNC);
465d4afb5ceSopenharmony_ci			}
466d4afb5ceSopenharmony_ci		}
467d4afb5ceSopenharmony_ci		(*ph)->wsi = NULL;
468d4afb5ceSopenharmony_ci		lws_ss_destroy(ph);
469d4afb5ceSopenharmony_ci	}
470d4afb5ceSopenharmony_ci
471d4afb5ceSopenharmony_ci	return -1; /* close connection */
472d4afb5ceSopenharmony_ci}
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_cistatic void
475d4afb5ceSopenharmony_cilws_ss_timeout_sul_check_cb(lws_sorted_usec_list_t *sul)
476d4afb5ceSopenharmony_ci{
477d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
478d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul);
479d4afb5ceSopenharmony_ci
480d4afb5ceSopenharmony_ci	lwsl_info("%s: retrying %s after backoff\n", __func__, lws_ss_tag(h));
481d4afb5ceSopenharmony_ci	/* we want to retry... */
482d4afb5ceSopenharmony_ci	h->seqstate = SSSEQ_DO_RETRY;
483d4afb5ceSopenharmony_ci
484d4afb5ceSopenharmony_ci	r = _lws_ss_request_tx(h);
485d4afb5ceSopenharmony_ci	_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, NULL, &h);
486d4afb5ceSopenharmony_ci}
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ciint
489d4afb5ceSopenharmony_cilws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
490d4afb5ceSopenharmony_ci			size_t olen, size_t *exp_ofs)
491d4afb5ceSopenharmony_ci{
492d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = (lws_ss_handle_t *)priv;
493d4afb5ceSopenharmony_ci	const char *replace = NULL;
494d4afb5ceSopenharmony_ci	size_t total, budget;
495d4afb5ceSopenharmony_ci	lws_ss_metadata_t *md = lws_ss_policy_metadata(h->policy, name),
496d4afb5ceSopenharmony_ci			  *hmd = lws_ss_get_handle_metadata(h, name);
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci	if (!md) {
499d4afb5ceSopenharmony_ci		lwsl_err("%s: Unknown metadata %s\n", __func__, name);
500d4afb5ceSopenharmony_ci
501d4afb5ceSopenharmony_ci		return LSTRX_FATAL_NAME_UNKNOWN;
502d4afb5ceSopenharmony_ci	}
503d4afb5ceSopenharmony_ci
504d4afb5ceSopenharmony_ci	if (!hmd)
505d4afb5ceSopenharmony_ci		return LSTRX_FILLED_OUT;
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	replace = hmd->value__may_own_heap;
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci	if (!replace)
510d4afb5ceSopenharmony_ci		return LSTRX_DONE;
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci	total = hmd->length;
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci	budget = olen - *pos;
515d4afb5ceSopenharmony_ci	total -= *exp_ofs;
516d4afb5ceSopenharmony_ci	if (total < budget)
517d4afb5ceSopenharmony_ci		budget = total;
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci	if (out)
520d4afb5ceSopenharmony_ci		memcpy(out + *pos, replace + (*exp_ofs), budget);
521d4afb5ceSopenharmony_ci	*exp_ofs += budget;
522d4afb5ceSopenharmony_ci	*pos += budget;
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci	if (budget == total)
525d4afb5ceSopenharmony_ci		return LSTRX_DONE;
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_ci	return LSTRX_FILLED_OUT;
528d4afb5ceSopenharmony_ci}
529d4afb5ceSopenharmony_ci
530d4afb5ceSopenharmony_ciint
531d4afb5ceSopenharmony_cilws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us)
532d4afb5ceSopenharmony_ci{
533d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &h->context->pt[h->tsi];
534d4afb5ceSopenharmony_ci
535d4afb5ceSopenharmony_ci	h->sul.cb = lws_ss_timeout_sul_check_cb;
536d4afb5ceSopenharmony_ci	__lws_sul_insert_us(&pt->pt_sul_owner[
537d4afb5ceSopenharmony_ci	            !!(h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)],
538d4afb5ceSopenharmony_ci		    &h->sul, us);
539d4afb5ceSopenharmony_ci
540d4afb5ceSopenharmony_ci	return 0;
541d4afb5ceSopenharmony_ci}
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_cilws_ss_state_return_t
544d4afb5ceSopenharmony_ci_lws_ss_backoff(lws_ss_handle_t *h, lws_usec_t us_override)
545d4afb5ceSopenharmony_ci{
546d4afb5ceSopenharmony_ci	uint64_t ms;
547d4afb5ceSopenharmony_ci	char conceal;
548d4afb5ceSopenharmony_ci
549d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
550d4afb5ceSopenharmony_ci
551d4afb5ceSopenharmony_ci	if (h->seqstate == SSSEQ_RECONNECT_WAIT)
552d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
553d4afb5ceSopenharmony_ci
554d4afb5ceSopenharmony_ci	/* figure out what we should do about another retry */
555d4afb5ceSopenharmony_ci
556d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: retry backoff after failure\n", __func__, lws_ss_tag(h));
557d4afb5ceSopenharmony_ci	ms = lws_retry_get_delay_ms(h->context, h->policy->retry_bo,
558d4afb5ceSopenharmony_ci				    &h->retry, &conceal);
559d4afb5ceSopenharmony_ci	if (!conceal) {
560d4afb5ceSopenharmony_ci		lwsl_info("%s: %s: abandon conn attempt \n",__func__, lws_ss_tag(h));
561d4afb5ceSopenharmony_ci
562d4afb5ceSopenharmony_ci		if (h->seqstate == SSSEQ_IDLE) /* been here? */
563d4afb5ceSopenharmony_ci			return LWSSSSRET_OK;
564d4afb5ceSopenharmony_ci
565d4afb5ceSopenharmony_ci		h->seqstate = SSSEQ_IDLE;
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci		return lws_ss_event_helper(h, LWSSSCS_ALL_RETRIES_FAILED);
568d4afb5ceSopenharmony_ci	}
569d4afb5ceSopenharmony_ci
570d4afb5ceSopenharmony_ci	/* Only increase our planned backoff, or go with it */
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci	if (us_override < (lws_usec_t)ms * LWS_US_PER_MS)
573d4afb5ceSopenharmony_ci		us_override = (lws_usec_t)(ms * LWS_US_PER_MS);
574d4afb5ceSopenharmony_ci
575d4afb5ceSopenharmony_ci	h->seqstate = SSSEQ_RECONNECT_WAIT;
576d4afb5ceSopenharmony_ci	lws_ss_set_timeout_us(h, us_override);
577d4afb5ceSopenharmony_ci
578d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: retry wait %dms\n", __func__, lws_ss_tag(h),
579d4afb5ceSopenharmony_ci						  (int)(us_override / 1000));
580d4afb5ceSopenharmony_ci
581d4afb5ceSopenharmony_ci	return LWSSSSRET_OK;
582d4afb5ceSopenharmony_ci}
583d4afb5ceSopenharmony_ci
584d4afb5ceSopenharmony_cilws_ss_state_return_t
585d4afb5ceSopenharmony_cilws_ss_backoff(lws_ss_handle_t *h)
586d4afb5ceSopenharmony_ci{
587d4afb5ceSopenharmony_ci	return _lws_ss_backoff(h, 0);
588d4afb5ceSopenharmony_ci}
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci/*
593d4afb5ceSopenharmony_ci * Local SMD <-> SS
594d4afb5ceSopenharmony_ci *
595d4afb5ceSopenharmony_ci * We pass received messages through to the SS handler synchronously, using the
596d4afb5ceSopenharmony_ci * lws service thread context.
597d4afb5ceSopenharmony_ci *
598d4afb5ceSopenharmony_ci * After the SS is created and registered, still nothing is going to come here
599d4afb5ceSopenharmony_ci * until the peer sends us his rx_class_mask and we update his registration with
600d4afb5ceSopenharmony_ci * it, because from SS creation his rx_class_mask defaults to 0.
601d4afb5ceSopenharmony_ci */
602d4afb5ceSopenharmony_ci
603d4afb5ceSopenharmony_cistatic int
604d4afb5ceSopenharmony_cilws_smd_ss_cb(void *opaque, lws_smd_class_t _class,
605d4afb5ceSopenharmony_ci	      lws_usec_t timestamp, void *buf, size_t len)
606d4afb5ceSopenharmony_ci{
607d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = (lws_ss_handle_t *)opaque;
608d4afb5ceSopenharmony_ci	uint8_t *p = (uint8_t *)buf - LWS_SMD_SS_RX_HEADER_LEN;
609d4afb5ceSopenharmony_ci
610d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
611d4afb5ceSopenharmony_ci
612d4afb5ceSopenharmony_ci	/*
613d4afb5ceSopenharmony_ci	 * When configured with SS enabled, lws over-allocates
614d4afb5ceSopenharmony_ci	 * LWS_SMD_SS_RX_HEADER_LEN bytes behind the payload of the queued
615d4afb5ceSopenharmony_ci	 * message, for prepending serialized class and timestamp data in-band
616d4afb5ceSopenharmony_ci	 * with the payload.
617d4afb5ceSopenharmony_ci	 */
618d4afb5ceSopenharmony_ci
619d4afb5ceSopenharmony_ci	lws_ser_wu64be(p, _class);
620d4afb5ceSopenharmony_ci	lws_ser_wu64be(p + 8, (uint64_t)timestamp);
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci	if (h->info.rx)
623d4afb5ceSopenharmony_ci		h->info.rx((void *)(h + 1), p, len + LWS_SMD_SS_RX_HEADER_LEN,
624d4afb5ceSopenharmony_ci		      LWSSS_FLAG_SOM | LWSSS_FLAG_EOM);
625d4afb5ceSopenharmony_ci
626d4afb5ceSopenharmony_ci	return 0;
627d4afb5ceSopenharmony_ci}
628d4afb5ceSopenharmony_ci
629d4afb5ceSopenharmony_cistatic void
630d4afb5ceSopenharmony_cilws_ss_smd_tx_cb(lws_sorted_usec_list_t *sul)
631d4afb5ceSopenharmony_ci{
632d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, u.smd.sul_write);
633d4afb5ceSopenharmony_ci	uint8_t buf[LWS_SMD_SS_RX_HEADER_LEN + LWS_SMD_MAX_PAYLOAD], *p;
634d4afb5ceSopenharmony_ci	size_t len = sizeof(buf);
635d4afb5ceSopenharmony_ci	lws_smd_class_t _class;
636d4afb5ceSopenharmony_ci	int flags = 0, n;
637d4afb5ceSopenharmony_ci
638d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
639d4afb5ceSopenharmony_ci
640d4afb5ceSopenharmony_ci	if (!h->info.tx)
641d4afb5ceSopenharmony_ci		return;
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_ci	n = h->info.tx((h + 1), h->txord++, buf, &len, &flags);
644d4afb5ceSopenharmony_ci	if (n)
645d4afb5ceSopenharmony_ci		/* nonzero return means don't want to send anything */
646d4afb5ceSopenharmony_ci		return;
647d4afb5ceSopenharmony_ci
648d4afb5ceSopenharmony_ci	// lwsl_notice("%s: (SS %p bound to _lws_smd creates message) tx len %d\n", __func__, h, (int)len);
649d4afb5ceSopenharmony_ci	// lwsl_hexdump_notice(buf, len);
650d4afb5ceSopenharmony_ci
651d4afb5ceSopenharmony_ci	assert(len >= LWS_SMD_SS_RX_HEADER_LEN);
652d4afb5ceSopenharmony_ci	_class = (lws_smd_class_t)lws_ser_ru64be(buf);
653d4afb5ceSopenharmony_ci	p = lws_smd_msg_alloc(h->context, _class, len - LWS_SMD_SS_RX_HEADER_LEN);
654d4afb5ceSopenharmony_ci	if (!p) {
655d4afb5ceSopenharmony_ci		// this can be rejected if nobody listening for this class
656d4afb5ceSopenharmony_ci		//lwsl_notice("%s: failed to alloc\n", __func__);
657d4afb5ceSopenharmony_ci		return;
658d4afb5ceSopenharmony_ci	}
659d4afb5ceSopenharmony_ci
660d4afb5ceSopenharmony_ci	memcpy(p, buf + LWS_SMD_SS_RX_HEADER_LEN, len - LWS_SMD_SS_RX_HEADER_LEN);
661d4afb5ceSopenharmony_ci	if (lws_smd_msg_send(h->context, p)) {
662d4afb5ceSopenharmony_ci		lwsl_notice("%s: failed to queue\n", __func__);
663d4afb5ceSopenharmony_ci		return;
664d4afb5ceSopenharmony_ci	}
665d4afb5ceSopenharmony_ci}
666d4afb5ceSopenharmony_ci
667d4afb5ceSopenharmony_ci#endif
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_cilws_ss_state_return_t
670d4afb5ceSopenharmony_ci_lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw)
671d4afb5ceSopenharmony_ci{
672d4afb5ceSopenharmony_ci	const char *prot, *_prot, *ipath, *_ipath, *ads, *_ads;
673d4afb5ceSopenharmony_ci	struct lws_client_connect_info i;
674d4afb5ceSopenharmony_ci	const struct ss_pcols *ssp;
675d4afb5ceSopenharmony_ci	size_t used_in, used_out;
676d4afb5ceSopenharmony_ci	union lws_ss_contemp ct;
677d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
678d4afb5ceSopenharmony_ci	int port, _port, tls;
679d4afb5ceSopenharmony_ci	char *path, ep[96];
680d4afb5ceSopenharmony_ci	lws_strexp_t exp;
681d4afb5ceSopenharmony_ci	struct lws *wsi;
682d4afb5ceSopenharmony_ci
683d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
684d4afb5ceSopenharmony_ci
685d4afb5ceSopenharmony_ci	if (!h->policy) {
686d4afb5ceSopenharmony_ci		lwsl_err("%s: ss with no policy\n", __func__);
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
689d4afb5ceSopenharmony_ci	}
690d4afb5ceSopenharmony_ci
691d4afb5ceSopenharmony_ci	/*
692d4afb5ceSopenharmony_ci	 * We are already bound to a sink?
693d4afb5ceSopenharmony_ci	 */
694d4afb5ceSopenharmony_ci
695d4afb5ceSopenharmony_ci//	if (h->h_sink)
696d4afb5ceSopenharmony_ci//		return 0;
697d4afb5ceSopenharmony_ci
698d4afb5ceSopenharmony_ci	if (!is_retry)
699d4afb5ceSopenharmony_ci		h->retry = 0;
700d4afb5ceSopenharmony_ci
701d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
702d4afb5ceSopenharmony_ci	if (h->policy == &pol_smd) {
703d4afb5ceSopenharmony_ci
704d4afb5ceSopenharmony_ci		if (h->u.smd.smd_peer)
705d4afb5ceSopenharmony_ci			return LWSSSSRET_OK;
706d4afb5ceSopenharmony_ci
707d4afb5ceSopenharmony_ci		// lwsl_notice("%s: received connect for _lws_smd, registering for class mask 0x%x\n",
708d4afb5ceSopenharmony_ci		//		__func__, h->info.manual_initial_tx_credit);
709d4afb5ceSopenharmony_ci
710d4afb5ceSopenharmony_ci		h->u.smd.smd_peer = lws_smd_register(h->context, h,
711d4afb5ceSopenharmony_ci					(h->info.flags & LWSSSINFLAGS_PROXIED) ?
712d4afb5ceSopenharmony_ci						LWSSMDREG_FLAG_PROXIED_SS : 0,
713d4afb5ceSopenharmony_ci					(lws_smd_class_t)h->info.manual_initial_tx_credit,
714d4afb5ceSopenharmony_ci					lws_smd_ss_cb);
715d4afb5ceSopenharmony_ci		if (!h->u.smd.smd_peer)
716d4afb5ceSopenharmony_ci			return LWSSSSRET_TX_DONT_SEND;
717d4afb5ceSopenharmony_ci
718d4afb5ceSopenharmony_ci		if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
719d4afb5ceSopenharmony_ci			return LWSSSSRET_TX_DONT_SEND;
720d4afb5ceSopenharmony_ci
721d4afb5ceSopenharmony_ci		if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
722d4afb5ceSopenharmony_ci			return LWSSSSRET_TX_DONT_SEND;
723d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
724d4afb5ceSopenharmony_ci	}
725d4afb5ceSopenharmony_ci#endif
726d4afb5ceSopenharmony_ci
727d4afb5ceSopenharmony_ci	/*
728d4afb5ceSopenharmony_ci	 * We're going to substitute ${metadata} in the endpoint at connection-
729d4afb5ceSopenharmony_ci	 * time, so this can be set dynamically...
730d4afb5ceSopenharmony_ci	 */
731d4afb5ceSopenharmony_ci
732d4afb5ceSopenharmony_ci	lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, ep, sizeof(ep));
733d4afb5ceSopenharmony_ci
734d4afb5ceSopenharmony_ci	if (lws_strexp_expand(&exp, h->policy->endpoint,
735d4afb5ceSopenharmony_ci			      strlen(h->policy->endpoint),
736d4afb5ceSopenharmony_ci			      &used_in, &used_out) != LSTRX_DONE) {
737d4afb5ceSopenharmony_ci		lwsl_err("%s: address strexp failed\n", __func__);
738d4afb5ceSopenharmony_ci
739d4afb5ceSopenharmony_ci		return LWSSSSRET_TX_DONT_SEND;
740d4afb5ceSopenharmony_ci	}
741d4afb5ceSopenharmony_ci
742d4afb5ceSopenharmony_ci	/*
743d4afb5ceSopenharmony_ci	 * ... in some cases, we might want the user to be able to override
744d4afb5ceSopenharmony_ci	 * some policy settings by what he provided in there.  For example,
745d4afb5ceSopenharmony_ci	 * if he set the endpoint to "https://myendpoint.com:4443/mypath" it
746d4afb5ceSopenharmony_ci	 * might be quite convenient to override the policy to follow the info
747d4afb5ceSopenharmony_ci	 * that was given for at least server, port and the url path.
748d4afb5ceSopenharmony_ci	 */
749d4afb5ceSopenharmony_ci
750d4afb5ceSopenharmony_ci	_port = port = h->policy->port;
751d4afb5ceSopenharmony_ci	_prot = prot = NULL;
752d4afb5ceSopenharmony_ci	_ipath = ipath = "";
753d4afb5ceSopenharmony_ci	_ads = ads = ep;
754d4afb5ceSopenharmony_ci
755d4afb5ceSopenharmony_ci	if (strchr(ep, ':') &&
756d4afb5ceSopenharmony_ci	    !lws_parse_uri(ep, &_prot, &_ads, &_port, &_ipath)) {
757d4afb5ceSopenharmony_ci		lwsl_debug("%s: using uri parse results '%s' '%s' %d '%s'\n",
758d4afb5ceSopenharmony_ci				__func__, _prot, _ads, _port, _ipath);
759d4afb5ceSopenharmony_ci		prot = _prot;
760d4afb5ceSopenharmony_ci		ads = _ads;
761d4afb5ceSopenharmony_ci		port = _port;
762d4afb5ceSopenharmony_ci		ipath = _ipath;
763d4afb5ceSopenharmony_ci	}
764d4afb5ceSopenharmony_ci
765d4afb5ceSopenharmony_ci	memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
766d4afb5ceSopenharmony_ci	i.context = h->context;
767d4afb5ceSopenharmony_ci	tls = !!(h->policy->flags & LWSSSPOLF_TLS);
768d4afb5ceSopenharmony_ci
769d4afb5ceSopenharmony_ci	if (prot && (!strcmp(prot, "http") || !strcmp(prot, "ws") ||
770d4afb5ceSopenharmony_ci		     !strcmp(prot, "mqtt")))
771d4afb5ceSopenharmony_ci		tls = 0;
772d4afb5ceSopenharmony_ci
773d4afb5ceSopenharmony_ci	if (tls) {
774d4afb5ceSopenharmony_ci		lwsl_info("%s: using tls\n", __func__);
775d4afb5ceSopenharmony_ci		i.ssl_connection = LCCSCF_USE_SSL;
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci		if (!h->policy->trust.store)
778d4afb5ceSopenharmony_ci			lwsl_info("%s: using platform trust store\n", __func__);
779d4afb5ceSopenharmony_ci		else {
780d4afb5ceSopenharmony_ci
781d4afb5ceSopenharmony_ci			i.vhost = lws_get_vhost_by_name(h->context,
782d4afb5ceSopenharmony_ci					h->policy->trust.store->name);
783d4afb5ceSopenharmony_ci			if (!i.vhost) {
784d4afb5ceSopenharmony_ci				lwsl_err("%s: missing vh for policy %s\n",
785d4afb5ceSopenharmony_ci					 __func__,
786d4afb5ceSopenharmony_ci					 h->policy->trust.store->name);
787d4afb5ceSopenharmony_ci
788d4afb5ceSopenharmony_ci				return -1;
789d4afb5ceSopenharmony_ci			}
790d4afb5ceSopenharmony_ci		}
791d4afb5ceSopenharmony_ci	}
792d4afb5ceSopenharmony_ci
793d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)
794d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_WAKE_SUSPEND__VALIDITY;
795d4afb5ceSopenharmony_ci
796d4afb5ceSopenharmony_ci	/* translate policy attributes to IP ToS flags */
797d4afb5ceSopenharmony_ci
798d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)
799d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_IP_LOW_LATENCY;
800d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)
801d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_IP_HIGH_THROUGHPUT;
802d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)
803d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_IP_HIGH_RELIABILITY;
804d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_ATTR_LOW_COST)
805d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_IP_LOW_COST;
806d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_PERF) /* collect conmon stats on this */
807d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_CONMON;
808d4afb5ceSopenharmony_ci
809d4afb5ceSopenharmony_ci	/* mark the connection with the streamtype priority from the policy */
810d4afb5ceSopenharmony_ci
811d4afb5ceSopenharmony_ci	i.priority = h->policy->priority;
812d4afb5ceSopenharmony_ci
813d4afb5ceSopenharmony_ci	i.ssl_connection |= LCCSCF_SECSTREAM_CLIENT;
814d4afb5ceSopenharmony_ci
815d4afb5ceSopenharmony_ci	if (conn_if_sspc_onw) {
816d4afb5ceSopenharmony_ci		i.ssl_connection |= LCCSCF_SECSTREAM_PROXY_ONWARD;
817d4afb5ceSopenharmony_ci		h->conn_if_sspc_onw = conn_if_sspc_onw;
818d4afb5ceSopenharmony_ci	}
819d4afb5ceSopenharmony_ci
820d4afb5ceSopenharmony_ci
821d4afb5ceSopenharmony_ci	i.address		= ads;
822d4afb5ceSopenharmony_ci	i.port			= port;
823d4afb5ceSopenharmony_ci	i.host			= i.address;
824d4afb5ceSopenharmony_ci	i.origin		= i.address;
825d4afb5ceSopenharmony_ci	i.opaque_user_data	= h;
826d4afb5ceSopenharmony_ci	i.seq			= h->seq;
827d4afb5ceSopenharmony_ci	i.retry_and_idle_policy	= h->policy->retry_bo;
828d4afb5ceSopenharmony_ci	i.sys_tls_client_cert	= h->policy->client_cert;
829d4afb5ceSopenharmony_ci
830d4afb5ceSopenharmony_ci	i.path			= ipath;
831d4afb5ceSopenharmony_ci		/* if this is not "", munge should use it instead of policy
832d4afb5ceSopenharmony_ci		 * url path
833d4afb5ceSopenharmony_ci		 */
834d4afb5ceSopenharmony_ci
835d4afb5ceSopenharmony_ci	ssp = ss_pcols[(int)h->policy->protocol];
836d4afb5ceSopenharmony_ci	if (!ssp) {
837d4afb5ceSopenharmony_ci		lwsl_err("%s: unsupported protocol\n", __func__);
838d4afb5ceSopenharmony_ci
839d4afb5ceSopenharmony_ci		return LWSSSSRET_TX_DONT_SEND;
840d4afb5ceSopenharmony_ci	}
841d4afb5ceSopenharmony_ci	i.alpn = ssp->alpn;
842d4afb5ceSopenharmony_ci
843d4afb5ceSopenharmony_ci	/*
844d4afb5ceSopenharmony_ci	 * For http, we can get the method from the http object, override in
845d4afb5ceSopenharmony_ci	 * the protocol-specific munge callback below if not http
846d4afb5ceSopenharmony_ci	 */
847d4afb5ceSopenharmony_ci	i.method = h->policy->u.http.method;
848d4afb5ceSopenharmony_ci	i.protocol = ssp->protocol->name; /* lws protocol name */
849d4afb5ceSopenharmony_ci	i.local_protocol_name = i.protocol;
850d4afb5ceSopenharmony_ci
851d4afb5ceSopenharmony_ci	path = lws_malloc(h->context->max_http_header_data, __func__);
852d4afb5ceSopenharmony_ci	if (!path) {
853d4afb5ceSopenharmony_ci		lwsl_warn("%s: OOM on path prealloc\n", __func__);
854d4afb5ceSopenharmony_ci		return LWSSSSRET_TX_DONT_SEND;
855d4afb5ceSopenharmony_ci	}
856d4afb5ceSopenharmony_ci
857d4afb5ceSopenharmony_ci	if (ssp->munge) /* eg, raw doesn't use; endpoint strexp already done */
858d4afb5ceSopenharmony_ci		ssp->munge(h, path, h->context->max_http_header_data, &i, &ct);
859d4afb5ceSopenharmony_ci
860d4afb5ceSopenharmony_ci	i.pwsi = &h->wsi;
861d4afb5ceSopenharmony_ci
862d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SSPLUGINS)
863d4afb5ceSopenharmony_ci	if (h->policy->plugins[0] && h->policy->plugins[0]->munge)
864d4afb5ceSopenharmony_ci		h->policy->plugins[0]->munge(h, path, h->context->max_http_header_data);
865d4afb5ceSopenharmony_ci#endif
866d4afb5ceSopenharmony_ci
867d4afb5ceSopenharmony_ci	lwsl_info("%s: connecting %s, '%s' '%s' %s\n", __func__, i.method,
868d4afb5ceSopenharmony_ci			i.alpn, i.address, i.path);
869d4afb5ceSopenharmony_ci
870d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
871d4afb5ceSopenharmony_ci	/* possibly already hanging connect retry... */
872d4afb5ceSopenharmony_ci	if (!h->cal_txn.mt)
873d4afb5ceSopenharmony_ci		lws_metrics_caliper_bind(h->cal_txn, h->context->mth_ss_conn);
874d4afb5ceSopenharmony_ci
875d4afb5ceSopenharmony_ci	if (h->policy->streamtype)
876d4afb5ceSopenharmony_ci		lws_metrics_tag_add(&h->cal_txn.mtags_owner, "ss",
877d4afb5ceSopenharmony_ci				    h->policy->streamtype);
878d4afb5ceSopenharmony_ci#endif
879d4afb5ceSopenharmony_ci
880d4afb5ceSopenharmony_ci	h->txn_ok = 0;
881d4afb5ceSopenharmony_ci	r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
882d4afb5ceSopenharmony_ci	if (r) {
883d4afb5ceSopenharmony_ci		lws_free(path);
884d4afb5ceSopenharmony_ci		return r;
885d4afb5ceSopenharmony_ci	}
886d4afb5ceSopenharmony_ci
887d4afb5ceSopenharmony_ci	h->inside_connect = 1;
888d4afb5ceSopenharmony_ci	h->pending_ret = LWSSSSRET_OK;
889d4afb5ceSopenharmony_ci	wsi = lws_client_connect_via_info(&i);
890d4afb5ceSopenharmony_ci	h->inside_connect = 0;
891d4afb5ceSopenharmony_ci	lws_free(path);
892d4afb5ceSopenharmony_ci	if (!wsi) {
893d4afb5ceSopenharmony_ci		/*
894d4afb5ceSopenharmony_ci		 * We already found that we could not connect, without even
895d4afb5ceSopenharmony_ci		 * having to go around the event loop
896d4afb5ceSopenharmony_ci		 */
897d4afb5ceSopenharmony_ci
898d4afb5ceSopenharmony_ci		if (h->pending_ret)
899d4afb5ceSopenharmony_ci			return h->pending_ret;
900d4afb5ceSopenharmony_ci
901d4afb5ceSopenharmony_ci		if (h->prev_ss_state != LWSSSCS_UNREACHABLE &&
902d4afb5ceSopenharmony_ci		    h->prev_ss_state != LWSSSCS_ALL_RETRIES_FAILED) {
903d4afb5ceSopenharmony_ci			/*
904d4afb5ceSopenharmony_ci			 * blocking DNS failure can get to unreachable via
905d4afb5ceSopenharmony_ci			 * CCE, and unreachable can get to ALL_RETRIES_FAILED
906d4afb5ceSopenharmony_ci			 */
907d4afb5ceSopenharmony_ci			r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
908d4afb5ceSopenharmony_ci			if (r)
909d4afb5ceSopenharmony_ci				return r;
910d4afb5ceSopenharmony_ci
911d4afb5ceSopenharmony_ci			r = lws_ss_backoff(h);
912d4afb5ceSopenharmony_ci			if (r)
913d4afb5ceSopenharmony_ci				return r;
914d4afb5ceSopenharmony_ci		}
915d4afb5ceSopenharmony_ci
916d4afb5ceSopenharmony_ci		return LWSSSSRET_TX_DONT_SEND;
917d4afb5ceSopenharmony_ci	}
918d4afb5ceSopenharmony_ci
919d4afb5ceSopenharmony_ci	return LWSSSSRET_OK;
920d4afb5ceSopenharmony_ci}
921d4afb5ceSopenharmony_ci
922d4afb5ceSopenharmony_cilws_ss_state_return_t
923d4afb5ceSopenharmony_cilws_ss_client_connect(lws_ss_handle_t *h)
924d4afb5ceSopenharmony_ci{
925d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
926d4afb5ceSopenharmony_ci
927d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
928d4afb5ceSopenharmony_ci
929d4afb5ceSopenharmony_ci	r = _lws_ss_client_connect(h, 0, 0);
930d4afb5ceSopenharmony_ci
931d4afb5ceSopenharmony_ci	return r;
932d4afb5ceSopenharmony_ci}
933d4afb5ceSopenharmony_ci
934d4afb5ceSopenharmony_ci/*
935d4afb5ceSopenharmony_ci * Public API
936d4afb5ceSopenharmony_ci */
937d4afb5ceSopenharmony_ci
938d4afb5ceSopenharmony_ci/*
939d4afb5ceSopenharmony_ci * Create either a stream or a sink
940d4afb5ceSopenharmony_ci */
941d4afb5ceSopenharmony_ci
942d4afb5ceSopenharmony_ciint
943d4afb5ceSopenharmony_cilws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
944d4afb5ceSopenharmony_ci	      void *opaque_user_data, lws_ss_handle_t **ppss,
945d4afb5ceSopenharmony_ci	      struct lws_sequencer *seq_owner, const char **ppayload_fmt)
946d4afb5ceSopenharmony_ci{
947d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[tsi];
948d4afb5ceSopenharmony_ci	const lws_ss_policy_t *pol;
949d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
950d4afb5ceSopenharmony_ci	lws_ss_metadata_t *smd;
951d4afb5ceSopenharmony_ci	lws_ss_handle_t *h;
952d4afb5ceSopenharmony_ci	size_t size;
953d4afb5ceSopenharmony_ci	void **v;
954d4afb5ceSopenharmony_ci	char *p;
955d4afb5ceSopenharmony_ci	int n;
956d4afb5ceSopenharmony_ci
957d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(context, tsi);
958d4afb5ceSopenharmony_ci
959d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_CPP)
960d4afb5ceSopenharmony_ci	pol = ssi->policy;
961d4afb5ceSopenharmony_ci	if (!pol) {
962d4afb5ceSopenharmony_ci#endif
963d4afb5ceSopenharmony_ci
964d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
965d4afb5ceSopenharmony_ci		lws_fi_ctx_t temp_fic;
966d4afb5ceSopenharmony_ci
967d4afb5ceSopenharmony_ci		/*
968d4afb5ceSopenharmony_ci		 * We have to do a temp inherit from context to find out
969d4afb5ceSopenharmony_ci		 * early if we are supposed to inject a fault concealing
970d4afb5ceSopenharmony_ci		 * the policy
971d4afb5ceSopenharmony_ci		 */
972d4afb5ceSopenharmony_ci
973d4afb5ceSopenharmony_ci		memset(&temp_fic, 0, sizeof(temp_fic));
974d4afb5ceSopenharmony_ci		lws_xos_init(&temp_fic.xos, lws_xos(&context->fic.xos));
975d4afb5ceSopenharmony_ci		lws_fi_inherit_copy(&temp_fic, &context->fic, "ss", ssi->streamtype);
976d4afb5ceSopenharmony_ci
977d4afb5ceSopenharmony_ci		if (lws_fi(&temp_fic, "ss_no_streamtype_policy"))
978d4afb5ceSopenharmony_ci			pol = NULL;
979d4afb5ceSopenharmony_ci		else
980d4afb5ceSopenharmony_ci			pol = lws_ss_policy_lookup(context, ssi->streamtype);
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci		lws_fi_destroy(&temp_fic);
983d4afb5ceSopenharmony_ci#else
984d4afb5ceSopenharmony_ci		pol = lws_ss_policy_lookup(context, ssi->streamtype);
985d4afb5ceSopenharmony_ci#endif
986d4afb5ceSopenharmony_ci		if (!pol) {
987d4afb5ceSopenharmony_ci			lwsl_cx_info(context, "unknown stream type %s",
988d4afb5ceSopenharmony_ci				  ssi->streamtype);
989d4afb5ceSopenharmony_ci			return 1;
990d4afb5ceSopenharmony_ci		}
991d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_CPP)
992d4afb5ceSopenharmony_ci	}
993d4afb5ceSopenharmony_ci#endif
994d4afb5ceSopenharmony_ci
995d4afb5ceSopenharmony_ci#if 0
996d4afb5ceSopenharmony_ci	if (ssi->flags & LWSSSINFLAGS_REGISTER_SINK) {
997d4afb5ceSopenharmony_ci		/*
998d4afb5ceSopenharmony_ci		 * This can register a secure streams sink as well as normal
999d4afb5ceSopenharmony_ci		 * secure streams connections.  If that's what's happening,
1000d4afb5ceSopenharmony_ci		 * confirm the policy agrees that this streamtype should be
1001d4afb5ceSopenharmony_ci		 * directed to a sink.
1002d4afb5ceSopenharmony_ci		 */
1003d4afb5ceSopenharmony_ci		if (!(pol->flags & LWSSSPOLF_LOCAL_SINK)) {
1004d4afb5ceSopenharmony_ci			/*
1005d4afb5ceSopenharmony_ci			 * Caller wanted to create a sink for this streamtype,
1006d4afb5ceSopenharmony_ci			 * but the policy does not agree the streamtype should
1007d4afb5ceSopenharmony_ci			 * be routed to a local sink.
1008d4afb5ceSopenharmony_ci			 */
1009d4afb5ceSopenharmony_ci			lwsl_err("%s: %s policy does not allow local sink\n",
1010d4afb5ceSopenharmony_ci				 __func__, ssi->streamtype);
1011d4afb5ceSopenharmony_ci
1012d4afb5ceSopenharmony_ci			return 1;
1013d4afb5ceSopenharmony_ci		}
1014d4afb5ceSopenharmony_ci	} else {
1015d4afb5ceSopenharmony_ci
1016d4afb5ceSopenharmony_ci		if (!(pol->flags & LWSSSPOLF_LOCAL_SINK)) {
1017d4afb5ceSopenharmony_ci
1018d4afb5ceSopenharmony_ci		}
1019d4afb5ceSopenharmony_ci//		lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_destroy_dll);
1020d4afb5ceSopenharmony_ci	}
1021d4afb5ceSopenharmony_ci#endif
1022d4afb5ceSopenharmony_ci
1023d4afb5ceSopenharmony_ci	/*
1024d4afb5ceSopenharmony_ci	 * We overallocate and point to things in the overallocation...
1025d4afb5ceSopenharmony_ci	 *
1026d4afb5ceSopenharmony_ci	 * 1) the user_alloc from the stream info
1027d4afb5ceSopenharmony_ci	 * 2) network auth plugin instantiation data
1028d4afb5ceSopenharmony_ci	 * 3) stream auth plugin instantiation data
1029d4afb5ceSopenharmony_ci	 * 4) as many metadata pointer structs as the policy tells
1030d4afb5ceSopenharmony_ci	 * 5) the streamtype name (length is not aligned)
1031d4afb5ceSopenharmony_ci	 *
1032d4afb5ceSopenharmony_ci	 * ... when we come to destroy it, just one free to do.
1033d4afb5ceSopenharmony_ci	 */
1034d4afb5ceSopenharmony_ci
1035d4afb5ceSopenharmony_ci	size = sizeof(*h) + ssi->user_alloc +
1036d4afb5ceSopenharmony_ci			(ssi->streamtype ? strlen(ssi->streamtype): 0) + 1;
1037d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SSPLUGINS)
1038d4afb5ceSopenharmony_ci	if (pol->plugins[0])
1039d4afb5ceSopenharmony_ci		size += pol->plugins[0]->alloc;
1040d4afb5ceSopenharmony_ci	if (pol->plugins[1])
1041d4afb5ceSopenharmony_ci		size += pol->plugins[1]->alloc;
1042d4afb5ceSopenharmony_ci#endif
1043d4afb5ceSopenharmony_ci	size += pol->metadata_count * sizeof(lws_ss_metadata_t);
1044d4afb5ceSopenharmony_ci
1045d4afb5ceSopenharmony_ci	h = lws_zalloc(size, __func__);
1046d4afb5ceSopenharmony_ci	if (!h)
1047d4afb5ceSopenharmony_ci		return 2;
1048d4afb5ceSopenharmony_ci
1049d4afb5ceSopenharmony_ci	h->lc.log_cx = context->log_cx;
1050d4afb5ceSopenharmony_ci
1051d4afb5ceSopenharmony_ci	if (ssi->sss_protocol_version)
1052d4afb5ceSopenharmony_ci		__lws_lc_tag(context, &context->lcg[LWSLCG_WSI_SS_CLIENT],
1053d4afb5ceSopenharmony_ci			     &h->lc, "%s|v%u|%u",
1054d4afb5ceSopenharmony_ci			     ssi->streamtype ? ssi->streamtype : "nostreamtype",
1055d4afb5ceSopenharmony_ci			     (unsigned int)ssi->sss_protocol_version,
1056d4afb5ceSopenharmony_ci			     (unsigned int)ssi->client_pid);
1057d4afb5ceSopenharmony_ci	else
1058d4afb5ceSopenharmony_ci		__lws_lc_tag(context, &context->lcg[LWSLCG_WSI_SS_CLIENT],
1059d4afb5ceSopenharmony_ci			     &h->lc, "%s",
1060d4afb5ceSopenharmony_ci			     ssi->streamtype ? ssi->streamtype : "nostreamtype");
1061d4afb5ceSopenharmony_ci
1062d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1063d4afb5ceSopenharmony_ci	h->fic.name = "ss";
1064d4afb5ceSopenharmony_ci	lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
1065d4afb5ceSopenharmony_ci	if (ssi->fic.fi_owner.count)
1066d4afb5ceSopenharmony_ci		lws_fi_import(&h->fic, &ssi->fic);
1067d4afb5ceSopenharmony_ci
1068d4afb5ceSopenharmony_ci	lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
1069d4afb5ceSopenharmony_ci#endif
1070d4afb5ceSopenharmony_ci
1071d4afb5ceSopenharmony_ci	h->info = *ssi;
1072d4afb5ceSopenharmony_ci	h->policy = pol;
1073d4afb5ceSopenharmony_ci	h->context = context;
1074d4afb5ceSopenharmony_ci	h->tsi = (uint8_t)tsi;
1075d4afb5ceSopenharmony_ci	h->seq = seq_owner;
1076d4afb5ceSopenharmony_ci
1077d4afb5ceSopenharmony_ci	if (h->info.flags & LWSSSINFLAGS_PROXIED)
1078d4afb5ceSopenharmony_ci		h->proxy_onward = 1;
1079d4afb5ceSopenharmony_ci
1080d4afb5ceSopenharmony_ci	/* start of overallocated area */
1081d4afb5ceSopenharmony_ci	p = (char *)(h + 1);
1082d4afb5ceSopenharmony_ci
1083d4afb5ceSopenharmony_ci	/* set the handle pointer in the user data struct */
1084d4afb5ceSopenharmony_ci	v = (void **)(p + ssi->handle_offset);
1085d4afb5ceSopenharmony_ci	*v = h;
1086d4afb5ceSopenharmony_ci
1087d4afb5ceSopenharmony_ci	/* set the opaque user data in the user data struct */
1088d4afb5ceSopenharmony_ci	v = (void **)(p + ssi->opaque_user_data_offset);
1089d4afb5ceSopenharmony_ci	*v = opaque_user_data;
1090d4afb5ceSopenharmony_ci
1091d4afb5ceSopenharmony_ci	p += ssi->user_alloc;
1092d4afb5ceSopenharmony_ci
1093d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SSPLUGINS)
1094d4afb5ceSopenharmony_ci	if (pol->plugins[0]) {
1095d4afb5ceSopenharmony_ci		h->nauthi = p;
1096d4afb5ceSopenharmony_ci		p += pol->plugins[0]->alloc;
1097d4afb5ceSopenharmony_ci	}
1098d4afb5ceSopenharmony_ci	if (pol->plugins[1]) {
1099d4afb5ceSopenharmony_ci		h->sauthi = p;
1100d4afb5ceSopenharmony_ci		p += pol->plugins[1]->alloc;
1101d4afb5ceSopenharmony_ci	}
1102d4afb5ceSopenharmony_ci#endif
1103d4afb5ceSopenharmony_ci
1104d4afb5ceSopenharmony_ci	if (pol->metadata_count) {
1105d4afb5ceSopenharmony_ci		h->metadata = (lws_ss_metadata_t *)p;
1106d4afb5ceSopenharmony_ci		p += pol->metadata_count * sizeof(lws_ss_metadata_t);
1107d4afb5ceSopenharmony_ci
1108d4afb5ceSopenharmony_ci		lwsl_cx_info(context, "%s metadata count %d",
1109d4afb5ceSopenharmony_ci			  pol->streamtype, pol->metadata_count);
1110d4afb5ceSopenharmony_ci	}
1111d4afb5ceSopenharmony_ci
1112d4afb5ceSopenharmony_ci	smd = pol->metadata;
1113d4afb5ceSopenharmony_ci	for (n = 0; n < pol->metadata_count; n++) {
1114d4afb5ceSopenharmony_ci		h->metadata[n].name = smd->name;
1115d4afb5ceSopenharmony_ci		if (n + 1 == pol->metadata_count)
1116d4afb5ceSopenharmony_ci			h->metadata[n].next = NULL;
1117d4afb5ceSopenharmony_ci		else
1118d4afb5ceSopenharmony_ci			h->metadata[n].next = &h->metadata[n + 1];
1119d4afb5ceSopenharmony_ci		smd = smd->next;
1120d4afb5ceSopenharmony_ci	}
1121d4afb5ceSopenharmony_ci
1122d4afb5ceSopenharmony_ci	if (ssi->streamtype)
1123d4afb5ceSopenharmony_ci		memcpy(p, ssi->streamtype, strlen(ssi->streamtype) + 1);
1124d4afb5ceSopenharmony_ci	/* don't mark accepted ss as being the server */
1125d4afb5ceSopenharmony_ci	if (ssi->flags & LWSSSINFLAGS_SERVER)
1126d4afb5ceSopenharmony_ci		h->info.flags &= (uint8_t)~LWSSSINFLAGS_SERVER;
1127d4afb5ceSopenharmony_ci	h->info.streamtype = p;
1128d4afb5ceSopenharmony_ci
1129d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
1130d4afb5ceSopenharmony_ci	lws_dll2_add_head(&h->list, &pt->ss_owner);
1131d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
1132d4afb5ceSopenharmony_ci
1133d4afb5ceSopenharmony_ci	if (ppss)
1134d4afb5ceSopenharmony_ci		*ppss = h;
1135d4afb5ceSopenharmony_ci
1136d4afb5ceSopenharmony_ci	if (ppayload_fmt)
1137d4afb5ceSopenharmony_ci		*ppayload_fmt = pol->payload_fmt;
1138d4afb5ceSopenharmony_ci
1139d4afb5ceSopenharmony_ci	if (ssi->flags & LWSSSINFLAGS_SERVER)
1140d4afb5ceSopenharmony_ci		/*
1141d4afb5ceSopenharmony_ci		 * return early for accepted connection flow
1142d4afb5ceSopenharmony_ci		 */
1143d4afb5ceSopenharmony_ci		return 0;
1144d4afb5ceSopenharmony_ci
1145d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
1146d4afb5ceSopenharmony_ci	/*
1147d4afb5ceSopenharmony_ci	 * For a local Secure Streams connection
1148d4afb5ceSopenharmony_ci	 */
1149d4afb5ceSopenharmony_ci	if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
1150d4afb5ceSopenharmony_ci	    pol == &pol_smd) {
1151d4afb5ceSopenharmony_ci
1152d4afb5ceSopenharmony_ci		/*
1153d4afb5ceSopenharmony_ci		 * So he has asked to be wired up to SMD over a SS link.
1154d4afb5ceSopenharmony_ci		 * Register him as an smd participant in his own right.
1155d4afb5ceSopenharmony_ci		 *
1156d4afb5ceSopenharmony_ci		 * Just for this case, ssi->manual_initial_tx_credit is used
1157d4afb5ceSopenharmony_ci		 * to set the rx class mask (this is part of the SS serialization
1158d4afb5ceSopenharmony_ci		 * format as well)
1159d4afb5ceSopenharmony_ci		 */
1160d4afb5ceSopenharmony_ci		h->u.smd.smd_peer = lws_smd_register(context, h, 0,
1161d4afb5ceSopenharmony_ci						     (lws_smd_class_t)ssi->manual_initial_tx_credit,
1162d4afb5ceSopenharmony_ci						     lws_smd_ss_cb);
1163d4afb5ceSopenharmony_ci		if (!h->u.smd.smd_peer || lws_fi(&h->fic, "ss_create_smd"))
1164d4afb5ceSopenharmony_ci			goto fail_creation;
1165d4afb5ceSopenharmony_ci		lwsl_cx_info(context, "registered SS SMD");
1166d4afb5ceSopenharmony_ci	}
1167d4afb5ceSopenharmony_ci#endif
1168d4afb5ceSopenharmony_ci
1169d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1170d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_SERVER) {
1171d4afb5ceSopenharmony_ci		const struct lws_protocols *pprot[3], **ppp = &pprot[0];
1172d4afb5ceSopenharmony_ci		struct lws_context_creation_info i;
1173d4afb5ceSopenharmony_ci		struct lws_vhost *vho = NULL;
1174d4afb5ceSopenharmony_ci
1175d4afb5ceSopenharmony_ci		lwsl_cx_info(context, "creating server");
1176d4afb5ceSopenharmony_ci
1177d4afb5ceSopenharmony_ci		if (h->policy->endpoint &&
1178d4afb5ceSopenharmony_ci		    h->policy->endpoint[0] == '!') {
1179d4afb5ceSopenharmony_ci			/*
1180d4afb5ceSopenharmony_ci			 * There's already a vhost existing that we want to
1181d4afb5ceSopenharmony_ci			 * bind to, we don't have to specify and create one.
1182d4afb5ceSopenharmony_ci			 *
1183d4afb5ceSopenharmony_ci			 * The vhost must enable any protocols that we want.
1184d4afb5ceSopenharmony_ci			 */
1185d4afb5ceSopenharmony_ci
1186d4afb5ceSopenharmony_ci			vho = lws_get_vhost_by_name(context,
1187d4afb5ceSopenharmony_ci						    &h->policy->endpoint[1]);
1188d4afb5ceSopenharmony_ci			if (!vho || lws_fi(&h->fic, "ss_create_vhost")) {
1189d4afb5ceSopenharmony_ci				lwsl_err("%s: no vhost %s\n", __func__,
1190d4afb5ceSopenharmony_ci						&h->policy->endpoint[1]);
1191d4afb5ceSopenharmony_ci				goto fail_creation;
1192d4afb5ceSopenharmony_ci			}
1193d4afb5ceSopenharmony_ci
1194d4afb5ceSopenharmony_ci			goto extant;
1195d4afb5ceSopenharmony_ci		}
1196d4afb5ceSopenharmony_ci
1197d4afb5ceSopenharmony_ci		/*
1198d4afb5ceSopenharmony_ci		 * This streamtype represents a server, we're being asked to
1199d4afb5ceSopenharmony_ci		 * instantiate a corresponding vhost for it
1200d4afb5ceSopenharmony_ci		 */
1201d4afb5ceSopenharmony_ci
1202d4afb5ceSopenharmony_ci		memset(&i, 0, sizeof i);
1203d4afb5ceSopenharmony_ci
1204d4afb5ceSopenharmony_ci		i.iface		= h->policy->endpoint;
1205d4afb5ceSopenharmony_ci		i.vhost_name	= h->policy->streamtype;
1206d4afb5ceSopenharmony_ci		i.port		= h->policy->port;
1207d4afb5ceSopenharmony_ci
1208d4afb5ceSopenharmony_ci		if (i.iface && i.iface[0] == '+') {
1209d4afb5ceSopenharmony_ci			i.iface++;
1210d4afb5ceSopenharmony_ci			i.options |= LWS_SERVER_OPTION_UNIX_SOCK;
1211d4afb5ceSopenharmony_ci		}
1212d4afb5ceSopenharmony_ci
1213d4afb5ceSopenharmony_ci		if (!ss_pcols[h->policy->protocol] ||
1214d4afb5ceSopenharmony_ci		    lws_fi(&h->fic, "ss_create_pcol")) {
1215d4afb5ceSopenharmony_ci			lwsl_err("%s: unsupp protocol", __func__);
1216d4afb5ceSopenharmony_ci			goto fail_creation;
1217d4afb5ceSopenharmony_ci		}
1218d4afb5ceSopenharmony_ci
1219d4afb5ceSopenharmony_ci		*ppp++ = ss_pcols[h->policy->protocol]->protocol;
1220d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
1221d4afb5ceSopenharmony_ci		if (h->policy->u.http.u.ws.subprotocol)
1222d4afb5ceSopenharmony_ci			/*
1223d4afb5ceSopenharmony_ci			 * He names a ws subprotocol, ie, we want to support
1224d4afb5ceSopenharmony_ci			 * ss-ws protocol in this vhost
1225d4afb5ceSopenharmony_ci			 */
1226d4afb5ceSopenharmony_ci			*ppp++ = &protocol_secstream_ws;
1227d4afb5ceSopenharmony_ci#endif
1228d4afb5ceSopenharmony_ci		*ppp = NULL;
1229d4afb5ceSopenharmony_ci		i.pprotocols = pprot;
1230d4afb5ceSopenharmony_ci
1231d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
1232d4afb5ceSopenharmony_ci		if (h->policy->flags & LWSSSPOLF_TLS) {
1233d4afb5ceSopenharmony_ci			i.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
1234d4afb5ceSopenharmony_ci			i.server_ssl_cert_mem =
1235d4afb5ceSopenharmony_ci				h->policy->trust.server.cert->ca_der;
1236d4afb5ceSopenharmony_ci			i.server_ssl_cert_mem_len = (unsigned int)
1237d4afb5ceSopenharmony_ci				h->policy->trust.server.cert->ca_der_len;
1238d4afb5ceSopenharmony_ci			i.server_ssl_private_key_mem =
1239d4afb5ceSopenharmony_ci				h->policy->trust.server.key->ca_der;
1240d4afb5ceSopenharmony_ci			i.server_ssl_private_key_mem_len = (unsigned int)
1241d4afb5ceSopenharmony_ci				h->policy->trust.server.key->ca_der_len;
1242d4afb5ceSopenharmony_ci		}
1243d4afb5ceSopenharmony_ci#endif
1244d4afb5ceSopenharmony_ci
1245d4afb5ceSopenharmony_ci		if (!lws_fi(&h->fic, "ss_srv_vh_fail"))
1246d4afb5ceSopenharmony_ci			vho = lws_create_vhost(context, &i);
1247d4afb5ceSopenharmony_ci		else
1248d4afb5ceSopenharmony_ci			vho = NULL;
1249d4afb5ceSopenharmony_ci		if (!vho) {
1250d4afb5ceSopenharmony_ci			lwsl_cx_err(context, "failed to create vh");
1251d4afb5ceSopenharmony_ci			goto fail_creation;
1252d4afb5ceSopenharmony_ci		}
1253d4afb5ceSopenharmony_ci
1254d4afb5ceSopenharmony_ciextant:
1255d4afb5ceSopenharmony_ci
1256d4afb5ceSopenharmony_ci		/*
1257d4afb5ceSopenharmony_ci		 * Mark this vhost as having to apply ss server semantics to
1258d4afb5ceSopenharmony_ci		 * any incoming accepted connection
1259d4afb5ceSopenharmony_ci		 */
1260d4afb5ceSopenharmony_ci		vho->ss_handle = h;
1261d4afb5ceSopenharmony_ci
1262d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_CREATING);
1263d4afb5ceSopenharmony_ci		lwsl_cx_info(context, "CREATING returned status %d", (int)r);
1264d4afb5ceSopenharmony_ci		if (r == LWSSSSRET_DESTROY_ME ||
1265d4afb5ceSopenharmony_ci		    lws_fi(&h->fic, "ss_create_destroy_me"))
1266d4afb5ceSopenharmony_ci			goto fail_creation;
1267d4afb5ceSopenharmony_ci
1268d4afb5ceSopenharmony_ci		lwsl_cx_notice(context, "created server %s",
1269d4afb5ceSopenharmony_ci				h->policy->streamtype);
1270d4afb5ceSopenharmony_ci
1271d4afb5ceSopenharmony_ci		return 0;
1272d4afb5ceSopenharmony_ci	}
1273d4afb5ceSopenharmony_ci#endif
1274d4afb5ceSopenharmony_ci
1275d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1276d4afb5ceSopenharmony_ci
1277d4afb5ceSopenharmony_ci	/*
1278d4afb5ceSopenharmony_ci	 * For static policy case, dynamically ref / instantiate the related
1279d4afb5ceSopenharmony_ci	 * trust store and vhost.  We do it by logical ss rather than connection
1280d4afb5ceSopenharmony_ci	 * because we don't want to expose the latency of creating the x.509
1281d4afb5ceSopenharmony_ci	 * trust store at the first connection.
1282d4afb5ceSopenharmony_ci	 *
1283d4afb5ceSopenharmony_ci	 * But it might be given the tls linkup takes time anyway, it can move
1284d4afb5ceSopenharmony_ci	 * to the ss connect code instead.
1285d4afb5ceSopenharmony_ci	 */
1286d4afb5ceSopenharmony_ci
1287d4afb5ceSopenharmony_ci	if (!lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */) ||
1288d4afb5ceSopenharmony_ci	    lws_fi(&h->fic, "ss_create_no_ts")) {
1289d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to get vhost / trust store\n", __func__);
1290d4afb5ceSopenharmony_ci		goto fail_creation;
1291d4afb5ceSopenharmony_ci	}
1292d4afb5ceSopenharmony_ci#else
1293d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1294d4afb5ceSopenharmony_ci        if (!ssi->streamtype &&
1295d4afb5ceSopenharmony_ci	    !lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */)) {
1296d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to get vhost / trust store\n", __func__);
1297d4afb5ceSopenharmony_ci		goto fail_creation;
1298d4afb5ceSopenharmony_ci	}
1299d4afb5ceSopenharmony_ci#endif
1300d4afb5ceSopenharmony_ci#endif
1301d4afb5ceSopenharmony_ci
1302d4afb5ceSopenharmony_ci	r = lws_ss_event_helper(h, LWSSSCS_CREATING);
1303d4afb5ceSopenharmony_ci	lwsl_ss_info(h, "CREATING returned status %d", (int)r);
1304d4afb5ceSopenharmony_ci	if (r == LWSSSSRET_DESTROY_ME ||
1305d4afb5ceSopenharmony_ci	    lws_fi(&h->fic, "ss_create_destroy_me"))
1306d4afb5ceSopenharmony_ci		goto fail_creation;
1307d4afb5ceSopenharmony_ci
1308d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
1309d4afb5ceSopenharmony_ci	if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
1310d4afb5ceSopenharmony_ci	    pol == &pol_smd) {
1311d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
1312d4afb5ceSopenharmony_ci		if (r || lws_fi(&h->fic, "ss_create_smd_1"))
1313d4afb5ceSopenharmony_ci			goto fail_creation;
1314d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
1315d4afb5ceSopenharmony_ci		if (r || lws_fi(&h->fic, "ss_create_smd_2"))
1316d4afb5ceSopenharmony_ci			goto fail_creation;
1317d4afb5ceSopenharmony_ci	}
1318d4afb5ceSopenharmony_ci#endif
1319d4afb5ceSopenharmony_ci
1320d4afb5ceSopenharmony_ci	if (!(ssi->flags & LWSSSINFLAGS_REGISTER_SINK) &&
1321d4afb5ceSopenharmony_ci	    ((h->policy->flags & LWSSSPOLF_NAILED_UP)
1322d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
1323d4afb5ceSopenharmony_ci		|| ((h->policy == &pol_smd) //&&
1324d4afb5ceSopenharmony_ci		    //(ssi->flags & LWSSSINFLAGS_PROXIED))
1325d4afb5ceSopenharmony_ci				)
1326d4afb5ceSopenharmony_ci#endif
1327d4afb5ceSopenharmony_ci			    )) {
1328d4afb5ceSopenharmony_ci		r = _lws_ss_client_connect(h, 0, 0);
1329d4afb5ceSopenharmony_ci		if (lws_fi(&h->fic, "ss_create_conn"))
1330d4afb5ceSopenharmony_ci			r = LWSSSSRET_DESTROY_ME;
1331d4afb5ceSopenharmony_ci		switch (r) {
1332d4afb5ceSopenharmony_ci		case LWSSSSRET_OK:
1333d4afb5ceSopenharmony_ci			break;
1334d4afb5ceSopenharmony_ci		case LWSSSSRET_TX_DONT_SEND:
1335d4afb5ceSopenharmony_ci		case LWSSSSRET_DISCONNECT_ME:
1336d4afb5ceSopenharmony_ci			if (lws_ss_backoff(h) == LWSSSSRET_DESTROY_ME)
1337d4afb5ceSopenharmony_ci				goto fail_creation;
1338d4afb5ceSopenharmony_ci			break;
1339d4afb5ceSopenharmony_ci		case LWSSSSRET_DESTROY_ME:
1340d4afb5ceSopenharmony_ci			goto fail_creation;
1341d4afb5ceSopenharmony_ci		}
1342d4afb5ceSopenharmony_ci	}
1343d4afb5ceSopenharmony_ci
1344d4afb5ceSopenharmony_ci	return 0;
1345d4afb5ceSopenharmony_ci
1346d4afb5ceSopenharmony_cifail_creation:
1347d4afb5ceSopenharmony_ci
1348d4afb5ceSopenharmony_ci	if (ppss)
1349d4afb5ceSopenharmony_ci		*ppss = NULL;
1350d4afb5ceSopenharmony_ci
1351d4afb5ceSopenharmony_ci	lws_ss_destroy(&h);
1352d4afb5ceSopenharmony_ci
1353d4afb5ceSopenharmony_ci	return 1;
1354d4afb5ceSopenharmony_ci}
1355d4afb5ceSopenharmony_ci
1356d4afb5ceSopenharmony_civoid *
1357d4afb5ceSopenharmony_cilws_ss_to_user_object(struct lws_ss_handle *h)
1358d4afb5ceSopenharmony_ci{
1359d4afb5ceSopenharmony_ci	return (void *)(h + 1);
1360d4afb5ceSopenharmony_ci}
1361d4afb5ceSopenharmony_ci
1362d4afb5ceSopenharmony_civoid
1363d4afb5ceSopenharmony_cilws_ss_destroy(lws_ss_handle_t **ppss)
1364d4afb5ceSopenharmony_ci{
1365d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
1366d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1367d4afb5ceSopenharmony_ci	struct lws_vhost *v = NULL;
1368d4afb5ceSopenharmony_ci#endif
1369d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = *ppss;
1370d4afb5ceSopenharmony_ci	lws_ss_metadata_t *pmd;
1371d4afb5ceSopenharmony_ci
1372d4afb5ceSopenharmony_ci	if (!h)
1373d4afb5ceSopenharmony_ci		return;
1374d4afb5ceSopenharmony_ci
1375d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1376d4afb5ceSopenharmony_ci
1377d4afb5ceSopenharmony_ci	if (h == h->h_in_svc) {
1378d4afb5ceSopenharmony_ci		lwsl_err("%s: illegal destroy, return LWSSSSRET_DESTROY_ME instead\n",
1379d4afb5ceSopenharmony_ci				__func__);
1380d4afb5ceSopenharmony_ci		assert(0);
1381d4afb5ceSopenharmony_ci		return;
1382d4afb5ceSopenharmony_ci	}
1383d4afb5ceSopenharmony_ci
1384d4afb5ceSopenharmony_ci	if (h->destroying) {
1385d4afb5ceSopenharmony_ci		lwsl_info("%s: reentrant destroy\n", __func__);
1386d4afb5ceSopenharmony_ci		return;
1387d4afb5ceSopenharmony_ci	}
1388d4afb5ceSopenharmony_ci	h->destroying = 1;
1389d4afb5ceSopenharmony_ci
1390d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
1391d4afb5ceSopenharmony_ci	if (h->conmon_json)
1392d4afb5ceSopenharmony_ci		lws_free_set_NULL(h->conmon_json);
1393d4afb5ceSopenharmony_ci#endif
1394d4afb5ceSopenharmony_ci
1395d4afb5ceSopenharmony_ci	if (h->wsi) {
1396d4afb5ceSopenharmony_ci		/*
1397d4afb5ceSopenharmony_ci		 * Don't let the wsi point to us any more,
1398d4afb5ceSopenharmony_ci		 * we (the ss object bound to the wsi) are going away now
1399d4afb5ceSopenharmony_ci		 */
1400d4afb5ceSopenharmony_ci		lws_set_opaque_user_data(h->wsi, NULL);
1401d4afb5ceSopenharmony_ci		lws_set_timeout(h->wsi, 1, LWS_TO_KILL_SYNC);
1402d4afb5ceSopenharmony_ci	}
1403d4afb5ceSopenharmony_ci
1404d4afb5ceSopenharmony_ci	/*
1405d4afb5ceSopenharmony_ci	 * if we bound an smd registration to the SS, unregister it
1406d4afb5ceSopenharmony_ci	 */
1407d4afb5ceSopenharmony_ci
1408d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
1409d4afb5ceSopenharmony_ci	if (h->policy == &pol_smd) {
1410d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->u.smd.sul_write);
1411d4afb5ceSopenharmony_ci
1412d4afb5ceSopenharmony_ci		if (h->u.smd.smd_peer) {
1413d4afb5ceSopenharmony_ci			lws_smd_unregister(h->u.smd.smd_peer);
1414d4afb5ceSopenharmony_ci			h->u.smd.smd_peer = NULL;
1415d4afb5ceSopenharmony_ci		}
1416d4afb5ceSopenharmony_ci	}
1417d4afb5ceSopenharmony_ci#endif
1418d4afb5ceSopenharmony_ci
1419d4afb5ceSopenharmony_ci	pt = &h->context->pt[h->tsi];
1420d4afb5ceSopenharmony_ci
1421d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
1422d4afb5ceSopenharmony_ci	*ppss = NULL;
1423d4afb5ceSopenharmony_ci	lws_dll2_remove(&h->list);
1424d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1425d4afb5ceSopenharmony_ci		lws_dll2_remove(&h->cli_list);
1426d4afb5ceSopenharmony_ci#endif
1427d4afb5ceSopenharmony_ci	lws_dll2_remove(&h->to_list);
1428d4afb5ceSopenharmony_ci	lws_sul_cancel(&h->sul_timeout);
1429d4afb5ceSopenharmony_ci
1430d4afb5ceSopenharmony_ci	/*
1431d4afb5ceSopenharmony_ci	 * for lss, DESTROYING deletes the C++ lss object, making the
1432d4afb5ceSopenharmony_ci	 * self-defined h->policy radioactive
1433d4afb5ceSopenharmony_ci	 */
1434d4afb5ceSopenharmony_ci
1435d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1436d4afb5ceSopenharmony_ci	if (h->policy && (h->policy->flags & LWSSSPOLF_SERVER))
1437d4afb5ceSopenharmony_ci		v = lws_get_vhost_by_name(h->context, h->policy->streamtype);
1438d4afb5ceSopenharmony_ci#endif
1439d4afb5ceSopenharmony_ci
1440d4afb5ceSopenharmony_ci	/*
1441d4afb5ceSopenharmony_ci	 * Since we also come here to unpick create, it's possible we failed
1442d4afb5ceSopenharmony_ci	 * the creation before issuing any states, even CREATING.  We should
1443d4afb5ceSopenharmony_ci	 * only issue cleanup states on destroy if we previously got as far as
1444d4afb5ceSopenharmony_ci	 * issuing CREATING.
1445d4afb5ceSopenharmony_ci	 */
1446d4afb5ceSopenharmony_ci
1447d4afb5ceSopenharmony_ci	if (h->prev_ss_state) {
1448d4afb5ceSopenharmony_ci		if (h->ss_dangling_connected)
1449d4afb5ceSopenharmony_ci			(void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
1450d4afb5ceSopenharmony_ci
1451d4afb5ceSopenharmony_ci		(void)lws_ss_event_helper(h, LWSSSCS_DESTROYING);
1452d4afb5ceSopenharmony_ci	}
1453d4afb5ceSopenharmony_ci
1454d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
1455d4afb5ceSopenharmony_ci
1456d4afb5ceSopenharmony_ci	/* in proxy case, metadata value on heap may need cleaning up */
1457d4afb5ceSopenharmony_ci
1458d4afb5ceSopenharmony_ci	pmd = h->metadata;
1459d4afb5ceSopenharmony_ci	while (pmd) {
1460d4afb5ceSopenharmony_ci		lwsl_info("%s: pmd %p\n", __func__, pmd);
1461d4afb5ceSopenharmony_ci		if (pmd->value_on_lws_heap)
1462d4afb5ceSopenharmony_ci			lws_free_set_NULL(pmd->value__may_own_heap);
1463d4afb5ceSopenharmony_ci
1464d4afb5ceSopenharmony_ci		pmd = pmd->next;
1465d4afb5ceSopenharmony_ci	}
1466d4afb5ceSopenharmony_ci
1467d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
1468d4afb5ceSopenharmony_ci	{
1469d4afb5ceSopenharmony_ci
1470d4afb5ceSopenharmony_ci		lws_ss_metadata_t *imd;
1471d4afb5ceSopenharmony_ci
1472d4afb5ceSopenharmony_ci		pmd = h->instant_metadata;
1473d4afb5ceSopenharmony_ci
1474d4afb5ceSopenharmony_ci		while (pmd) {
1475d4afb5ceSopenharmony_ci			imd = pmd;
1476d4afb5ceSopenharmony_ci			pmd = pmd->next;
1477d4afb5ceSopenharmony_ci
1478d4afb5ceSopenharmony_ci			lwsl_info("%s: instant md %p\n", __func__, imd);
1479d4afb5ceSopenharmony_ci			lws_free(imd);
1480d4afb5ceSopenharmony_ci		}
1481d4afb5ceSopenharmony_ci		h->instant_metadata = NULL;
1482d4afb5ceSopenharmony_ci
1483d4afb5ceSopenharmony_ci		if (h->imd_ac)
1484d4afb5ceSopenharmony_ci			lwsac_free(&h->imd_ac);
1485d4afb5ceSopenharmony_ci	}
1486d4afb5ceSopenharmony_ci#endif
1487d4afb5ceSopenharmony_ci
1488d4afb5ceSopenharmony_ci	lws_sul_cancel(&h->sul);
1489d4afb5ceSopenharmony_ci
1490d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1491d4afb5ceSopenharmony_ci
1492d4afb5ceSopenharmony_ci	/*
1493d4afb5ceSopenharmony_ci	 * For static policy case, dynamically ref / instantiate the related
1494d4afb5ceSopenharmony_ci	 * trust store and vhost.  We do it by logical ss rather than connection
1495d4afb5ceSopenharmony_ci	 * because we don't want to expose the latency of creating the x.509
1496d4afb5ceSopenharmony_ci	 * trust store at the first connection.
1497d4afb5ceSopenharmony_ci	 *
1498d4afb5ceSopenharmony_ci	 * But it might be given the tls linkup takes time anyway, it can move
1499d4afb5ceSopenharmony_ci	 * to the ss connect code instead.
1500d4afb5ceSopenharmony_ci	 */
1501d4afb5ceSopenharmony_ci
1502d4afb5ceSopenharmony_ci	if (h->policy)
1503d4afb5ceSopenharmony_ci		lws_ss_policy_unref_trust_store(h->context, h->policy);
1504d4afb5ceSopenharmony_ci#else
1505d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_CPP)
1506d4afb5ceSopenharmony_ci	if (!h->info.streamtype || !*(h->info.streamtype))
1507d4afb5ceSopenharmony_ci		lws_ss_policy_unref_trust_store(h->context, h->policy);
1508d4afb5ceSopenharmony_ci#endif
1509d4afb5ceSopenharmony_ci#endif
1510d4afb5ceSopenharmony_ci
1511d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1512d4afb5ceSopenharmony_ci	if (v)
1513d4afb5ceSopenharmony_ci		/*
1514d4afb5ceSopenharmony_ci		 * For server, the policy describes a vhost that implements the
1515d4afb5ceSopenharmony_ci		 * server, when we take down the ss, we take down the related
1516d4afb5ceSopenharmony_ci		 * vhost (if it got that far)
1517d4afb5ceSopenharmony_ci		 */
1518d4afb5ceSopenharmony_ci		lws_vhost_destroy(v);
1519d4afb5ceSopenharmony_ci#endif
1520d4afb5ceSopenharmony_ci
1521d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1522d4afb5ceSopenharmony_ci	lws_fi_destroy(&h->fic);
1523d4afb5ceSopenharmony_ci#endif
1524d4afb5ceSopenharmony_ci
1525d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
1526d4afb5ceSopenharmony_ci	/*
1527d4afb5ceSopenharmony_ci	 * If any hanging caliper measurement, dump it, and free any tags
1528d4afb5ceSopenharmony_ci	 */
1529d4afb5ceSopenharmony_ci	lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1530d4afb5ceSopenharmony_ci#endif
1531d4afb5ceSopenharmony_ci
1532d4afb5ceSopenharmony_ci	lws_sul_cancel(&h->sul_timeout);
1533d4afb5ceSopenharmony_ci
1534d4afb5ceSopenharmony_ci	/* confirm no sul left scheduled in handle or user allocation object */
1535d4afb5ceSopenharmony_ci	lws_sul_debug_zombies(h->context, h, sizeof(*h) + h->info.user_alloc,
1536d4afb5ceSopenharmony_ci			      __func__);
1537d4afb5ceSopenharmony_ci
1538d4afb5ceSopenharmony_ci	__lws_lc_untag(h->context, &h->lc);
1539d4afb5ceSopenharmony_ci
1540d4afb5ceSopenharmony_ci	lws_explicit_bzero((void *)h, sizeof(*h) + h->info.user_alloc);
1541d4afb5ceSopenharmony_ci
1542d4afb5ceSopenharmony_ci	lws_free_set_NULL(h);
1543d4afb5ceSopenharmony_ci}
1544d4afb5ceSopenharmony_ci
1545d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1546d4afb5ceSopenharmony_civoid
1547d4afb5ceSopenharmony_cilws_ss_server_ack(struct lws_ss_handle *h, int nack)
1548d4afb5ceSopenharmony_ci{
1549d4afb5ceSopenharmony_ci	h->txn_resp = nack;
1550d4afb5ceSopenharmony_ci	h->txn_resp_set = 1;
1551d4afb5ceSopenharmony_ci}
1552d4afb5ceSopenharmony_ci
1553d4afb5ceSopenharmony_civoid
1554d4afb5ceSopenharmony_cilws_ss_server_foreach_client(struct lws_ss_handle *h, lws_sssfec_cb cb,
1555d4afb5ceSopenharmony_ci			     void *arg)
1556d4afb5ceSopenharmony_ci{
1557d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, h->src_list.head) {
1558d4afb5ceSopenharmony_ci		struct lws_ss_handle *h =
1559d4afb5ceSopenharmony_ci			lws_container_of(d, struct lws_ss_handle, cli_list);
1560d4afb5ceSopenharmony_ci
1561d4afb5ceSopenharmony_ci		cb(h, arg);
1562d4afb5ceSopenharmony_ci
1563d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(d, d1);
1564d4afb5ceSopenharmony_ci}
1565d4afb5ceSopenharmony_ci#endif
1566d4afb5ceSopenharmony_ci
1567d4afb5ceSopenharmony_cilws_ss_state_return_t
1568d4afb5ceSopenharmony_cilws_ss_request_tx(lws_ss_handle_t *h)
1569d4afb5ceSopenharmony_ci{
1570d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
1571d4afb5ceSopenharmony_ci
1572d4afb5ceSopenharmony_ci	r = _lws_ss_request_tx(h);
1573d4afb5ceSopenharmony_ci
1574d4afb5ceSopenharmony_ci	return r;
1575d4afb5ceSopenharmony_ci}
1576d4afb5ceSopenharmony_ci
1577d4afb5ceSopenharmony_cilws_ss_state_return_t
1578d4afb5ceSopenharmony_ci_lws_ss_request_tx(lws_ss_handle_t *h)
1579d4afb5ceSopenharmony_ci{
1580d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
1581d4afb5ceSopenharmony_ci
1582d4afb5ceSopenharmony_ci	// lwsl_notice("%s: h %p, wsi %p\n", __func__, h, h->wsi);
1583d4afb5ceSopenharmony_ci
1584d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1585d4afb5ceSopenharmony_ci
1586d4afb5ceSopenharmony_ci	if (h->wsi) {
1587d4afb5ceSopenharmony_ci		lws_callback_on_writable(h->wsi);
1588d4afb5ceSopenharmony_ci
1589d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
1590d4afb5ceSopenharmony_ci	}
1591d4afb5ceSopenharmony_ci
1592d4afb5ceSopenharmony_ci	if (!h->policy) {
1593d4afb5ceSopenharmony_ci		/* avoid crash */
1594d4afb5ceSopenharmony_ci		lwsl_err("%s: null policy\n", __func__);
1595d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
1596d4afb5ceSopenharmony_ci	}
1597d4afb5ceSopenharmony_ci
1598d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_SERVER)
1599d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
1600d4afb5ceSopenharmony_ci
1601d4afb5ceSopenharmony_ci	/*
1602d4afb5ceSopenharmony_ci	 * there's currently no wsi / connection associated with the ss handle
1603d4afb5ceSopenharmony_ci	 */
1604d4afb5ceSopenharmony_ci
1605d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD)
1606d4afb5ceSopenharmony_ci	if (h->policy == &pol_smd) {
1607d4afb5ceSopenharmony_ci		/*
1608d4afb5ceSopenharmony_ci		 * He's an _lws_smd... and no wsi... since we're just going
1609d4afb5ceSopenharmony_ci		 * to queue it, we could call his tx() right here, but rather
1610d4afb5ceSopenharmony_ci		 * than surprise him let's set a sul to do it next time around
1611d4afb5ceSopenharmony_ci		 * the event loop
1612d4afb5ceSopenharmony_ci		 */
1613d4afb5ceSopenharmony_ci
1614d4afb5ceSopenharmony_ci		lws_sul_schedule(h->context, 0, &h->u.smd.sul_write,
1615d4afb5ceSopenharmony_ci				 lws_ss_smd_tx_cb, 1);
1616d4afb5ceSopenharmony_ci
1617d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
1618d4afb5ceSopenharmony_ci	}
1619d4afb5ceSopenharmony_ci#endif
1620d4afb5ceSopenharmony_ci
1621d4afb5ceSopenharmony_ci	if (h->seqstate != SSSEQ_IDLE &&
1622d4afb5ceSopenharmony_ci	    h->seqstate != SSSEQ_DO_RETRY)
1623d4afb5ceSopenharmony_ci		return LWSSSSRET_OK;
1624d4afb5ceSopenharmony_ci
1625d4afb5ceSopenharmony_ci	h->seqstate = SSSEQ_TRY_CONNECT;
1626d4afb5ceSopenharmony_ci	if (h->prev_ss_state != LWSSSCS_POLL) { /* possible if we were created
1627d4afb5ceSopenharmony_ci						 * before we could action it */
1628d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_POLL);
1629d4afb5ceSopenharmony_ci		if (r)
1630d4afb5ceSopenharmony_ci			return r;
1631d4afb5ceSopenharmony_ci	}
1632d4afb5ceSopenharmony_ci
1633d4afb5ceSopenharmony_ci	/*
1634d4afb5ceSopenharmony_ci	 * Retries operate via lws_ss_request_tx(), explicitly ask for a
1635d4afb5ceSopenharmony_ci	 * reconnection to clear the retry limit
1636d4afb5ceSopenharmony_ci	 */
1637d4afb5ceSopenharmony_ci	r = _lws_ss_client_connect(h, 1, 0);
1638d4afb5ceSopenharmony_ci	if (r == LWSSSSRET_DESTROY_ME)
1639d4afb5ceSopenharmony_ci		return r;
1640d4afb5ceSopenharmony_ci
1641d4afb5ceSopenharmony_ci	if (r)
1642d4afb5ceSopenharmony_ci		return lws_ss_backoff(h);
1643d4afb5ceSopenharmony_ci
1644d4afb5ceSopenharmony_ci	return LWSSSSRET_OK;
1645d4afb5ceSopenharmony_ci}
1646d4afb5ceSopenharmony_ci
1647d4afb5ceSopenharmony_cilws_ss_state_return_t
1648d4afb5ceSopenharmony_cilws_ss_request_tx_len(lws_ss_handle_t *h, unsigned long len)
1649d4afb5ceSopenharmony_ci{
1650d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1651d4afb5ceSopenharmony_ci
1652d4afb5ceSopenharmony_ci	if (h->wsi && h->policy &&
1653d4afb5ceSopenharmony_ci	    (h->policy->protocol == LWSSSP_H1 ||
1654d4afb5ceSopenharmony_ci	     h->policy->protocol == LWSSSP_H2 ||
1655d4afb5ceSopenharmony_ci	     h->policy->protocol == LWSSSP_WS))
1656d4afb5ceSopenharmony_ci		h->wsi->http.writeable_len = len;
1657d4afb5ceSopenharmony_ci	else
1658d4afb5ceSopenharmony_ci		h->writeable_len = len;
1659d4afb5ceSopenharmony_ci
1660d4afb5ceSopenharmony_ci	return lws_ss_request_tx(h);
1661d4afb5ceSopenharmony_ci}
1662d4afb5ceSopenharmony_ci
1663d4afb5ceSopenharmony_ci/*
1664d4afb5ceSopenharmony_ci * private helpers
1665d4afb5ceSopenharmony_ci */
1666d4afb5ceSopenharmony_ci
1667d4afb5ceSopenharmony_ci/* used on context destroy when iterating listed lws_ss on a pt */
1668d4afb5ceSopenharmony_ci
1669d4afb5ceSopenharmony_ciint
1670d4afb5ceSopenharmony_cilws_ss_destroy_dll(struct lws_dll2 *d, void *user)
1671d4afb5ceSopenharmony_ci{
1672d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
1673d4afb5ceSopenharmony_ci
1674d4afb5ceSopenharmony_ci	lws_ss_destroy(&h);
1675d4afb5ceSopenharmony_ci
1676d4afb5ceSopenharmony_ci	return 0;
1677d4afb5ceSopenharmony_ci}
1678d4afb5ceSopenharmony_ci
1679d4afb5ceSopenharmony_ciint
1680d4afb5ceSopenharmony_cilws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user)
1681d4afb5ceSopenharmony_ci{
1682d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
1683d4afb5ceSopenharmony_ci
1684d4afb5ceSopenharmony_ci	if (lws_ss_event_helper(h, LWSSSCS_EVENT_WAIT_CANCELLED))
1685d4afb5ceSopenharmony_ci		lwsl_warn("%s: cancel event ignores return\n", __func__);
1686d4afb5ceSopenharmony_ci
1687d4afb5ceSopenharmony_ci	return 0;
1688d4afb5ceSopenharmony_ci}
1689d4afb5ceSopenharmony_ci
1690d4afb5ceSopenharmony_cistruct lws_sequencer *
1691d4afb5ceSopenharmony_cilws_ss_get_sequencer(lws_ss_handle_t *h)
1692d4afb5ceSopenharmony_ci{
1693d4afb5ceSopenharmony_ci	return h->seq;
1694d4afb5ceSopenharmony_ci}
1695d4afb5ceSopenharmony_ci
1696d4afb5ceSopenharmony_cistruct lws_context *
1697d4afb5ceSopenharmony_cilws_ss_get_context(struct lws_ss_handle *h)
1698d4afb5ceSopenharmony_ci{
1699d4afb5ceSopenharmony_ci	return h->context;
1700d4afb5ceSopenharmony_ci}
1701d4afb5ceSopenharmony_ci
1702d4afb5ceSopenharmony_ciconst char *
1703d4afb5ceSopenharmony_cilws_ss_rideshare(struct lws_ss_handle *h)
1704d4afb5ceSopenharmony_ci{
1705d4afb5ceSopenharmony_ci	if (!h->rideshare)
1706d4afb5ceSopenharmony_ci		return h->policy->streamtype;
1707d4afb5ceSopenharmony_ci
1708d4afb5ceSopenharmony_ci	return h->rideshare->streamtype;
1709d4afb5ceSopenharmony_ci}
1710d4afb5ceSopenharmony_ci
1711d4afb5ceSopenharmony_ciint
1712d4afb5ceSopenharmony_cilws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t bump)
1713d4afb5ceSopenharmony_ci{
1714d4afb5ceSopenharmony_ci	const struct ss_pcols *ssp;
1715d4afb5ceSopenharmony_ci
1716d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1717d4afb5ceSopenharmony_ci
1718d4afb5ceSopenharmony_ci	ssp = ss_pcols[(int)h->policy->protocol];
1719d4afb5ceSopenharmony_ci
1720d4afb5ceSopenharmony_ci	if (h->wsi && ssp && ssp->tx_cr_add)
1721d4afb5ceSopenharmony_ci		return ssp->tx_cr_add(h, bump);
1722d4afb5ceSopenharmony_ci
1723d4afb5ceSopenharmony_ci	return 0;
1724d4afb5ceSopenharmony_ci}
1725d4afb5ceSopenharmony_ci
1726d4afb5ceSopenharmony_ciint
1727d4afb5ceSopenharmony_cilws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h)
1728d4afb5ceSopenharmony_ci{
1729d4afb5ceSopenharmony_ci	const struct ss_pcols *ssp;
1730d4afb5ceSopenharmony_ci
1731d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1732d4afb5ceSopenharmony_ci
1733d4afb5ceSopenharmony_ci	ssp = ss_pcols[(int)h->policy->protocol];
1734d4afb5ceSopenharmony_ci
1735d4afb5ceSopenharmony_ci	if (h->wsi && ssp && ssp->tx_cr_add)
1736d4afb5ceSopenharmony_ci		return ssp->tx_cr_est(h);
1737d4afb5ceSopenharmony_ci
1738d4afb5ceSopenharmony_ci	return 0;
1739d4afb5ceSopenharmony_ci}
1740d4afb5ceSopenharmony_ci
1741d4afb5ceSopenharmony_ci/*
1742d4afb5ceSopenharmony_ci * protocol-independent handler for ss timeout
1743d4afb5ceSopenharmony_ci */
1744d4afb5ceSopenharmony_ci
1745d4afb5ceSopenharmony_cistatic void
1746d4afb5ceSopenharmony_cilws_ss_to_cb(lws_sorted_usec_list_t *sul)
1747d4afb5ceSopenharmony_ci{
1748d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul_timeout);
1749d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
1750d4afb5ceSopenharmony_ci
1751d4afb5ceSopenharmony_ci	lwsl_info("%s: %s timeout fired\n", __func__, lws_ss_tag(h));
1752d4afb5ceSopenharmony_ci
1753d4afb5ceSopenharmony_ci	r = lws_ss_event_helper(h, LWSSSCS_TIMEOUT);
1754d4afb5ceSopenharmony_ci	if (r != LWSSSSRET_DISCONNECT_ME && r != LWSSSSRET_DESTROY_ME)
1755d4afb5ceSopenharmony_ci		return;
1756d4afb5ceSopenharmony_ci
1757d4afb5ceSopenharmony_ci	if (h->wsi)
1758d4afb5ceSopenharmony_ci		lws_set_timeout(h->wsi, 1, LWS_TO_KILL_ASYNC);
1759d4afb5ceSopenharmony_ci
1760d4afb5ceSopenharmony_ci	_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, h->wsi, &h);
1761d4afb5ceSopenharmony_ci}
1762d4afb5ceSopenharmony_ci
1763d4afb5ceSopenharmony_civoid
1764d4afb5ceSopenharmony_cilws_ss_start_timeout(struct lws_ss_handle *h, unsigned int timeout_ms)
1765d4afb5ceSopenharmony_ci{
1766d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1767d4afb5ceSopenharmony_ci
1768d4afb5ceSopenharmony_ci	if (!timeout_ms && !h->policy->timeout_ms)
1769d4afb5ceSopenharmony_ci		return;
1770d4afb5ceSopenharmony_ci
1771d4afb5ceSopenharmony_ci	lws_sul_schedule(h->context, 0, &h->sul_timeout, lws_ss_to_cb,
1772d4afb5ceSopenharmony_ci			 (timeout_ms ? timeout_ms : h->policy->timeout_ms) *
1773d4afb5ceSopenharmony_ci			 LWS_US_PER_MS);
1774d4afb5ceSopenharmony_ci}
1775d4afb5ceSopenharmony_ci
1776d4afb5ceSopenharmony_civoid
1777d4afb5ceSopenharmony_cilws_ss_cancel_timeout(struct lws_ss_handle *h)
1778d4afb5ceSopenharmony_ci{
1779d4afb5ceSopenharmony_ci	lws_service_assert_loop_thread(h->context, h->tsi);
1780d4afb5ceSopenharmony_ci	lws_sul_cancel(&h->sul_timeout);
1781d4afb5ceSopenharmony_ci}
1782d4afb5ceSopenharmony_ci
1783d4afb5ceSopenharmony_civoid
1784d4afb5ceSopenharmony_cilws_ss_change_handlers(struct lws_ss_handle *h,
1785d4afb5ceSopenharmony_ci	lws_ss_state_return_t (*rx)(void *userobj, const uint8_t *buf,
1786d4afb5ceSopenharmony_ci				    size_t len, int flags),
1787d4afb5ceSopenharmony_ci	lws_ss_state_return_t (*tx)(void *userobj, lws_ss_tx_ordinal_t ord,
1788d4afb5ceSopenharmony_ci				    uint8_t *buf, size_t *len, int *flags),
1789d4afb5ceSopenharmony_ci	lws_ss_state_return_t (*state)(void *userobj, void *h_src /* ss handle type */,
1790d4afb5ceSopenharmony_ci				       lws_ss_constate_t state,
1791d4afb5ceSopenharmony_ci				       lws_ss_tx_ordinal_t ack))
1792d4afb5ceSopenharmony_ci{
1793d4afb5ceSopenharmony_ci	if (rx)
1794d4afb5ceSopenharmony_ci		h->info.rx = rx;
1795d4afb5ceSopenharmony_ci	if (tx)
1796d4afb5ceSopenharmony_ci		h->info.tx = tx;
1797d4afb5ceSopenharmony_ci	if (state)
1798d4afb5ceSopenharmony_ci		h->info.state = state;
1799d4afb5ceSopenharmony_ci}
1800d4afb5ceSopenharmony_ci
1801d4afb5ceSopenharmony_ciconst char *
1802d4afb5ceSopenharmony_cilws_ss_tag(struct lws_ss_handle *h)
1803d4afb5ceSopenharmony_ci{
1804d4afb5ceSopenharmony_ci	if (!h)
1805d4afb5ceSopenharmony_ci		return "[null ss]";
1806d4afb5ceSopenharmony_ci	return lws_lc_tag(&h->lc);
1807d4afb5ceSopenharmony_ci}
1808d4afb5ceSopenharmony_ci
1809d4afb5ceSopenharmony_cistruct lws_log_cx *
1810d4afb5ceSopenharmony_cilwsl_ss_get_cx(struct lws_ss_handle *ss)
1811d4afb5ceSopenharmony_ci{
1812d4afb5ceSopenharmony_ci	if (!ss)
1813d4afb5ceSopenharmony_ci		return NULL;
1814d4afb5ceSopenharmony_ci
1815d4afb5ceSopenharmony_ci	return ss->lc.log_cx;
1816d4afb5ceSopenharmony_ci}
1817d4afb5ceSopenharmony_ci
1818d4afb5ceSopenharmony_civoid
1819d4afb5ceSopenharmony_cilws_log_prepend_ss(struct lws_log_cx *cx, void *obj, char **p, char *e)
1820d4afb5ceSopenharmony_ci{
1821d4afb5ceSopenharmony_ci	struct lws_ss_handle *h = (struct lws_ss_handle *)obj;
1822d4afb5ceSopenharmony_ci
1823d4afb5ceSopenharmony_ci	*p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
1824d4afb5ceSopenharmony_ci			lws_ss_tag(h));
1825d4afb5ceSopenharmony_ci}
1826d4afb5ceSopenharmony_ci
1827d4afb5ceSopenharmony_ci#if defined(_DEBUG)
1828d4afb5ceSopenharmony_civoid
1829d4afb5ceSopenharmony_cilws_ss_assert_extant(struct lws_context *cx, int tsi, struct lws_ss_handle *h)
1830d4afb5ceSopenharmony_ci{
1831d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &cx->pt[tsi];
1832d4afb5ceSopenharmony_ci
1833d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, pt->ss_owner.head) {
1834d4afb5ceSopenharmony_ci		struct lws_ss_handle *h1 = lws_container_of(d,
1835d4afb5ceSopenharmony_ci						struct lws_ss_handle, list);
1836d4afb5ceSopenharmony_ci
1837d4afb5ceSopenharmony_ci		if (h == h1)
1838d4afb5ceSopenharmony_ci			return; /* okay */
1839d4afb5ceSopenharmony_ci
1840d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(d, d1);
1841d4afb5ceSopenharmony_ci
1842d4afb5ceSopenharmony_ci	/*
1843d4afb5ceSopenharmony_ci	 * The ss handle is not listed in the pt ss handle owner...
1844d4afb5ceSopenharmony_ci	 */
1845d4afb5ceSopenharmony_ci
1846d4afb5ceSopenharmony_ci	assert(0);
1847d4afb5ceSopenharmony_ci}
1848d4afb5ceSopenharmony_ci#endif
1849