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 33typedef 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) 94static 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 111struct lws_log_cx * 112lwsl_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 121void 122lws_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 130static void 131lws_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 146int 147lws_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 200int 201lws_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 259int 260lws_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 301int 302lws_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 358int 359lws_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: 663payload_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 1527swallow: 1528 break; 1529 1530 default: 1531 goto hangup; 1532 } 1533 } 1534 1535 return LWSSSSRET_OK; 1536 1537hangup: 1538 1539 lwsl_cx_notice(context, "hangup"); 1540 1541 return LWSSSSRET_DISCONNECT_ME; 1542} 1543