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