• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 const struct lws_role_ops *available_roles[] = {
28 #if defined(LWS_ROLE_H2)
29 	&role_ops_h2,
30 #endif
31 #if defined(LWS_ROLE_H1)
32 	&role_ops_h1,
33 #endif
34 #if defined(LWS_ROLE_WS)
35 	&role_ops_ws,
36 #endif
37 #if defined(LWS_ROLE_DBUS)
38 	&role_ops_dbus,
39 #endif
40 #if defined(LWS_ROLE_RAW_PROXY)
41 	&role_ops_raw_proxy,
42 #endif
43 #if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
44 	&role_ops_mqtt,
45 #endif
46 	NULL
47 };
48 
49 const struct lws_event_loop_ops *available_event_libs[] = {
50 #if defined(LWS_WITH_POLL)
51 	&event_loop_ops_poll,
52 #endif
53 #if defined(LWS_WITH_LIBUV)
54 	&event_loop_ops_uv,
55 #endif
56 #if defined(LWS_WITH_LIBEVENT)
57 	&event_loop_ops_event,
58 #endif
59 #if defined(LWS_WITH_LIBEV)
60 	&event_loop_ops_ev,
61 #endif
62 	NULL
63 };
64 
65 #if defined(LWS_WITH_ABSTRACT)
66 const struct lws_protocols *available_abstract_protocols[] = {
67 #if defined(LWS_ROLE_RAW)
68 	&protocol_abs_client_raw_skt,
69 #endif
70 	NULL
71 };
72 #endif
73 
74 #if defined(LWS_WITH_SECURE_STREAMS)
75 const struct lws_protocols *available_secstream_protocols[] = {
76 #if defined(LWS_ROLE_H1)
77 	&protocol_secstream_h1,
78 #endif
79 #if defined(LWS_ROLE_H2)
80 	&protocol_secstream_h2,
81 #endif
82 #if defined(LWS_ROLE_WS)
83 	&protocol_secstream_ws,
84 #endif
85 #if defined(LWS_ROLE_MQTT)
86 	&protocol_secstream_mqtt,
87 #endif
88 	NULL
89 };
90 #endif
91 
92 static const char * const mount_protocols[] = {
93 	"http://",
94 	"https://",
95 	"file://",
96 	"cgi://",
97 	">http://",
98 	">https://",
99 	"callback://"
100 };
101 
102 const struct lws_role_ops *
lws_role_by_name(const char * name)103 lws_role_by_name(const char *name)
104 {
105 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
106 		if (!strcmp(ar->name, name))
107 			return ar;
108 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
109 
110 	if (!strcmp(name, role_ops_raw_skt.name))
111 		return &role_ops_raw_skt;
112 
113 #if defined(LWS_ROLE_RAW_FILE)
114 	if (!strcmp(name, role_ops_raw_file.name))
115 		return &role_ops_raw_file;
116 #endif
117 
118 	return NULL;
119 }
120 
121 int
lws_role_call_alpn_negotiated(struct lws * wsi,const char * alpn)122 lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
123 {
124 #if defined(LWS_WITH_TLS)
125 	if (!alpn)
126 		return 0;
127 
128 	lwsl_info("%s: '%s'\n", __func__, alpn);
129 
130 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
131 		if (ar->alpn && !strcmp(ar->alpn, alpn) && ar->alpn_negotiated)
132 			return ar->alpn_negotiated(wsi, alpn);
133 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
134 #endif
135 	return 0;
136 }
137 
138 int
lws_role_call_adoption_bind(struct lws * wsi,int type,const char * prot)139 lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
140 {
141 	int n;
142 
143 	/*
144 	 * if the vhost is told to bind accepted sockets to a given role,
145 	 * then look it up by name and try to bind to the specific role.
146 	 */
147 	if (lws_check_opt(wsi->vhost->options,
148 			  LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG) &&
149 	    wsi->vhost->listen_accept_role) {
150 		const struct lws_role_ops *role =
151 			lws_role_by_name(wsi->vhost->listen_accept_role);
152 
153 		if (!prot)
154 			prot = wsi->vhost->listen_accept_protocol;
155 
156 		if (!role)
157 			lwsl_err("%s: can't find role '%s'\n", __func__,
158 				  wsi->vhost->listen_accept_role);
159 
160 		if (role && role->adoption_bind) {
161 			n = role->adoption_bind(wsi, type, prot);
162 			if (n < 0)
163 				return -1;
164 			if (n) /* did the bind */
165 				return 0;
166 		}
167 
168 		if (type & _LWS_ADOPT_FINISH) {
169 			lwsl_debug("%s: leaving bound to role %s\n", __func__,
170 				   wsi->role_ops->name);
171 			return 0;
172 		}
173 
174 
175 		lwsl_warn("%s: adoption bind to role '%s', "
176 			  "protocol '%s', type 0x%x, failed\n", __func__,
177 			  wsi->vhost->listen_accept_role, prot, type);
178 	}
179 
180 	/*
181 	 * Otherwise ask each of the roles in order of preference if they
182 	 * want to bind to this accepted socket
183 	 */
184 
185 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
186 		if (ar->adoption_bind && ar->adoption_bind(wsi, type, prot))
187 			return 0;
188 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
189 
190 	/* fall back to raw socket role if, eg, h1 not configured */
191 
192 	if (role_ops_raw_skt.adoption_bind &&
193 	    role_ops_raw_skt.adoption_bind(wsi, type, prot))
194 		return 0;
195 
196 #if defined(LWS_ROLE_RAW_FILE)
197 
198 	/* fall back to raw file role if, eg, h1 not configured */
199 
200 	if (role_ops_raw_file.adoption_bind &&
201 	    role_ops_raw_file.adoption_bind(wsi, type, prot))
202 		return 0;
203 #endif
204 
205 	return 1;
206 }
207 
208 #if defined(LWS_WITH_CLIENT)
209 int
lws_role_call_client_bind(struct lws * wsi,const struct lws_client_connect_info * i)210 lws_role_call_client_bind(struct lws *wsi,
211 			  const struct lws_client_connect_info *i)
212 {
213 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
214 		if (ar->client_bind) {
215 			int m = ar->client_bind(wsi, i);
216 			if (m < 0)
217 				return m;
218 			if (m)
219 				return 0;
220 		}
221 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
222 
223 	/* fall back to raw socket role if, eg, h1 not configured */
224 
225 	if (role_ops_raw_skt.client_bind &&
226 	    role_ops_raw_skt.client_bind(wsi, i))
227 		return 0;
228 
229 	return 1;
230 }
231 #endif
232 
233 void *
lws_protocol_vh_priv_zalloc(struct lws_vhost * vhost,const struct lws_protocols * prot,int size)234 lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
235 			    const struct lws_protocols *prot, int size)
236 {
237 	int n = 0;
238 
239 	/* allocate the vh priv array only on demand */
240 	if (!vhost->protocol_vh_privs) {
241 		vhost->protocol_vh_privs = (void **)lws_zalloc(
242 				vhost->count_protocols * sizeof(void *),
243 				"protocol_vh_privs");
244 		if (!vhost->protocol_vh_privs)
245 			return NULL;
246 	}
247 
248 	while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
249 		n++;
250 
251 	if (n == vhost->count_protocols) {
252 		n = 0;
253 		while (n < vhost->count_protocols &&
254 		       strcmp(vhost->protocols[n].name, prot->name))
255 			n++;
256 
257 		if (n == vhost->count_protocols)
258 			return NULL;
259 	}
260 
261 	vhost->protocol_vh_privs[n] = lws_zalloc(size, "vh priv");
262 	return vhost->protocol_vh_privs[n];
263 }
264 
265 void *
lws_protocol_vh_priv_get(struct lws_vhost * vhost,const struct lws_protocols * prot)266 lws_protocol_vh_priv_get(struct lws_vhost *vhost,
267 			 const struct lws_protocols *prot)
268 {
269 	int n = 0;
270 
271 	if (!vhost || !vhost->protocol_vh_privs || !prot)
272 		return NULL;
273 
274 	while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
275 		n++;
276 
277 	if (n == vhost->count_protocols) {
278 		n = 0;
279 		while (n < vhost->count_protocols &&
280 		       strcmp(vhost->protocols[n].name, prot->name))
281 			n++;
282 
283 		if (n == vhost->count_protocols) {
284 			lwsl_err("%s: unknown protocol %p\n", __func__, prot);
285 			return NULL;
286 		}
287 	}
288 
289 	return vhost->protocol_vh_privs[n];
290 }
291 
292 const struct lws_protocol_vhost_options *
lws_vhost_protocol_options(struct lws_vhost * vh,const char * name)293 lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
294 {
295 	const struct lws_protocol_vhost_options *pvo = vh->pvo;
296 
297 	if (!name)
298 		return NULL;
299 
300 	while (pvo) {
301 		if (!strcmp(pvo->name, name))
302 			return pvo;
303 		pvo = pvo->next;
304 	}
305 
306 	return NULL;
307 }
308 
309 int
lws_protocol_init_vhost(struct lws_vhost * vh,int * any)310 lws_protocol_init_vhost(struct lws_vhost *vh, int *any)
311 {
312 	const struct lws_protocol_vhost_options *pvo, *pvo1;
313 	struct lws *wsi = vh->context->pt[0].fake_wsi;
314 	int n;
315 
316 	wsi->context = vh->context;
317 	wsi->vhost = vh;
318 
319 	/* initialize supported protocols on this vhost */
320 
321 	for (n = 0; n < vh->count_protocols; n++) {
322 		wsi->protocol = &vh->protocols[n];
323 		if (!vh->protocols[n].name)
324 			continue;
325 		pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
326 		if (pvo) {
327 			/*
328 			 * linked list of options specific to
329 			 * vh + protocol
330 			 */
331 			pvo1 = pvo;
332 			pvo = pvo1->options;
333 
334 			while (pvo) {
335 				lwsl_debug(
336 					"    vhost \"%s\", "
337 					"protocol \"%s\", "
338 					"option \"%s\"\n",
339 						vh->name,
340 						vh->protocols[n].name,
341 						pvo->name);
342 
343 				if (!strcmp(pvo->name, "default")) {
344 					lwsl_info("Setting default "
345 					   "protocol for vh %s to %s\n",
346 					   vh->name,
347 					   vh->protocols[n].name);
348 					vh->default_protocol_index = n;
349 				}
350 				if (!strcmp(pvo->name, "raw")) {
351 					lwsl_info("Setting raw "
352 					   "protocol for vh %s to %s\n",
353 					   vh->name,
354 					   vh->protocols[n].name);
355 					vh->raw_protocol_index = n;
356 				}
357 				pvo = pvo->next;
358 			}
359 
360 			pvo = pvo1->options;
361 		}
362 
363 #if defined(LWS_WITH_TLS)
364 		if (any)
365 			*any |= !!vh->tls.ssl_ctx;
366 #endif
367 
368 		/*
369 		 * inform all the protocols that they are doing their
370 		 * one-time initialization if they want to.
371 		 *
372 		 * NOTE the wsi is all zeros except for the context, vh
373 		 * + protocol ptrs so lws_get_context(wsi) etc can work
374 		 */
375 		if (vh->protocols[n].callback(wsi,
376 				LWS_CALLBACK_PROTOCOL_INIT, NULL,
377 				(void *)pvo, 0)) {
378 			if (vh->protocol_vh_privs[n]) {
379 				lws_free(vh->protocol_vh_privs[n]);
380 				vh->protocol_vh_privs[n] = NULL;
381 			}
382 			lwsl_err("%s: protocol %s failed init\n",
383 				 __func__, vh->protocols[n].name);
384 
385 			return 1;
386 		}
387 	}
388 
389 	vh->created_vhost_protocols = 1;
390 
391 	return 0;
392 }
393 
394 /*
395  * inform every vhost that hasn't already done it, that
396  * his protocols are initializing
397  */
398 int
lws_protocol_init(struct lws_context * context)399 lws_protocol_init(struct lws_context *context)
400 {
401 	struct lws_vhost *vh = context->vhost_list;
402 	int any = 0;
403 
404 	if (context->doing_protocol_init)
405 		return 0;
406 
407 	context->doing_protocol_init = 1;
408 
409 	lwsl_info("%s\n", __func__);
410 
411 	while (vh) {
412 
413 		/* only do the protocol init once for a given vhost */
414 		if (vh->created_vhost_protocols ||
415 		    (lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT)))
416 			goto next;
417 
418 		if (lws_protocol_init_vhost(vh, &any))
419 			return 1;
420 next:
421 		vh = vh->vhost_next;
422 	}
423 
424 	context->doing_protocol_init = 0;
425 
426 	if (!context->protocol_init_done && lws_finalize_startup(context))
427 		return 1;
428 
429 	context->protocol_init_done = 1;
430 
431 #if defined(LWS_WITH_SERVER)
432 	if (any)
433 		lws_tls_check_all_cert_lifetimes(context);
434 #endif
435 
436 	return 0;
437 }
438 
439 
440 /* list of supported protocols and callbacks */
441 
442 static const struct lws_protocols protocols_dummy[] = {
443 	/* first protocol must always be HTTP handler */
444 
445 	{
446 		"http-only",			/* name */
447 		lws_callback_http_dummy,	/* callback */
448 		0,				/* per_session_data_size */
449 		0,				/* rx_buffer_size */
450 		0,				/* id */
451 		NULL,				/* user */
452 		0				/* tx_packet_size */
453 	},
454 	/*
455 	 * the other protocols are provided by lws plugins
456 	 */
457 	{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
458 };
459 
460 
461 #ifdef LWS_PLAT_OPTEE
462 #undef LWS_HAVE_GETENV
463 #endif
464 
465 struct lws_vhost *
lws_create_vhost(struct lws_context * context,const struct lws_context_creation_info * info)466 lws_create_vhost(struct lws_context *context,
467 		 const struct lws_context_creation_info *info)
468 {
469 	struct lws_vhost *vh = lws_zalloc(sizeof(*vh), "create vhost"),
470 			 **vh1 = &context->vhost_list;
471 	const struct lws_http_mount *mounts;
472 	const struct lws_protocols *pcols = info->protocols;
473 #ifdef LWS_WITH_PLUGINS
474 	struct lws_plugin *plugin = context->plugin_list;
475 #endif
476 	struct lws_protocols *lwsp;
477 	int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0;
478 	char buf[96];
479 #if ((defined(LWS_CLIENT_HTTP_PROXYING) && defined(LWS_WITH_CLIENT)) \
480 		|| defined(LWS_WITH_SOCKS5)) && defined(LWS_HAVE_GETENV)
481 	char *p;
482 #endif
483 #if defined(LWS_WITH_SYS_ASYNC_DNS)
484 	extern struct lws_protocols lws_async_dns_protocol;
485 #endif
486 	int n;
487 
488 	if (!vh)
489 		return NULL;
490 
491 #if LWS_MAX_SMP > 1
492 	pthread_mutex_init(&vh->lock, NULL);
493 #endif
494 
495 	if (!pcols && !info->pprotocols)
496 		pcols = &protocols_dummy[0];
497 
498 	vh->context = context;
499 	if (!info->vhost_name)
500 		vh->name = "default";
501 	else
502 		vh->name = info->vhost_name;
503 
504 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
505 	vh->http.error_document_404 = info->error_document_404;
506 #endif
507 
508 	if (lws_check_opt(info->options, LWS_SERVER_OPTION_ONLY_RAW))
509 		lwsl_info("%s set to only support RAW\n", vh->name);
510 
511 	vh->iface = info->iface;
512 #if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
513 	vh->bind_iface = info->bind_iface;
514 #endif
515 	/* apply the context default lws_retry */
516 
517 	if (info->retry_and_idle_policy)
518 		vh->retry_policy = info->retry_and_idle_policy;
519 	else
520 		vh->retry_policy = &context->default_retry;
521 
522 	/*
523 	 * let's figure out how many protocols the user is handing us, using the
524 	 * old or new way depending on what he gave us
525 	 */
526 
527 	if (!pcols)
528 		for (vh->count_protocols = 0;
529 			info->pprotocols[vh->count_protocols];
530 			vh->count_protocols++)
531 			;
532 	else
533 		for (vh->count_protocols = 0;
534 			pcols[vh->count_protocols].callback;
535 			vh->count_protocols++)
536 				;
537 
538 	vh->options = info->options;
539 	vh->pvo = info->pvo;
540 	vh->headers = info->headers;
541 	vh->user = info->user;
542 	vh->finalize = info->finalize;
543 	vh->finalize_arg = info->finalize_arg;
544 	vh->listen_accept_role = info->listen_accept_role;
545 	vh->listen_accept_protocol = info->listen_accept_protocol;
546 	vh->unix_socket_perms = info->unix_socket_perms;
547 
548 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
549 		if (ar->init_vhost)
550 			if (ar->init_vhost(vh, info))
551 				return NULL;
552 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
553 
554 
555 	if (info->keepalive_timeout)
556 		vh->keepalive_timeout = info->keepalive_timeout;
557 	else
558 		vh->keepalive_timeout = 5;
559 
560 	if (info->timeout_secs_ah_idle)
561 		vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
562 	else
563 		vh->timeout_secs_ah_idle = 10;
564 
565 #if defined(LWS_WITH_TLS)
566 
567 	vh->tls.alpn = info->alpn;
568 	vh->tls.ssl_info_event_mask = info->ssl_info_event_mask;
569 
570 	if (info->ecdh_curve)
571 		lws_strncpy(vh->tls.ecdh_curve, info->ecdh_curve,
572 			    sizeof(vh->tls.ecdh_curve));
573 
574 	/* carefully allocate and take a copy of cert + key paths if present */
575 	n = 0;
576 	if (info->ssl_cert_filepath)
577 		n += (int)strlen(info->ssl_cert_filepath) + 1;
578 	if (info->ssl_private_key_filepath)
579 		n += (int)strlen(info->ssl_private_key_filepath) + 1;
580 
581 	if (n) {
582 		vh->tls.key_path = vh->tls.alloc_cert_path =
583 					lws_malloc(n, "vh paths");
584 		if (info->ssl_cert_filepath) {
585 			n = (int)strlen(info->ssl_cert_filepath) + 1;
586 			memcpy(vh->tls.alloc_cert_path,
587 			       info->ssl_cert_filepath, n);
588 			vh->tls.key_path += n;
589 		}
590 		if (info->ssl_private_key_filepath)
591 			memcpy(vh->tls.key_path, info->ssl_private_key_filepath,
592 			       strlen(info->ssl_private_key_filepath) + 1);
593 	}
594 #endif
595 
596 #if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
597 	fx = 1;
598 #endif
599 #if defined(LWS_WITH_ABSTRACT)
600 	abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1;
601 #endif
602 #if defined(LWS_WITH_SECURE_STREAMS)
603 	sec_pcol_count = (int)LWS_ARRAY_SIZE(available_secstream_protocols) - 1;
604 #endif
605 
606 	/*
607 	 * give the vhost a unified list of protocols including:
608 	 *
609 	 * - internal, async_dns if enabled (first vhost only)
610 	 * - internal, abstracted ones
611 	 * - the ones that came from plugins
612 	 * - his user protocols
613 	 */
614 	lwsp = lws_zalloc(sizeof(struct lws_protocols) *
615 				(vh->count_protocols +
616 				   abs_pcol_count + sec_pcol_count +
617 				   context->plugin_protocol_count +
618 				   fx + 1),
619 			  "vhost-specific plugin table");
620 	if (!lwsp) {
621 		lwsl_err("OOM\n");
622 		return NULL;
623 	}
624 
625 	/*
626 	 * 1: user protocols (from pprotocols or protocols)
627 	 */
628 
629 	m = vh->count_protocols;
630 	if (!pcols) {
631 		for (n = 0; n < m; n++)
632 			memcpy(&lwsp[n], info->pprotocols[n], sizeof(lwsp[0]));
633 	} else
634 		memcpy(lwsp, pcols, sizeof(struct lws_protocols) * m);
635 
636 	/*
637 	 * 2: abstract protocols
638 	 */
639 #if defined(LWS_WITH_ABSTRACT)
640 	for (n = 0; n < abs_pcol_count; n++) {
641 		memcpy(&lwsp[m++], available_abstract_protocols[n],
642 		       sizeof(*lwsp));
643 		vh->count_protocols++;
644 	}
645 #endif
646 	/*
647 	 * 3: async dns protocol (first vhost only)
648 	 */
649 #if defined(LWS_WITH_SYS_ASYNC_DNS)
650 	if (!context->vhost_list) {
651 		memcpy(&lwsp[m++], &lws_async_dns_protocol,
652 		       sizeof(struct lws_protocols));
653 		vh->count_protocols++;
654 	}
655 #endif
656 
657 #if defined(LWS_WITH_SECURE_STREAMS)
658 	for (n = 0; n < sec_pcol_count; n++) {
659 		memcpy(&lwsp[m++], available_secstream_protocols[n],
660 		       sizeof(*lwsp));
661 		vh->count_protocols++;
662 	}
663 #endif
664 
665 	/*
666 	 * 3: For compatibility, all protocols enabled on vhost if only
667 	 * the default vhost exists.  Otherwise only vhosts who ask
668 	 * for a protocol get it enabled.
669 	 */
670 
671 	if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
672 		f = 0;
673 	(void)f;
674 #ifdef LWS_WITH_PLUGINS
675 	if (plugin) {
676 		while (plugin) {
677 			for (n = 0; n < plugin->caps.count_protocols; n++) {
678 				/*
679 				 * for compatibility's sake, no pvo implies
680 				 * allow all protocols
681 				 */
682 				if (f || lws_vhost_protocol_options(vh,
683 				    plugin->caps.protocols[n].name)) {
684 					memcpy(&lwsp[m],
685 					       &plugin->caps.protocols[n],
686 					       sizeof(struct lws_protocols));
687 					m++;
688 					vh->count_protocols++;
689 				}
690 			}
691 			plugin = plugin->list;
692 		}
693 	}
694 #endif
695 
696 #if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
697 	memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(*lwsp));
698 	vh->count_protocols++;
699 #endif
700 
701 	vh->protocols = lwsp;
702 	vh->allocated_vhost_protocols = 1;
703 
704 	vh->same_vh_protocol_owner = (struct lws_dll2_owner *)
705 			lws_zalloc(sizeof(struct lws_dll2_owner) *
706 				   vh->count_protocols, "same vh list");
707 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
708 	vh->http.mount_list = info->mounts;
709 #endif
710 
711 #ifdef LWS_WITH_UNIX_SOCK
712 	if (LWS_UNIX_SOCK_ENABLED(vh)) {
713 		lwsl_info("Creating Vhost '%s' path \"%s\", %d protocols\n",
714 				vh->name, vh->iface, vh->count_protocols);
715 	} else
716 #endif
717 	{
718 		switch(info->port) {
719 		case CONTEXT_PORT_NO_LISTEN:
720 			strcpy(buf, "(serving disabled)");
721 			break;
722 		case CONTEXT_PORT_NO_LISTEN_SERVER:
723 			strcpy(buf, "(no listener)");
724 			break;
725 		default:
726 			lws_snprintf(buf, sizeof(buf), "port %u", info->port);
727 			break;
728 		}
729 		lwsl_info("Creating Vhost '%s' %s, %d protocols, IPv6 %s\n",
730 			    vh->name, buf, vh->count_protocols,
731 			    LWS_IPV6_ENABLED(vh) ? "on" : "off");
732 	}
733 	mounts = info->mounts;
734 	while (mounts) {
735 		(void)mount_protocols[0];
736 		lwsl_info("   mounting %s%s to %s\n",
737 			  mount_protocols[mounts->origin_protocol],
738 			  mounts->origin, mounts->mountpoint);
739 
740 		mounts = mounts->mount_next;
741 	}
742 
743 	vh->listen_port = info->port;
744 
745 #if defined(LWS_WITH_SOCKS5)
746 	vh->socks_proxy_port = 0;
747 	vh->socks_proxy_address[0] = '\0';
748 #endif
749 
750 #if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING)
751 	/* either use proxy from info, or try get it from env var */
752 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
753 	vh->http.http_proxy_port = 0;
754 	vh->http.http_proxy_address[0] = '\0';
755 	/* http proxy */
756 	if (info->http_proxy_address) {
757 		/* override for backwards compatibility */
758 		if (info->http_proxy_port)
759 			vh->http.http_proxy_port = info->http_proxy_port;
760 		lws_set_proxy(vh, info->http_proxy_address);
761 	} else
762 #endif
763 	{
764 #ifdef LWS_HAVE_GETENV
765 #if defined(__COVERITY__)
766 		p = NULL;
767 #else
768 		p = getenv("http_proxy"); /* coverity[tainted_scalar] */
769 		if (p) {
770 			lws_strncpy(buf, p, sizeof(buf));
771 			lws_set_proxy(vh, buf);
772 		}
773 #endif
774 #endif
775 	}
776 #endif
777 #if defined(LWS_WITH_SOCKS5)
778 	lws_socks5c_ads_server(vh, info);
779 #endif
780 
781 	vh->ka_time = info->ka_time;
782 	vh->ka_interval = info->ka_interval;
783 	vh->ka_probes = info->ka_probes;
784 
785 	if (vh->options & LWS_SERVER_OPTION_STS)
786 		lwsl_notice("   STS enabled\n");
787 
788 #ifdef LWS_WITH_ACCESS_LOG
789 	if (info->log_filepath) {
790 		vh->log_fd = lws_open(info->log_filepath,
791 				  O_CREAT | O_APPEND | O_RDWR, 0600);
792 		if (vh->log_fd == (int)LWS_INVALID_FILE) {
793 			lwsl_err("unable to open log filepath %s\n",
794 				 info->log_filepath);
795 			goto bail;
796 		}
797 #ifndef WIN32
798 		if (context->uid != -1)
799 			if (chown(info->log_filepath, context->uid,
800 				  context->gid) == -1)
801 				lwsl_err("unable to chown log file %s\n",
802 						info->log_filepath);
803 #endif
804 	} else
805 		vh->log_fd = (int)LWS_INVALID_FILE;
806 #endif
807 	if (lws_context_init_server_ssl(info, vh)) {
808 		lwsl_err("%s: lws_context_init_server_ssl failed\n", __func__);
809 		goto bail1;
810 	}
811 	if (lws_context_init_client_ssl(info, vh)) {
812 		lwsl_err("%s: lws_context_init_client_ssl failed\n", __func__);
813 		goto bail1;
814 	}
815 #if defined(LWS_WITH_SERVER)
816 	lws_context_lock(context, "create_vhost");
817 	n = _lws_vhost_init_server(info, vh);
818 	lws_context_unlock(context);
819 	if (n < 0) {
820 		lwsl_err("init server failed\n");
821 		goto bail1;
822 	}
823 #endif
824 	n = !!context->vhost_list;
825 
826 	while (1) {
827 		if (!(*vh1)) {
828 			*vh1 = vh;
829 			break;
830 		}
831 		vh1 = &(*vh1)->vhost_next;
832 	};
833 
834 #if defined(LWS_WITH_SYS_ASYNC_DNS)
835 	if (!n && lws_async_dns_init(context))
836 		goto bail1;
837 #endif
838 
839 	/* for the case we are adding a vhost much later, after server init */
840 
841 	if (context->protocol_init_done)
842 		if (lws_protocol_init(context)) {
843 			lwsl_err("%s: lws_protocol_init failed\n", __func__);
844 			goto bail1;
845 		}
846 
847 	return vh;
848 
849 bail1:
850 	lws_vhost_destroy(vh);
851 
852 	return NULL;
853 
854 #ifdef LWS_WITH_ACCESS_LOG
855 bail:
856 	lws_free(vh);
857 #endif
858 
859 	return NULL;
860 }
861 
862 int
lws_init_vhost_client_ssl(const struct lws_context_creation_info * info,struct lws_vhost * vhost)863 lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
864 			  struct lws_vhost *vhost)
865 {
866 	struct lws_context_creation_info i;
867 
868 	memcpy(&i, info, sizeof(i));
869 	i.port = CONTEXT_PORT_NO_LISTEN;
870 
871 	return lws_context_init_client_ssl(&i, vhost);
872 }
873 
874 void
lws_cancel_service_pt(struct lws * wsi)875 lws_cancel_service_pt(struct lws *wsi)
876 {
877 	lws_plat_pipe_signal(wsi);
878 }
879 
880 void
lws_cancel_service(struct lws_context * context)881 lws_cancel_service(struct lws_context *context)
882 {
883 	struct lws_context_per_thread *pt = &context->pt[0];
884 	short m = context->count_threads;
885 
886 	if (context->being_destroyed1)
887 		return;
888 
889 	lwsl_info("%s\n", __func__);
890 
891 	while (m--) {
892 		if (pt->pipe_wsi)
893 			lws_plat_pipe_signal(pt->pipe_wsi);
894 		pt++;
895 	}
896 }
897 
898 int
lws_create_event_pipes(struct lws_context * context)899 lws_create_event_pipes(struct lws_context *context)
900 {
901 	struct lws *wsi;
902 	int n;
903 
904 	/*
905 	 * Create the pt event pipes... these are unique in that they are
906 	 * not bound to a vhost or protocol (both are NULL)
907 	 */
908 
909 #if LWS_MAX_SMP > 1
910 	for (n = 0; n < context->count_threads; n++) {
911 #else
912 	n = 0;
913 	{
914 #endif
915 		if (context->pt[n].pipe_wsi)
916 			return 0;
917 
918 		wsi = lws_zalloc(sizeof(*wsi), "event pipe wsi");
919 		if (!wsi) {
920 			lwsl_err("%s: Out of mem\n", __func__);
921 			return 1;
922 		}
923 		wsi->context = context;
924 		lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_pipe);
925 		wsi->protocol = NULL;
926 		wsi->tsi = n;
927 		wsi->vhost = NULL;
928 		wsi->event_pipe = 1;
929 		wsi->desc.sockfd = LWS_SOCK_INVALID;
930 		context->pt[n].pipe_wsi = wsi;
931 		context->count_wsi_allocated++;
932 
933 		if (!lws_plat_pipe_create(wsi)) {
934 			/*
935 			 * platform code returns 0 if it actually created pipes
936 			 * and initialized pt->dummy_pipe_fds[].  If it used
937 			 * some other mechanism outside of signaling in the
938 			 * normal event loop, we skip treating the pipe as
939 			 * related to dummy_pipe_fds[], adding it to the fds,
940 			 * etc.
941 			 */
942 
943 			wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
944 			lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
945 
946 			if (context->event_loop_ops->sock_accept)
947 				if (context->event_loop_ops->sock_accept(wsi))
948 					return 1;
949 
950 			if (__insert_wsi_socket_into_fds(context, wsi))
951 				return 1;
952 		}
953 	}
954 
955 	return 0;
956 }
957 
958 void
959 lws_destroy_event_pipe(struct lws *wsi)
960 {
961 	lwsl_info("%s\n", __func__);
962 
963 	if (lws_socket_is_valid(wsi->desc.sockfd))
964 		__remove_wsi_socket_from_fds(wsi);
965 
966 	if (!wsi->context->event_loop_ops->destroy_wsi &&
967 	    wsi->context->event_loop_ops->wsi_logical_close) {
968 		wsi->context->event_loop_ops->wsi_logical_close(wsi);
969 		lws_plat_pipe_close(wsi);
970 		return;
971 	}
972 
973 	if (wsi->context->event_loop_ops->destroy_wsi)
974 		wsi->context->event_loop_ops->destroy_wsi(wsi);
975 	lws_plat_pipe_close(wsi);
976 	wsi->context->count_wsi_allocated--;
977 	lws_free(wsi);
978 }
979 
980 
981 void
982 lws_vhost_destroy1(struct lws_vhost *vh)
983 {
984 	struct lws_context *context = vh->context;
985 
986 	lwsl_info("%s\n", __func__);
987 
988 	lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */
989 
990 	if (vh->being_destroyed)
991 		goto out;
992 
993 	lws_vhost_lock(vh); /* -------------- vh { */
994 
995 #if defined(LWS_WITH_NETWORK)
996 	/*
997 	 * PHASE 1: take down or reassign any listen wsi
998 	 *
999 	 * Are there other vhosts that are piggybacking on our listen socket?
1000 	 * If so we need to hand the listen socket off to one of the others
1001 	 * so it will remain open.
1002 	 *
1003 	 * If not, leave it attached to the closing vhost, the vh being marked
1004 	 * being_destroyed will defeat any service and it will get closed in
1005 	 * later phases.
1006 	 */
1007 
1008 	if (vh->lserv_wsi)
1009 		lws_start_foreach_ll(struct lws_vhost *, v,
1010 				     context->vhost_list) {
1011 			if (v != vh &&
1012 			    !v->being_destroyed &&
1013 			    v->listen_port == vh->listen_port &&
1014 			    ((!v->iface && !vh->iface) ||
1015 			    (v->iface && vh->iface &&
1016 			    !strcmp(v->iface, vh->iface)))) {
1017 				/*
1018 				 * this can only be a listen wsi, which is
1019 				 * restricted... it has no protocol or other
1020 				 * bindings or states.  So we can simply
1021 				 * swap it to a vhost that has the same
1022 				 * iface + port, but is not closing.
1023 				 */
1024 				assert(v->lserv_wsi == NULL);
1025 				v->lserv_wsi = vh->lserv_wsi;
1026 
1027 				lwsl_notice("%s: listen skt from %s to %s\n",
1028 					    __func__, vh->name, v->name);
1029 
1030 				if (v->lserv_wsi) {
1031 					lws_vhost_unbind_wsi(vh->lserv_wsi);
1032 					lws_vhost_bind_wsi(v, v->lserv_wsi);
1033 				}
1034 
1035 				break;
1036 			}
1037 		} lws_end_foreach_ll(v, vhost_next);
1038 
1039 #endif
1040 
1041 	lws_vhost_unlock(vh); /* } vh -------------- */
1042 
1043 	/*
1044 	 * lws_check_deferred_free() will notice there is a vhost that is
1045 	 * marked for destruction during the next 1s, for all tsi.
1046 	 *
1047 	 * It will start closing all wsi on this vhost.  When the last wsi
1048 	 * is closed, it will trigger lws_vhost_destroy2()
1049 	 */
1050 
1051 out:
1052 	lws_context_unlock(context); /* --------------------------- context { */
1053 }
1054 
1055 #if defined(LWS_WITH_ABSTRACT)
1056 static int
1057 destroy_ais(struct lws_dll2 *d, void *user)
1058 {
1059 	lws_abs_t *ai = lws_container_of(d, lws_abs_t, abstract_instances);
1060 
1061 	lws_abs_destroy_instance(&ai);
1062 
1063 	return 0;
1064 }
1065 #endif
1066 
1067 void
1068 __lws_vhost_destroy2(struct lws_vhost *vh)
1069 {
1070 	const struct lws_protocols *protocol = NULL;
1071 	struct lws_context *context = vh->context;
1072 	struct lws_deferred_free *df;
1073 	struct lws wsi;
1074 	int n;
1075 
1076 	vh->being_destroyed = 0;
1077 
1078 #if defined(LWS_WITH_CLIENT)
1079 	/*
1080 	 * destroy any wsi that are associated with us but have no socket
1081 	 * (and will otherwise be missed for destruction)
1082 	 */
1083 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1084 			      vh->vh_awaiting_socket_owner.head) {
1085 		struct lws *w =
1086 			lws_container_of(d, struct lws, vh_awaiting_socket);
1087 
1088 		lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1089 				   "awaiting skt");
1090 
1091 	} lws_end_foreach_dll_safe(d, d1);
1092 #endif
1093 
1094 	/*
1095 	 * destroy any pending timed events
1096 	 */
1097 
1098 	while (vh->timed_vh_protocol_list)
1099 		__lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
1100 
1101 	/*
1102 	 * let the protocols destroy the per-vhost protocol objects
1103 	 */
1104 
1105 	memset(&wsi, 0, sizeof(wsi));
1106 	wsi.context = vh->context;
1107 	wsi.vhost = vh; /* not a real bound wsi */
1108 	protocol = vh->protocols;
1109 	if (protocol && vh->created_vhost_protocols) {
1110 		n = 0;
1111 		while (n < vh->count_protocols) {
1112 			wsi.protocol = protocol;
1113 
1114 			if (protocol->callback)
1115 				protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
1116 					   NULL, NULL, 0);
1117 			protocol++;
1118 			n++;
1119 		}
1120 	}
1121 
1122 	/*
1123 	 * remove vhost from context list of vhosts
1124 	 */
1125 
1126 	lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_list) {
1127 		if (*pv == vh) {
1128 			*pv = vh->vhost_next;
1129 			break;
1130 		}
1131 	} lws_end_foreach_llp(pv, vhost_next);
1132 
1133 	/* add ourselves to the pending destruction list */
1134 
1135 	vh->vhost_next = vh->context->vhost_pending_destruction_list;
1136 	vh->context->vhost_pending_destruction_list = vh;
1137 
1138 	lwsl_info("%s: %p\n", __func__, vh);
1139 
1140 	/* if we are still on deferred free list, remove ourselves */
1141 
1142 	lws_start_foreach_llp(struct lws_deferred_free **, pdf,
1143 			      context->deferred_free_list) {
1144 		if ((*pdf)->payload == vh) {
1145 			df = *pdf;
1146 			*pdf = df->next;
1147 			lws_free(df);
1148 			break;
1149 		}
1150 	} lws_end_foreach_llp(pdf, next);
1151 
1152 	/* remove ourselves from the pending destruction list */
1153 
1154 	lws_start_foreach_llp(struct lws_vhost **, pv,
1155 			      context->vhost_pending_destruction_list) {
1156 		if ((*pv) == vh) {
1157 			*pv = (*pv)->vhost_next;
1158 			break;
1159 		}
1160 	} lws_end_foreach_llp(pv, vhost_next);
1161 
1162 	/*
1163 	 * Free all the allocations associated with the vhost
1164 	 */
1165 
1166 	protocol = vh->protocols;
1167 	if (protocol) {
1168 		n = 0;
1169 		while (n < vh->count_protocols) {
1170 			if (vh->protocol_vh_privs &&
1171 			    vh->protocol_vh_privs[n]) {
1172 				lws_free(vh->protocol_vh_privs[n]);
1173 				vh->protocol_vh_privs[n] = NULL;
1174 			}
1175 			protocol++;
1176 			n++;
1177 		}
1178 	}
1179 	if (vh->protocol_vh_privs)
1180 		lws_free(vh->protocol_vh_privs);
1181 	lws_ssl_SSL_CTX_destroy(vh);
1182 	lws_free(vh->same_vh_protocol_owner);
1183 
1184 	if (
1185 #if defined(LWS_WITH_PLUGINS)
1186 		context->plugin_list ||
1187 #endif
1188 	    (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) ||
1189 	    vh->allocated_vhost_protocols)
1190 		lws_free((void *)vh->protocols);
1191 #if defined(LWS_WITH_NETWORK)
1192 	LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
1193 		if (ar->destroy_vhost)
1194 			ar->destroy_vhost(vh);
1195 	LWS_FOR_EVERY_AVAILABLE_ROLE_END;
1196 #endif
1197 
1198 #ifdef LWS_WITH_ACCESS_LOG
1199 	if (vh->log_fd != (int)LWS_INVALID_FILE)
1200 		close(vh->log_fd);
1201 #endif
1202 
1203 #if defined (LWS_WITH_TLS)
1204 	lws_free_set_NULL(vh->tls.alloc_cert_path);
1205 #endif
1206 
1207 #if LWS_MAX_SMP > 1
1208        pthread_mutex_destroy(&vh->lock);
1209 #endif
1210 
1211 #if defined(LWS_WITH_UNIX_SOCK)
1212 	if (LWS_UNIX_SOCK_ENABLED(vh)) {
1213 		n = unlink(vh->iface);
1214 		if (n)
1215 			lwsl_info("Closing unix socket %s: errno %d\n",
1216 				  vh->iface, errno);
1217 	}
1218 #endif
1219 	/*
1220 	 * although async event callbacks may still come for wsi handles with
1221 	 * pending close in the case of asycn event library like libuv,
1222 	 * they do not refer to the vhost.  So it's safe to free.
1223 	 */
1224 
1225 	if (vh->finalize)
1226 		vh->finalize(vh, vh->finalize_arg);
1227 
1228 #if defined(LWS_WITH_ABSTRACT)
1229 	/*
1230 	 * abstract instances
1231 	 */
1232 
1233 	lws_dll2_foreach_safe(&vh->abstract_instances_owner, NULL, destroy_ais);
1234 #endif
1235 
1236 	lwsl_info("  %s: Freeing vhost %p\n", __func__, vh);
1237 
1238 	memset(vh, 0, sizeof(*vh));
1239 	lws_free(vh);
1240 }
1241 
1242 /*
1243  * each service thread calls this once a second or so
1244  */
1245 
1246 int
1247 lws_check_deferred_free(struct lws_context *context, int tsi, int force)
1248 {
1249 	struct lws_context_per_thread *pt;
1250 	int n;
1251 
1252 	/*
1253 	 * If we see a vhost is being destroyed, forcibly close every wsi on
1254 	 * this tsi associated with this vhost.  That will include the listen
1255 	 * socket if it is still associated with the closing vhost.
1256 	 *
1257 	 * For SMP, we do this once per tsi per destroyed vhost.  The reference
1258 	 * counting on the vhost as the bound wsi close will notice that there
1259 	 * are no bound wsi left, that vhost destruction can complete,
1260 	 * and perform it.  It doesn't matter which service thread does that
1261 	 * because there is nothing left using the vhost to conflict.
1262 	 */
1263 
1264 	lws_context_lock(context, "check deferred free"); /* ------ context { */
1265 
1266 	lws_start_foreach_ll_safe(struct lws_vhost *, v, context->vhost_list, vhost_next) {
1267 		if (v->being_destroyed
1268 #if LWS_MAX_SMP > 1
1269 			&& !v->close_flow_vs_tsi[tsi]
1270 #endif
1271 		) {
1272 
1273 			pt = &context->pt[tsi];
1274 
1275 			lws_pt_lock(pt, "vhost removal"); /* -------------- pt { */
1276 
1277 #if LWS_MAX_SMP > 1
1278 			v->close_flow_vs_tsi[tsi] = 1;
1279 #endif
1280 
1281 			for (n = 0; (unsigned int)n < pt->fds_count; n++) {
1282 				struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
1283 				if (!wsi)
1284 					continue;
1285 				if (wsi->vhost != v)
1286 					continue;
1287 
1288 				__lws_close_free_wsi(wsi,
1289 					LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
1290 					"vh destroy"
1291 					/* no protocol close */);
1292 				n--;
1293 			}
1294 
1295 			lws_pt_unlock(pt); /* } pt -------------- */
1296 		}
1297 	} lws_end_foreach_ll_safe(v);
1298 
1299 
1300 	lws_context_unlock(context); /* } context ------------------- */
1301 
1302 	return 0;
1303 }
1304 
1305 
1306 void
1307 lws_vhost_destroy(struct lws_vhost *vh)
1308 {
1309 	struct lws_deferred_free *df = lws_malloc(sizeof(*df), "deferred free");
1310 	struct lws_context *context = vh->context;
1311 
1312 	if (!df)
1313 		return;
1314 
1315 	lws_context_lock(context, __func__); /* ------ context { */
1316 
1317 	lws_vhost_destroy1(vh);
1318 
1319 	lwsl_debug("%s: count_bound_wsi %d\n", __func__, vh->count_bound_wsi);
1320 
1321 	if (!vh->count_bound_wsi) {
1322 		/*
1323 		 * After listen handoff, there are already no wsi bound to this
1324 		 * vhost by any pt: nothing can be servicing any wsi belonging
1325 		 * to it any more.
1326 		 *
1327 		 * Finalize the vh destruction immediately
1328 		 */
1329 		__lws_vhost_destroy2(vh);
1330 		lws_free(df);
1331 
1332 		goto out;
1333 	}
1334 
1335 	/* part 2 is deferred to allow all the handle closes to complete */
1336 
1337 	df->next = vh->context->deferred_free_list;
1338 	df->deadline = lws_now_secs();
1339 	df->payload = vh;
1340 	vh->context->deferred_free_list = df;
1341 
1342 out:
1343 	lws_context_unlock(context); /* } context ------------------- */
1344 }
1345 
1346 
1347 void *
1348 lws_vhost_user(struct lws_vhost *vhost)
1349 {
1350 	return vhost->user;
1351 }
1352 
1353 int
1354 lws_get_vhost_listen_port(struct lws_vhost *vhost)
1355 {
1356 	return vhost->listen_port;
1357 }
1358 
1359 #if defined(LWS_WITH_SERVER)
1360 void
1361 lws_context_deprecate(struct lws_context *context, lws_reload_func cb)
1362 {
1363 	struct lws_vhost *vh = context->vhost_list, *vh1;
1364 
1365 	/*
1366 	 * "deprecation" means disable the context from accepting any new
1367 	 * connections and free up listen sockets to be used by a replacement
1368 	 * context.
1369 	 *
1370 	 * Otherwise the deprecated context remains operational, until its
1371 	 * number of connected sockets falls to zero, when it is deleted.
1372 	 */
1373 
1374 	/* for each vhost, close his listen socket */
1375 
1376 	while (vh) {
1377 		struct lws *wsi = vh->lserv_wsi;
1378 
1379 		if (wsi) {
1380 			wsi->socket_is_permanently_unusable = 1;
1381 			lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "ctx deprecate");
1382 			wsi->context->deprecation_pending_listen_close_count++;
1383 			/*
1384 			 * other vhosts can share the listen port, they
1385 			 * point to the same wsi.  So zap those too.
1386 			 */
1387 			vh1 = context->vhost_list;
1388 			while (vh1) {
1389 				if (vh1->lserv_wsi == wsi)
1390 					vh1->lserv_wsi = NULL;
1391 				vh1 = vh1->vhost_next;
1392 			}
1393 		}
1394 		vh = vh->vhost_next;
1395 	}
1396 
1397 	context->deprecated = 1;
1398 	context->deprecation_cb = cb;
1399 }
1400 #endif
1401 
1402 #if defined(LWS_WITH_NETWORK)
1403 
1404 struct lws_vhost *
1405 lws_get_vhost_by_name(struct lws_context *context, const char *name)
1406 {
1407 	lws_start_foreach_ll(struct lws_vhost *, v,
1408 			     context->vhost_list) {
1409 		if (!strcmp(v->name, name))
1410 			return v;
1411 
1412 	} lws_end_foreach_ll(v, vhost_next);
1413 
1414 	return NULL;
1415 }
1416 
1417 
1418 #if defined(LWS_WITH_CLIENT)
1419 /*
1420  * This is the logic checking to see if the new connection wsi should have a
1421  * pipelining or muxing relationship with an existing "active connection" to
1422  * the same endpoint under the same conditions.
1423  *
1424  * This was originally in the client code but since the list is held on the
1425  * vhost (to ensure the same client tls ctx is involved) it's cleaner in vhost.c
1426  */
1427 
1428 int
1429 lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin)
1430 {
1431 	if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
1432 		struct lws *w = lws_container_of(
1433 				wsi->dll2_cli_txn_queue.owner, struct lws,
1434 				dll2_cli_txn_queue_owner);
1435 		*nwsi = w;
1436 
1437 		return ACTIVE_CONNS_QUEUED;
1438 	}
1439 
1440 #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
1441 	if (wsi->mux.parent_wsi) {
1442 		/*
1443 		 * We already decided...
1444 		 */
1445 
1446 		*nwsi = wsi->mux.parent_wsi;
1447 
1448 		return ACTIVE_CONNS_MUXED;
1449 	}
1450 #endif
1451 
1452 	lws_vhost_lock(wsi->vhost); /* ----------------------------------- { */
1453 
1454 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1455 				   wsi->vhost->dll_cli_active_conns_owner.head) {
1456 		struct lws *w = lws_container_of(d, struct lws,
1457 						 dll_cli_active_conns);
1458 
1459 		lwsl_debug("%s: check %p %p %s %s %d %d\n", __func__, wsi, w,
1460 			    adsin, w->cli_hostname_copy, wsi->c_port, w->c_port);
1461 
1462 		if (w != wsi &&
1463 		    /*
1464 		     * "same internet protocol"... this is a bit tricky,
1465 		     * since h2 start out as h1
1466 		     */
1467 		    (w->role_ops == wsi->role_ops ||
1468 		     (lwsi_role_http(w) && lwsi_role_http(wsi))) &&
1469 		    w->cli_hostname_copy &&
1470 		    !strcmp(adsin, w->cli_hostname_copy) &&
1471 #if defined(LWS_WITH_TLS)
1472 		    (wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
1473 		     (w->tls.use_ssl & LCCSCF_USE_SSL) &&
1474 #endif
1475 		    wsi->c_port == w->c_port) {
1476 
1477 			/*
1478 			 * There's already an active connection.
1479 			 *
1480 			 * The server may have told the existing active
1481 			 * connection that it doesn't support pipelining...
1482 			 */
1483 			if (w->keepalive_rejected) {
1484 				lwsl_notice("defeating pipelining due to no "
1485 					  "keepalive on server\n");
1486 				goto solo;
1487 			}
1488 
1489 #if defined(LWS_WITH_HTTP2)
1490 			/*
1491 			 * h2: if in usable state already: just use it without
1492 			 *     going through the queue
1493 			 */
1494 			if (w->client_h2_alpn && w->client_mux_migrated &&
1495 			    (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
1496 			     lwsi_state(w) == LRS_ESTABLISHED ||
1497 			     lwsi_state(w) == LRS_IDLING)) {
1498 
1499 				lwsl_notice("%s: just join h2 directly 0x%x\n",
1500 						__func__, lwsi_state(w));
1501 
1502 				if (lwsi_state(w) == LRS_IDLING) {
1503 					// lwsi_set_state(w, LRS_ESTABLISHED);
1504 					_lws_generic_transaction_completed_active_conn(&w);
1505 				}
1506 
1507 				//lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
1508 
1509 				wsi->client_h2_alpn = 1;
1510 				lws_wsi_h2_adopt(w, wsi);
1511 				lws_vhost_unlock(wsi->vhost); /* } ---------- */
1512 
1513 				*nwsi = w;
1514 
1515 				return ACTIVE_CONNS_MUXED;
1516 			}
1517 #endif
1518 
1519 #if defined(LWS_ROLE_MQTT)
1520 			/*
1521 			 * MQTT: if in usable state already: just use it without
1522 			 *	 going through the queue
1523 			 */
1524 
1525 			if (lwsi_role_mqtt(wsi) && w->client_mux_migrated &&
1526 			    lwsi_state(w) == LRS_ESTABLISHED) {
1527 
1528 				if (lws_wsi_mqtt_adopt(w, wsi)) {
1529 					lwsl_notice("%s: join mqtt directly\n", __func__);
1530 					lws_dll2_remove(&wsi->dll2_cli_txn_queue);
1531 					wsi->client_mux_substream = 1;
1532 
1533 					lws_vhost_unlock(wsi->vhost); /* } ---------- */
1534 
1535 
1536 					return ACTIVE_CONNS_MUXED;
1537 				}
1538 			}
1539 #endif
1540 
1541 			/*
1542 			 * If the connection is viable but not yet in a usable
1543 			 * state, let's attach ourselves to it and wait for it
1544 			 * to get there or fail.
1545 			 */
1546 
1547 			lwsl_notice("%s: apply %p to txn queue on %p state 0x%lx\n",
1548 				  __func__, wsi, w, (unsigned long)w->wsistate);
1549 			/*
1550 			 * ...let's add ourselves to his transaction queue...
1551 			 * we are adding ourselves at the TAIL
1552 			 */
1553 			lws_dll2_add_tail(&wsi->dll2_cli_txn_queue,
1554 					  &w->dll2_cli_txn_queue_owner);
1555 
1556 			if (lwsi_state(w) == LRS_IDLING) {
1557 				// lwsi_set_state(w, LRS_ESTABLISHED);
1558 				_lws_generic_transaction_completed_active_conn(&w);
1559 			}
1560 
1561 			/*
1562 			 * For eg, h1 next we'd pipeline our headers out on him,
1563 			 * and wait for our turn at client transaction_complete
1564 			 * to take over parsing the rx.
1565 			 */
1566 			lws_vhost_unlock(wsi->vhost); /* } ---------- */
1567 
1568 			*nwsi = w;
1569 
1570 			return ACTIVE_CONNS_QUEUED;
1571 		}
1572 
1573 	} lws_end_foreach_dll_safe(d, d1);
1574 
1575 solo:
1576 	lws_vhost_unlock(wsi->vhost); /* } ---------------------------------- */
1577 
1578 	/* there is nobody already connected in the same way */
1579 
1580 	return ACTIVE_CONNS_SOLO;
1581 }
1582 #endif
1583 #endif
1584