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