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 * When the user code is in a different process, a non-tls unix domain socket 26 * proxy is used to asynchronusly transfer buffers in each direction via the 27 * network stack, without explicit IPC 28 * 29 * user_process{ [user code] | shim | socket-}------ lws_process{ lws } 30 * 31 * Lws exposes a listening unix domain socket in this case, the user processes 32 * connect to it and pass just info.streamtype in an initial tx packet. All 33 * packets are prepended by a 1-byte type field when used in this mode. See 34 * lws-secure-streams.h for documentation and definitions. 35 * 36 * Proxying in either direction can face the situation it cannot send the onward 37 * packet immediately and is subject to separating the write request from the 38 * write action. To make the best use of memory, a single preallocated buffer 39 * stashes pending packets in all four directions (c->p, p->c, p->ss, ss->p). 40 * This allows it to adapt to different traffic patterns without wasted areas 41 * dedicated to traffic that isn't coming in a particular application. 42 * 43 * A shim is provided to monitor the process' unix domain socket and regenerate 44 * the secure sockets api there with callbacks happening in the process thread 45 * context. 46 * 47 * This file implements the listening unix domain socket proxy... this code is 48 * only going to run on a Linux-class device with its implications about memory 49 * availability. 50 */ 51 52#include <private-lib-core.h> 53 54struct raw_pss { 55 struct conn *conn; 56}; 57 58/* 59 * Proxy - onward secure-stream handler 60 */ 61 62typedef struct ss_proxy_onward { 63 lws_ss_handle_t *ss; 64 struct conn *conn; 65} ss_proxy_t; 66 67void 68lws_proxy_clean_conn_ss(struct lws *wsi) 69{ 70#if 0 71 lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data; 72 struct conn *conn = h->conn_if_sspc_onw; 73 74 if (!wsi) 75 return; 76 77 if (conn && conn->ss) 78 conn->ss->wsi = NULL; 79#endif 80} 81 82 83void 84ss_proxy_onward_link_req_writeable(lws_ss_handle_t *h_onward) 85{ 86 ss_proxy_t *m = (ss_proxy_t *)&h_onward[1]; 87 88 if (m->conn->wsi) /* if possible, request client conn write */ 89 lws_callback_on_writable(m->conn->wsi); 90} 91 92int 93__lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size) 94{ 95 struct conn *conn = (struct conn *)parconn; 96 struct lws_context_per_thread *pt; 97 98 if (!conn || !conn->wsi || !conn->ss) 99 return -1; 100 101 pt = &conn->wsi->a.context->pt[(int)conn->wsi->tsi]; 102 103 if (lws_fi(&conn->ss->fic, "ssproxy_dsh_create_oom")) 104 return -1; 105 conn->dsh = lws_dsh_create(&pt->ss_dsh_owner, dsh_size, 2); 106 if (!conn->dsh) 107 return -1; 108 109 __lws_lc_tag_append(&conn->wsi->lc, lws_ss_tag(conn->ss)); 110 111 return 0; 112} 113 114/* Onward secure streams payload interface */ 115 116static lws_ss_state_return_t 117ss_proxy_onward_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 118{ 119 ss_proxy_t *m = (ss_proxy_t *)userobj; 120 const char *rsp = NULL; 121 int n; 122 123 // lwsl_notice("%s: len %d\n", __func__, (int)len); 124 125 /* 126 * The onward secure stream connection has received something. 127 */ 128 129 if (m->ss->rideshare != m->ss->policy && m->ss->rideshare) { 130 rsp = m->ss->rideshare->streamtype; 131 flags |= LWSSS_FLAG_RIDESHARE; 132 } 133 134 /* 135 * Apply SSS framing around this chunk of RX and stash it in the dsh 136 * in ss -> proxy [ -> client] direction. This can fail... 137 */ 138 139 if (lws_fi(&m->ss->fic, "ssproxy_dsh_rx_queue_oom")) 140 n = 1; 141 else 142 n = lws_ss_serialize_rx_payload(m->conn->dsh, buf, len, 143 flags, rsp); 144 if (n) 145 /* 146 * We couldn't buffer this rx, eg due to OOM, let's escalate it 147 * to be a "loss of connection", which it basically is... 148 */ 149 return LWSSSSRET_DISCONNECT_ME; 150 151 /* 152 * Manage rx flow on the SS (onward) side according to our situation 153 * in the dsh holding proxy->client serialized forwarding rx 154 */ 155 156 if (!m->conn->onward_in_flow_control && m->ss->wsi && 157 m->ss->policy->proxy_buflen_rxflow_on_above && 158 lws_dsh_get_size(m->conn->dsh, KIND_SS_TO_P) >= 159 m->ss->policy->proxy_buflen_rxflow_on_above) { 160 lwsl_info("%s: %s: rxflow disabling rx (%lu / %lu, hwm %lu)\n", __func__, 161 lws_wsi_tag(m->ss->wsi), 162 (unsigned long)lws_dsh_get_size(m->conn->dsh, KIND_SS_TO_P), 163 (unsigned long)m->ss->policy->proxy_buflen, 164 (unsigned long)m->ss->policy->proxy_buflen_rxflow_on_above); 165 /* 166 * stop taking in rx once the onward wsi rx is above the 167 * high water mark 168 */ 169 lws_rx_flow_control(m->ss->wsi, 0); 170 m->conn->onward_in_flow_control = 1; 171 } 172 173 if (m->conn->wsi) /* if possible, request client conn write */ 174 lws_callback_on_writable(m->conn->wsi); 175 176 return LWSSSSRET_OK; 177} 178 179/* 180 * we are transmitting buffered payload originally from the client on to the ss 181 */ 182 183static lws_ss_state_return_t 184ss_proxy_onward_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, 185 size_t *len, int *flags) 186{ 187 ss_proxy_t *m = (ss_proxy_t *)userobj; 188 void *p; 189 size_t si; 190 191 if (!m->conn->ss || m->conn->state != LPCSPROX_OPERATIONAL) { 192 lwsl_notice("%s: ss not ready\n", __func__); 193 *len = 0; 194 195 return LWSSSSRET_TX_DONT_SEND; 196 } 197 198 /* 199 * The onward secure stream says that we could send something to it 200 * (by putting it in buf, and setting *len and *flags)... dredge the 201 * next thing out of the dsh 202 */ 203 204 if (lws_ss_deserialize_tx_payload(m->conn->dsh, m->ss->wsi, 205 ord, buf, len, flags)) 206 return LWSSSSRET_TX_DONT_SEND; 207 208 /* ... there's more we want to send? */ 209 if (!lws_dsh_get_head(m->conn->dsh, KIND_C_TO_P, (void **)&p, &si)) 210 _lws_ss_request_tx(m->conn->ss); 211 212 if (!*len && !*flags) 213 /* we don't actually want to send anything */ 214 return LWSSSSRET_TX_DONT_SEND; 215 216 lwsl_info("%s: onward tx %d fl 0x%x\n", __func__, (int)*len, *flags); 217 218#if 0 219 { 220 int ff = open("/tmp/z", O_RDWR | O_CREAT | O_APPEND, 0666); 221 if (ff == -1) 222 lwsl_err("%s: errno %d\n", __func__, errno); 223 write(ff, buf, *len); 224 close(ff); 225 } 226#endif 227 228 return LWSSSSRET_OK; 229} 230 231static lws_ss_state_return_t 232ss_proxy_onward_state(void *userobj, void *sh, 233 lws_ss_constate_t state, lws_ss_tx_ordinal_t ack) 234{ 235 ss_proxy_t *m = (ss_proxy_t *)userobj; 236 size_t dsh_size; 237 238 switch (state) { 239 case LWSSSCS_CREATING: 240 241 /* 242 * conn is private to -process.c, call thru to a) adjust 243 * the accepted incoming proxy link wsi tag name to be 244 * appended with the onward ss tag information now we 245 * have it, and b) allocate the dsh buffer now we 246 * can find out the policy about it for the streamtype. 247 */ 248 249 dsh_size = m->ss->policy->proxy_buflen ? 250 m->ss->policy->proxy_buflen : 32768; 251 252 lwsl_notice("%s: %s: initializing dsh max len %lu\n", 253 __func__, lws_ss_tag(m->ss), 254 (unsigned long)dsh_size); 255 256 /* this includes ssproxy_dsh_create_oom fault generation */ 257 258 if (__lws_ss_proxy_bind_ss_to_conn_wsi(m->conn, dsh_size)) { 259 260 /* failed to allocate the dsh */ 261 262 lwsl_notice("%s: dsh init failed\n", __func__); 263 264 return LWSSSSRET_DESTROY_ME; 265 } 266 break; 267 268 case LWSSSCS_DESTROYING: 269 if (!m->conn) 270 break; 271 if (!m->conn->wsi) { 272 /* 273 * Our onward secure stream is closing and our client 274 * connection has already gone away... destroy the conn. 275 */ 276 lwsl_info("%s: Destroying conn\n", __func__); 277 lws_dsh_destroy(&m->conn->dsh); 278 free(m->conn); 279 m->conn = NULL; 280 return 0; 281 } else 282 lwsl_info("%s: ss DESTROYING, wsi up\n", __func__); 283 break; 284 285 default: 286 break; 287 } 288 if (!m->conn) { 289 lwsl_warn("%s: dropping state due to conn not up\n", __func__); 290 291 return LWSSSSRET_OK; 292 } 293 294 if (lws_ss_serialize_state(m->conn->wsi, m->conn->dsh, state, ack)) 295 /* 296 * Failed to alloc state packet that we want to send in dsh, 297 * we will lose coherence and have to disconnect the link 298 */ 299 return LWSSSSRET_DISCONNECT_ME; 300 301 if (m->conn->wsi) /* if possible, request client conn write */ 302 lws_callback_on_writable(m->conn->wsi); 303 304 return LWSSSSRET_OK; 305} 306 307void 308ss_proxy_onward_txcr(void *userobj, int bump) 309{ 310 ss_proxy_t *m = (ss_proxy_t *)userobj; 311 312 if (!m->conn) 313 return; 314 315 lws_ss_serialize_txcr(m->conn->dsh, bump); 316 317 if (m->conn->wsi) /* if possible, request client conn write */ 318 lws_callback_on_writable(m->conn->wsi); 319} 320 321/* 322 * Client <-> Proxy connection, usually on Unix Domain Socket 323 */ 324 325static int 326callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason, 327 void *user, void *in, size_t len) 328{ 329 struct raw_pss *pss = (struct raw_pss *)user; 330 const lws_ss_policy_t *rsp; 331 struct conn *conn = NULL; 332 lws_ss_metadata_t *md; 333 lws_ss_info_t ssi; 334 const uint8_t *cp; 335 char s[512]; 336 uint8_t *p; 337 size_t si; 338 char pay; 339 int n; 340 341 if (pss) 342 conn = pss->conn; 343 344 switch (reason) { 345 case LWS_CALLBACK_PROTOCOL_INIT: 346 break; 347 348 case LWS_CALLBACK_PROTOCOL_DESTROY: 349 break; 350 351 /* callbacks related to raw socket descriptor "accepted side" */ 352 353 case LWS_CALLBACK_RAW_ADOPT: 354 lwsl_info("LWS_CALLBACK_RAW_ADOPT\n"); 355 if (!pss) 356 return -1; 357 358 if (lws_fi(&wsi->fic, "ssproxy_client_adopt_oom")) 359 pss->conn = NULL; 360 else 361 pss->conn = malloc(sizeof(struct conn)); 362 if (!pss->conn) 363 return -1; 364 365 memset(pss->conn, 0, sizeof(*pss->conn)); 366 367 /* dsh is allocated when the onward ss is done */ 368 369 pss->conn->wsi = wsi; 370 wsi->bound_ss_proxy_conn = 1; /* opaque is conn */ 371 372 pss->conn->state = LPCSPROX_WAIT_INITIAL_TX; 373 374 /* 375 * Client is expected to follow the unix domain socket 376 * acceptance up rapidly with an initial tx containing the 377 * streamtype name. We can't create the stream until then. 378 */ 379 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, 3); 380 break; 381 382 case LWS_CALLBACK_RAW_CLOSE: 383 lwsl_info("LWS_CALLBACK_RAW_CLOSE:\n"); 384 385 if (!conn) 386 break; 387 388 /* 389 * the client unix domain socket connection (wsi / conn->wsi) 390 * has closed... eg, client has exited or otherwise has 391 * definitively finished with the proxying and onward connection 392 * 393 * But right now, the SS and possibly the SS onward wsi are 394 * still live... 395 */ 396 397 assert(conn->wsi == wsi); 398 conn->wsi = NULL; 399 400 lwsl_notice("%s: cli->prox link %s closing\n", __func__, 401 lws_wsi_tag(wsi)); 402 403 /* sever relationship with conn */ 404 lws_set_opaque_user_data(wsi, NULL); 405 406 /* 407 * The current wsi is decoupled from the pss / conn and 408 * the conn no longer has a pointer on it. 409 * 410 * If there's an outgoing, proxied SS conn on our behalf, we 411 * have to destroy those 412 */ 413 414 if (conn->ss) { 415 struct lws *cw = conn->ss->wsi; 416 /* 417 * conn->ss is the onward connection SS 418 */ 419 420 lwsl_info("%s: destroying %s, wsi %s\n", 421 __func__, lws_ss_tag(conn->ss), 422 lws_wsi_tag(conn->ss->wsi)); 423 424 /* sever conn relationship with ss about to be deleted */ 425 426 conn->ss->wsi = NULL; 427 428 if (cw && wsi != cw) { 429 430 /* disconnect onward SS from its wsi */ 431 432 lws_set_opaque_user_data(cw, NULL); 433 434 /* 435 * The wsi doing the onward connection can no 436 * longer relate to the conn... otherwise when 437 * he gets callbacks he wants to bind to 438 * the ss we are about to delete 439 */ 440 lws_wsi_close(cw, LWS_TO_KILL_ASYNC); 441 } 442 443 lws_ss_destroy(&conn->ss); 444 /* 445 * Conn may have gone, at ss destroy handler in 446 * ssi.state for proxied ss 447 */ 448 break; 449 } 450 451 if (conn->state == LPCSPROX_DESTROYED || !conn->ss) { 452 /* 453 * There's no onward secure stream and our client 454 * connection is closing. Destroy the conn. 455 */ 456 lws_dsh_destroy(&conn->dsh); 457 free(conn); 458 pss->conn = NULL; 459 } else 460 lwsl_debug("%s: CLOSE; %s\n", __func__, lws_ss_tag(conn->ss)); 461 462 break; 463 464 case LWS_CALLBACK_RAW_RX: 465 /* 466 * ie, the proxy is receiving something from a client 467 */ 468 lwsl_info("%s: RX: rx %d\n", __func__, (int)len); 469 470 if (!conn || !conn->wsi) { 471 lwsl_err("%s: rx with bad conn state\n", __func__); 472 473 return -1; 474 } 475 476 // lwsl_hexdump_info(in, len); 477 478 if (conn->state == LPCSPROX_WAIT_INITIAL_TX) { 479 memset(&ssi, 0, sizeof(ssi)); 480 ssi.user_alloc = sizeof(ss_proxy_t); 481 ssi.handle_offset = offsetof(ss_proxy_t, ss); 482 ssi.opaque_user_data_offset = 483 offsetof(ss_proxy_t, conn); 484 ssi.rx = ss_proxy_onward_rx; 485 ssi.tx = ss_proxy_onward_tx; 486 } 487 ssi.state = ss_proxy_onward_state; 488 ssi.flags = 0; 489 490 // coverity[uninit_use_in_call] 491 n = lws_ss_deserialize_parse(&conn->parser, 492 lws_get_context(wsi), conn->dsh, in, len, 493 &conn->state, conn, &conn->ss, &ssi, 0); 494 switch (n) { 495 case LWSSSSRET_OK: 496 break; 497 case LWSSSSRET_DISCONNECT_ME: 498 return -1; 499 case LWSSSSRET_DESTROY_ME: 500 if (conn->ss) 501 lws_ss_destroy(&conn->ss); 502 return -1; 503 } 504 505 if (conn->state == LPCSPROX_REPORTING_FAIL || 506 conn->state == LPCSPROX_REPORTING_OK) 507 lws_callback_on_writable(conn->wsi); 508 509 break; 510 511 case LWS_CALLBACK_RAW_WRITEABLE: 512 513 lwsl_debug("%s: %s: LWS_CALLBACK_RAW_WRITEABLE, state 0x%x\n", 514 __func__, lws_wsi_tag(wsi), lwsi_state(wsi)); 515 516 /* 517 * We can transmit something back to the client from the dsh 518 * of stuff we received on its behalf from the ss 519 */ 520 521 if (!conn || !conn->wsi) 522 break; 523 524 n = 0; 525 pay = 0; 526 527 s[3] = 0; 528 cp = (const uint8_t *)s; 529 switch (conn->state) { 530 case LPCSPROX_REPORTING_FAIL: 531 s[3] = 1; 532 /* fallthru */ 533 case LPCSPROX_REPORTING_OK: 534 s[0] = LWSSS_SER_RXPRE_CREATE_RESULT; 535 s[1] = 0; 536 s[2] = 1; 537 538 n = 8; 539 540 lws_ser_wu32be((uint8_t *)&s[4], conn->ss && 541 conn->ss->policy ? 542 conn->ss->policy->client_buflen : 0); 543 544 /* 545 * If there's rideshare sequencing, it's added after the 546 * first 4 bytes or the create result, comma-separated 547 */ 548 549 if (conn->ss) { 550 rsp = conn->ss->policy; 551 552 while (rsp) { 553 if (n != 4 && n < (int)sizeof(s) - 2) 554 s[n++] = ','; 555 n += lws_snprintf(&s[n], sizeof(s) - (unsigned int)n, 556 "%s", rsp->streamtype); 557 rsp = lws_ss_policy_lookup(wsi->a.context, 558 rsp->rideshare_streamtype); 559 } 560 } 561 s[2] = (char)(n - 3); 562 conn->state = LPCSPROX_OPERATIONAL; 563 lws_set_timeout(wsi, 0, 0); 564 break; 565 566 case LPCSPROX_OPERATIONAL: 567 568 /* 569 * returning [onward -> ] proxy]-> client 570 * rx metadata has priority 1 571 */ 572 573 md = conn->ss->metadata; 574 while (md) { 575 // lwsl_notice("%s: check %s: %d\n", __func__, 576 // md->name, md->pending_onward); 577 if (md->pending_onward) { 578 size_t naml = strlen(md->name); 579 580 // lwsl_notice("%s: proxy issuing rxmd\n", __func__); 581 582 if (4 + naml + md->length > sizeof(s)) { 583 lwsl_err("%s: rxmdata too big\n", 584 __func__); 585 goto hangup; 586 } 587 md->pending_onward = 0; 588 p = (uint8_t *)s; 589 p[0] = LWSSS_SER_RXPRE_METADATA; 590 lws_ser_wu16be(&p[1], (uint16_t)(1 + naml + 591 md->length)); 592 p[3] = (uint8_t)naml; 593 memcpy(&p[4], md->name, naml); 594 p += 4 + naml; 595 memcpy(p, md->value__may_own_heap, 596 md->length); 597 p += md->length; 598 599 n = lws_ptr_diff(p, cp); 600 goto again; 601 } 602 603 md = md->next; 604 } 605 606 /* 607 * If we have performance data, render it in JSON 608 * and send that in LWSSS_SER_RXPRE_PERF has 609 * priority 2 610 */ 611 612#if defined(LWS_WITH_CONMON) 613 if (conn->ss->conmon_json) { 614 unsigned int xlen = conn->ss->conmon_len; 615 616 if (xlen > sizeof(s) - 3) 617 xlen = sizeof(s) - 3; 618 cp = (uint8_t *)s; 619 p = (uint8_t *)s; 620 p[0] = LWSSS_SER_RXPRE_PERF; 621 lws_ser_wu16be(&p[1], (uint16_t)xlen); 622 memcpy(&p[3], conn->ss->conmon_json, xlen); 623 624 lws_free_set_NULL(conn->ss->conmon_json); 625 n = (int)(xlen + 3); 626 627 pay = 0; 628 goto again; 629 } 630#endif 631 /* 632 * if no fresh rx metadata, just pass through incoming 633 * dsh 634 */ 635 636 if (lws_dsh_get_head(conn->dsh, KIND_SS_TO_P, 637 (void **)&p, &si)) 638 break; 639 640 cp = p; 641 642#if 0 643 if (cp[0] == LWSSS_SER_RXPRE_RX_PAYLOAD && 644 wsi->a.context->detailed_latency_cb) { 645 646 /* 647 * we're fulfilling rx that came in on ss 648 * by sending it back out to the client on 649 * the Unix Domain Socket 650 * 651 * + 7 u32 write will compute latency here... 652 * + 11 u32 ust we received from ss 653 * 654 * lws_write will report it and fill in 655 * LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE 656 */ 657 658 us = lws_now_usecs(); 659 lws_ser_wu32be(&p[7], us - 660 lws_ser_ru64be(&p[11])); 661 lws_ser_wu64be(&p[11], us); 662 663 wsi->detlat.acc_size = 664 wsi->detlat.req_size = si - 19; 665 /* time proxy held it */ 666 wsi->detlat.latencies[ 667 LAT_DUR_PROXY_RX_TO_ONWARD_TX] = 668 lws_ser_ru32be(&p[7]); 669 } 670#endif 671 pay = 1; 672 n = (int)si; 673 break; 674 default: 675 break; 676 } 677again: 678 if (!n) 679 break; 680 681 if (lws_fi(&wsi->fic, "ssproxy_client_write_fail")) 682 n = -1; 683 else 684 n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW); 685 if (n < 0) { 686 lwsl_info("%s: WRITEABLE: %d\n", __func__, n); 687 688 goto hangup; 689 } 690 691 switch (conn->state) { 692 case LPCSPROX_REPORTING_FAIL: 693 goto hangup; 694 case LPCSPROX_OPERATIONAL: 695 if (!conn) 696 break; 697 if (pay) { 698 lws_dsh_free((void **)&p); 699 700 /* 701 * Did we go below the rx flow threshold for 702 * this dsh? 703 */ 704 705 if (conn->onward_in_flow_control && 706 conn->ss->policy->proxy_buflen_rxflow_on_above && 707 conn->ss->wsi && 708 lws_dsh_get_size(conn->dsh, KIND_SS_TO_P) < 709 conn->ss->policy->proxy_buflen_rxflow_off_below) { 710 lwsl_info("%s: %s: rxflow enabling rx (%lu / %lu, lwm %lu)\n", __func__, 711 lws_wsi_tag(conn->ss->wsi), 712 (unsigned long)lws_dsh_get_size(conn->dsh, KIND_SS_TO_P), 713 (unsigned long)conn->ss->policy->proxy_buflen, 714 (unsigned long)conn->ss->policy->proxy_buflen_rxflow_off_below); 715 /* 716 * Resume receiving taking in rx once 717 * below the low threshold 718 */ 719 lws_rx_flow_control(conn->ss->wsi, 720 LWS_RXFLOW_ALLOW); 721 conn->onward_in_flow_control = 0; 722 } 723 } 724 if (!lws_dsh_get_head(conn->dsh, KIND_SS_TO_P, 725 (void **)&p, &si)) { 726 if (!lws_send_pipe_choked(wsi)) { 727 cp = p; 728 pay = 1; 729 n = (int)si; 730 goto again; 731 } 732 lws_callback_on_writable(wsi); 733 } 734 break; 735 default: 736 break; 737 } 738 break; 739 740 default: 741 break; 742 } 743 744 return lws_callback_http_dummy(wsi, reason, user, in, len); 745 746hangup: 747 /* hang up on him */ 748 749 return -1; 750} 751 752static const struct lws_protocols protocols[] = { 753 { 754 "ssproxy-protocol", 755 callback_ss_proxy, 756 sizeof(struct raw_pss), 757 2048, 2048, NULL, 0 758 }, 759 { NULL, NULL, 0, 0, 0, NULL, 0 } 760}; 761 762/* 763 * called from create_context() 764 */ 765 766int 767lws_ss_proxy_create(struct lws_context *context, const char *bind, int port) 768{ 769 struct lws_context_creation_info info; 770 771 memset(&info, 0, sizeof(info)); 772 773 info.vhost_name = "ssproxy"; 774 info.options = LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG | 775 LWS_SERVER_OPTION_SS_PROXY; 776 info.port = port; 777 if (!port) { 778 if (!bind) 779#if defined(__linux__) 780 bind = "@proxy.ss.lws"; 781#else 782 bind = "/tmp/proxy.ss.lws"; 783#endif 784 info.options |= LWS_SERVER_OPTION_UNIX_SOCK; 785 } 786 info.iface = bind; 787#if defined(__linux__) 788 info.unix_socket_perms = "root:root"; 789#else 790#endif 791 info.listen_accept_role = "raw-skt"; 792 info.listen_accept_protocol = "ssproxy-protocol"; 793 info.protocols = protocols; 794 795 if (!lws_create_vhost(context, &info)) { 796 lwsl_err("%s: Failed to create ss proxy vhost\n", __func__); 797 798 return 1; 799 } 800 801 return 0; 802} 803