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