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