1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include "private-lib-core.h" 26 27void 28lws_tls_session_vh_destroy(struct lws_vhost *vh); 29 30const struct lws_role_ops *available_roles[] = { 31#if defined(LWS_ROLE_H2) 32 &role_ops_h2, 33#endif 34#if defined(LWS_ROLE_H1) 35 &role_ops_h1, 36#endif 37#if defined(LWS_ROLE_WS) 38 &role_ops_ws, 39#endif 40#if defined(LWS_ROLE_DBUS) 41 &role_ops_dbus, 42#endif 43#if defined(LWS_ROLE_RAW_PROXY) 44 &role_ops_raw_proxy, 45#endif 46#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT) 47 &role_ops_mqtt, 48#endif 49#if defined(LWS_WITH_NETLINK) 50 &role_ops_netlink, 51#endif 52 NULL 53}; 54 55#if defined(LWS_WITH_ABSTRACT) 56const struct lws_protocols *available_abstract_protocols[] = { 57#if defined(LWS_ROLE_RAW) 58 &protocol_abs_client_raw_skt, 59#endif 60 NULL 61}; 62#endif 63 64#if defined(LWS_WITH_SECURE_STREAMS) 65const struct lws_protocols *available_secstream_protocols[] = { 66#if defined(LWS_ROLE_H1) 67 &protocol_secstream_h1, 68#endif 69#if defined(LWS_ROLE_H2) 70 &protocol_secstream_h2, 71#endif 72#if defined(LWS_ROLE_WS) 73 &protocol_secstream_ws, 74#endif 75#if defined(LWS_ROLE_MQTT) 76 &protocol_secstream_mqtt, 77#endif 78 &protocol_secstream_raw, 79 NULL 80}; 81#endif 82 83static const char * const mount_protocols[] = { 84 "http://", 85 "https://", 86 "file://", 87 "cgi://", 88 ">http://", 89 ">https://", 90 "callback://" 91}; 92 93const struct lws_role_ops * 94lws_role_by_name(const char *name) 95{ 96 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 97 if (!strcmp(ar->name, name)) 98 return ar; 99 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 100 101 if (!strcmp(name, role_ops_raw_skt.name)) 102 return &role_ops_raw_skt; 103 104#if defined(LWS_ROLE_RAW_FILE) 105 if (!strcmp(name, role_ops_raw_file.name)) 106 return &role_ops_raw_file; 107#endif 108 109 return NULL; 110} 111 112int 113lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn) 114{ 115#if defined(LWS_WITH_TLS) 116 if (!alpn) 117 return 0; 118 119#if !defined(LWS_ESP_PLATFORM) 120 lwsl_wsi_info(wsi, "'%s'", alpn); 121#endif 122 123 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 124 if (ar->alpn && !strcmp(ar->alpn, alpn) && 125 lws_rops_fidx(ar, LWS_ROPS_alpn_negotiated)) { 126#if defined(LWS_WITH_SERVER) 127 lws_metrics_tag_wsi_add(wsi, "upg", ar->name); 128#endif 129 return (lws_rops_func_fidx(ar, LWS_ROPS_alpn_negotiated)). 130 alpn_negotiated(wsi, alpn); 131 } 132 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 133#endif 134 return 0; 135} 136 137int 138lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot) 139{ 140 int n; 141 142 /* 143 * if the vhost is told to bind accepted sockets to a given role, 144 * then look it up by name and try to bind to the specific role. 145 */ 146 if (lws_check_opt(wsi->a.vhost->options, 147 LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG) && 148 wsi->a.vhost->listen_accept_role) { 149 const struct lws_role_ops *role = 150 lws_role_by_name(wsi->a.vhost->listen_accept_role); 151 152 if (!prot) 153 prot = wsi->a.vhost->listen_accept_protocol; 154 155 if (!role) 156 lwsl_wsi_err(wsi, "can't find role '%s'", 157 wsi->a.vhost->listen_accept_role); 158 159 if (!strcmp(wsi->a.vhost->listen_accept_role, "raw-proxy")) 160 type |= LWS_ADOPT_FLAG_RAW_PROXY; 161 162 if (role && lws_rops_fidx(role, LWS_ROPS_adoption_bind)) { 163 n = (lws_rops_func_fidx(role, LWS_ROPS_adoption_bind)). 164 adoption_bind(wsi, type, prot); 165 if (n < 0) 166 return -1; 167 if (n) /* did the bind */ 168 return 0; 169 } 170 171 if (type & _LWS_ADOPT_FINISH) { 172 lwsl_wsi_debug(wsi, "leaving bound to role %s", 173 wsi->role_ops->name); 174 return 0; 175 } 176 177 lwsl_wsi_warn(wsi, "adoption bind to role '%s', " 178 "protocol '%s', type 0x%x, failed", 179 wsi->a.vhost->listen_accept_role, prot, type); 180 } 181 182 /* 183 * Otherwise ask each of the roles in order of preference if they 184 * want to bind to this accepted socket 185 */ 186 187 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 188 if (lws_rops_fidx(ar, LWS_ROPS_adoption_bind) && 189 (lws_rops_func_fidx(ar, LWS_ROPS_adoption_bind)). 190 adoption_bind(wsi, type, prot)) 191 return 0; 192 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 193 194 /* fall back to raw socket role if, eg, h1 not configured */ 195 196 if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind) && 197 (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind)). 198 adoption_bind(wsi, type, prot)) 199 return 0; 200 201#if defined(LWS_ROLE_RAW_FILE) 202 203 lwsl_wsi_notice(wsi, "falling back to raw file role bind"); 204 205 /* fall back to raw file role if, eg, h1 not configured */ 206 207 if (lws_rops_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind) && 208 (lws_rops_func_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind)). 209 adoption_bind(wsi, type, prot)) 210 return 0; 211#endif 212 213 return 1; 214} 215 216#if defined(LWS_WITH_CLIENT) 217int 218lws_role_call_client_bind(struct lws *wsi, 219 const struct lws_client_connect_info *i) 220{ 221 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 222 if (lws_rops_fidx(ar, LWS_ROPS_client_bind)) { 223 int m = (lws_rops_func_fidx(ar, LWS_ROPS_client_bind)). 224 client_bind(wsi, i); 225 226 if (m < 0) 227 return m; 228 if (m) 229 return 0; 230 } 231 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 232 233 /* fall back to raw socket role if, eg, h1 not configured */ 234 235 if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind) && 236 (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind)). 237 client_bind(wsi, i)) 238 return 0; 239 240 return 1; 241} 242#endif 243 244void * 245lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, 246 const struct lws_protocols *prot, int size) 247{ 248 int n = 0; 249 250 if (!vhost || !prot || !vhost->protocols || !prot->name) 251 return NULL; 252 253 /* allocate the vh priv array only on demand */ 254 if (!vhost->protocol_vh_privs) { 255 vhost->protocol_vh_privs = (void **)lws_zalloc( 256 (size_t)vhost->count_protocols * sizeof(void *), 257 "protocol_vh_privs"); 258 259 if (!vhost->protocol_vh_privs) 260 return NULL; 261 } 262 263 while (n < vhost->count_protocols && &vhost->protocols[n] != prot) 264 n++; 265 266 if (n == vhost->count_protocols) { 267 n = 0; 268 while (n < vhost->count_protocols) { 269 if (vhost->protocols[n].name && 270 !strcmp(vhost->protocols[n].name, prot->name)) 271 break; 272 n++; 273 } 274 275 if (n == vhost->count_protocols) { 276 lwsl_vhost_err(vhost, "unknown protocol %p", prot); 277 return NULL; 278 } 279 } 280 281 vhost->protocol_vh_privs[n] = lws_zalloc((size_t)size, "vh priv"); 282 return vhost->protocol_vh_privs[n]; 283} 284 285void * 286lws_protocol_vh_priv_get(struct lws_vhost *vhost, 287 const struct lws_protocols *prot) 288{ 289 int n = 0; 290 291 if (!vhost || !vhost->protocols || 292 !vhost->protocol_vh_privs || !prot || !prot->name) 293 return NULL; 294 295 while (n < vhost->count_protocols && &vhost->protocols[n] != prot) 296 n++; 297 298 if (n == vhost->count_protocols) { 299 n = 0; 300 while (n < vhost->count_protocols) { 301 if (vhost->protocols[n].name && 302 !strcmp(vhost->protocols[n].name, prot->name)) 303 break; 304 n++; 305 } 306 307 if (n == vhost->count_protocols) { 308 lwsl_vhost_err(vhost, "unknown protocol %p", prot); 309 return NULL; 310 } 311 } 312 313 return vhost->protocol_vh_privs[n]; 314} 315 316void * 317lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname, 318 const char *pvo_name, const char *pvo_value) 319{ 320 struct lws_vhost *vh; 321 int n; 322 323 /* let's go through all the vhosts */ 324 325 vh = cx->vhost_list; 326 while (vh) { 327 328 if (vh->protocol_vh_privs) { 329 330 for (n = 0; n < vh->count_protocols; n++) { 331 const struct lws_protocol_vhost_options *pv; 332 333 if (strcmp(vh->protocols[n].name, protname)) 334 continue; 335 336 /* this vh has an instance of the required protocol */ 337 338 pv = lws_pvo_search(vh->pvo, protname); 339 if (!pv) 340 continue; 341 342 pv = lws_pvo_search(pv->options, pvo_name); 343 if (!pv) 344 continue; 345 346 /* ... he also has a pvo of the right name... */ 347 if (!strcmp(pv->value, pvo_value)) 348 /* 349 * ... yes, the pvo has the right value too, 350 * return a pointer to this vhost-protocol 351 * private alloc (ie, its "vhd") 352 */ 353 return vh->protocol_vh_privs[n]; 354 } 355 } else 356 lwsl_vhost_notice(vh, "no privs yet"); 357 vh = vh->vhost_next; 358 } 359 360 return NULL; 361} 362 363const struct lws_protocol_vhost_options * 364lws_vhost_protocol_options(struct lws_vhost *vh, const char *name) 365{ 366 const struct lws_protocol_vhost_options *pvo = vh->pvo; 367 368 if (!name) 369 return NULL; 370 371 while (pvo) { 372 if (!strcmp(pvo->name, name)) 373 return pvo; 374 pvo = pvo->next; 375 } 376 377 return NULL; 378} 379 380int 381lws_protocol_init_vhost(struct lws_vhost *vh, int *any) 382{ 383 const struct lws_protocol_vhost_options *pvo, *pvo1; 384 int n; 385#if defined(LWS_PLAT_FREERTOS) 386 struct lws_a _lwsa, *lwsa = &_lwsa; 387 388 memset(&_lwsa, 0, sizeof(_lwsa)); 389#else 390 struct lws _lws; 391 struct lws_a *lwsa = &_lws.a; 392 393 memset(&_lws, 0, sizeof(_lws)); 394#endif 395 396 lwsa->context = vh->context; 397 lwsa->vhost = vh; 398 399 /* initialize supported protocols on this vhost */ 400 401 for (n = 0; n < vh->count_protocols; n++) { 402 lwsa->protocol = &vh->protocols[n]; 403 if (!vh->protocols[n].name) 404 continue; 405 pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name); 406 if (pvo) { 407 /* 408 * linked list of options specific to 409 * vh + protocol 410 */ 411 pvo1 = pvo; 412 pvo = pvo1->options; 413 414 while (pvo) { 415 lwsl_vhost_debug(vh, "protocol \"%s\", " 416 "option \"%s\"", 417 vh->protocols[n].name, 418 pvo->name); 419 420 if (!strcmp(pvo->name, "default")) { 421 lwsl_vhost_info(vh, "Setting default " 422 "protocol to %s", 423 vh->protocols[n].name); 424 vh->default_protocol_index = (unsigned char)n; 425 } 426 if (!strcmp(pvo->name, "raw")) { 427 lwsl_vhost_info(vh, "Setting raw " 428 "protocol to %s", 429 vh->protocols[n].name); 430 vh->raw_protocol_index = (unsigned char)n; 431 } 432 pvo = pvo->next; 433 } 434 } else 435 lwsl_vhost_debug(vh, "not instantiating %s", 436 vh->protocols[n].name); 437 438#if defined(LWS_WITH_TLS) 439 if (any) 440 *any |= !!vh->tls.ssl_ctx; 441#endif 442 443 pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name); 444 445 /* 446 * inform all the protocols that they are doing their 447 * one-time initialization if they want to. 448 * 449 * NOTE the fakewsi is garbage, except the key pointers that are 450 * prepared in case the protocol handler wants to touch them 451 */ 452 453 if (pvo 454#if !defined(LWS_WITH_PLUGINS) 455 /* 456 * with plugins, you have to explicitly 457 * instantiate them per-vhost with pvos. 458 * 459 * Without plugins, not setting the vhost pvo 460 * list at creation enables all the protocols 461 * by default, for backwards compatibility 462 */ 463 || !vh->pvo 464#endif 465 ) { 466 lwsl_vhost_info(vh, "init %s.%s", vh->name, 467 vh->protocols[n].name); 468 if (vh->protocols[n].callback((struct lws *)lwsa, 469 LWS_CALLBACK_PROTOCOL_INIT, NULL, 470#if !defined(LWS_WITH_PLUGINS) 471 (void *)(pvo ? pvo->options : NULL), 472#else 473 (void *)pvo->options, 474#endif 475 0)) { 476 if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) { 477 lws_free(vh->protocol_vh_privs[n]); 478 vh->protocol_vh_privs[n] = NULL; 479 } 480 lwsl_vhost_err(vh, "protocol %s failed init", 481 vh->protocols[n].name); 482 483 return 1; 484 } 485 } 486 } 487 488 vh->created_vhost_protocols = 1; 489 490 return 0; 491} 492 493/* 494 * inform every vhost that hasn't already done it, that 495 * his protocols are initializing 496 */ 497int 498lws_protocol_init(struct lws_context *context) 499{ 500 struct lws_vhost *vh = context->vhost_list; 501 int any = 0, r = 0; 502 503 if (context->doing_protocol_init) 504 return 0; 505 506 context->doing_protocol_init = 1; 507 508 lwsl_cx_info(context, "\n"); 509 510 while (vh) { 511 512 /* only do the protocol init once for a given vhost */ 513 if (vh->created_vhost_protocols || 514 (lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))) 515 goto next; 516 517 if (lws_protocol_init_vhost(vh, &any)) { 518 lwsl_vhost_warn(vh, "init vhost %s failed", vh->name); 519 r = -1; 520 } 521next: 522 vh = vh->vhost_next; 523 } 524 525 context->doing_protocol_init = 0; 526 527 if (r) 528 lwsl_cx_warn(context, "some protocols did not init"); 529 530 if (!context->protocol_init_done) { 531 532 context->protocol_init_done = 1; 533 lws_finalize_startup(context); 534 535 return 0; 536 } 537 538#if defined(LWS_WITH_SERVER) 539 if (any) { 540 lws_tls_check_all_cert_lifetimes(context); 541 } 542#endif 543 544 return 0; 545} 546 547 548/* list of supported protocols and callbacks */ 549 550static const struct lws_protocols protocols_dummy[] = { 551 /* first protocol must always be HTTP handler */ 552 553 { 554 "http-only", /* name */ 555 lws_callback_http_dummy, /* callback */ 556 0, /* per_session_data_size */ 557 0, /* rx_buffer_size */ 558 0, /* id */ 559 NULL, /* user */ 560 0 /* tx_packet_size */ 561 }, 562 /* 563 * the other protocols are provided by lws plugins 564 */ 565 { NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */ 566}; 567 568 569#ifdef LWS_PLAT_OPTEE 570#undef LWS_HAVE_GETENV 571#endif 572 573struct lws_vhost * 574lws_create_vhost(struct lws_context *context, 575 const struct lws_context_creation_info *info) 576{ 577 struct lws_vhost *vh, **vh1 = &context->vhost_list; 578 const struct lws_http_mount *mounts; 579 const struct lws_protocols *pcols = info->protocols; 580#ifdef LWS_WITH_PLUGINS 581 struct lws_plugin *plugin = context->plugin_list; 582#endif 583 struct lws_protocols *lwsp; 584 int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0; 585 const char *name = "default"; 586 char buf[96]; 587 char *p; 588#if defined(LWS_WITH_SYS_ASYNC_DNS) 589 extern struct lws_protocols lws_async_dns_protocol; 590#endif 591 int n; 592 593 if (info->vhost_name) 594 name = info->vhost_name; 595 596 if (lws_fi(&info->fic, "vh_create_oom")) 597 vh = NULL; 598 else 599 vh = lws_zalloc(sizeof(*vh) + strlen(name) + 1 600#if defined(LWS_WITH_EVENT_LIBS) 601 + context->event_loop_ops->evlib_size_vh 602#endif 603 , __func__); 604 if (!vh) 605 goto early_bail; 606 607 if (info->log_cx) 608 vh->lc.log_cx = info->log_cx; 609 else 610 vh->lc.log_cx = &log_cx; 611 612#if defined(LWS_WITH_EVENT_LIBS) 613 vh->evlib_vh = (void *)&vh[1]; 614 vh->name = (const char *)vh->evlib_vh + 615 context->event_loop_ops->evlib_size_vh; 616#else 617 vh->name = (const char *)&vh[1]; 618#endif 619 memcpy((char *)vh->name, name, strlen(name) + 1); 620 621#if LWS_MAX_SMP > 1 622 lws_mutex_refcount_init(&vh->mr); 623#endif 624 625 if (!pcols && !info->pprotocols) 626 pcols = &protocols_dummy[0]; 627 628 vh->context = context; 629 { 630 char *end = buf + sizeof(buf) - 1; 631 p = buf; 632 633 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", vh->name); 634 if (info->iface) 635 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%s", info->iface); 636 if (info->port && !(info->port & 0xffff)) 637 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%u", info->port); 638 } 639 640 __lws_lc_tag(context, &context->lcg[LWSLCG_VHOST], &vh->lc, "%s|%s|%d", 641 buf, info->iface ? info->iface : "", info->port); 642 643#if defined(LWS_WITH_SYS_FAULT_INJECTION) 644 vh->fic.name = "vh"; 645 if (info->fic.fi_owner.count) 646 /* 647 * This moves all the lws_fi_t from info->fi to the vhost fi, 648 * leaving it empty 649 */ 650 lws_fi_import(&vh->fic, &info->fic); 651 652 lws_fi_inherit_copy(&vh->fic, &context->fic, "vh", vh->name); 653 if (lws_fi(&vh->fic, "vh_create_oom")) 654 goto bail; 655#endif 656 657#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 658 vh->http.error_document_404 = info->error_document_404; 659#endif 660 661 if (lws_check_opt(info->options, LWS_SERVER_OPTION_ONLY_RAW)) 662 lwsl_vhost_info(vh, "set to only support RAW"); 663 664 vh->iface = info->iface; 665#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32) 666 vh->bind_iface = info->bind_iface; 667#endif 668#if defined(LWS_WITH_CLIENT) 669 if (info->connect_timeout_secs) 670 vh->connect_timeout_secs = (int)info->connect_timeout_secs; 671 else 672 vh->connect_timeout_secs = 20; 673#endif 674 /* apply the context default lws_retry */ 675 676 if (info->retry_and_idle_policy) 677 vh->retry_policy = info->retry_and_idle_policy; 678 else 679 vh->retry_policy = &context->default_retry; 680 681 /* 682 * let's figure out how many protocols the user is handing us, using the 683 * old or new way depending on what he gave us 684 */ 685 686 if (!pcols) 687 for (vh->count_protocols = 0; 688 info->pprotocols[vh->count_protocols]; 689 vh->count_protocols++) 690 ; 691 else 692 for (vh->count_protocols = 0; 693 pcols[vh->count_protocols].callback; 694 vh->count_protocols++) 695 ; 696 697 vh->options = info->options; 698 vh->pvo = info->pvo; 699 vh->headers = info->headers; 700 vh->user = info->user; 701 vh->finalize = info->finalize; 702 vh->finalize_arg = info->finalize_arg; 703 vh->listen_accept_role = info->listen_accept_role; 704 vh->listen_accept_protocol = info->listen_accept_protocol; 705 vh->unix_socket_perms = info->unix_socket_perms; 706 vh->fo_listen_queue = info->fo_listen_queue; 707 708 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 709 if (lws_rops_fidx(ar, LWS_ROPS_init_vhost) && 710 (lws_rops_func_fidx(ar, LWS_ROPS_init_vhost)).init_vhost(vh, info)) 711 return NULL; 712 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 713 714 715 if (info->keepalive_timeout) 716 vh->keepalive_timeout = info->keepalive_timeout; 717 else 718 vh->keepalive_timeout = 5; 719 720 if (info->timeout_secs_ah_idle) 721 vh->timeout_secs_ah_idle = (int)info->timeout_secs_ah_idle; 722 else 723 vh->timeout_secs_ah_idle = 10; 724 725#if defined(LWS_WITH_TLS) 726 727 vh->tls.alpn = info->alpn; 728 vh->tls.ssl_info_event_mask = info->ssl_info_event_mask; 729 730 if (info->ecdh_curve) 731 lws_strncpy(vh->tls.ecdh_curve, info->ecdh_curve, 732 sizeof(vh->tls.ecdh_curve)); 733 734 /* carefully allocate and take a copy of cert + key paths if present */ 735 n = 0; 736 if (info->ssl_cert_filepath) 737 n += (int)strlen(info->ssl_cert_filepath) + 1; 738 if (info->ssl_private_key_filepath) 739 n += (int)strlen(info->ssl_private_key_filepath) + 1; 740 741 if (n) { 742 vh->tls.key_path = vh->tls.alloc_cert_path = 743 lws_malloc((unsigned int)n, "vh paths"); 744 if (info->ssl_cert_filepath) { 745 n = (int)strlen(info->ssl_cert_filepath) + 1; 746 memcpy(vh->tls.alloc_cert_path, 747 info->ssl_cert_filepath, (unsigned int)n); 748 vh->tls.key_path += n; 749 } 750 if (info->ssl_private_key_filepath) 751 memcpy(vh->tls.key_path, info->ssl_private_key_filepath, 752 strlen(info->ssl_private_key_filepath) + 1); 753 } 754#endif 755 756#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS) 757 fx = 1; 758#endif 759#if defined(LWS_WITH_ABSTRACT) 760 abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1; 761#endif 762#if defined(LWS_WITH_SECURE_STREAMS) 763 sec_pcol_count = (int)LWS_ARRAY_SIZE(available_secstream_protocols) - 1; 764#endif 765 766 /* 767 * give the vhost a unified list of protocols including: 768 * 769 * - internal, async_dns if enabled (first vhost only) 770 * - internal, abstracted ones 771 * - the ones that came from plugins 772 * - his user protocols 773 */ 774 775 if (lws_fi(&vh->fic, "vh_create_pcols_oom")) 776 lwsp = NULL; 777 else 778 lwsp = lws_zalloc(sizeof(struct lws_protocols) * 779 ((unsigned int)vh->count_protocols + 780 (unsigned int)abs_pcol_count + 781 (unsigned int)sec_pcol_count + 782 (unsigned int)context->plugin_protocol_count + 783 (unsigned int)fx + 1), "vh plugin table"); 784 if (!lwsp) { 785 lwsl_err("OOM\n"); 786 goto bail; 787 } 788 789 /* 790 * 1: user protocols (from pprotocols or protocols) 791 */ 792 793 m = vh->count_protocols; 794 if (!pcols) { 795 for (n = 0; n < m; n++) 796 memcpy(&lwsp[n], info->pprotocols[n], sizeof(lwsp[0])); 797 } else 798 memcpy(lwsp, pcols, sizeof(struct lws_protocols) * (unsigned int)m); 799 800 /* 801 * 2: abstract protocols 802 */ 803#if defined(LWS_WITH_ABSTRACT) 804 for (n = 0; n < abs_pcol_count; n++) { 805 memcpy(&lwsp[m++], available_abstract_protocols[n], 806 sizeof(*lwsp)); 807 vh->count_protocols++; 808 } 809#endif 810 /* 811 * 3: async dns protocol (first vhost only) 812 */ 813#if defined(LWS_WITH_SYS_ASYNC_DNS) 814 if (!context->vhost_list) { 815 memcpy(&lwsp[m++], &lws_async_dns_protocol, 816 sizeof(struct lws_protocols)); 817 vh->count_protocols++; 818 } 819#endif 820 821#if defined(LWS_WITH_SECURE_STREAMS) 822 for (n = 0; n < sec_pcol_count; n++) { 823 memcpy(&lwsp[m++], available_secstream_protocols[n], 824 sizeof(*lwsp)); 825 vh->count_protocols++; 826 } 827#endif 828 829 /* 830 * 3: For compatibility, all protocols enabled on vhost if only 831 * the default vhost exists. Otherwise only vhosts who ask 832 * for a protocol get it enabled. 833 */ 834 835 if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) 836 f = 0; 837 (void)f; 838#ifdef LWS_WITH_PLUGINS 839 if (plugin) { 840 while (plugin) { 841 const lws_plugin_protocol_t *plpr = 842 (const lws_plugin_protocol_t *)plugin->hdr; 843 844 for (n = 0; n < plpr->count_protocols; n++) { 845 /* 846 * for compatibility's sake, no pvo implies 847 * allow all protocols 848 */ 849 if (f || lws_vhost_protocol_options(vh, 850 plpr->protocols[n].name)) { 851 memcpy(&lwsp[m], 852 &plpr->protocols[n], 853 sizeof(struct lws_protocols)); 854 m++; 855 vh->count_protocols++; 856 } 857 } 858 plugin = plugin->list; 859 } 860 } 861#endif 862 863#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS) 864 memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(*lwsp)); 865 vh->count_protocols++; 866#endif 867 868 vh->protocols = lwsp; 869 vh->allocated_vhost_protocols = 1; 870 871 vh->same_vh_protocol_owner = (struct lws_dll2_owner *) 872 lws_zalloc(sizeof(struct lws_dll2_owner) * 873 (unsigned int)vh->count_protocols, "same vh list"); 874#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 875 vh->http.mount_list = info->mounts; 876#endif 877 878#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER) 879 { 880 char *end = buf + sizeof(buf) - 1; 881 p = buf; 882 883 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "vh.%s", vh->name); 884 if (info->iface) 885 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%s", info->iface); 886 if (info->port && !(info->port & 0xffff)) 887 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%u", info->port); 888 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".rx"); 889 vh->mt_traffic_rx = lws_metric_create(context, 0, buf); 890 p[-2] = 't'; 891 vh->mt_traffic_tx = lws_metric_create(context, 0, buf); 892 } 893#endif 894 895#ifdef LWS_WITH_UNIX_SOCK 896 if (LWS_UNIX_SOCK_ENABLED(vh)) { 897 lwsl_vhost_info(vh, "Creating '%s' path \"%s\", %d protocols", 898 vh->name, vh->iface, vh->count_protocols); 899 } else 900#endif 901 { 902 switch(info->port) { 903 case CONTEXT_PORT_NO_LISTEN: 904 strcpy(buf, "(serving disabled)"); 905 break; 906 case CONTEXT_PORT_NO_LISTEN_SERVER: 907 strcpy(buf, "(no listener)"); 908 break; 909 default: 910 lws_snprintf(buf, sizeof(buf), "port %u", info->port); 911 break; 912 } 913 lwsl_vhost_info(vh, "Creating Vhost '%s' %s, %d protocols, IPv6 %s", 914 vh->name, buf, vh->count_protocols, 915 LWS_IPV6_ENABLED(vh) ? "on" : "off"); 916 } 917 mounts = info->mounts; 918 while (mounts) { 919 (void)mount_protocols[0]; 920 lwsl_vhost_info(vh, " mounting %s%s to %s", 921 mount_protocols[mounts->origin_protocol], 922 mounts->origin ? mounts->origin : "none", 923 mounts->mountpoint); 924 925 mounts = mounts->mount_next; 926 } 927 928 vh->listen_port = info->port; 929 930#if defined(LWS_WITH_SOCKS5) 931 vh->socks_proxy_port = 0; 932 vh->socks_proxy_address[0] = '\0'; 933#endif 934 935#if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING) 936 /* either use proxy from info, or try get it from env var */ 937#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 938 vh->http.http_proxy_port = 0; 939 vh->http.http_proxy_address[0] = '\0'; 940 /* http proxy */ 941 if (info->http_proxy_address) { 942 /* override for backwards compatibility */ 943 if (info->http_proxy_port) 944 vh->http.http_proxy_port = info->http_proxy_port; 945 lws_set_proxy(vh, info->http_proxy_address); 946 } else 947#endif 948 { 949#ifdef LWS_HAVE_GETENV 950#if defined(__COVERITY__) 951 p = NULL; 952#else 953 p = getenv("http_proxy"); /* coverity[tainted_scalar] */ 954 if (p) { 955 lws_strncpy(buf, p, sizeof(buf)); 956 lws_set_proxy(vh, buf); 957 } 958#endif 959#endif 960 } 961#endif 962#if defined(LWS_WITH_SOCKS5) 963 lws_socks5c_ads_server(vh, info); 964#endif 965 966 vh->ka_time = info->ka_time; 967 vh->ka_interval = info->ka_interval; 968 vh->ka_probes = info->ka_probes; 969 970 if (vh->options & LWS_SERVER_OPTION_STS) 971 lwsl_vhost_notice(vh, " STS enabled"); 972 973#ifdef LWS_WITH_ACCESS_LOG 974 if (info->log_filepath) { 975 if (lws_fi(&vh->fic, "vh_create_access_log_open_fail")) 976 vh->log_fd = (int)LWS_INVALID_FILE; 977 else 978 vh->log_fd = lws_open(info->log_filepath, 979 O_CREAT | O_APPEND | O_RDWR, 0600); 980 if (vh->log_fd == (int)LWS_INVALID_FILE) { 981 lwsl_vhost_err(vh, "unable to open log filepath %s", 982 info->log_filepath); 983 goto bail; 984 } 985#ifndef WIN32 986 if (context->uid != (uid_t)-1) 987 if (chown(info->log_filepath, context->uid, 988 context->gid) == -1) 989 lwsl_vhost_err(vh, "unable to chown log file %s", 990 info->log_filepath); 991#endif 992 } else 993 vh->log_fd = (int)LWS_INVALID_FILE; 994#endif 995 if (lws_fi(&vh->fic, "vh_create_ssl_srv") || 996 lws_context_init_server_ssl(info, vh)) { 997 lwsl_vhost_err(vh, "lws_context_init_server_ssl failed"); 998 goto bail1; 999 } 1000 if (lws_fi(&vh->fic, "vh_create_ssl_cli") || 1001 lws_context_init_client_ssl(info, vh)) { 1002 lwsl_vhost_err(vh, "lws_context_init_client_ssl failed"); 1003 goto bail1; 1004 } 1005#if defined(LWS_WITH_SERVER) 1006 lws_context_lock(context, __func__); 1007 if (lws_fi(&vh->fic, "vh_create_srv_init")) 1008 n = -1; 1009 else 1010 n = _lws_vhost_init_server(info, vh); 1011 lws_context_unlock(context); 1012 if (n < 0) { 1013 lwsl_vhost_err(vh, "init server failed\n"); 1014 goto bail1; 1015 } 1016#endif 1017 1018#if defined(LWS_WITH_SYS_ASYNC_DNS) 1019 n = !!context->vhost_list; 1020#endif 1021 1022 while (1) { 1023 if (!(*vh1)) { 1024 *vh1 = vh; 1025 break; 1026 } 1027 vh1 = &(*vh1)->vhost_next; 1028 }; 1029 1030#if defined(LWS_WITH_SYS_ASYNC_DNS) 1031 if (!n) 1032 lws_async_dns_init(context); 1033#endif 1034 1035 /* for the case we are adding a vhost much later, after server init */ 1036 1037 if (context->protocol_init_done) 1038 if (lws_fi(&vh->fic, "vh_create_protocol_init") || 1039 lws_protocol_init(context)) { 1040 lwsl_vhost_err(vh, "lws_protocol_init failed"); 1041 goto bail1; 1042 } 1043 1044 return vh; 1045 1046bail1: 1047 lws_vhost_destroy(vh); 1048 1049 return NULL; 1050 1051bail: 1052 __lws_lc_untag(vh->context, &vh->lc); 1053 lws_fi_destroy(&vh->fic); 1054 lws_free(vh); 1055 1056early_bail: 1057 lws_fi_destroy(&info->fic); 1058 1059 return NULL; 1060} 1061 1062int 1063lws_init_vhost_client_ssl(const struct lws_context_creation_info *info, 1064 struct lws_vhost *vhost) 1065{ 1066 struct lws_context_creation_info i; 1067 1068 memcpy(&i, info, sizeof(i)); 1069 i.port = CONTEXT_PORT_NO_LISTEN; 1070 1071 return lws_context_init_client_ssl(&i, vhost); 1072} 1073 1074void 1075lws_cancel_service_pt(struct lws *wsi) 1076{ 1077 lws_plat_pipe_signal(wsi->a.context, wsi->tsi); 1078} 1079 1080void 1081lws_cancel_service(struct lws_context *context) 1082{ 1083 struct lws_context_per_thread *pt = &context->pt[0]; 1084 short m; 1085 1086 if (context->service_no_longer_possible) 1087 return; 1088 1089 lwsl_cx_debug(context, "\n"); 1090 1091 for (m = 0; m < context->count_threads; m++) { 1092 if (pt->pipe_wsi) 1093 lws_plat_pipe_signal(pt->context, m); 1094 pt++; 1095 } 1096} 1097 1098int 1099__lws_create_event_pipes(struct lws_context *context) 1100{ 1101 struct lws_context_per_thread *pt; 1102 struct lws *wsi; 1103 int n; 1104 1105 /* 1106 * Create the pt event pipes... these are unique in that they are 1107 * not bound to a vhost or protocol (both are NULL) 1108 */ 1109 1110#if LWS_MAX_SMP > 1 1111 for (n = 0; n < context->count_threads; n++) { 1112#else 1113 n = 0; 1114 { 1115#endif 1116 pt = &context->pt[n]; 1117 1118 if (pt->pipe_wsi) 1119 return 0; 1120 1121 wsi = __lws_wsi_create_with_role(context, n, &role_ops_pipe, 1122 NULL); 1123 if (!wsi) 1124 return 1; 1125 1126 __lws_lc_tag(context, &context->lcg[LWSLCG_WSI], &wsi->lc, 1127 "pipe"); 1128 1129 wsi->event_pipe = 1; 1130 pt->pipe_wsi = wsi; 1131 1132 if (!lws_plat_pipe_create(wsi)) { 1133 /* 1134 * platform code returns 0 if it actually created pipes 1135 * and initialized pt->dummy_pipe_fds[]. If it used 1136 * some other mechanism outside of signaling in the 1137 * normal event loop, we skip treating the pipe as 1138 * related to dummy_pipe_fds[], adding it to the fds, 1139 * etc. 1140 */ 1141 1142 wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0]; 1143 // lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd); 1144 1145 if (lws_wsi_inject_to_loop(pt, wsi)) 1146 goto bail; 1147 } 1148 } 1149 1150 return 0; 1151 1152bail: 1153 1154 return 1; 1155} 1156 1157void 1158lws_destroy_event_pipe(struct lws *wsi) 1159{ 1160 int n; 1161 1162 lwsl_wsi_info(wsi, "in"); 1163 1164 n = lws_wsi_extract_from_loop(wsi); 1165 lws_plat_pipe_close(wsi); 1166 if (!n) 1167 lws_free(wsi); 1168} 1169 1170/* 1171 * Start close process for any wsi bound to this vhost that belong to the 1172 * service thread we are called from. Because of async event lib close, or 1173 * protocol staged close on wsi, latency with pts joining in closing their 1174 * wsi on the vhost, this may take some time. 1175 * 1176 * When the wsi count bound to the vhost (from all pts) drops to zero, the 1177 * vhost destruction will be finalized. 1178 */ 1179 1180void 1181__lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh) 1182{ 1183#if LWS_MAX_SMP > 1 1184 /* calling pt thread has done its wsi dieback */ 1185 int tsi = lws_pthread_self_to_tsi(vh->context); 1186#else 1187 int tsi = 0; 1188#endif 1189 struct lws_context *ctx = vh->context; 1190 struct lws_context_per_thread *pt = &ctx->pt[tsi]; 1191 unsigned int n; 1192 1193#if LWS_MAX_SMP > 1 1194 if (vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)]) 1195 /* this pt has already done its bit */ 1196 return; 1197#endif 1198 1199#if defined(LWS_WITH_CLIENT) 1200 /* 1201 * destroy any wsi that are associated with us but have no socket 1202 * (and will otherwise be missed for destruction) 1203 */ 1204 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1205 vh->vh_awaiting_socket_owner.head) { 1206 struct lws *w = 1207 lws_container_of(d, struct lws, vh_awaiting_socket); 1208 1209 if (w->tsi == tsi) { 1210 1211 lwsl_vhost_debug(vh, "closing aso"); 1212 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, 1213 "awaiting skt"); 1214 } 1215 1216 } lws_end_foreach_dll_safe(d, d1); 1217#endif 1218 1219 /* 1220 * Close any wsi on this pt bound to the vhost 1221 */ 1222 1223 n = 0; 1224 while (n < pt->fds_count) { 1225 struct lws *wsi = wsi_from_fd(ctx, pt->fds[n].fd); 1226 1227 if (wsi && wsi->tsi == tsi && wsi->a.vhost == vh) { 1228 1229 lwsl_wsi_debug(wsi, "pt %d: closin, role %s", tsi, 1230 wsi->role_ops->name); 1231 1232 lws_wsi_close(wsi, LWS_TO_KILL_ASYNC); 1233 1234 if (pt->pipe_wsi == wsi) 1235 pt->pipe_wsi = NULL; 1236 } 1237 n++; 1238 } 1239 1240#if LWS_MAX_SMP > 1 1241 /* calling pt thread has done its wsi dieback */ 1242 vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)] = 1; 1243#endif 1244} 1245 1246#if defined(LWS_WITH_NETWORK) 1247 1248/* returns nonzero if v1 and v2 can share listen sockets */ 1249int 1250lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2) 1251{ 1252 return ((!v1->iface && !v2->iface) || 1253 (v1->iface && v2->iface && !strcmp(v1->iface, v2->iface))) && 1254 v1->listen_port == v2->listen_port; 1255} 1256 1257/* helper to interate every listen socket on any vhost and call cb on it */ 1258int 1259lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg, 1260 lws_dll2_foreach_cb_t cb) 1261{ 1262 struct lws_vhost *v = cx->vhost_list; 1263 int n; 1264 1265 while (v) { 1266 1267 n = lws_dll2_foreach_safe(&v->listen_wsi, arg, cb); 1268 if (n) 1269 return n; 1270 1271 v = v->vhost_next; 1272 } 1273 1274 return 0; 1275} 1276 1277#endif 1278 1279/* 1280 * Mark the vhost as being destroyed, so things trying to use it abort. 1281 * 1282 * Dispose of the listen socket. 1283 */ 1284 1285void 1286lws_vhost_destroy1(struct lws_vhost *vh) 1287{ 1288 struct lws_context *context = vh->context; 1289 int n; 1290 1291 lwsl_vhost_info(vh, "\n"); 1292 1293 lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */ 1294 1295 if (vh->being_destroyed) 1296 goto out; 1297 1298 /* 1299 * let's lock all the pts, to enforce pt->vh order... pt is refcounted 1300 * so it's OK if we acquire it later inside this 1301 */ 1302 1303 for (n = 0; n < context->count_threads; n++) 1304 lws_pt_lock((&context->pt[n]), __func__); 1305 1306 lws_vhost_lock(vh); /* -------------- vh { */ 1307 1308#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_TLS) 1309 lws_tls_session_vh_destroy(vh); 1310#endif 1311 1312 vh->being_destroyed = 1; 1313 lws_dll2_add_tail(&vh->vh_being_destroyed_list, 1314 &context->owner_vh_being_destroyed); 1315 1316#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SERVER) 1317 /* 1318 * PHASE 1: take down or reassign any listen wsi 1319 * 1320 * Are there other vhosts that are piggybacking on our listen sockets? 1321 * If so we need to hand each listen socket off to one of the others 1322 * so it will remain open. 1323 * 1324 * If not, close the listen socket now. 1325 * 1326 * Either way the listen socket response to the vhost close is 1327 * immediately performed. 1328 */ 1329 1330 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1331 lws_dll2_get_head(&vh->listen_wsi)) { 1332 struct lws *wsi = lws_container_of(d, struct lws, listen_list); 1333 1334 /* 1335 * For each of our listen sockets, check every other vhost to 1336 * see if another vhost should be given our listen socket. 1337 * 1338 * ipv4 and ipv6 sockets will both match and be migrated. 1339 */ 1340 1341 lws_start_foreach_ll(struct lws_vhost *, v, 1342 context->vhost_list) { 1343 if (v != vh && !v->being_destroyed && 1344 lws_vhost_compare_listen(v, vh)) { 1345 /* 1346 * this can only be a listen wsi, which is 1347 * restricted... it has no protocol or other 1348 * bindings or states. So we can simply 1349 * swap it to a vhost that has the same 1350 * iface + port, but is not closing. 1351 */ 1352 1353 lwsl_vhost_notice(vh, "listen skt migrate -> %s", 1354 lws_vh_tag(v)); 1355 1356 lws_dll2_remove(&wsi->listen_list); 1357 lws_dll2_add_tail(&wsi->listen_list, 1358 &v->listen_wsi); 1359 1360 /* req cx + vh lock */ 1361 /* 1362 * If the vhost sees it's being destroyed and 1363 * in the unbind the number of wsis bound to 1364 * it falls to zero, it will destroy the 1365 * vhost opportunistically before we can 1366 * complete the transfer. Add a fake wsi 1367 * bind temporarily to disallow this... 1368 */ 1369 v->count_bound_wsi++; 1370 __lws_vhost_unbind_wsi(wsi); 1371 lws_vhost_bind_wsi(v, wsi); 1372 /* 1373 * ... remove the fake wsi bind 1374 */ 1375 v->count_bound_wsi--; 1376 break; 1377 } 1378 } lws_end_foreach_ll(v, vhost_next); 1379 1380 } lws_end_foreach_dll_safe(d, d1); 1381 1382 /* 1383 * If any listen wsi left we couldn't pass to other vhosts, close them 1384 */ 1385 1386 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1387 lws_dll2_get_head(&vh->listen_wsi)) { 1388 struct lws *wsi = lws_container_of(d, struct lws, listen_list); 1389 1390 lws_dll2_remove(&wsi->listen_list); 1391 lws_wsi_close(wsi, LWS_TO_KILL_ASYNC); 1392 1393 } lws_end_foreach_dll_safe(d, d1); 1394 1395#endif 1396#if defined(LWS_WITH_TLS_JIT_TRUST) 1397 lws_sul_cancel(&vh->sul_unref); 1398#endif 1399 1400 lws_vhost_unlock(vh); /* } vh -------------- */ 1401 1402 for (n = 0; n < context->count_threads; n++) 1403 lws_pt_unlock((&context->pt[n])); 1404 1405out: 1406 lws_context_unlock(context); /* --------------------------- context { */ 1407} 1408 1409#if defined(LWS_WITH_ABSTRACT) 1410static int 1411destroy_ais(struct lws_dll2 *d, void *user) 1412{ 1413 lws_abs_t *ai = lws_container_of(d, lws_abs_t, abstract_instances); 1414 1415 lws_abs_destroy_instance(&ai); 1416 1417 return 0; 1418} 1419#endif 1420 1421/* 1422 * Either start close or destroy any wsi on the vhost that belong to this pt, 1423 * if SMP mark the vh that we have done it for 1424 * 1425 * Must not have lock on vh 1426 */ 1427 1428void 1429__lws_vhost_destroy2(struct lws_vhost *vh) 1430{ 1431 const struct lws_protocols *protocol = NULL; 1432 struct lws_context *context = vh->context; 1433 struct lws wsi; 1434 int n; 1435 1436 vh->being_destroyed = 0; 1437 1438 // lwsl_info("%s: %s\n", __func__, vh->name); 1439 1440 /* 1441 * remove ourselves from the defer binding list 1442 */ 1443 lws_start_foreach_llp(struct lws_vhost **, pv, 1444 vh->context->no_listener_vhost_list) { 1445 if (*pv == vh) { 1446 lwsl_debug("deferred iface: removing vh %s\n", 1447 (*pv)->name); 1448 *pv = vh->no_listener_vhost_list; 1449 vh->no_listener_vhost_list = NULL; 1450 break; 1451 } 1452 } lws_end_foreach_llp(pv, no_listener_vhost_list); 1453 1454 /* 1455 * let the protocols destroy the per-vhost protocol objects 1456 */ 1457 1458 memset(&wsi, 0, sizeof(wsi)); 1459 wsi.a.context = vh->context; 1460 wsi.a.vhost = vh; /* not a real bound wsi */ 1461 protocol = vh->protocols; 1462 if (protocol && vh->created_vhost_protocols) { 1463 n = 0; 1464 while (n < vh->count_protocols) { 1465 wsi.a.protocol = protocol; 1466 1467 lwsl_vhost_debug(vh, "protocol destroy"); 1468 1469 if (protocol->callback) 1470 protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY, 1471 NULL, NULL, 0); 1472 protocol++; 1473 n++; 1474 } 1475 } 1476 1477 /* 1478 * remove vhost from context list of vhosts 1479 */ 1480 1481 lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_list) { 1482 if (*pv == vh) { 1483 *pv = vh->vhost_next; 1484 break; 1485 } 1486 } lws_end_foreach_llp(pv, vhost_next); 1487 1488 /* add ourselves to the pending destruction list */ 1489 1490 if (vh->context->vhost_pending_destruction_list != vh) { 1491 vh->vhost_next = vh->context->vhost_pending_destruction_list; 1492 vh->context->vhost_pending_destruction_list = vh; 1493 } 1494 1495 //lwsl_debug("%s: do dfl '%s'\n", __func__, vh->name); 1496 1497 /* remove ourselves from the pending destruction list */ 1498 1499 lws_start_foreach_llp(struct lws_vhost **, pv, 1500 context->vhost_pending_destruction_list) { 1501 if ((*pv) == vh) { 1502 *pv = (*pv)->vhost_next; 1503 break; 1504 } 1505 } lws_end_foreach_llp(pv, vhost_next); 1506 1507 /* 1508 * Free all the allocations associated with the vhost 1509 */ 1510 1511 protocol = vh->protocols; 1512 if (protocol) { 1513 n = 0; 1514 while (n < vh->count_protocols) { 1515 if (vh->protocol_vh_privs && 1516 vh->protocol_vh_privs[n]) { 1517 lws_free(vh->protocol_vh_privs[n]); 1518 vh->protocol_vh_privs[n] = NULL; 1519 } 1520 protocol++; 1521 n++; 1522 } 1523 } 1524 if (vh->protocol_vh_privs) 1525 lws_free(vh->protocol_vh_privs); 1526 lws_ssl_SSL_CTX_destroy(vh); 1527 lws_free(vh->same_vh_protocol_owner); 1528 1529 if ( 1530#if defined(LWS_WITH_PLUGINS) 1531 context->plugin_list || 1532#endif 1533 (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) || 1534 vh->allocated_vhost_protocols) 1535 lws_free((void *)vh->protocols); 1536#if defined(LWS_WITH_NETWORK) 1537 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) 1538 if (lws_rops_fidx(ar, LWS_ROPS_destroy_vhost)) 1539 lws_rops_func_fidx(ar, LWS_ROPS_destroy_vhost). 1540 destroy_vhost(vh); 1541 LWS_FOR_EVERY_AVAILABLE_ROLE_END; 1542#endif 1543 1544#ifdef LWS_WITH_ACCESS_LOG 1545 if (vh->log_fd != (int)LWS_INVALID_FILE) 1546 close(vh->log_fd); 1547#endif 1548 1549#if defined (LWS_WITH_TLS) 1550 lws_free_set_NULL(vh->tls.alloc_cert_path); 1551#endif 1552 1553#if LWS_MAX_SMP > 1 1554 lws_mutex_refcount_destroy(&vh->mr); 1555#endif 1556 1557#if defined(LWS_WITH_UNIX_SOCK) 1558 if (LWS_UNIX_SOCK_ENABLED(vh)) { 1559 n = unlink(vh->iface); 1560 if (n) 1561 lwsl_vhost_info(vh, "Closing unix socket %s: errno %d\n", 1562 vh->iface, errno); 1563 } 1564#endif 1565 /* 1566 * although async event callbacks may still come for wsi handles with 1567 * pending close in the case of asycn event library like libuv, 1568 * they do not refer to the vhost. So it's safe to free. 1569 */ 1570 1571 if (vh->finalize) 1572 vh->finalize(vh, vh->finalize_arg); 1573 1574#if defined(LWS_WITH_ABSTRACT) 1575 /* 1576 * abstract instances 1577 */ 1578 1579 lws_dll2_foreach_safe(&vh->abstract_instances_owner, NULL, destroy_ais); 1580#endif 1581 1582#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SYS_METRICS) 1583 lws_metric_destroy(&vh->mt_traffic_rx, 0); 1584 lws_metric_destroy(&vh->mt_traffic_tx, 0); 1585#endif 1586 1587 lws_dll2_remove(&vh->vh_being_destroyed_list); 1588 1589#if defined(LWS_WITH_SYS_FAULT_INJECTION) 1590 lws_fi_destroy(&vh->fic); 1591#endif 1592#if defined(LWS_WITH_TLS_JIT_TRUST) 1593 lws_sul_cancel(&vh->sul_unref); 1594#endif 1595 1596 __lws_lc_untag(vh->context, &vh->lc); 1597 1598 memset(vh, 0, sizeof(*vh)); 1599 lws_free(vh); 1600} 1601 1602/* 1603 * Starts the vhost destroy process 1604 * 1605 * Vhosts are not simple to deal with because they are an abstraction that 1606 * crosses SMP thread boundaries, a wsi on any pt can bind to any vhost. If we 1607 * want another pt to do something to its wsis safely, we have to asynchronously 1608 * ask it to do it. 1609 * 1610 * In addition, with event libs, closing any handles (which are bound to vhosts 1611 * in their wsi) can happens asynchronously, so we can't just linearly do some 1612 * cleanup flow and free it in one step. 1613 * 1614 * The vhost destroy is cut into two pieces: 1615 * 1616 * 1) dispose of the listen socket, either by passing it on to another vhost 1617 * that was already sharing it, or just closing it. 1618 * 1619 * If any wsi bound to the vhost, mark the vhost as in the process of being 1620 * destroyed, triggering each pt to close all wsi bound to the vhost next 1621 * time around the event loop. Call lws_cancel_service() so all the pts wake 1622 * to deal with this without long poll waits making delays. 1623 * 1624 * 2) When the number of wsis bound to the vhost reaches zero, do the final 1625 * vhost destroy flow, this can be triggered from any pt. 1626 */ 1627 1628void 1629lws_vhost_destroy(struct lws_vhost *vh) 1630{ 1631 struct lws_context *context = vh->context; 1632 1633 lws_context_lock(context, __func__); /* ------ context { */ 1634 1635 /* dispose of the listen socket one way or another */ 1636 lws_vhost_destroy1(vh); 1637 1638 /* start async closure of all wsi on this pt thread attached to vh */ 1639 __lws_vhost_destroy_pt_wsi_dieback_start(vh); 1640 1641 lwsl_vhost_info(vh, "count_bound_wsi %d", vh->count_bound_wsi); 1642 1643 /* if there are none, finalize now since no further chance */ 1644 if (!vh->count_bound_wsi) { 1645 __lws_vhost_destroy2(vh); 1646 1647 goto out; 1648 } 1649 1650 /* 1651 * We have some wsi bound to this vhost, we have to wait for these to 1652 * complete close and unbind before progressing the vhost removal. 1653 * 1654 * When the last bound wsi on this vh is destroyed we will auto-call 1655 * __lws_vhost_destroy2() to finalize vh destruction 1656 */ 1657 1658#if LWS_MAX_SMP > 1 1659 /* alert other pts they also need to do dieback flow for their wsi */ 1660 lws_cancel_service(context); 1661#endif 1662 1663out: 1664 lws_context_unlock(context); /* } context ------------------- */ 1665} 1666 1667 1668void * 1669lws_vhost_user(struct lws_vhost *vhost) 1670{ 1671 return vhost->user; 1672} 1673 1674int 1675lws_get_vhost_listen_port(struct lws_vhost *vhost) 1676{ 1677 return vhost->listen_port; 1678} 1679 1680#if defined(LWS_WITH_SERVER) 1681void 1682lws_context_deprecate(struct lws_context *cx, lws_reload_func cb) 1683{ 1684 struct lws_vhost *vh = cx->vhost_list; 1685 1686 /* 1687 * "deprecation" means disable the cx from accepting any new 1688 * connections and free up listen sockets to be used by a replacement 1689 * cx. 1690 * 1691 * Otherwise the deprecated cx remains operational, until its 1692 * number of connected sockets falls to zero, when it is deleted. 1693 * 1694 * So, for each vhost, close his listen sockets 1695 */ 1696 1697 while (vh) { 1698 1699 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1700 lws_dll2_get_head(&vh->listen_wsi)) { 1701 struct lws *wsi = lws_container_of(d, struct lws, 1702 listen_list); 1703 1704 wsi->socket_is_permanently_unusable = 1; 1705 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 1706 __func__); 1707 cx->deprecation_pending_listen_close_count++; 1708 1709 } lws_end_foreach_dll_safe(d, d1); 1710 1711 vh = vh->vhost_next; 1712 } 1713 1714 cx->deprecated = 1; 1715 cx->deprecation_cb = cb; 1716} 1717#endif 1718 1719#if defined(LWS_WITH_NETWORK) 1720 1721struct lws_vhost * 1722lws_get_vhost_by_name(struct lws_context *context, const char *name) 1723{ 1724 lws_start_foreach_ll(struct lws_vhost *, v, 1725 context->vhost_list) { 1726 if (!v->being_destroyed && !strcmp(v->name, name)) 1727 return v; 1728 1729 } lws_end_foreach_ll(v, vhost_next); 1730 1731 return NULL; 1732} 1733 1734 1735#if defined(LWS_WITH_CLIENT) 1736/* 1737 * This is the logic checking to see if the new connection wsi should have a 1738 * pipelining or muxing relationship with an existing "active connection" to 1739 * the same endpoint under the same conditions. 1740 * 1741 * This was originally in the client code but since the list is held on the 1742 * vhost (to ensure the same client tls ctx is involved) it's cleaner in vhost.c 1743 * 1744 * ACTIVE_CONNS_QUEUED: We're queued on an active connection, set *nwsi to that 1745 * ACTIVE_CONNS_MUXED: We are joining an active mux conn *nwsi as a child 1746 * ACTIVE_CONNS_SOLO: There's no existing conn to join either way 1747 */ 1748 1749int 1750lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin) 1751{ 1752#if defined(LWS_WITH_TLS) 1753 const char *my_alpn = lws_wsi_client_stash_item(wsi, CIS_ALPN, 1754 _WSI_TOKEN_CLIENT_ALPN); 1755#endif 1756#if defined(LWS_WITH_TLS) 1757 char newconn_cannot_use_h1 = 0; 1758 1759 if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && 1760 my_alpn && !strstr(my_alpn, "http/1.1")) 1761 /* 1762 * new guy wants to use tls, he specifies the alpn and he does 1763 * not list h1 as a choice ==> he can't bind to existing h1 1764 */ 1765 newconn_cannot_use_h1 = 1; 1766#endif 1767 1768 if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) { 1769 struct lws *w = lws_container_of( 1770 wsi->dll2_cli_txn_queue.owner, struct lws, 1771 dll2_cli_txn_queue_owner); 1772 *nwsi = w; 1773 1774 return ACTIVE_CONNS_QUEUED; 1775 } 1776 1777#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) 1778 if (wsi->mux.parent_wsi) { 1779 /* 1780 * We already decided... 1781 */ 1782 1783 *nwsi = wsi->mux.parent_wsi; 1784 1785 return ACTIVE_CONNS_MUXED; 1786 } 1787#endif 1788 1789 lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */ 1790 lws_vhost_lock(wsi->a.vhost); /* ----------------------------------- { */ 1791 1792 lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 1793 wsi->a.vhost->dll_cli_active_conns_owner.head) { 1794 struct lws *w = lws_container_of(d, struct lws, 1795 dll_cli_active_conns); 1796 1797 lwsl_wsi_debug(wsi, "check %s %s %s %d %d", 1798 lws_wsi_tag(w), adsin, 1799 w->cli_hostname_copy ? w->cli_hostname_copy : 1800 "null", 1801 wsi->c_port, w->c_port); 1802 1803 if (w != wsi && 1804 /* 1805 * "same internet protocol"... this is a bit tricky, 1806 * since h2 start out as h1, and may stay at h1. 1807 * 1808 * But an idle h1 connection cannot be used by a connection 1809 * request that doesn't have http/1.1 in its alpn list... 1810 */ 1811 (w->role_ops == wsi->role_ops || 1812 (lwsi_role_http(w) && lwsi_role_http(wsi))) && 1813 /* ... same role, or at least both some kind of http */ 1814 w->cli_hostname_copy && !strcmp(adsin, w->cli_hostname_copy) && 1815 /* same endpoint hostname */ 1816#if defined(LWS_WITH_TLS) 1817 !(newconn_cannot_use_h1 && w->role_ops == &role_ops_h1) && 1818 /* if we can't use h1, old guy must not be h1 */ 1819 (wsi->tls.use_ssl & LCCSCF_USE_SSL) == 1820 (w->tls.use_ssl & LCCSCF_USE_SSL) && 1821 /* must both agree on tls use or not */ 1822#endif 1823 wsi->c_port == w->c_port) { 1824 /* same endpoint port */ 1825 1826 /* 1827 * There's already an active connection. 1828 * 1829 * The server may have told the existing active 1830 * connection that it doesn't support pipelining... 1831 */ 1832 if (w->keepalive_rejected) { 1833 lwsl_wsi_notice(w, "defeating pipelining"); 1834 goto solo; 1835 } 1836 1837#if defined(LWS_WITH_HTTP2) 1838 /* 1839 * h2: if in usable state already: just use it without 1840 * going through the queue 1841 */ 1842 if (w->client_h2_alpn && w->client_mux_migrated && 1843 (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS || 1844 lwsi_state(w) == LRS_ESTABLISHED || 1845 lwsi_state(w) == LRS_IDLING)) { 1846 1847 lwsl_wsi_notice(w, "just join h2 directly 0x%x", 1848 lwsi_state(w)); 1849 1850 if (lwsi_state(w) == LRS_IDLING) 1851 _lws_generic_transaction_completed_active_conn(&w, 0); 1852 1853 //lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2); 1854 1855 wsi->client_h2_alpn = 1; 1856 lws_wsi_h2_adopt(w, wsi); 1857 lws_vhost_unlock(wsi->a.vhost); /* } ---------- */ 1858 lws_context_unlock(wsi->a.context); /* -------------- cx { */ 1859 1860 *nwsi = w; 1861 1862 return ACTIVE_CONNS_MUXED; 1863 } 1864#endif 1865 1866#if defined(LWS_ROLE_MQTT) 1867 /* 1868 * MQTT: if in usable state already: just use it without 1869 * going through the queue 1870 */ 1871 1872 if (lwsi_role_mqtt(wsi) && w->client_mux_migrated && 1873 lwsi_state(w) == LRS_ESTABLISHED) { 1874 1875 if (lws_wsi_mqtt_adopt(w, wsi)) { 1876 lwsl_wsi_notice(w, "join mqtt directly"); 1877 lws_dll2_remove(&wsi->dll2_cli_txn_queue); 1878 wsi->client_mux_substream = 1; 1879 1880 lws_vhost_unlock(wsi->a.vhost); /* } ---------- */ 1881 lws_context_unlock(wsi->a.context); /* -------------- cx { */ 1882 1883 return ACTIVE_CONNS_MUXED; 1884 } 1885 } 1886#endif 1887 1888 /* 1889 * If the connection is viable but not yet in a usable 1890 * state, let's attach ourselves to it and wait for it 1891 * to get there or fail. 1892 */ 1893 1894 lwsl_wsi_notice(wsi, "apply txn queue %s, state 0x%lx", 1895 lws_wsi_tag(w), 1896 (unsigned long)w->wsistate); 1897 /* 1898 * ...let's add ourselves to his transaction queue... 1899 * we are adding ourselves at the TAIL 1900 */ 1901 lws_dll2_add_tail(&wsi->dll2_cli_txn_queue, 1902 &w->dll2_cli_txn_queue_owner); 1903 1904 if (lwsi_state(w) == LRS_IDLING) 1905 _lws_generic_transaction_completed_active_conn(&w, 0); 1906 1907 /* 1908 * For eg, h1 next we'd pipeline our headers out on him, 1909 * and wait for our turn at client transaction_complete 1910 * to take over parsing the rx. 1911 */ 1912 lws_vhost_unlock(wsi->a.vhost); /* } ---------- */ 1913 lws_context_unlock(wsi->a.context); /* -------------- cx { */ 1914 1915 *nwsi = w; 1916 1917 return ACTIVE_CONNS_QUEUED; 1918 } 1919 1920 } lws_end_foreach_dll_safe(d, d1); 1921 1922solo: 1923 lws_vhost_unlock(wsi->a.vhost); /* } ---------------------------------- */ 1924 lws_context_unlock(wsi->a.context); /* -------------- cx { */ 1925 1926 /* there is nobody already connected in the same way */ 1927 1928 return ACTIVE_CONNS_SOLO; 1929} 1930#endif 1931#endif 1932 1933const char * 1934lws_vh_tag(struct lws_vhost *vh) 1935{ 1936 return lws_lc_tag(&vh->lc); 1937} 1938 1939struct lws_log_cx * 1940lwsl_vhost_get_cx(struct lws_vhost *vh) 1941{ 1942 if (!vh) 1943 return NULL; 1944 1945 return vh->lc.log_cx; 1946} 1947 1948void 1949lws_log_prepend_vhost(struct lws_log_cx *cx, void *obj, char **p, char *e) 1950{ 1951 struct lws_vhost *vh = (struct lws_vhost *)obj; 1952 1953 *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ", 1954 lws_vh_tag(vh)); 1955} 1956