1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include "private-lib-core.h" 26 27const char * 28lws_wsi_tag(struct lws *wsi) 29{ 30 if (!wsi) 31 return "[null wsi]"; 32 return lws_lc_tag(&wsi->lc); 33} 34 35#if defined (_DEBUG) 36void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role) 37{ 38 wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role; 39 40 lwsl_wsi_debug(wsi, "state 0x%lx", (unsigned long)wsi->wsistate); 41} 42 43void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs) 44{ 45 lws_wsi_state_t old = wsi->wsistate; 46 47 wsi->wsistate = (old & (unsigned int)(~LRS_MASK)) | lrs; 48 49 lwsl_wsi_debug(wsi, "lwsi_set_state 0x%lx -> 0x%lx", 50 (unsigned long)old, (unsigned long)wsi->wsistate); 51} 52#endif 53 54 55void 56lws_log_prepend_wsi(struct lws_log_cx *cx, void *obj, char **p, char *e) 57{ 58 struct lws *wsi = (struct lws *)obj; 59 60 *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ", 61 lws_wsi_tag(wsi)); 62} 63 64void 65lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi) 66{ 67 if (wsi->a.vhost == vh) 68 return; 69 70 lws_context_lock(vh->context, __func__); /* ---------- context { */ 71 wsi->a.vhost = vh; 72 73#if defined(LWS_WITH_TLS_JIT_TRUST) 74 if (!vh->count_bound_wsi && vh->grace_after_unref) { 75 lwsl_wsi_info(wsi, "in use"); 76 lws_sul_cancel(&vh->sul_unref); 77 } 78#endif 79 80 vh->count_bound_wsi++; 81 lws_context_unlock(vh->context); /* } context ---------- */ 82 83 lwsl_wsi_debug(wsi, "vh %s: wsi %s/%s, count_bound_wsi %d\n", 84 vh->name, wsi->role_ops ? wsi->role_ops->name : "none", 85 wsi->a.protocol ? wsi->a.protocol->name : "none", 86 vh->count_bound_wsi); 87 assert(wsi->a.vhost->count_bound_wsi > 0); 88} 89 90 91/* req cx lock... acquires vh lock */ 92void 93__lws_vhost_unbind_wsi(struct lws *wsi) 94{ 95 struct lws_vhost *vh = wsi->a.vhost; 96 97 if (!vh) 98 return; 99 100 lws_context_assert_lock_held(wsi->a.context); 101 102 lws_vhost_lock(vh); 103 104 assert(vh->count_bound_wsi > 0); 105 vh->count_bound_wsi--; 106 107#if defined(LWS_WITH_TLS_JIT_TRUST) 108 if (!vh->count_bound_wsi && vh->grace_after_unref) 109 lws_tls_jit_trust_vh_start_grace(vh); 110#endif 111 112 lwsl_wsi_debug(wsi, "vh %s: count_bound_wsi %d", 113 vh->name, vh->count_bound_wsi); 114 115 lws_vhost_unlock(vh); 116 117 if (!vh->count_bound_wsi && vh->being_destroyed) 118 /* 119 * We have closed all wsi that were bound to this vhost 120 * by any pt: nothing can be servicing any wsi belonging 121 * to it any more. 122 * 123 * Finalize the vh destruction... must drop vh lock 124 */ 125 __lws_vhost_destroy2(vh); 126 127 wsi->a.vhost = NULL; 128} 129 130struct lws * 131lws_get_network_wsi(struct lws *wsi) 132{ 133 if (!wsi) 134 return NULL; 135 136#if defined(LWS_WITH_HTTP2) || defined(LWS_ROLE_MQTT) 137 if (!wsi->mux_substream 138#if defined(LWS_WITH_CLIENT) 139 && !wsi->client_mux_substream 140#endif 141 ) 142 return wsi; 143 144 while (wsi->mux.parent_wsi) 145 wsi = wsi->mux.parent_wsi; 146#endif 147 148 return wsi; 149} 150 151 152const struct lws_protocols * 153lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name) 154{ 155 int n; 156 157 for (n = 0; n < vh->count_protocols; n++) 158 if (vh->protocols[n].name && !strcmp(name, vh->protocols[n].name)) 159 return &vh->protocols[n]; 160 161 return NULL; 162} 163 164int 165lws_callback_all_protocol(struct lws_context *context, 166 const struct lws_protocols *protocol, int reason) 167{ 168 struct lws_context_per_thread *pt = &context->pt[0]; 169 unsigned int n, m = context->count_threads; 170 struct lws *wsi; 171 172 while (m--) { 173 for (n = 0; n < pt->fds_count; n++) { 174 wsi = wsi_from_fd(context, pt->fds[n].fd); 175 if (!wsi) 176 continue; 177 if (wsi->a.protocol == protocol) 178 protocol->callback(wsi, 179 (enum lws_callback_reasons)reason, 180 wsi->user_space, NULL, 0); 181 } 182 pt++; 183 } 184 185 return 0; 186} 187 188void * 189lws_evlib_wsi_to_evlib_pt(struct lws *wsi) 190{ 191 struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 192 193 return pt->evlib_pt; 194} 195 196void * 197lws_evlib_tsi_to_evlib_pt(struct lws_context *cx, int tsi) 198{ 199 struct lws_context_per_thread *pt = &cx->pt[tsi]; 200 201 return pt->evlib_pt; 202} 203 204int 205lws_callback_all_protocol_vhost_args(struct lws_vhost *vh, 206 const struct lws_protocols *protocol, int reason, 207 void *argp, size_t len) 208{ 209 struct lws_context *context = vh->context; 210 struct lws_context_per_thread *pt = &context->pt[0]; 211 unsigned int n, m = context->count_threads; 212 struct lws *wsi; 213 214 while (m--) { 215 for (n = 0; n < pt->fds_count; n++) { 216 wsi = wsi_from_fd(context, pt->fds[n].fd); 217 if (!wsi) 218 continue; 219 if (wsi->a.vhost == vh && (wsi->a.protocol == protocol || 220 !protocol)) 221 wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason, 222 wsi->user_space, argp, len); 223 } 224 pt++; 225 } 226 227 return 0; 228} 229 230int 231lws_callback_all_protocol_vhost(struct lws_vhost *vh, 232 const struct lws_protocols *protocol, int reason) 233{ 234 return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0); 235} 236 237int 238lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, size_t len) 239{ 240 int n; 241 242 for (n = 0; n < wsi->a.vhost->count_protocols; n++) 243 if (wsi->a.vhost->protocols[n].callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len)) 244 return 1; 245 246 return 0; 247} 248 249#if defined(LWS_WITH_SYS_FAULT_INJECTION) 250/* 251 * We want to inject a fault that makes it feel like the peer hung up on us, 252 * or we were otherwise cut off. 253 */ 254void 255lws_wsi_fault_timedclose_cb(lws_sorted_usec_list_t *s) 256{ 257 struct lws *wsi = lws_container_of(s, struct lws, sul_fault_timedclose); 258 259 lwsl_wsi_warn(wsi, "force-closing"); 260 lws_wsi_close(wsi, LWS_TO_KILL_ASYNC); 261} 262#endif 263 264#if defined(LWS_WITH_SYS_FAULT_INJECTION) 265void 266lws_wsi_fault_timedclose(struct lws *wsi) 267{ 268 uint64_t u; 269 270 if (!lws_fi(&wsi->fic, "timedclose")) 271 return; 272 273 if (lws_fi_range(&wsi->fic, "timedclose_ms", &u)) 274 return; 275 276 lwsl_wsi_warn(wsi, "injecting close in %ums", (unsigned int)u); 277 lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->sul_fault_timedclose, 278 lws_wsi_fault_timedclose_cb, 279 (lws_usec_t)(u * 1000ull)); 280} 281#endif 282 283 284/* 285 * We need the context lock 286 */ 287 288struct lws * 289__lws_wsi_create_with_role(struct lws_context *context, int tsi, 290 const struct lws_role_ops *ops, 291 lws_log_cx_t *log_cx_template) 292{ 293 size_t s = sizeof(struct lws); 294 struct lws *wsi; 295 296 assert(tsi >= 0 && tsi < LWS_MAX_SMP); 297 298 lws_context_assert_lock_held(context); 299 300#if defined(LWS_WITH_EVENT_LIBS) 301 s += context->event_loop_ops->evlib_size_wsi; 302#endif 303 304 wsi = lws_zalloc(s, __func__); 305 306 if (!wsi) { 307 lwsl_cx_err(context, "OOM"); 308 return NULL; 309 } 310 311 if (log_cx_template) 312 wsi->lc.log_cx = log_cx_template; 313 else 314 wsi->lc.log_cx = context->log_cx; 315 316#if defined(LWS_WITH_EVENT_LIBS) 317 wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi); 318#endif 319 wsi->a.context = context; 320 lws_role_transition(wsi, 0, LRS_UNCONNECTED, ops); 321 wsi->pending_timeout = NO_PENDING_TIMEOUT; 322 wsi->a.protocol = NULL; 323 wsi->tsi = (char)tsi; 324 wsi->a.vhost = NULL; 325 wsi->desc.sockfd = LWS_SOCK_INVALID; 326 wsi->position_in_fds_table = LWS_NO_FDS_POS; 327 328#if defined(LWS_WITH_SYS_FAULT_INJECTION) 329 lws_xos_init(&wsi->fic.xos, lws_xos(&context->fic.xos)); 330#endif 331 332 lws_fi_inherit_copy(&wsi->fic, &context->fic, "wsi", NULL); 333 334 if (lws_fi(&wsi->fic, "createfail")) { 335 lws_fi_destroy(&wsi->fic); 336 lws_free(wsi); 337 return NULL; 338 } 339 340 return wsi; 341} 342 343int 344lws_wsi_inject_to_loop(struct lws_context_per_thread *pt, struct lws *wsi) 345{ 346 int ret = 1; 347 348 lws_pt_lock(pt, __func__); /* -------------- pt { */ 349 350 if (pt->context->event_loop_ops->sock_accept) 351 if (pt->context->event_loop_ops->sock_accept(wsi)) 352 goto bail; 353 354 if (__insert_wsi_socket_into_fds(pt->context, wsi)) 355 goto bail; 356 357 ret = 0; 358 359bail: 360 lws_pt_unlock(pt); 361 362 return ret; 363} 364 365/* 366 * Take a copy of wsi->desc.sockfd before calling this, then close it 367 * afterwards 368 */ 369 370int 371lws_wsi_extract_from_loop(struct lws *wsi) 372{ 373 if (lws_socket_is_valid(wsi->desc.sockfd)) 374 __remove_wsi_socket_from_fds(wsi); 375 376 if (!wsi->a.context->event_loop_ops->destroy_wsi && 377 wsi->a.context->event_loop_ops->wsi_logical_close) { 378 wsi->a.context->event_loop_ops->wsi_logical_close(wsi); 379 return 1; /* close / destroy continues async */ 380 } 381 382 if (wsi->a.context->event_loop_ops->destroy_wsi) 383 wsi->a.context->event_loop_ops->destroy_wsi(wsi); 384 385 return 0; /* he is destroyed */ 386} 387 388int 389lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in, 390 size_t len) 391{ 392 int n; 393 struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi"); 394 395 if (!wsi) 396 return 1; 397 398 wsi->a.context = vh->context; 399 lws_vhost_bind_wsi(vh, wsi); 400 401 for (n = 0; n < wsi->a.vhost->count_protocols; n++) { 402 wsi->a.protocol = &vh->protocols[n]; 403 if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len)) { 404 lws_free(wsi); 405 return 1; 406 } 407 } 408 409 lws_free(wsi); 410 411 return 0; 412} 413 414 415int 416lws_rx_flow_control(struct lws *wsi, int _enable) 417{ 418 struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 419 int en = _enable; 420 421 // h2 ignores rx flow control atm 422 if (lwsi_role_h2(wsi) || wsi->mux_substream || 423 lwsi_role_h2_ENCAPSULATION(wsi)) 424 return 0; // !!! 425 426 lwsl_wsi_info(wsi, "0x%x", _enable); 427 428 if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) { 429 /* 430 * convert user bool style to bitmap style... in user simple 431 * bool style _enable = 0 = flow control it, = 1 = allow rx 432 */ 433 en = LWS_RXFLOW_REASON_APPLIES | LWS_RXFLOW_REASON_USER_BOOL; 434 if (_enable & 1) 435 en |= LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT; 436 } 437 438 lws_pt_lock(pt, __func__); 439 440 /* any bit set in rxflow_bitmap DISABLEs rxflow control */ 441 if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT) 442 wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap & ~(en & 0xff)); 443 else 444 wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap | (en & 0xff)); 445 446 if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) == 447 wsi->rxflow_change_to) 448 goto skip; 449 450 wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | 451 (!wsi->rxflow_bitmap); 452 453 lwsl_wsi_info(wsi, "bitmap 0x%x: en 0x%x, ch 0x%x", 454 wsi->rxflow_bitmap, en, wsi->rxflow_change_to); 455 456 if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW || 457 !wsi->rxflow_will_be_applied) { 458 en = __lws_rx_flow_control(wsi); 459 lws_pt_unlock(pt); 460 461 return en; 462 } 463 464skip: 465 lws_pt_unlock(pt); 466 467 return 0; 468} 469 470void 471lws_rx_flow_allow_all_protocol(const struct lws_context *context, 472 const struct lws_protocols *protocol) 473{ 474 const struct lws_context_per_thread *pt = &context->pt[0]; 475 struct lws *wsi; 476 unsigned int n, m = context->count_threads; 477 478 while (m--) { 479 for (n = 0; n < pt->fds_count; n++) { 480 wsi = wsi_from_fd(context, pt->fds[n].fd); 481 if (!wsi) 482 continue; 483 if (wsi->a.protocol == protocol) 484 lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW); 485 } 486 pt++; 487 } 488} 489 490int user_callback_handle_rxflow(lws_callback_function callback_function, 491 struct lws *wsi, 492 enum lws_callback_reasons reason, void *user, 493 void *in, size_t len) 494{ 495 int n; 496 497 wsi->rxflow_will_be_applied = 1; 498 n = callback_function(wsi, reason, user, in, len); 499 wsi->rxflow_will_be_applied = 0; 500 if (!n) 501 n = __lws_rx_flow_control(wsi); 502 503 return n; 504} 505 506int 507__lws_rx_flow_control(struct lws *wsi) 508{ 509 struct lws *wsic = wsi->child_list; 510 511 // h2 ignores rx flow control atm 512 if (lwsi_role_h2(wsi) || wsi->mux_substream || 513 lwsi_role_h2_ENCAPSULATION(wsi)) 514 return 0; // !!! 515 516 /* if he has children, do those if they were changed */ 517 while (wsic) { 518 if (wsic->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE) 519 __lws_rx_flow_control(wsic); 520 521 wsic = wsic->sibling_list; 522 } 523 524 /* there is no pending change */ 525 if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)) 526 return 0; 527 528 /* stuff is still buffered, not ready to really accept new input */ 529 if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) { 530 /* get ourselves called back to deal with stashed buffer */ 531 lws_callback_on_writable(wsi); 532 // return 0; 533 } 534 535 /* now the pending is cleared, we can change rxflow state */ 536 537 wsi->rxflow_change_to &= (~LWS_RXFLOW_PENDING_CHANGE) & 3; 538 539 lwsl_wsi_info(wsi, "rxflow: change_to %d", 540 wsi->rxflow_change_to & LWS_RXFLOW_ALLOW); 541 542 /* adjust the pollfd for this wsi */ 543 544 if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) { 545 lwsl_wsi_info(wsi, "reenable POLLIN"); 546 // lws_buflist_describe(&wsi->buflist, NULL, __func__); 547 if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) { 548 lwsl_wsi_info(wsi, "fail"); 549 return -1; 550 } 551 } else 552 if (__lws_change_pollfd(wsi, LWS_POLLIN, 0)) 553 return -1; 554 555 return 0; 556} 557 558 559const struct lws_protocols * 560lws_get_protocol(struct lws *wsi) 561{ 562 return wsi->a.protocol; 563} 564 565 566int 567lws_ensure_user_space(struct lws *wsi) 568{ 569 if (!wsi->a.protocol) 570 return 0; 571 572 /* allocate the per-connection user memory (if any) */ 573 574 if (wsi->a.protocol->per_session_data_size && !wsi->user_space) { 575 wsi->user_space = lws_zalloc( 576 wsi->a.protocol->per_session_data_size, "user space"); 577 if (wsi->user_space == NULL) { 578 lwsl_wsi_err(wsi, "OOM"); 579 return 1; 580 } 581 } else 582 lwsl_wsi_debug(wsi, "protocol pss %lu, user_space=%p", 583 (long)wsi->a.protocol->per_session_data_size, 584 wsi->user_space); 585 return 0; 586} 587 588void * 589lws_adjust_protocol_psds(struct lws *wsi, size_t new_size) 590{ 591 ((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size = 592 new_size; 593 594 if (lws_ensure_user_space(wsi)) 595 return NULL; 596 597 return wsi->user_space; 598} 599 600int 601lws_get_tsi(struct lws *wsi) 602{ 603 return (int)wsi->tsi; 604} 605 606int 607lws_is_ssl(struct lws *wsi) 608{ 609#if defined(LWS_WITH_TLS) 610 return wsi->tls.use_ssl & LCCSCF_USE_SSL; 611#else 612 (void)wsi; 613 return 0; 614#endif 615} 616 617#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS) 618lws_tls_conn* 619lws_get_ssl(struct lws *wsi) 620{ 621 return wsi->tls.ssl; 622} 623#endif 624 625int 626lws_has_buffered_out(struct lws *wsi) 627{ 628 if (wsi->buflist_out) 629 return 1; 630 631#if defined(LWS_ROLE_H2) 632 { 633 struct lws *nwsi = lws_get_network_wsi(wsi); 634 635 if (nwsi->buflist_out) 636 return 1; 637 } 638#endif 639 640 return 0; 641} 642 643int 644lws_partial_buffered(struct lws *wsi) 645{ 646 return lws_has_buffered_out(wsi); 647} 648 649lws_fileofs_t 650lws_get_peer_write_allowance(struct lws *wsi) 651{ 652 if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) 653 return -1; 654 655 return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit). 656 tx_credit(wsi, LWSTXCR_US_TO_PEER, 0); 657} 658 659void 660lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state, 661 const struct lws_role_ops *ops) 662{ 663#if (_LWS_ENABLED_LOGS & LLL_DEBUG) 664 const char *name = "(unset)"; 665#endif 666 wsi->wsistate = (unsigned int)role | (unsigned int)state; 667 if (ops) 668 wsi->role_ops = ops; 669#if (_LWS_ENABLED_LOGS & LLL_DEBUG) 670 if (wsi->role_ops) 671 name = wsi->role_ops->name; 672 lwsl_wsi_debug(wsi, "wsistate 0x%lx, ops %s", 673 (unsigned long)wsi->wsistate, name); 674#endif 675} 676 677int 678lws_parse_uri(char *p, const char **prot, const char **ads, int *port, 679 const char **path) 680{ 681 const char *end; 682 char unix_skt = 0; 683 684 /* cut up the location into address, port and path */ 685 *prot = p; 686 while (*p && (*p != ':' || p[1] != '/' || p[2] != '/')) 687 p++; 688 if (!*p) { 689 end = p; 690 p = (char *)*prot; 691 *prot = end; 692 } else { 693 *p = '\0'; 694 p += 3; 695 } 696 if (*p == '+') /* unix skt */ 697 unix_skt = 1; 698 699 *ads = p; 700 if (!strcmp(*prot, "http") || !strcmp(*prot, "ws")) 701 *port = 80; 702 else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss")) 703 *port = 443; 704 705 if (*p == '[') { 706 ++(*ads); 707 while (*p && *p != ']') 708 p++; 709 if (*p) 710 *p++ = '\0'; 711 } else 712 while (*p && *p != ':' && (unix_skt || *p != '/')) 713 p++; 714 715 if (*p == ':') { 716 *p++ = '\0'; 717 *port = atoi(p); 718 while (*p && *p != '/') 719 p++; 720 } 721 *path = "/"; 722 if (*p) { 723 *p++ = '\0'; 724 if (*p) 725 *path = p; 726 } 727 728 return 0; 729} 730 731/* ... */ 732 733int 734lws_get_urlarg_by_name_safe(struct lws *wsi, const char *name, char *buf, int len) 735{ 736 int n = 0, fraglen, sl = (int)strlen(name); 737 738 do { 739 fraglen = lws_hdr_copy_fragment(wsi, buf, len, 740 WSI_TOKEN_HTTP_URI_ARGS, n); 741 742 if (fraglen < 0) 743 break; 744 745 if (fraglen + 1 < len && 746 fraglen >= sl && 747 !strncmp(buf, name, (size_t)sl)) { 748 /* 749 * If he left off the trailing =, trim it from the 750 * result 751 */ 752 753 if (name[sl - 1] != '=' && 754 sl < fraglen && 755 buf[sl] == '=') 756 sl++; 757 758 memmove(buf, buf + sl, (size_t)(fraglen - sl)); 759 buf[fraglen - sl] = '\0'; 760 761 return fraglen - sl; 762 } 763 764 n++; 765 } while (1); 766 767 return -1; 768} 769 770const char * 771lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len) 772{ 773 int n = lws_get_urlarg_by_name_safe(wsi, name, buf, len); 774 775 return n < 0 ? NULL : buf; 776} 777 778 779#if defined(LWS_WITHOUT_EXTENSIONS) 780 781/* we need to provide dummy callbacks for internal exts 782 * so user code runs when faced with a lib compiled with 783 * extensions disabled. 784 */ 785 786int 787lws_extension_callback_pm_deflate(struct lws_context *context, 788 const struct lws_extension *ext, 789 struct lws *wsi, 790 enum lws_extension_callback_reasons reason, 791 void *user, void *in, size_t len) 792{ 793 (void)context; 794 (void)ext; 795 (void)wsi; 796 (void)reason; 797 (void)user; 798 (void)in; 799 (void)len; 800 801 return 0; 802} 803 804int 805lws_set_extension_option(struct lws *wsi, const char *ext_name, 806 const char *opt_name, const char *opt_val) 807{ 808 return -1; 809} 810#endif 811 812int 813lws_is_cgi(struct lws *wsi) { 814#ifdef LWS_WITH_CGI 815 return !!wsi->http.cgi; 816#else 817 return 0; 818#endif 819} 820 821const struct lws_protocol_vhost_options * 822lws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name) 823{ 824 while (pvo) { 825 if (!strcmp(pvo->name, name)) 826 break; 827 828 pvo = pvo->next; 829 } 830 831 return pvo; 832} 833 834int 835lws_pvo_get_str(void *in, const char *name, const char **result) 836{ 837 const struct lws_protocol_vhost_options *pv = 838 lws_pvo_search((const struct lws_protocol_vhost_options *)in, 839 name); 840 841 if (!pv) 842 return 1; 843 844 *result = (const char *)pv->value; 845 846 return 0; 847} 848 849int 850lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len) 851{ 852 struct lws_vhost *v = pt->context->vhost_list; 853 lws_fakewsi_def_plwsa(pt); 854 int n, ret = 0; 855 856 lws_fakewsi_prep_plwsa_ctx(pt->context); 857#if !defined(LWS_PLAT_FREERTOS) && LWS_MAX_SMP > 1 858 ((struct lws *)plwsa)->tsi = (char)(int)(pt - &pt->context->pt[0]); 859#endif 860 861 while (v) { 862 const struct lws_protocols *p = v->protocols; 863 864 plwsa->vhost = v; /* not a real bound wsi */ 865 866 for (n = 0; n < v->count_protocols; n++) { 867 plwsa->protocol = p; 868 if (p->callback && 869 p->callback((struct lws *)plwsa, (enum lws_callback_reasons)reason, NULL, in, len)) 870 ret |= 1; 871 p++; 872 } 873 874 v = v->vhost_next; 875 } 876 877 return ret; 878} 879 880void * 881lws_wsi_user(struct lws *wsi) 882{ 883 return wsi->user_space; 884} 885 886int 887lws_wsi_tsi(struct lws *wsi) 888{ 889 return wsi->tsi; 890} 891 892 893void 894lws_set_wsi_user(struct lws *wsi, void *data) 895{ 896 if (!wsi->user_space_externally_allocated && wsi->user_space) 897 lws_free(wsi->user_space); 898 899 wsi->user_space_externally_allocated = 1; 900 wsi->user_space = data; 901} 902 903struct lws * 904lws_get_parent(const struct lws *wsi) 905{ 906 return wsi->parent; 907} 908 909struct lws * 910lws_get_child(const struct lws *wsi) 911{ 912 return wsi->child_list; 913} 914 915void * 916lws_get_opaque_parent_data(const struct lws *wsi) 917{ 918 return wsi->opaque_parent_data; 919} 920 921void 922lws_set_opaque_parent_data(struct lws *wsi, void *data) 923{ 924 wsi->opaque_parent_data = data; 925} 926 927void * 928lws_get_opaque_user_data(const struct lws *wsi) 929{ 930 return wsi->a.opaque_user_data; 931} 932 933void 934lws_set_opaque_user_data(struct lws *wsi, void *data) 935{ 936 wsi->a.opaque_user_data = data; 937} 938 939int 940lws_get_child_pending_on_writable(const struct lws *wsi) 941{ 942 return wsi->parent_pending_cb_on_writable; 943} 944 945void 946lws_clear_child_pending_on_writable(struct lws *wsi) 947{ 948 wsi->parent_pending_cb_on_writable = 0; 949} 950 951 952 953const char * 954lws_get_vhost_name(struct lws_vhost *vhost) 955{ 956 return vhost->name; 957} 958 959int 960lws_get_vhost_port(struct lws_vhost *vhost) 961{ 962 return vhost->listen_port; 963} 964 965void * 966lws_get_vhost_user(struct lws_vhost *vhost) 967{ 968 return vhost->user; 969} 970 971const char * 972lws_get_vhost_iface(struct lws_vhost *vhost) 973{ 974 return vhost->iface; 975} 976 977lws_sockfd_type 978lws_get_socket_fd(struct lws *wsi) 979{ 980 if (!wsi) 981 return -1; 982 return wsi->desc.sockfd; 983} 984 985 986struct lws_vhost * 987lws_vhost_get(struct lws *wsi) 988{ 989 return wsi->a.vhost; 990} 991 992struct lws_vhost * 993lws_get_vhost(struct lws *wsi) 994{ 995 return wsi->a.vhost; 996} 997 998const struct lws_protocols * 999lws_protocol_get(struct lws *wsi) 1000{ 1001 return wsi->a.protocol; 1002} 1003 1004#if defined(LWS_WITH_UDP) 1005const struct lws_udp * 1006lws_get_udp(const struct lws *wsi) 1007{ 1008 return wsi->udp; 1009} 1010#endif 1011 1012struct lws_context * 1013lws_get_context(const struct lws *wsi) 1014{ 1015 return wsi->a.context; 1016} 1017 1018struct lws_log_cx * 1019lwsl_wsi_get_cx(struct lws *wsi) 1020{ 1021 if (!wsi) 1022 return NULL; 1023 1024 return wsi->lc.log_cx; 1025} 1026 1027#if defined(LWS_WITH_CLIENT) 1028int 1029_lws_generic_transaction_completed_active_conn(struct lws **_wsi, char take_vh_lock) 1030{ 1031 struct lws *wnew, *wsi = *_wsi; 1032 1033 /* 1034 * Are we constitutionally capable of having a queue, ie, we are on 1035 * the "active client connections" list? 1036 * 1037 * If not, that's it for us. 1038 */ 1039 1040 if (lws_dll2_is_detached(&wsi->dll_cli_active_conns)) 1041 return 0; /* no new transaction */ 1042 1043 /* 1044 * With h1 queuing, the original "active client" moves his attributes 1045 * like fd, ssl, queue and active client list entry to the next guy in 1046 * the queue before closing... it's because the user code knows the 1047 * individual wsi and the action must take place in the correct wsi 1048 * context. Note this means we don't truly pipeline headers. 1049 * 1050 * Trying to keep the original "active client" in place to do the work 1051 * of the wsi breaks down when dealing with queued POSTs otherwise; it's 1052 * also competing with the real mux child arrangements and complicating 1053 * the code. 1054 * 1055 * For that reason, see if we have any queued child now... 1056 */ 1057 1058 if (!wsi->dll2_cli_txn_queue_owner.head) { 1059 /* 1060 * Nothing pipelined... we should hang around a bit 1061 * in case something turns up... otherwise we'll close 1062 */ 1063 lwsl_wsi_info(wsi, "nothing pipelined waiting"); 1064 lwsi_set_state(wsi, LRS_IDLING); 1065 1066 lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 1067 wsi->keep_warm_secs); 1068 1069 return 0; /* no new transaction right now */ 1070 } 1071 1072 /* 1073 * We have a queued child wsi we should bequeath our assets to, before 1074 * closing ourself 1075 */ 1076 1077 if (take_vh_lock) 1078 lws_vhost_lock(wsi->a.vhost); 1079 1080 wnew = lws_container_of(wsi->dll2_cli_txn_queue_owner.head, struct lws, 1081 dll2_cli_txn_queue); 1082 1083 assert(wsi != wnew); 1084 1085 lws_dll2_remove(&wnew->dll2_cli_txn_queue); 1086 1087 assert(lws_socket_is_valid(wsi->desc.sockfd)); 1088 1089 __lws_change_pollfd(wsi, LWS_POLLOUT | LWS_POLLIN, 0); 1090 1091 /* copy the fd */ 1092 wnew->desc = wsi->desc; 1093 1094 assert(lws_socket_is_valid(wnew->desc.sockfd)); 1095 1096 /* disconnect the fd from association with old wsi */ 1097 1098 if (__remove_wsi_socket_from_fds(wsi)) 1099 return -1; 1100 1101 sanity_assert_no_wsi_traces(wsi->a.context, wsi); 1102 sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd); 1103 wsi->desc.sockfd = LWS_SOCK_INVALID; 1104 1105 __lws_wsi_remove_from_sul(wsi); 1106 1107 /* 1108 * ... we're doing some magic here in terms of handing off the socket 1109 * that has been active to a wsi that has not yet itself been active... 1110 * depending on the event lib we may need to give a magic spark to the 1111 * new guy and snuff out the old guy's magic spark at that level as well 1112 */ 1113 1114#if defined(LWS_WITH_EVENT_LIBS) 1115 if (wsi->a.context->event_loop_ops->destroy_wsi) 1116 wsi->a.context->event_loop_ops->destroy_wsi(wsi); 1117 if (wsi->a.context->event_loop_ops->sock_accept) 1118 wsi->a.context->event_loop_ops->sock_accept(wnew); 1119#endif 1120 1121 /* point the fd table entry to new guy */ 1122 1123 assert(lws_socket_is_valid(wnew->desc.sockfd)); 1124 1125 if (__insert_wsi_socket_into_fds(wsi->a.context, wnew)) 1126 return -1; 1127 1128#if defined(LWS_WITH_TLS) 1129 /* pass on the tls */ 1130 1131 wnew->tls = wsi->tls; 1132 wsi->tls.client_bio = NULL; 1133 wsi->tls.ssl = NULL; 1134 wsi->tls.use_ssl = 0; 1135#endif 1136 1137 /* take over his copy of his endpoint as an active connection */ 1138 1139 if (!wnew->cli_hostname_copy && wsi->cli_hostname_copy) { 1140 wnew->cli_hostname_copy = wsi->cli_hostname_copy; 1141 wsi->cli_hostname_copy = NULL; 1142 } 1143 wnew->keep_warm_secs = wsi->keep_warm_secs; 1144 1145 /* 1146 * selected queued guy now replaces the original leader on the 1147 * active client conn list 1148 */ 1149 1150 lws_dll2_remove(&wsi->dll_cli_active_conns); 1151 lws_dll2_add_tail(&wnew->dll_cli_active_conns, 1152 &wsi->a.vhost->dll_cli_active_conns_owner); 1153 1154 /* move any queued guys to queue on new active conn */ 1155 1156 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1157 wsi->dll2_cli_txn_queue_owner.head) { 1158 struct lws *ww = lws_container_of(d, struct lws, 1159 dll2_cli_txn_queue); 1160 1161 lws_dll2_remove(&ww->dll2_cli_txn_queue); 1162 lws_dll2_add_tail(&ww->dll2_cli_txn_queue, 1163 &wnew->dll2_cli_txn_queue_owner); 1164 1165 } lws_end_foreach_dll_safe(d, d1); 1166 1167 if (take_vh_lock) 1168 lws_vhost_unlock(wsi->a.vhost); 1169 1170 /* 1171 * The original leader who passed on all his powers already can die... 1172 * in the call stack above us there are guys who still want to touch 1173 * him, so have him die next time around the event loop, not now. 1174 */ 1175 1176 wsi->already_did_cce = 1; /* so the close doesn't trigger a CCE */ 1177 lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC); 1178 1179 /* after the first one, they can only be coming from the queue */ 1180 wnew->transaction_from_pipeline_queue = 1; 1181 1182 lwsl_wsi_notice(wsi, " pipeline queue passed -> %s", lws_wsi_tag(wnew)); 1183 1184 *_wsi = wnew; /* inform caller we swapped */ 1185 1186 return 1; /* new transaction */ 1187} 1188#endif 1189 1190int LWS_WARN_UNUSED_RESULT 1191lws_raw_transaction_completed(struct lws *wsi) 1192{ 1193 if (lws_has_buffered_out(wsi)) { 1194 /* 1195 * ...so he tried to send something large, but it went out 1196 * as a partial, but he immediately called us to say he wants 1197 * to close the connection. 1198 * 1199 * Defer the close until the last part of the partial is sent. 1200 * 1201 */ 1202 1203 lwsl_wsi_debug(wsi, "deferring due to partial"); 1204 wsi->close_when_buffered_out_drained = 1; 1205 lws_callback_on_writable(wsi); 1206 1207 return 0; 1208 } 1209 1210 return -1; 1211} 1212 1213int 1214lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p, 1215 const char *reason) 1216{ 1217// if (wsi->a.protocol == p) 1218// return 0; 1219 const struct lws_protocols *vp = wsi->a.vhost->protocols, *vpo; 1220 1221 if (wsi->a.protocol && wsi->protocol_bind_balance) { 1222 wsi->a.protocol->callback(wsi, 1223 wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)], 1224 wsi->user_space, (void *)reason, 0); 1225 wsi->protocol_bind_balance = 0; 1226 } 1227 if (!wsi->user_space_externally_allocated) 1228 lws_free_set_NULL(wsi->user_space); 1229 1230 lws_same_vh_protocol_remove(wsi); 1231 1232 wsi->a.protocol = p; 1233 if (!p) 1234 return 0; 1235 1236 if (lws_ensure_user_space(wsi)) 1237 return 1; 1238 1239 if (p > vp && p < &vp[wsi->a.vhost->count_protocols]) 1240 lws_same_vh_protocol_insert(wsi, (int)(p - vp)); 1241 else { 1242 int n = wsi->a.vhost->count_protocols; 1243 int hit = 0; 1244 1245 vpo = vp; 1246 1247 while (n--) { 1248 if (p->name && vp->name && !strcmp(p->name, vp->name)) { 1249 hit = 1; 1250 lws_same_vh_protocol_insert(wsi, (int)(vp - vpo)); 1251 break; 1252 } 1253 vp++; 1254 } 1255 if (!hit) 1256 lwsl_err("%s: %p is not in vhost '%s' protocols list\n", 1257 __func__, p, wsi->a.vhost->name); 1258 } 1259 1260 if (wsi->a.protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[ 1261 !!lwsi_role_server(wsi)], 1262 wsi->user_space, NULL, 0)) 1263 return 1; 1264 1265 wsi->protocol_bind_balance = 1; 1266 1267 return 0; 1268} 1269 1270void 1271lws_http_close_immortal(struct lws *wsi) 1272{ 1273 struct lws *nwsi; 1274 1275 if (!wsi->mux_substream) 1276 return; 1277 1278 assert(wsi->mux_stream_immortal); 1279 wsi->mux_stream_immortal = 0; 1280 1281 nwsi = lws_get_network_wsi(wsi); 1282 lwsl_wsi_debug(wsi, "%s (%d)", lws_wsi_tag(nwsi), 1283 nwsi->immortal_substream_count); 1284 assert(nwsi->immortal_substream_count); 1285 nwsi->immortal_substream_count--; 1286 if (!nwsi->immortal_substream_count) 1287 /* 1288 * since we closed the only immortal stream on this nwsi, we 1289 * need to reapply a normal timeout regime to the nwsi 1290 */ 1291 lws_set_timeout(nwsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 1292 wsi->a.vhost->keepalive_timeout ? 1293 wsi->a.vhost->keepalive_timeout : 31); 1294} 1295 1296void 1297lws_mux_mark_immortal(struct lws *wsi) 1298{ 1299 struct lws *nwsi; 1300 1301 lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); 1302 1303 if (!wsi->mux_substream 1304#if defined(LWS_WITH_CLIENT) 1305 && !wsi->client_mux_substream 1306#endif 1307 ) { 1308 lwsl_wsi_err(wsi, "not mux substream"); 1309 return; 1310 } 1311 1312 if (wsi->mux_stream_immortal) 1313 /* only need to handle it once per child wsi */ 1314 return; 1315 1316 nwsi = lws_get_network_wsi(wsi); 1317 if (!nwsi) 1318 return; 1319 1320 lwsl_wsi_debug(wsi, "%s (%d)\n", lws_wsi_tag(nwsi), 1321 nwsi->immortal_substream_count); 1322 1323 wsi->mux_stream_immortal = 1; 1324 assert(nwsi->immortal_substream_count < 255); /* largest count */ 1325 nwsi->immortal_substream_count++; 1326 if (nwsi->immortal_substream_count == 1) 1327 lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0); 1328} 1329 1330int 1331lws_http_mark_sse(struct lws *wsi) 1332{ 1333 if (!wsi) 1334 return 0; 1335 1336 lws_http_headers_detach(wsi); 1337 lws_mux_mark_immortal(wsi); 1338 1339 if (wsi->mux_substream) 1340 wsi->h2_stream_carries_sse = 1; 1341 1342 return 0; 1343} 1344 1345#if defined(LWS_WITH_CLIENT) 1346 1347const char * 1348lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx) 1349{ 1350 /* try the generic client stash */ 1351 if (wsi->stash) 1352 return wsi->stash->cis[stash_idx]; 1353 1354#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 1355 /* if not, use the ah stash if applicable */ 1356 return lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)hdr_idx); 1357#else 1358 return NULL; 1359#endif 1360} 1361#endif 1362 1363#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) 1364 1365void 1366lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, unsigned int sid) 1367{ 1368 lwsl_wsi_info(wsi, "par %s: assign sid %d (curr %d)", 1369 lws_wsi_tag(parent_wsi), sid, wsi->mux.my_sid); 1370 1371 if (wsi->mux.my_sid && wsi->mux.my_sid != (unsigned int)sid) 1372 assert(0); 1373 1374 wsi->mux.my_sid = sid; 1375 wsi->mux.parent_wsi = parent_wsi; 1376 wsi->role_ops = parent_wsi->role_ops; 1377 1378 /* new guy's sibling is whoever was the first child before */ 1379 wsi->mux.sibling_list = parent_wsi->mux.child_list; 1380 1381 /* first child is now the new guy */ 1382 parent_wsi->mux.child_list = wsi; 1383 1384 parent_wsi->mux.child_count++; 1385} 1386 1387struct lws * 1388lws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid) 1389{ 1390 lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) { 1391 if (wsi->mux.my_sid == sid) 1392 return wsi; 1393 } lws_end_foreach_ll(wsi, mux.sibling_list); 1394 1395 return NULL; 1396} 1397 1398void 1399lws_wsi_mux_dump_children(struct lws *wsi) 1400{ 1401#if defined(_DEBUG) 1402 if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO)) 1403 return; 1404 1405 lws_start_foreach_llp(struct lws **, w, 1406 wsi->mux.parent_wsi->mux.child_list) { 1407 lwsl_wsi_info(wsi, " \\---- child %s %s\n", 1408 (*w)->role_ops ? (*w)->role_ops->name : "?", 1409 lws_wsi_tag(*w)); 1410 assert(*w != (*w)->mux.sibling_list); 1411 } lws_end_foreach_llp(w, mux.sibling_list); 1412#endif 1413} 1414 1415void 1416lws_wsi_mux_close_children(struct lws *wsi, int reason) 1417{ 1418 struct lws *wsi2; 1419 struct lws **w; 1420 1421 if (!wsi->mux.child_list) 1422 return; 1423 1424 w = &wsi->mux.child_list; 1425 while (*w) { 1426 lwsl_wsi_info((*w), " closing child"); 1427 /* disconnect from siblings */ 1428 wsi2 = (*w)->mux.sibling_list; 1429 assert (wsi2 != *w); 1430 (*w)->mux.sibling_list = NULL; 1431 (*w)->socket_is_permanently_unusable = 1; 1432 __lws_close_free_wsi(*w, (enum lws_close_status)reason, "mux child recurse"); 1433 *w = wsi2; 1434 } 1435} 1436 1437 1438void 1439lws_wsi_mux_sibling_disconnect(struct lws *wsi) 1440{ 1441 struct lws *wsi2; 1442 1443 lws_start_foreach_llp(struct lws **, w, 1444 wsi->mux.parent_wsi->mux.child_list) { 1445 1446 /* disconnect from siblings */ 1447 if (*w == wsi) { 1448 wsi2 = (*w)->mux.sibling_list; 1449 (*w)->mux.sibling_list = NULL; 1450 *w = wsi2; 1451 lwsl_wsi_debug(wsi, " disentangled from sibling %s", 1452 lws_wsi_tag(wsi2)); 1453 break; 1454 } 1455 } lws_end_foreach_llp(w, mux.sibling_list); 1456 wsi->mux.parent_wsi->mux.child_count--; 1457 1458 wsi->mux.parent_wsi = NULL; 1459} 1460 1461void 1462lws_wsi_mux_dump_waiting_children(struct lws *wsi) 1463{ 1464#if defined(_DEBUG) 1465 lwsl_info("%s: %s: children waiting for POLLOUT service:\n", 1466 __func__, lws_wsi_tag(wsi)); 1467 1468 wsi = wsi->mux.child_list; 1469 while (wsi) { 1470 lwsl_wsi_info(wsi, " %c sid %u: 0x%x %s %s", 1471 wsi->mux.requested_POLLOUT ? '*' : ' ', 1472 wsi->mux.my_sid, lwsi_state(wsi), 1473 wsi->role_ops->name, 1474 wsi->a.protocol ? wsi->a.protocol->name : "noprotocol"); 1475 1476 wsi = wsi->mux.sibling_list; 1477 } 1478#endif 1479} 1480 1481int 1482lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi) 1483{ 1484 struct lws /* *network_wsi = lws_get_network_wsi(wsi), */ *wsi2; 1485 //int already = network_wsi->mux.requested_POLLOUT; 1486 1487 /* mark everybody above him as requesting pollout */ 1488 1489 wsi2 = wsi; 1490 while (wsi2) { 1491 wsi2->mux.requested_POLLOUT = 1; 1492 lwsl_wsi_info(wsi2, "sid %u, pending writable", 1493 wsi2->mux.my_sid); 1494 wsi2 = wsi2->mux.parent_wsi; 1495 } 1496 1497 return 0; // already; 1498} 1499 1500struct lws * 1501lws_wsi_mux_move_child_to_tail(struct lws **wsi2) 1502{ 1503 struct lws *w = *wsi2; 1504 1505 while (w) { 1506 if (!w->mux.sibling_list) { /* w is the current last */ 1507 lwsl_wsi_debug(w, "*wsi2 = %s\n", lws_wsi_tag(*wsi2)); 1508 1509 if (w == *wsi2) /* we are already last */ 1510 break; 1511 1512 /* last points to us as new last */ 1513 w->mux.sibling_list = *wsi2; 1514 1515 /* guy pointing to us until now points to 1516 * our old next */ 1517 *wsi2 = (*wsi2)->mux.sibling_list; 1518 1519 /* we point to nothing because we are last */ 1520 w->mux.sibling_list->mux.sibling_list = NULL; 1521 1522 /* w becomes us */ 1523 w = w->mux.sibling_list; 1524 break; 1525 } 1526 w = w->mux.sibling_list; 1527 } 1528 1529 /* clear the waiting for POLLOUT on the guy that was chosen */ 1530 1531 if (w) 1532 w->mux.requested_POLLOUT = 0; 1533 1534 return w; 1535} 1536 1537int 1538lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi) 1539{ 1540 struct lws *w = wsi->mux.child_list; 1541 1542 while (w) { 1543 if (w->mux.requested_POLLOUT) { 1544 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) 1545 return -1; 1546 return 0; 1547 } 1548 w = w->mux.sibling_list; 1549 } 1550 1551 if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) 1552 return -1; 1553 1554 return 0; 1555} 1556 1557int 1558lws_wsi_txc_check_skint(struct lws_tx_credit *txc, int32_t tx_cr) 1559{ 1560 if (txc->tx_cr <= 0) { 1561 /* 1562 * If other side is not able to cope with us sending any DATA 1563 * so no matter if we have POLLOUT on our side if it's DATA we 1564 * want to send. 1565 */ 1566 1567 if (!txc->skint) 1568 lwsl_info("%s: %p: skint (%d)\n", __func__, txc, 1569 (int)txc->tx_cr); 1570 1571 txc->skint = 1; 1572 1573 return 1; 1574 } 1575 1576 if (txc->skint) 1577 lwsl_info("%s: %p: unskint (%d)\n", __func__, txc, 1578 (int)txc->tx_cr); 1579 1580 txc->skint = 0; 1581 1582 return 0; 1583} 1584 1585#if defined(_DEBUG) 1586void 1587lws_wsi_txc_describe(struct lws_tx_credit *txc, const char *at, uint32_t sid) 1588{ 1589 lwsl_info("%s: %p: %s: sid %d: %speer-to-us: %d, us-to-peer: %d\n", 1590 __func__, txc, at, (int)sid, txc->skint ? "SKINT, " : "", 1591 (int)txc->peer_tx_cr_est, (int)txc->tx_cr); 1592} 1593#endif 1594 1595int 1596lws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add) 1597{ 1598 if (wsi->role_ops && lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) 1599 return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit). 1600 tx_credit(wsi, peer_to_us, add); 1601 1602 return 0; 1603} 1604 1605/* 1606 * Let the protocol know about incoming tx credit window updates if it's 1607 * managing the flow control manually (it may want to proxy this information) 1608 */ 1609 1610int 1611lws_wsi_txc_report_manual_txcr_in(struct lws *wsi, int32_t bump) 1612{ 1613 if (!wsi->txc.manual) 1614 /* 1615 * If we don't care about managing it manually, no need to 1616 * report it 1617 */ 1618 return 0; 1619 1620 return user_callback_handle_rxflow(wsi->a.protocol->callback, 1621 wsi, LWS_CALLBACK_WSI_TX_CREDIT_GET, 1622 wsi->user_space, NULL, (size_t)bump); 1623} 1624 1625#if defined(LWS_WITH_CLIENT) 1626 1627int 1628lws_wsi_mux_apply_queue(struct lws *wsi) 1629{ 1630 /* we have a transaction queue that wants to pipeline */ 1631 1632 lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */ 1633 lws_vhost_lock(wsi->a.vhost); 1634 1635 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1636 wsi->dll2_cli_txn_queue_owner.head) { 1637 struct lws *w = lws_container_of(d, struct lws, 1638 dll2_cli_txn_queue); 1639 1640#if defined(LWS_ROLE_H2) 1641 if (lwsi_role_http(wsi) && 1642 lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) { 1643 lwsl_wsi_info(w, "cli pipeq to be h2"); 1644 1645 lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2); 1646 1647 /* remove ourselves from client queue */ 1648 lws_dll2_remove(&w->dll2_cli_txn_queue); 1649 1650 /* attach ourselves as an h2 stream */ 1651 lws_wsi_h2_adopt(wsi, w); 1652 } 1653#endif 1654 1655#if defined(LWS_ROLE_MQTT) 1656 if (lwsi_role_mqtt(wsi) && 1657 lwsi_state(wsi) == LRS_ESTABLISHED) { 1658 lwsl_wsi_info(w, "cli pipeq to be mqtt\n"); 1659 1660 /* remove ourselves from client queue */ 1661 lws_dll2_remove(&w->dll2_cli_txn_queue); 1662 1663 /* attach ourselves as an h2 stream */ 1664 lws_wsi_mqtt_adopt(wsi, w); 1665 } 1666#endif 1667 1668 } lws_end_foreach_dll_safe(d, d1); 1669 1670 lws_vhost_unlock(wsi->a.vhost); 1671 lws_context_unlock(wsi->a.context); /* } cx -------------- */ 1672 1673 return 0; 1674} 1675 1676#endif 1677 1678#endif 1679