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 * In the case Secure Streams protocol needs to pass through a buffer,
26 * or a streamed connection, the protocol metadata must be serialized. This
27 * file provides internal apis to perform the serialization and deserialization
28 * in and out of an lws_dsh fifo-type buffer.
29 */
30
31 #include <private-lib-core.h>
32
33 typedef enum {
34 RPAR_TYPE,
35 RPAR_LEN_MSB,
36 RPAR_LEN_LSB,
37
38 RPAR_FLAG_B3,
39 RPAR_FLAG_B2,
40 RPAR_FLAG_B1,
41 RPAR_FLAG_B0,
42
43 RPAR_LATA3,
44 RPAR_LATA2,
45 RPAR_LATA1,
46 RPAR_LATA0,
47
48 RPAR_LATB7,
49 RPAR_LATB6,
50 RPAR_LATB5,
51 RPAR_LATB4,
52 RPAR_LATB3,
53 RPAR_LATB2,
54 RPAR_LATB1,
55 RPAR_LATB0,
56
57 RPAR_RIDESHARE_LEN,
58 RPAR_RIDESHARE,
59
60 RPAR_PERF,
61
62 RPAR_RESULT_CREATION_DSH,
63 RPAR_RESULT_CREATION_RIDESHARE,
64
65 RPAR_METADATA_NAMELEN,
66 RPAR_METADATA_NAME,
67 RPAR_METADATA_VALUE,
68
69 RPAR_PAYLOAD,
70
71 RPAR_RX_TXCR_UPDATE,
72
73 RPAR_STREAMTYPE,
74 RPAR_INIT_PROVERS,
75 RPAR_INIT_PID,
76 RPAR_INITTXC0,
77
78 RPAR_TXCR0,
79
80 RPAR_TIMEOUT0,
81
82 RPAR_PAYLEN0,
83
84 RPAR_RESULT_CREATION,
85
86 RPAR_STATEINDEX,
87 RPAR_ORD3,
88 RPAR_ORD2,
89 RPAR_ORD1,
90 RPAR_ORD0,
91 } rx_parser_t;
92
93 #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
94 static const char *sn[] = {
95 "unset",
96
97 "LPCSPROX_WAIT_INITIAL_TX",
98 "LPCSPROX_REPORTING_FAIL",
99 "LPCSPROX_REPORTING_OK",
100 "LPCSPROX_OPERATIONAL",
101 "LPCSPROX_DESTROYED",
102
103 "LPCSCLI_SENDING_INITIAL_TX",
104 "LPCSCLI_WAITING_CREATE_RESULT",
105 "LPCSCLI_LOCAL_CONNECTED",
106 "LPCSCLI_ONWARD_CONNECT",
107 "LPCSCLI_OPERATIONAL",
108 };
109 #endif
110
111 struct lws_log_cx *
lwsl_sspc_get_cx(struct lws_sspc_handle * sspc)112 lwsl_sspc_get_cx(struct lws_sspc_handle *sspc)
113 {
114 if (!sspc)
115 return NULL;
116
117 return sspc->lc.log_cx;
118 }
119
120
121 void
lws_log_prepend_sspc(struct lws_log_cx * cx,void * obj,char ** p,char * e)122 lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e)
123 {
124 struct lws_sspc_handle *h = (struct lws_sspc_handle *)obj;
125
126 *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
127 lws_sspc_tag(h));
128 }
129
130 static void
lws_ss_serialize_state_transition(lws_sspc_handle_t * h,lws_ss_conn_states_t * state,int new_state)131 lws_ss_serialize_state_transition(lws_sspc_handle_t *h,
132 lws_ss_conn_states_t *state, int new_state)
133 {
134 #if defined(_DEBUG)
135 lwsl_sspc_info(h, "%s -> %s", sn[*state], sn[new_state]);
136 #endif
137 *state = (lws_ss_conn_states_t)new_state;
138 }
139
140
141 /*
142 * event loop received something and is queueing it for the foreign side of
143 * the dsh to consume later as serialized rx
144 */
145
146 int
lws_ss_serialize_rx_payload(struct lws_dsh * dsh,const uint8_t * buf,size_t len,int flags,const char * rsp)147 lws_ss_serialize_rx_payload(struct lws_dsh *dsh, const uint8_t *buf,
148 size_t len, int flags, const char *rsp)
149 {
150 lws_usec_t us = lws_now_usecs();
151 uint8_t pre[128];
152 int est = 19, l = 0;
153
154 if (flags & LWSSS_FLAG_RIDESHARE) {
155 /*
156 * We should have the rideshare name if we have been told it's
157 * on a non-default rideshare
158 */
159 assert(rsp);
160 if (!rsp)
161 return 1;
162 l = (int)strlen(rsp);
163 est += 1 + l;
164 } else
165 assert(!rsp);
166
167 // lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
168 // lwsl_hexdump_info(buf, len);
169
170 pre[0] = LWSSS_SER_RXPRE_RX_PAYLOAD;
171 lws_ser_wu16be(&pre[1], (uint16_t)(len + (size_t)est - 3));
172 lws_ser_wu32be(&pre[3], (uint32_t)flags);
173 lws_ser_wu32be(&pre[7], 0); /* write will compute latency here... */
174 lws_ser_wu64be(&pre[11], (uint64_t)us); /* ... and set this to the write time */
175
176 /*
177 * If we are on a non-default rideshare, append the non-default name to
178 * the headers of the payload part, 1-byte length first
179 */
180
181 if (flags & LWSSS_FLAG_RIDESHARE) {
182 pre[19] = (uint8_t)l;
183 memcpy(&pre[20], rsp, (unsigned int)l);
184 }
185
186 if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)est, buf, len)) {
187 lwsl_err("%s: unable to alloc in dsh 1\n", __func__);
188
189 return 1;
190 }
191
192 return 0;
193 }
194
195 /*
196 * event loop is consuming dsh-buffered, already-serialized tx from the
197 * foreign side
198 */
199
200 int
lws_ss_deserialize_tx_payload(struct lws_dsh * dsh,struct lws * wsi,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)201 lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
202 lws_ss_tx_ordinal_t ord, uint8_t *buf,
203 size_t *len, int *flags)
204 {
205 uint8_t *p;
206 size_t si;
207
208 if (lws_dsh_get_head(dsh, KIND_C_TO_P, (void **)&p, &si)) {
209 *len = 0;
210 return 0;
211 }
212
213 /*
214 * The packet in the dsh has a proxying serialization header, process
215 * and strip it so we just forward the payload
216 */
217
218 if (*len <= si - 23 || si < 23) {
219 /*
220 * What comes out of the dsh needs to fit in the tx buffer...
221 * we have arrangements at the proxy rx of the client UDS to
222 * chop chunks larger than 1380 into seuqential lumps of 1380
223 */
224 lwsl_err("%s: *len = %d, si = %d\n", __func__, (int)*len, (int)si);
225 assert(0);
226 return 1;
227 }
228 if (p[0] != LWSSS_SER_TXPRE_TX_PAYLOAD) {
229 assert(0);
230 return 1;
231 }
232
233 *len = (size_t)(lws_ser_ru16be(&p[1]) - (23 - 3));
234 if (*len != si - 23) {
235 /*
236 * We cannot accept any length that doesn't reflect the actual
237 * length of what came in from the dsh, either something nasty
238 * happened with truncation or we are being attacked
239 */
240 assert(0);
241
242 return 1;
243 }
244
245 memcpy(buf, p + 23, si - 23);
246
247 *flags = (int)lws_ser_ru32be(&p[3]);
248
249 lws_dsh_free((void **)&p);
250
251 return 0;
252 }
253
254 /*
255 * event loop side is issuing state, serialize and put it in the dbuf for
256 * the foreign side to consume later
257 */
258
259 int
lws_ss_serialize_state(struct lws * wsi,struct lws_dsh * dsh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)260 lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
261 lws_ss_tx_ordinal_t ack)
262 {
263 uint8_t pre[12];
264 int n = 4;
265
266 if (state == LWSSSCS_EVENT_WAIT_CANCELLED)
267 return 0;
268
269 lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
270 (unsigned int)ack);
271
272 pre[0] = LWSSS_SER_RXPRE_CONNSTATE;
273 pre[1] = 0;
274
275 if (state > 255) {
276 pre[2] = 8;
277 lws_ser_wu32be(&pre[3], state);
278 n = 7;
279 } else {
280 pre[2] = 5;
281 pre[3] = (uint8_t)state;
282 }
283
284 lws_ser_wu32be(&pre[n], ack);
285
286 if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)n + 4, NULL, 0) ||
287 (wsi && lws_fi(&wsi->fic, "sspc_dsh_ss2p_oom"))) {
288 lwsl_err("%s: unable to alloc in dsh 2\n", __func__);
289
290 return 1;
291 }
292
293 return 0;
294 }
295
296 /*
297 * event loop side was told about remote peer tx credit window update, serialize
298 * and put it in the dbuf for the foreign side to consume later
299 */
300
301 int
lws_ss_serialize_txcr(struct lws_dsh * dsh,int txcr)302 lws_ss_serialize_txcr(struct lws_dsh *dsh, int txcr)
303 {
304 uint8_t pre[7];
305
306 lwsl_info("%s: %d\n", __func__, txcr);
307
308 pre[0] = LWSSS_SER_RXPRE_TXCR_UPDATE;
309 pre[1] = 0;
310 pre[2] = 4;
311 lws_ser_wu32be(&pre[3], (uint32_t)txcr);
312
313 if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, 7, NULL, 0)) {
314 lwsl_err("%s: unable to alloc in dsh 2\n", __func__);
315
316 return 1;
317 }
318
319 return 0;
320 }
321
322 /*
323 * event loop side is consuming serialized data from the client via dsh, parse
324 * it using a bytewise parser for the serialization header(s)...
325 * it's possibly coalesced
326 *
327 * client: pss is pointing to the start of userdata. We can use
328 * pss_to_sspc_h(_pss, _ssi) to convert that to a pointer to the sspc
329 * handle
330 *
331 * proxy: pss is pointing to &conn->ss, a pointer to the ss handle
332 *
333 * Returns one of
334 *
335 * LWSSSSRET_OK
336 * LWSSSSRET_DISCONNECT_ME
337 * LWSSSSRET_DESTROY_ME
338 */
339
340 /* convert userdata ptr _pss to handle pointer, allowing for any layout in
341 * userdata */
342 #define client_pss_to_sspc_h(_pss, _ssi) (*((lws_sspc_handle_t **) \
343 ((uint8_t *)_pss) + _ssi->handle_offset))
344 /* client pss to sspc userdata */
345 #define client_pss_to_userdata(_pss) ((void *)_pss)
346 /* proxy convert pss to ss handle */
347 #define proxy_pss_to_ss_h(_pss) (*_pss)
348
349 /* convert userdata ptr _pss to handle pointer, allowing for any layout in
350 * userdata */
351 #define client_pss_to_sspc_h(_pss, _ssi) (*((lws_sspc_handle_t **) \
352 ((uint8_t *)_pss) + _ssi->handle_offset))
353 /* client pss to sspc userdata */
354 #define client_pss_to_userdata(_pss) ((void *)_pss)
355 /* proxy convert pss to ss handle */
356 #define proxy_pss_to_ss_h(_pss) (*_pss)
357
358 int
lws_ss_deserialize_parse(struct lws_ss_serialization_parser * par,struct lws_context * context,struct lws_dsh * dsh,const uint8_t * cp,size_t len,lws_ss_conn_states_t * state,void * parconn,lws_ss_handle_t ** pss,lws_ss_info_t * ssi,char client)359 lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
360 struct lws_context *context,
361 struct lws_dsh *dsh, const uint8_t *cp, size_t len,
362 lws_ss_conn_states_t *state, void *parconn,
363 lws_ss_handle_t **pss, lws_ss_info_t *ssi, char client)
364 {
365 lws_ss_state_return_t r;
366 lws_ss_metadata_t *pm;
367 lws_sspc_handle_t *h;
368 uint8_t pre[23];
369 uint32_t flags;
370 lws_usec_t us;
371 uint8_t *p;
372 int n;
373
374 while (len--) {
375
376 switch (par->ps) {
377 case RPAR_TYPE:
378 par->type = *cp++;
379 par->ps++;
380 break;
381
382 case RPAR_LEN_MSB: /* this is remaining frame length */
383 par->rem = (uint16_t)((*cp++) << 8);
384 par->ps++;
385 break;
386
387 case RPAR_LEN_LSB:
388 par->rem = (uint16_t)(par->rem | *cp++);
389 switch (par->type) {
390
391 /* event loop side */
392
393 case LWSSS_SER_TXPRE_TX_PAYLOAD:
394 if (client)
395 goto hangup;
396 if (*state != LPCSPROX_OPERATIONAL)
397 goto hangup;
398
399 par->ps = RPAR_FLAG_B3;
400 break;
401
402 case LWSSS_SER_TXPRE_DESTROYING:
403 if (client)
404 goto hangup;
405 par->ps = RPAR_TYPE;
406 lwsl_cx_notice(context, "DESTROYING");
407 goto hangup;
408
409 case LWSSS_SER_TXPRE_ONWARD_CONNECT:
410 if (client)
411 goto hangup;
412
413 if (*state != LPCSPROX_OPERATIONAL)
414 goto hangup;
415
416 par->ps = RPAR_TYPE;
417 lwsl_cx_notice(context, "ONWARD_CONNECT");
418
419 /*
420 * Shrug it off if we are already connecting or
421 * connected
422 */
423
424 if (!proxy_pss_to_ss_h(pss) ||
425 proxy_pss_to_ss_h(pss)->wsi)
426 break;
427
428 /*
429 * We're going to try to do the onward connect
430 */
431
432 if ((proxy_pss_to_ss_h(pss) &&
433 lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_onward_conn_fail")) ||
434 _lws_ss_client_connect(proxy_pss_to_ss_h(pss),
435 0, parconn) ==
436 LWSSSSRET_DESTROY_ME)
437 goto hangup;
438 break;
439
440 case LWSSS_SER_TXPRE_STREAMTYPE:
441 if (client)
442 goto hangup;
443 if (*state != LPCSPROX_WAIT_INITIAL_TX)
444 goto hangup;
445 if (par->rem < 1 + 4 + 1)
446 goto hangup;
447 par->ps = RPAR_INIT_PROVERS;
448 break;
449
450 case LWSSS_SER_TXPRE_METADATA:
451 if (client)
452 goto hangup;
453 if (par->rem < 3)
454 goto hangup;
455 par->ctr = 0;
456 par->ps = RPAR_METADATA_NAMELEN;
457 break;
458
459 case LWSSS_SER_TXPRE_TXCR_UPDATE:
460 par->ps = RPAR_TXCR0;
461 par->ctr = 0;
462 break;
463
464 case LWSSS_SER_TXPRE_TIMEOUT_UPDATE:
465 if (client)
466 goto hangup;
467 if (par->rem != 4)
468 goto hangup;
469 par->ps = RPAR_TIMEOUT0;
470 par->ctr = 0;
471 break;
472
473 case LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT:
474 if (client)
475 goto hangup;
476 if (par->rem != 4)
477 goto hangup;
478 par->ps = RPAR_PAYLEN0;
479 par->ctr = 0;
480 break;
481
482 /* client side */
483
484 case LWSSS_SER_RXPRE_RX_PAYLOAD:
485 if (!client)
486 goto hangup;
487 if (*state != LPCSCLI_OPERATIONAL &&
488 *state != LPCSCLI_LOCAL_CONNECTED)
489 goto hangup;
490
491 par->rideshare[0] = '\0';
492 par->ps = RPAR_FLAG_B3;
493 break;
494
495 case LWSSS_SER_RXPRE_CREATE_RESULT:
496 if (!client)
497 goto hangup;
498 if (*state != LPCSCLI_WAITING_CREATE_RESULT)
499 goto hangup;
500
501 if (par->rem < 1)
502 goto hangup;
503
504 par->ps = RPAR_RESULT_CREATION;
505 break;
506
507 case LWSSS_SER_RXPRE_CONNSTATE:
508 if (!client)
509 goto hangup;
510 if (*state != LPCSCLI_LOCAL_CONNECTED &&
511 *state != LPCSCLI_OPERATIONAL)
512 goto hangup;
513
514 if (par->rem < 5 || par->rem > 8)
515 goto hangup;
516
517 par->ps = RPAR_STATEINDEX;
518 par->ctr = 0;
519 break;
520
521 case LWSSS_SER_RXPRE_METADATA:
522 if (!client)
523 goto hangup;
524 if (par->rem < 3)
525 goto hangup;
526 par->ctr = 0;
527 par->ps = RPAR_METADATA_NAMELEN;
528 break;
529
530 case LWSSS_SER_RXPRE_TXCR_UPDATE:
531 par->ctr = 0;
532 par->ps = RPAR_RX_TXCR_UPDATE;
533 break;
534
535 case LWSSS_SER_RXPRE_PERF:
536 par->ctr = 0;
537 if (!par->rem)
538 goto hangup;
539 par->ps = RPAR_PERF;
540 break;
541
542 default:
543 lwsl_cx_notice(context, "bad type 0x%x",
544 par->type);
545 goto hangup;
546 }
547 break;
548
549 case RPAR_FLAG_B3:
550 case RPAR_FLAG_B2:
551 case RPAR_FLAG_B1:
552 case RPAR_FLAG_B0:
553 par->flags <<= 8;
554 par->flags |= *cp++;
555 par->ps++;
556 if (!par->rem--)
557 goto hangup;
558 break;
559
560 case RPAR_LATA3:
561 case RPAR_LATA2:
562 case RPAR_LATA1:
563 case RPAR_LATA0:
564 par->usd_phandling <<= 8;
565 par->usd_phandling |= *cp++;
566 par->ps++;
567 if (!par->rem--)
568 goto hangup;
569 break;
570
571 case RPAR_LATB7:
572 case RPAR_LATB6:
573 case RPAR_LATB5:
574 case RPAR_LATB4:
575 case RPAR_LATB3:
576 case RPAR_LATB2:
577 case RPAR_LATB1:
578 case RPAR_LATB0:
579 par->ust_pwait <<= 8;
580 par->ust_pwait |= *cp++;
581 par->ps++;
582 par->frag1 = 1;
583 if (!par->rem--)
584 goto hangup;
585
586 if (par->ps == RPAR_RIDESHARE_LEN &&
587 !(par->flags & LWSSS_FLAG_RIDESHARE))
588 par->ps = RPAR_PAYLOAD;
589
590 if (par->rem)
591 break;
592
593 /* fallthru - handle 0-length payload */
594
595 if (!(par->flags & LWSSS_FLAG_RIDESHARE))
596 goto payload_ff;
597 goto hangup;
598
599 /*
600 * Inbound rideshare info is provided on the RX packet
601 * itself
602 */
603
604 case RPAR_RIDESHARE_LEN:
605 par->slen = *cp++;
606 par->ctr = 0;
607 par->ps++;
608 if (par->rem-- < par->slen)
609 goto hangup;
610 break;
611
612 case RPAR_PERF:
613 n = (int)len + 1;
614 if (n > par->rem)
615 n = par->rem;
616
617 if (client &&
618 client_pss_to_sspc_h(pss, ssi) &&
619 ssi->rx) {
620 int ret;
621
622 /* we still have an sspc handle */
623 ret = ssi->rx(client_pss_to_userdata(pss),
624 (uint8_t *)cp, (unsigned int)n,
625 (int)(LWSSS_FLAG_SOM | LWSSS_FLAG_EOM |
626 LWSSS_FLAG_PERF_JSON));
627
628 if (lws_fi(&client_pss_to_sspc_h(pss, ssi)->fic,
629 "sspc_perf_rx_fake_destroy_me"))
630 ret = LWSSSSRET_DESTROY_ME;
631
632 switch (ret) {
633 case LWSSSSRET_OK:
634 break;
635 case LWSSSSRET_DISCONNECT_ME:
636 goto hangup;
637 case LWSSSSRET_DESTROY_ME:
638 return LWSSSSRET_DESTROY_ME;
639 }
640 }
641 if (n) {
642 cp += n;
643 par->rem = (uint16_t)(par->rem - (uint16_t)(unsigned int)n);
644 len = (len + 1) - (unsigned int)n;
645 }
646 if (!par->rem)
647 par->ps = RPAR_TYPE;
648 break;
649
650 case RPAR_RIDESHARE:
651 par->rideshare[par->ctr++] = (char)*cp++;
652 if (!par->rem--)
653 goto hangup;
654 if (par->ctr != par->slen)
655 break;
656 par->ps = RPAR_PAYLOAD;
657 if (par->rem)
658 break;
659
660 /* fallthru - handle 0-length payload */
661
662 case RPAR_PAYLOAD:
663 payload_ff:
664 n = (int)len + 1;
665 if (n > par->rem)
666 n = par->rem;
667 /*
668 * We get called with a serialized buffer of a size
669 * chosen by the client. We can only create dsh entries
670 * with up to 1380 payload, to guarantee we can emit
671 * them on the onward connection atomically.
672 *
673 * If 1380 isn't enough to cover what was handed to us,
674 * we'll stop at 1380 and go around again and create
675 * more dsh entries for the rest, with their own
676 * headers.
677 */
678
679 if (n > 1380)
680 n = 1380;
681
682 /*
683 * Since we're in the business of fragmenting client
684 * serialized payloads at 1380, we have to deal with
685 * refragmenting the SOM / EOM flags that covered the
686 * whole client serialized packet, so they apply to
687 * each dsh entry we split it into correctly
688 */
689
690 flags = par->flags & LWSSS_FLAG_RELATED_START;
691 if (par->frag1)
692 /*
693 * Only set the first time we came to this
694 * state after deserialization of the header
695 */
696 flags |= par->flags &
697 (LWSSS_FLAG_SOM | LWSSS_FLAG_POLL);
698
699 if (par->rem == n)
700 /*
701 * We are going to complete the advertised
702 * payload length from the client on this dsh,
703 * so give him the EOM type flags if any
704 */
705 flags |= par->flags & (LWSSS_FLAG_EOM |
706 LWSSS_FLAG_RELATED_END);
707
708 par->frag1 = 0;
709 us = lws_now_usecs();
710
711 if (!client) {
712 lws_ss_handle_t *hss;
713
714 /*
715 * Proxy - we received some serialized tx from
716 * the client.
717 *
718 * The header for buffering private to the
719 * proxy is 23 bytes vs 19, so we can hold the
720 * current time when it was buffered
721 * additionally
722 */
723
724 hss = proxy_pss_to_ss_h(pss);
725 if (hss)
726 lwsl_ss_info(hss, "C2P RX: len %d", (int)n);
727
728 p = pre;
729 pre[0] = LWSSS_SER_TXPRE_TX_PAYLOAD;
730 lws_ser_wu16be(&p[1], (uint16_t)((unsigned int)n + 23 - 3));
731 lws_ser_wu32be(&p[3], flags);
732 /* us held at client before written */
733 lws_ser_wu32be(&p[7], par->usd_phandling);
734 /* us taken for transit to proxy */
735 lws_ser_wu32be(&p[11], (uint32_t)(us - (lws_usec_t)par->ust_pwait));
736 /* time used later to find proxy hold time */
737 lws_ser_wu64be(&p[15], (uint64_t)us);
738
739 if ((hss &&
740 lws_fi(&hss->fic, "ssproxy_dsh_c2p_pay_oom")) ||
741 lws_dsh_alloc_tail(dsh, KIND_C_TO_P, pre,
742 23, cp, (unsigned int)n)) {
743 lwsl_ss_err(hss, "unable to alloc in dsh 3");
744
745 return LWSSSSRET_DISCONNECT_ME;
746 }
747
748 if (hss)
749 _lws_ss_request_tx(hss);
750 } else {
751
752 /*
753 * Client receives some RX from proxy
754 *
755 * Pass whatever payload we have to ss user
756 */
757
758 h = lws_container_of(par, lws_sspc_handle_t,
759 parser);
760 h->txc.peer_tx_cr_est -= n;
761
762 lwsl_sspc_info(h, "P2C RX: len %d", (int)n);
763
764 if (ssi->rx && client_pss_to_sspc_h(pss, ssi)) {
765 /* we still have an sspc handle */
766 int ret;
767
768 ret = ssi->rx(client_pss_to_userdata(pss),
769 (uint8_t *)cp, (unsigned int)n, (int)flags);
770
771 if (client_pss_to_sspc_h(pss, ssi) &&
772 lws_fi(&client_pss_to_sspc_h(pss, ssi)->fic, "sspc_rx_fake_destroy_me"))
773 ret = LWSSSSRET_DESTROY_ME;
774
775 switch (ret) {
776 case LWSSSSRET_OK:
777 break;
778 case LWSSSSRET_DISCONNECT_ME:
779 goto hangup;
780 case LWSSSSRET_DESTROY_ME:
781 return LWSSSSRET_DESTROY_ME;
782 }
783 }
784
785 #if 0
786 if (lws_det_lat_active(context)) {
787 lws_detlat_t d;
788
789 d.type = LDLT_READ;
790 d.acc_size = d.req_size = n;
791 d.latencies[LAT_DUR_USERCB] =
792 lws_now_usecs() - us;
793 d.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
794 par->usd_phandling;
795 d.latencies[LAT_DUR_PROXY_CLIENT_WRITE_TO_PROXY_RX] =
796 us - par->ust_pwait;
797
798 lws_det_lat_cb(context, &d);
799 }
800 #endif
801 }
802
803 if (n) {
804 cp += n;
805 par->rem = (uint16_t)(par->rem - (uint16_t)(unsigned int)n);
806 len = (len + 1) - (unsigned int)n;
807 /*
808 * if we didn't consume it all, we'll come
809 * around again and produce more dsh entries up
810 * to 1380 each until it is gone
811 */
812 }
813 if (!par->rem)
814 par->ps = RPAR_TYPE;
815 break;
816
817 case RPAR_RX_TXCR_UPDATE:
818 if (!--par->rem && par->ctr != 3)
819 goto hangup;
820
821 par->temp32 = (par->temp32 << 8) | *cp++;
822 if (++par->ctr < 4)
823 break;
824
825 /*
826 * Proxy is telling us remote endpoint is allowing us
827 * par->temp32 more bytes tx credit to write to it
828 */
829
830 h = lws_container_of(par, lws_sspc_handle_t, parser);
831 h->txc.tx_cr += par->temp32;
832 lwsl_info("%s: RX_PEER_TXCR: %d\n", __func__, par->temp32);
833 lws_sspc_request_tx(h); /* in case something waiting */
834 par->ctr = 0;
835 par->ps = RPAR_TYPE;
836 break;
837
838 case RPAR_INIT_PROVERS:
839 /* Protocol version byte for this connection */
840 par->protocol_version = *cp++;
841
842 /*
843 * So we have to know what versions of the serialization
844 * protocol we can support at the proxy side, and
845 * reject anythng we don't know how to deal with
846 * noisily in the logs.
847 */
848
849 if (par->protocol_version != 1) {
850 lwsl_err("%s: Rejecting client with "
851 "unsupported SSv%d protocol\n",
852 __func__, par->protocol_version);
853
854 goto hangup;
855 }
856
857 if (!--par->rem)
858 goto hangup;
859 par->ctr = 0;
860 par->ps = RPAR_INIT_PID;
861 break;
862
863
864 case RPAR_INIT_PID:
865 if (!--par->rem)
866 goto hangup;
867
868 par->temp32 = (par->temp32 << 8) | *cp++;
869 if (++par->ctr < 4)
870 break;
871
872 par->client_pid = (uint32_t)par->temp32;
873 par->ctr = 0;
874 par->ps = RPAR_INITTXC0;
875 break;
876
877 case RPAR_INITTXC0:
878 if (!--par->rem)
879 goto hangup;
880
881 par->temp32 = (par->temp32 << 8) | *cp++;
882 if (++par->ctr < 4)
883 break;
884
885 par->txcr_out = par->temp32;
886 par->ctr = 0;
887 par->ps = RPAR_STREAMTYPE;
888 break;
889
890 /*
891 * These are the client adjusting our / the remote peer ability
892 * to send back to him. He's sending a signed u32 BE
893 */
894
895 case RPAR_TXCR0:
896
897 par->temp32 = (par->temp32 << 8) | *cp++;
898 if (++par->ctr < 4) {
899 if (!--par->rem)
900 goto hangup;
901 break;
902 }
903
904 if (--par->rem)
905 goto hangup;
906
907 if (!client) {
908 /*
909 * We're the proxy, being told by the client
910 * that it wants to allow more tx from the peer
911 * on the onward connection towards it.
912 */
913 #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
914 if (proxy_pss_to_ss_h(pss) &&
915 proxy_pss_to_ss_h(pss)->wsi) {
916 lws_wsi_tx_credit(
917 proxy_pss_to_ss_h(pss)->wsi,
918 LWSTXCR_PEER_TO_US,
919 par->temp32);
920 lwsl_notice("%s: proxy RX_PEER_TXCR: +%d (est %d)\n",
921 __func__, par->temp32,
922 proxy_pss_to_ss_h(pss)->wsi->
923 txc.peer_tx_cr_est);
924 _lws_ss_request_tx(proxy_pss_to_ss_h(pss));
925 } else
926 #endif
927 lwsl_info("%s: dropping TXCR\n", __func__);
928 } else {
929 /*
930 * We're the client, being told by the proxy
931 * about tx credit being given to us from the
932 * remote peer, allowing the client to write to
933 * it.
934 */
935 h = lws_container_of(par, lws_sspc_handle_t,
936 parser);
937 h->txc.tx_cr += par->temp32;
938 lwsl_info("%s: client RX_PEER_TXCR: %d\n",
939 __func__, par->temp32);
940 lws_sspc_request_tx(h); /* in case something waiting */
941 }
942 par->ps = RPAR_TYPE;
943 break;
944
945 case RPAR_TIMEOUT0:
946
947 par->temp32 = (par->temp32 << 8) | *cp++;
948 if (++par->ctr < 4) {
949 if (!--par->rem)
950 goto hangup;
951 break;
952 }
953
954 if (--par->rem)
955 goto hangup;
956
957 /*
958 * Proxy...
959 *
960 * *pss may have gone away asynchronously inbetweentimes
961 */
962
963 if (proxy_pss_to_ss_h(pss)) {
964
965 if ((unsigned int)par->temp32 == 0xffffffff) {
966 lwsl_notice("%s: cancel ss timeout\n",
967 __func__);
968 lws_ss_cancel_timeout(
969 proxy_pss_to_ss_h(pss));
970 } else {
971
972 if (!par->temp32)
973 par->temp32 = (int)
974 proxy_pss_to_ss_h(pss)->
975 policy->timeout_ms;
976
977 lwsl_notice("%s: set ss timeout for +%ums\n",
978 __func__, par->temp32);
979
980 lws_ss_start_timeout(
981 proxy_pss_to_ss_h(pss), (unsigned int)
982 par->temp32);
983 }
984 }
985
986 par->ps = RPAR_TYPE;
987 break;
988
989 case RPAR_PAYLEN0:
990 /*
991 * It's the length from lws_ss_request_tx_len() being
992 * passed up to the proxy
993 */
994 par->temp32 = (par->temp32 << 8) | *cp++;
995 if (++par->ctr < 4) {
996 if (!--par->rem)
997 goto hangup;
998 break;
999 }
1000
1001 if (--par->rem)
1002 goto hangup;
1003
1004 lwsl_notice("%s: set payload len %u\n", __func__,
1005 par->temp32);
1006
1007 par->ps = RPAR_TYPE;
1008
1009 if (proxy_pss_to_ss_h(pss)) {
1010 r = lws_ss_request_tx_len(proxy_pss_to_ss_h(pss),
1011 (unsigned long)par->temp32);
1012 if (r == LWSSSSRET_DESTROY_ME)
1013 goto hangup;
1014 }
1015 break;
1016
1017 case RPAR_METADATA_NAMELEN:
1018 /* both client and proxy */
1019 if (!--par->rem)
1020 goto hangup;
1021 par->slen = *cp++;
1022 if (par->slen >= sizeof(par->metadata_name) - 1)
1023 goto hangup;
1024 par->ctr = 0;
1025 par->ps++;
1026 break;
1027
1028 case RPAR_METADATA_NAME:
1029 /* both client and proxy */
1030 if (!--par->rem)
1031 goto hangup;
1032 par->metadata_name[par->ctr++] = (char)*cp++;
1033 if (par->ctr != par->slen)
1034 break;
1035 par->metadata_name[par->ctr] = '\0';
1036 par->ps = RPAR_METADATA_VALUE;
1037
1038 if (client) {
1039 lws_sspc_metadata_t *md;
1040 lws_sspc_handle_t *h =
1041 client_pss_to_sspc_h(pss, ssi);
1042
1043 /*
1044 * client side does not have access to policy
1045 * and any metadata are new to it each time,
1046 * we allocate them, removing any existing with
1047 * the same name first
1048 */
1049
1050 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1051 lws_dll2_get_head(
1052 &h->metadata_owner_rx)) {
1053 md = lws_container_of(d,
1054 lws_sspc_metadata_t, list);
1055
1056 if (!strcmp(md->name,
1057 par->metadata_name)) {
1058 lws_dll2_remove(&md->list);
1059 lws_free(md);
1060 }
1061
1062 } lws_end_foreach_dll_safe(d, d1);
1063
1064 /*
1065 * Create the client's rx metadata entry
1066 */
1067
1068 if (h && lws_fi(&h->fic, "sspc_rx_metadata_oom"))
1069 md = NULL;
1070 else
1071 md = lws_malloc(sizeof(lws_sspc_metadata_t) +
1072 par->rem + 1, "rxmeta");
1073 if (!md) {
1074 lwsl_err("%s: OOM\n", __func__);
1075 goto hangup;
1076 }
1077
1078 if (!h)
1079 /* coverity */
1080 goto hangup;
1081
1082 memset(md, 0, sizeof(lws_sspc_metadata_t));
1083
1084 lws_strncpy(md->name, par->metadata_name,
1085 sizeof(md->name));
1086 md->len = par->rem;
1087 par->rxmetaval = (uint8_t *)&md[1];
1088 /*
1089 * Overallocate by 1 and put a NUL just beyond
1090 * the official md->len, so value can be easily
1091 * dereferenced safely for NUL-terminated string
1092 * apis that's the most common usage
1093 */
1094 par->rxmetaval[md->len] = '\0';
1095 lws_dll2_add_tail(&md->list,
1096 &h->metadata_owner_rx);
1097 par->ctr = 0;
1098 break;
1099 }
1100
1101 /* proxy side is receiving it */
1102
1103 if (!proxy_pss_to_ss_h(pss))
1104 goto hangup;
1105
1106 if (!proxy_pss_to_ss_h(pss)->policy) {
1107 lwsl_err("%s: null policy\n", __func__);
1108 goto hangup;
1109 }
1110
1111 /*
1112 * This is the policy's metadata list for the given
1113 * name
1114 */
1115 pm = lws_ss_policy_metadata(
1116 proxy_pss_to_ss_h(pss)->policy,
1117 par->metadata_name);
1118 if (!pm) {
1119 lwsl_err("%s: metadata %s not in proxy policy\n",
1120 __func__, par->metadata_name);
1121
1122 goto hangup;
1123 }
1124
1125 par->ssmd = lws_ss_get_handle_metadata(
1126 proxy_pss_to_ss_h(pss),
1127 par->metadata_name);
1128
1129 if (par->ssmd) {
1130
1131 if (par->ssmd->value_on_lws_heap)
1132 lws_free_set_NULL(par->ssmd->value__may_own_heap);
1133 par->ssmd->value_on_lws_heap = 0;
1134
1135 if (proxy_pss_to_ss_h(pss) &&
1136 lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_rx_metadata_oom"))
1137 par->ssmd->value__may_own_heap = NULL;
1138 else
1139 par->ssmd->value__may_own_heap =
1140 lws_malloc((unsigned int)par->rem + 1, "metadata");
1141
1142 if (!par->ssmd->value__may_own_heap) {
1143 lwsl_err("%s: OOM mdv\n", __func__);
1144 goto hangup;
1145 }
1146 par->ssmd->length = par->rem;
1147 ((uint8_t *)par->ssmd->value__may_own_heap)[par->rem] = '\0';
1148 /* mark it as needing cleanup */
1149 par->ssmd->value_on_lws_heap = 1;
1150 }
1151 par->ctr = 0;
1152 break;
1153
1154 case RPAR_METADATA_VALUE:
1155 /* both client and proxy */
1156
1157 if (client) {
1158 *par->rxmetaval++ = *cp++;
1159 } else {
1160
1161 if (!par->ssmd) {
1162 /* we don't recognize the name */
1163
1164 cp++;
1165
1166 if (--par->rem)
1167 break;
1168
1169 par->ps = RPAR_TYPE;
1170 break;
1171 }
1172
1173 ((uint8_t *)(par->ssmd->value__may_own_heap))[par->ctr++] = *cp++;
1174 }
1175
1176 if (--par->rem)
1177 break;
1178
1179 /* we think we got all the value */
1180 if (client) {
1181 h = lws_container_of(par, lws_sspc_handle_t, parser);
1182 lwsl_sspc_notice(h, "RX METADATA %s",
1183 par->metadata_name);
1184 } else {
1185 lwsl_ss_info(proxy_pss_to_ss_h(pss),
1186 "RPAR_METADATA_VALUE for %s (len %d)",
1187 par->ssmd->name,
1188 (int)par->ssmd->length);
1189 lwsl_hexdump_ss_info(proxy_pss_to_ss_h(pss),
1190 par->ssmd->value__may_own_heap,
1191 par->ssmd->length);
1192 }
1193 par->ps = RPAR_TYPE;
1194 break;
1195
1196 case RPAR_STREAMTYPE:
1197
1198 /* only the proxy can get these */
1199
1200 if (client)
1201 goto hangup;
1202 if (par->ctr == sizeof(par->streamtype) - 1)
1203 goto hangup;
1204
1205 /*
1206 * We can only expect to get this if we ourselves are
1207 * in the state that we're waiting for it. If it comes
1208 * later it's a protocol error.
1209 */
1210
1211 if (*state != LPCSPROX_WAIT_INITIAL_TX)
1212 goto hangup;
1213
1214 /*
1215 * We're the proxy, creating an SS on behalf of a
1216 * client
1217 */
1218
1219 par->streamtype[par->ctr++] = (char)*cp++;
1220 if (--par->rem)
1221 break;
1222
1223 par->ps = RPAR_TYPE;
1224 par->streamtype[par->ctr] = '\0';
1225 lwsl_info("%s: proxy ss '%s', sssv%d, txcr %d\n",
1226 __func__, par->streamtype,
1227 par->protocol_version, par->txcr_out);
1228
1229 ssi->streamtype = par->streamtype;
1230 if (par->txcr_out) // !!!
1231 ssi->manual_initial_tx_credit = par->txcr_out;
1232
1233 /*
1234 * Even for a synthetic SS proxing action like _lws_smd,
1235 * we create an actual SS in the proxy representing the
1236 * connection
1237 */
1238
1239 ssi->flags |= LWSSSINFLAGS_PROXIED;
1240 ssi->sss_protocol_version = par->protocol_version;
1241 ssi->client_pid = par->client_pid;
1242
1243 if (lws_ss_create(context, 0, ssi, parconn, pss,
1244 NULL, NULL)) {
1245 /*
1246 * We're unable to create the onward secure
1247 * stream he asked for... schedule a chance to
1248 * inform him
1249 */
1250 lwsl_err("%s: create '%s' fail\n", __func__,
1251 par->streamtype);
1252 *state = LPCSPROX_REPORTING_FAIL;
1253 break;
1254 } else {
1255 lwsl_debug("%s: create '%s' OK\n",
1256 __func__, par->streamtype);
1257 *state = LPCSPROX_REPORTING_OK;
1258 }
1259
1260 if (*pss) {
1261 (*pss)->being_serialized = 1;
1262 #if defined(LWS_WITH_SYS_SMD)
1263 if ((*pss)->policy != &pol_smd)
1264 /*
1265 * In SMD case we overloaded the
1266 * initial credit to be the class mask
1267 */
1268 #endif
1269 {
1270 lwsl_info("%s: Created SS initial credit %d\n",
1271 __func__, par->txcr_out);
1272
1273 (*pss)->info.manual_initial_tx_credit = par->txcr_out;
1274 }
1275 }
1276
1277 /* parent needs to schedule write on client conn */
1278 break;
1279
1280 /* clientside states */
1281
1282 case RPAR_RESULT_CREATION:
1283 if (*cp++) {
1284 lwsl_err("%s: stream creation failed\n",
1285 __func__);
1286 goto hangup;
1287 }
1288
1289 if (--par->rem < 4)
1290 goto hangup;
1291
1292 par->ps = RPAR_RESULT_CREATION_DSH;
1293 par->ctr = 0;
1294 break;
1295
1296 case RPAR_RESULT_CREATION_DSH:
1297
1298 par->temp32 = (par->temp32 << 8) | (*cp++);
1299 if (!par->rem--)
1300 goto hangup;
1301 if (++par->ctr < 4)
1302 break;
1303
1304 /*
1305 * Client (par->temp32 == dsh alloc)
1306 */
1307
1308 h = lws_container_of(par, lws_sspc_handle_t, parser);
1309
1310 lws_ss_serialize_state_transition(h, state,
1311 LPCSCLI_LOCAL_CONNECTED);
1312
1313 lws_set_timeout(h->cwsi, NO_PENDING_TIMEOUT, 0);
1314
1315 if (h->dsh)
1316 goto hangup;
1317
1318 /*
1319 * This is telling us that the streamtype could be (and
1320 * was) created at the proxy. It's not telling us that
1321 * the onward peer connection could be connected.
1322 *
1323 * We'll get a proxied state() coming later that informs
1324 * us about the situation with that.
1325 *
1326 * However at this point, we should choose to inform
1327 * the client that his stream was created... we will
1328 * later get a proxied CREATING state from the peer
1329 * but we should do it now and suppress the later one.
1330 *
1331 * The reason is he may set metadata in CREATING, and
1332 * we will try to do writeables to sync the stream to
1333 * proxy and ultimately bring up the onward connection
1334 * now we are in LOCAL_CONNECTED. We need to do the
1335 * CREATING now so we'll know the metadata to sync.
1336 */
1337
1338 #if defined(LWS_WITH_SYS_METRICS)
1339 /*
1340 * If any hanging caliper measurement, dump it, and free any tags
1341 */
1342 lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
1343 #endif
1344
1345 if (!h->creating_cb_done) {
1346 if (lws_ss_check_next_state_sspc(h,
1347 &h->prev_ss_state,
1348 LWSSSCS_CREATING))
1349 return LWSSSSRET_DESTROY_ME;
1350 h->prev_ss_state = (uint8_t)LWSSSCS_CREATING;
1351 h->creating_cb_done = 1;
1352 } else
1353 h->prev_ss_state = LWSSSCS_DISCONNECTED;
1354
1355 if (ssi->state) {
1356 n = ssi->state(client_pss_to_userdata(pss),
1357 NULL, h->prev_ss_state, 0);
1358 switch (n) {
1359 case LWSSSSRET_OK:
1360 break;
1361 case LWSSSSRET_DISCONNECT_ME:
1362 goto hangup;
1363 case LWSSSSRET_DESTROY_ME:
1364 return LWSSSSRET_DESTROY_ME;
1365 }
1366 }
1367
1368 h->dsh = lws_dsh_create(NULL, (size_t)(par->temp32 ?
1369 par->temp32 : 32768), 1);
1370 if (!h->dsh)
1371 goto hangup;
1372
1373 lws_callback_on_writable(h->cwsi);
1374
1375 par->rsl_pos = 0;
1376 par->rsl_idx = 0;
1377
1378 memset(&h->rideshare_ofs[0], 0, sizeof(h->rideshare_ofs[0]));
1379 h->rideshare_list[0] = '\0';
1380 h->rsidx = 0;
1381
1382 /* no rideshare data is OK */
1383 par->ps = RPAR_TYPE;
1384
1385 if (par->rem) {
1386 par->ps = RPAR_RESULT_CREATION_RIDESHARE;
1387 if (par->rem >= sizeof(h->rideshare_list))
1388 goto hangup;
1389 }
1390 break;
1391
1392 case RPAR_RESULT_CREATION_RIDESHARE:
1393 h = lws_container_of(par, lws_sspc_handle_t, parser);
1394 if (*cp == ',') {
1395 cp++;
1396 h->rideshare_list[par->rsl_pos++] = '\0';
1397 if (par->rsl_idx == LWS_ARRAY_SIZE(h->rideshare_ofs))
1398 goto hangup;
1399 h->rideshare_ofs[++par->rsl_idx] = par->rsl_pos;
1400 } else
1401 h->rideshare_list[par->rsl_pos++] = (char)*cp++;
1402 if (!--par->rem)
1403 par->ps = RPAR_TYPE;
1404 break;
1405
1406 case RPAR_STATEINDEX:
1407 par->ctr = (par->ctr << 8) | (*cp++);
1408 if (--par->rem == 4)
1409 par->ps = RPAR_ORD3;
1410 break;
1411
1412 case RPAR_ORD3:
1413 par->flags = (uint32_t)((*cp++) << 24);
1414 par->ps++;
1415 break;
1416
1417 case RPAR_ORD2:
1418 par->flags |= (uint32_t)((*cp++) << 16);
1419 par->ps++;
1420 break;
1421
1422 case RPAR_ORD1:
1423 par->flags |= (uint32_t)((*cp++) << 8);
1424 par->ps++;
1425 break;
1426
1427 case RPAR_ORD0:
1428 par->flags |= (uint32_t)(*cp++);
1429 par->ps++;
1430 par->ps = RPAR_TYPE;
1431
1432 /*
1433 * Client received a proxied state change
1434 */
1435
1436 h = client_pss_to_sspc_h(pss, ssi);
1437 if (!h)
1438 /*
1439 * Since we're being informed we need to have
1440 * a stream to inform. Assume whatever set this
1441 * to NULL has started to close it.
1442 */
1443 break;
1444
1445 switch (par->ctr) {
1446 case LWSSSCS_DISCONNECTED:
1447 case LWSSSCS_UNREACHABLE:
1448 case LWSSSCS_AUTH_FAILED:
1449 lws_ss_serialize_state_transition(h, state,
1450 LPCSCLI_LOCAL_CONNECTED);
1451 h->conn_req_state = LWSSSPC_ONW_NONE;
1452 break;
1453
1454 case LWSSSCS_CONNECTED:
1455 lwsl_sspc_info(h, "CONNECTED %s",
1456 ssi->streamtype);
1457 if (*state == LPCSCLI_OPERATIONAL)
1458 /*
1459 * Don't allow to see connected more
1460 * than once for one connection
1461 */
1462 goto swallow;
1463
1464 lws_ss_serialize_state_transition(h, state,
1465 LPCSCLI_OPERATIONAL);
1466
1467 h->conn_req_state = LWSSSPC_ONW_CONN;
1468 break;
1469 case LWSSSCS_TIMEOUT:
1470 break;
1471 default:
1472 break;
1473 }
1474
1475 if (par->ctr < 0)
1476 goto hangup;
1477
1478 #if defined(_DEBUG)
1479 lwsl_sspc_info(h, "forwarding proxied state %s",
1480 lws_ss_state_name(par->ctr));
1481 #endif
1482
1483 if (par->ctr == LWSSSCS_CREATING) {
1484 h = lws_container_of(par, lws_sspc_handle_t, parser);
1485 if (h->creating_cb_done)
1486 /*
1487 * We have told him he's CREATING when
1488 * we heard we had linked up to the
1489 * proxy, so suppress the remote
1490 * CREATING so that he only sees it once
1491 */
1492 break;
1493
1494 h->creating_cb_done = 1;
1495 }
1496
1497 if (ssi->state) {
1498 h = lws_container_of(par, lws_sspc_handle_t, parser);
1499 lws_ss_constate_t cs = (lws_ss_constate_t)par->ctr;
1500
1501 if (cs == LWSSSCS_CONNECTED)
1502 h->ss_dangling_connected = 1;
1503 if (cs == LWSSSCS_DISCONNECTED)
1504 h->ss_dangling_connected = 0;
1505
1506 if (lws_ss_check_next_state_sspc(h,
1507 &h->prev_ss_state, cs))
1508 return LWSSSSRET_DESTROY_ME;
1509
1510 if (cs < LWSSSCS_USER_BASE)
1511 h->prev_ss_state = (uint8_t)cs;
1512
1513 h->h_in_svc = h;
1514 n = ssi->state(client_pss_to_userdata(pss),
1515 NULL, cs, par->flags);
1516 h->h_in_svc = NULL;
1517 switch (n) {
1518 case LWSSSSRET_OK:
1519 break;
1520 case LWSSSSRET_DISCONNECT_ME:
1521 goto hangup;
1522 case LWSSSSRET_DESTROY_ME:
1523 return LWSSSSRET_DESTROY_ME;
1524 }
1525 }
1526
1527 swallow:
1528 break;
1529
1530 default:
1531 goto hangup;
1532 }
1533 }
1534
1535 return LWSSSSRET_OK;
1536
1537 hangup:
1538
1539 lwsl_cx_notice(context, "hangup");
1540
1541 return LWSSSSRET_DISCONNECT_ME;
1542 }
1543