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