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