• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 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 #ifndef LWS_BUILD_HASH
28 #define LWS_BUILD_HASH "unknown-build-hash"
29 #endif
30 
31 static const char *library_version = LWS_LIBRARY_VERSION;
32 
33 #if defined(LWS_WITH_MBEDTLS)
34 extern const char *mbedtls_client_preload_filepath;
35 #endif
36 
37 #if defined(LWS_HAVE_SYS_RESOURCE_H)
38 /* for setrlimit */
39 #include <sys/resource.h>
40 #endif
41 
42 #if defined(LWS_WITH_NETWORK)
43 /* in ms */
44 static uint32_t default_backoff_table[] = { 1000, 3000, 9000, 17000 };
45 #endif
46 
47 /**
48  * lws_get_library_version: get version and git hash library built from
49  *
50  *	returns a const char * to a string like "1.1 178d78c"
51  *	representing the library version followed by the git head hash it
52  *	was built from
53  */
54 const char *
lws_get_library_version(void)55 lws_get_library_version(void)
56 {
57 	return library_version;
58 }
59 
60 #if defined(LWS_WITH_NETWORK)
61 
62 #if defined(LWS_WITH_SYS_STATE)
63 
64 static const char * system_state_names[] = {
65 	"undef",
66 	"CONTEXT_CREATED",
67 	"INITIALIZED",
68 	"IFACE_COLDPLUG",
69 	"DHCP",
70 	"CPD_PRE_TIME",
71 	"TIME_VALID",
72 	"CPD_POST_TIME",
73 	"POLICY_VALID",
74 	"REGISTERED",
75 	"AUTH1",
76 	"AUTH2",
77 	"OPERATIONAL",
78 	"POLICY_INVALID",
79 	"DESTROYING"
80 };
81 
82 
83 /*
84  * Handle provoking protocol init when we pass through the right system state
85  */
86 
87 static int
lws_state_notify_protocol_init(struct lws_state_manager * mgr,struct lws_state_notify_link * link,int current,int target)88 lws_state_notify_protocol_init(struct lws_state_manager *mgr,
89 			       struct lws_state_notify_link *link, int current,
90 			       int target)
91 {
92 	struct lws_context *context = lws_container_of(mgr, struct lws_context,
93 						       mgr_system);
94 #if defined(LWS_WITH_SECURE_STREAMS) && \
95     defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
96 	lws_system_blob_t *ab0, *ab1;
97 #endif
98 	int n;
99 
100 	/*
101 	 * Deal with any attachments that were waiting for the right state
102 	 * to come along
103 	 */
104 
105 	for (n = 0; n < context->count_threads; n++)
106 		lws_system_do_attach(&context->pt[n]);
107 
108 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
109 	if (target == LWS_SYSTATE_DHCP) {
110 		/*
111 		 * Don't let it past here until at least one iface has been
112 		 * configured for operation with DHCP
113 		 */
114 
115 		if (!lws_dhcpc_status(context, NULL))
116 			return 1;
117 	}
118 #endif
119 
120 #if defined(LWS_WITH_SYS_NTPCLIENT)
121 	if (target == LWS_SYSTATE_TIME_VALID &&
122 	    lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */ {
123 		lws_ntpc_trigger(context);
124 
125 		return 1;
126 	}
127 #endif
128 
129 #if defined(LWS_WITH_NETLINK)
130 	/*
131 	 * If we're going to use netlink routing data for DNS, we have to
132 	 * wait to collect it asynchronously from the platform first.  Netlink
133 	 * role init starts a ctx sul for 350ms (reset to 100ms each time some
134 	 * new netlink data comes) that sets nl_initial_done and tries to move
135 	 * us to OPERATIONAL
136 	 */
137 
138 	if (target == LWS_SYSTATE_IFACE_COLDPLUG &&
139 	    context->netlink &&
140 	    !context->nl_initial_done) {
141 		lwsl_cx_info(context, "waiting for netlink coldplug");
142 
143 		return 1;
144 	}
145 #endif
146 
147 #if defined(LWS_WITH_SECURE_STREAMS) && \
148     defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
149 	/*
150 	 * Skip this if we are running something without the policy for it
151 	 *
152 	 * If root token is empty, skip too.
153 	 */
154 
155 	ab0 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 0);
156 	ab1 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 1);
157 
158 	if (target == LWS_SYSTATE_AUTH1 &&
159 	    context->pss_policies && ab0 && ab1 &&
160 	    !lws_system_blob_get_size(ab0) &&
161 	    lws_system_blob_get_size(ab1)) {
162 		lwsl_cx_info(context,
163 			     "AUTH1 state triggering api.amazon.com auth");
164 		/*
165 		 * Start trying to acquire it if it's not already in progress
166 		 * returns nonzero if we determine it's not needed
167 		 */
168 		if (!lws_ss_sys_auth_api_amazon_com(context))
169 			return 1;
170 	}
171 #endif
172 
173 #if defined(LWS_WITH_SECURE_STREAMS)
174 #if defined(LWS_WITH_DRIVERS)
175 	/*
176 	 * See if we should do the SS Captive Portal Detection
177 	 */
178 	if (target == LWS_SYSTATE_CPD_PRE_TIME) {
179 		if (lws_system_cpd_state_get(context) == LWS_CPD_INTERNET_OK)
180 			return 0; /* allow it */
181 
182 		/*
183 		 * Don't allow it to move past here until we get an IP and
184 		 * CPD passes, driven by SMD
185 		 */
186 
187 		return 1;
188 	}
189 #endif
190 
191 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
192 	/*
193 	 * Skip this if we are running something without the policy for it
194 	 */
195 	if (target == LWS_SYSTATE_POLICY_VALID &&
196 	    context->pss_policies && !context->policy_updated) {
197 
198 		if (context->hss_fetch_policy)
199 			return 1;
200 
201 		lwsl_cx_debug(context, "starting policy fetch");
202 		/*
203 		 * Start trying to acquire it if it's not already in progress
204 		 * returns nonzero if we determine it's not needed
205 		 */
206 		if (!lws_ss_sys_fetch_policy(context))
207 			/* we have it */
208 			return 0;
209 
210 		/* deny while we fetch it */
211 
212 		return 1;
213 	}
214 #endif
215 #endif
216 
217 	/* protocol part */
218 
219 	if (context->protocol_init_done)
220 		return 0;
221 
222 	if (target != LWS_SYSTATE_POLICY_VALID)
223 		return 0;
224 
225 	lwsl_cx_info(context, "doing protocol init on POLICY_VALID\n");
226 
227 	return lws_protocol_init(context);
228 }
229 
230 static void
lws_context_creation_completion_cb(lws_sorted_usec_list_t * sul)231 lws_context_creation_completion_cb(lws_sorted_usec_list_t *sul)
232 {
233 	struct lws_context *context = lws_container_of(sul, struct lws_context,
234 						       sul_system_state);
235 
236 	/* if nothing is there to intercept anything, go all the way */
237 	lws_state_transition_steps(&context->mgr_system,
238 				   LWS_SYSTATE_OPERATIONAL);
239 }
240 #endif /* WITH_SYS_STATE */
241 
242 #if defined(LWS_WITH_SYS_SMD)
243 static int
lws_system_smd_cb(void * opaque,lws_smd_class_t _class,lws_usec_t timestamp,void * buf,size_t len)244 lws_system_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
245 		  void *buf, size_t len)
246 {
247 	struct lws_context *cx = (struct lws_context *)opaque;
248 
249 	if (_class != LWSSMDCL_NETWORK)
250 		return 0;
251 
252 	/* something external requested CPD check */
253 
254 	if (!lws_json_simple_strcmp(buf, len, "\"trigger\":", "cpdcheck"))
255 		lws_system_cpd_start(cx);
256 	else
257 		/*
258 		 * IP acquisition on any interface triggers captive portal
259 		 * check on default route
260 		 */
261 		if (!lws_json_simple_strcmp(buf, len, "\"type\":", "ipacq"))
262 			lws_system_cpd_start(cx);
263 
264 #if defined(LWS_WITH_SYS_NTPCLIENT)
265 	/*
266 	 * Captive portal detect showing internet workable triggers NTP Client
267 	 */
268 	if (!lws_json_simple_strcmp(buf, len, "\"type\":", "cps") &&
269 	    !lws_json_simple_strcmp(buf, len, "\"result\":", "OK") &&
270 	    lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */
271 		lws_ntpc_trigger(cx);
272 #endif
273 
274 #if defined(LWS_WITH_SYS_DHCP_CLIENT) && 0
275 	/*
276 	 * Any network interface linkup triggers DHCP
277 	 */
278 	if (!lws_json_simple_strcmp(buf, len, "\"type\":", "linkup"))
279 		lws_ntpc_trigger(cx);
280 
281 #endif
282 
283 #if defined(LWS_WITH_DRIVERS) && defined(LWS_WITH_NETWORK)
284 	lws_netdev_smd_cb(opaque, _class, timestamp, buf, len);
285 #endif
286 
287 	return 0;
288 }
289 #endif
290 
291 
292 
293 #endif /* NETWORK */
294 
295 #if !defined(LWS_WITH_NO_LOGS)
296 
297 static const char * const opts_str =
298 #if defined(LWS_WITH_NETWORK)
299 			"NET "
300 #else
301 			"NoNET "
302 #endif
303 #if defined(LWS_WITH_CLIENT)
304 			"CLI "
305 #endif
306 #if defined(LWS_WITH_SERVER)
307 			"SRV "
308 #endif
309 #if defined(LWS_ROLE_H1)
310 			"H1 "
311 #endif
312 #if defined(LWS_ROLE_H2)
313 			"H2 "
314 #endif
315 #if defined(LWS_ROLE_WS)
316 			"WS "
317 #endif
318 #if defined(LWS_ROLE_MQTT)
319 			"MQTT "
320 #endif
321 #if defined(LWS_WITH_SECURE_STREAMS) && !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
322 			"SS-JSON-POL "
323 #endif
324 #if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
325 			"SS-STATIC-POL "
326 #endif
327 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
328 			"SSPROX "
329 #endif
330 #if defined(LWS_WITH_CONMON)
331 			"ConMon "
332 #endif
333 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
334 			"FLTINJ "
335 #endif
336 #if defined(LWS_WITH_SYS_ASYNC_DNS)
337 			"ASYNC_DNS "
338 #endif
339 #if defined(LWS_WITH_SYS_NTPCLIENT)
340 			"NTPCLIENT "
341 #endif
342 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
343 			"DHCP_CLIENT "
344 #endif
345 ;
346 
347 #endif
348 
349 #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
350 static const struct lws_evlib_map {
351 	uint64_t	flag;
352 	const char	*name;
353 } map[] = {
354 	{ LWS_SERVER_OPTION_LIBUV,    "evlib_uv" },
355 	{ LWS_SERVER_OPTION_LIBEVENT, "evlib_event" },
356 	{ LWS_SERVER_OPTION_GLIB,     "evlib_glib" },
357 	{ LWS_SERVER_OPTION_LIBEV,    "evlib_ev" },
358 	{ LWS_SERVER_OPTION_SDEVENT,  "evlib_sd" },
359 	{ LWS_SERVER_OPTION_ULOOP,    "evlib_uloop" },
360 };
361 static const char * const dlist[] = {
362 	".",				/* Priority 1: plugins in cwd */
363 	LWS_INSTALL_LIBDIR,		/* Priority 2: plugins in install dir */
364 	NULL
365 };
366 #endif
367 
368 struct lws_context *
lws_create_context(const struct lws_context_creation_info * info)369 lws_create_context(const struct lws_context_creation_info *info)
370 {
371 	struct lws_context *context = NULL;
372 #if !defined(LWS_WITH_NO_LOGS)
373 	const char *s = "IPv6-absent";
374 #endif
375 #if defined(LWS_WITH_FILE_OPS)
376 	struct lws_plat_file_ops *prev;
377 #endif
378 #ifndef LWS_NO_DAEMONIZE
379 	pid_t pid_daemon = get_daemonize_pid();
380 #endif
381 #if defined(LWS_WITH_NETWORK)
382 	const lws_plugin_evlib_t *plev = NULL;
383 	unsigned short count_threads = 1;
384 	uint8_t *u;
385 	uint16_t us_wait_resolution = 0;
386 #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
387 	struct lws_cache_creation_info ci;
388 #endif
389 #if defined(LWS_WITH_MBEDTLS)
390 	char mbedtls_version[32];
391 #endif
392 
393 #if defined(__ANDROID__)
394 	struct rlimit rt;
395 #endif
396 	size_t
397 #if defined(LWS_PLAT_FREERTOS)
398 		/* smaller default, can set in info->pt_serv_buf_size */
399 		s1 = 2048,
400 #else
401 		s1 = 4096,
402 #endif
403 		size = sizeof(struct lws_context);
404 #endif
405 
406 	int n;
407 	unsigned int lpf = info->fd_limit_per_thread;
408 #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
409 	struct lws_plugin		*evlib_plugin_list = NULL;
410 #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
411 	char		*ld_env;
412 #endif
413 #endif
414 #if defined(LWS_WITH_LIBUV)
415 	char fatal_exit_defer = 0;
416 #endif
417 
418 
419 	if (lws_fi(&info->fic, "ctx_createfail1"))
420 		goto early_bail;
421 
422 	if (lpf) {
423 		lpf+= 2;
424 #if defined(LWS_WITH_SYS_ASYNC_DNS)
425 		lpf++;
426 #endif
427 #if defined(LWS_WITH_SYS_NTPCLIENT)
428 		lpf++;
429 #endif
430 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
431 		lpf++;
432 #endif
433 	}
434 
435 #if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_NO_LOGS)
436 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
437 		s = "IPV6-on";
438 	else
439 		s = "IPV6-off";
440 #endif
441 
442 	if (lws_plat_context_early_init())
443 		goto early_bail;
444 
445 #if defined(LWS_WITH_NETWORK)
446 	if (info->count_threads)
447 		count_threads = (unsigned short)info->count_threads;
448 
449 	if (count_threads > LWS_MAX_SMP)
450 		count_threads = LWS_MAX_SMP;
451 
452 	if (info->pt_serv_buf_size)
453 		s1 = info->pt_serv_buf_size;
454 
455 	/* pt fakewsi and the pt serv buf allocations ride after the context */
456 	size += count_threads * s1;
457 #if !defined(LWS_PLAT_FREERTOS)
458 	size += (count_threads * sizeof(struct lws));
459 #endif
460 
461 	if (info->event_lib_custom) {
462 		plev = info->event_lib_custom;
463 		us_wait_resolution = 0;
464 	}
465 #if defined(LWS_WITH_POLL)
466 	else {
467 		extern const lws_plugin_evlib_t evlib_poll;
468 		plev = &evlib_poll;
469 #if !defined(LWS_PLAT_FREERTOS)
470 		/*
471 		 * ... freertos has us-resolution select()...
472 		 * others are to ms-resolution poll()
473 		 */
474 		us_wait_resolution = 1000;
475 #endif
476 	}
477 #endif
478 
479 #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
480 
481 	/*
482 	 * New style dynamically loaded event lib support
483 	 *
484 	 * We have to pick and load the event lib plugin before we allocate
485 	 * the context object, so we can overallocate it correctly
486 	 */
487 
488 #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
489 	ld_env = getenv("LD_LIBRARY_PATH");
490 	lwsl_info("%s: ev lib path %s, '%s'\n", __func__,
491 			LWS_INSTALL_LIBDIR, ld_env);
492 #endif
493 
494 	for (n = 0; n < (int)LWS_ARRAY_SIZE(map); n++) {
495 		char ok = 0;
496 
497 		if (!lws_check_opt(info->options, map[n].flag))
498 			continue;
499 
500 		if (!lws_plugins_init(&evlib_plugin_list,
501 				     dlist, "lws_evlib_plugin",
502 				     map[n].name, NULL, NULL))
503 			ok = 1;
504 
505 		if (!ok || lws_fi(&info->fic, "ctx_createfail_plugin_init")) {
506 			lwsl_err("%s: failed to load %s\n", __func__,
507 					map[n].name);
508 			goto bail;
509 		}
510 
511 #if defined(LWS_WITH_LIBUV)
512 		if (!n) /* libuv */
513 			fatal_exit_defer = !!info->foreign_loops;
514 #endif
515 
516 		if (!evlib_plugin_list ||
517 		    lws_fi(&info->fic, "ctx_createfail_evlib_plugin")) {
518 			lwsl_err("%s: unable to load evlib plugin %s\n",
519 					__func__, map[n].name);
520 
521 			goto bail;
522 		}
523 		plev = (const lws_plugin_evlib_t *)evlib_plugin_list->hdr;
524 		break;
525 	}
526 #else
527 #if defined(LWS_WITH_EVENT_LIBS)
528 	/*
529 	 * set the context event loops ops struct
530 	 *
531 	 * after this, all event_loop actions use the generic ops
532 	 */
533 
534 	/*
535 	 * oldstyle built-in event lib support
536 	 *
537 	 * We have composed them into the libwebsockets lib itself, we can
538 	 * just pick the ops we want and done
539 	 */
540 
541 #if defined(LWS_WITH_LIBUV)
542 	if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) {
543 		extern const lws_plugin_evlib_t evlib_uv;
544 		plev = &evlib_uv;
545 		fatal_exit_defer = !!info->foreign_loops;
546 		us_wait_resolution = 0;
547 	}
548 #endif
549 
550 #if defined(LWS_WITH_LIBEVENT)
551 	if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT)) {
552 		extern const lws_plugin_evlib_t evlib_event;
553 		plev = &evlib_event;
554 		us_wait_resolution = 0;
555 	}
556 #endif
557 
558 #if defined(LWS_WITH_GLIB)
559 	if (lws_check_opt(info->options, LWS_SERVER_OPTION_GLIB)) {
560 		extern const lws_plugin_evlib_t evlib_glib;
561 		plev = &evlib_glib;
562 		us_wait_resolution = 0;
563 	}
564 #endif
565 
566 #if defined(LWS_WITH_LIBEV)
567 	if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) {
568 		extern const lws_plugin_evlib_t evlib_ev;
569 		plev = &evlib_ev;
570 		us_wait_resolution = 0;
571 	}
572 #endif
573 
574 #if defined(LWS_WITH_SDEVENT)
575     if (lws_check_opt(info->options, LWS_SERVER_OPTION_SDEVENT)) {
576         extern const lws_plugin_evlib_t evlib_sd;
577         plev = &evlib_sd;
578         us_wait_resolution = 0;
579     }
580 #endif
581 
582 #if defined(LWS_WITH_ULOOP)
583     if (lws_check_opt(info->options, LWS_SERVER_OPTION_ULOOP)) {
584         extern const lws_plugin_evlib_t evlib_uloop;
585         plev = &evlib_uloop;
586         us_wait_resolution = 0;
587     }
588 #endif
589 
590 #endif /* with event libs */
591 
592 #endif /* not with ev plugins */
593 
594 	if (!plev || lws_fi(&info->fic, "ctx_createfail_evlib_sel"))
595 		goto fail_event_libs;
596 
597 #if defined(LWS_WITH_NETWORK)
598 	size += (size_t)plev->ops->evlib_size_ctx /* the ctx evlib priv */ +
599 		(count_threads * (size_t)plev->ops->evlib_size_pt) /* the pt evlib priv */;
600 #endif
601 
602 	context = lws_zalloc(size, "context");
603 	if (!context || lws_fi(&info->fic, "ctx_createfail_oom_ctx")) {
604 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
605 		lws_free(context);
606 #endif
607 		lwsl_err("OOM");
608 		goto early_bail;
609 	}
610 
611 #if defined(LWS_WITH_SYS_STATE)
612    // NOTE: we need to init this fields because they may be used in logger when context destroying
613 	context->mgr_system.state_names = system_state_names;
614 	context->mgr_system.context = context;
615 #endif
616 
617 #if defined(LWS_WITH_NETWORK)
618 	context->event_loop_ops = plev->ops;
619 	context->us_wait_resolution = us_wait_resolution;
620 #if defined(LWS_WITH_TLS_JIT_TRUST)
621 	{
622 		struct lws_cache_creation_info ci;
623 
624 		memset(&ci, 0, sizeof(ci));
625 		ci.cx = context;
626 		ci.ops = &lws_cache_ops_heap;
627 		ci.name = "jitt";
628 		ci.max_footprint = info->jitt_cache_max_footprint;
629 		context->trust_cache = lws_cache_create(&ci);
630 	}
631 #endif
632 #endif
633 #if defined(LWS_WITH_EVENT_LIBS)
634 	/* at the very end */
635 	context->evlib_ctx = (uint8_t *)context + size -
636 					plev->ops->evlib_size_ctx;
637 #endif
638 #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
639 	context->evlib_plugin_list = evlib_plugin_list;
640 #endif
641 
642 #if !defined(LWS_PLAT_FREERTOS)
643 	context->uid = info->uid;
644 	context->gid = info->gid;
645 	context->username = info->username;
646 	context->groupname = info->groupname;
647 #endif
648 	context->name			= info->vhost_name;
649 	if (info->log_cx)
650 		context->log_cx = info->log_cx;
651 	else
652 		context->log_cx = &log_cx;
653 	lwsl_refcount_cx(context->log_cx, 1);
654 
655 	context->system_ops = info->system_ops;
656 	context->pt_serv_buf_size = (unsigned int)s1;
657 	context->protocols_copy = info->protocols;
658 #if defined(LWS_WITH_TLS_JIT_TRUST)
659 	context->vh_idle_grace_ms = info->vh_idle_grace_ms ?
660 			info->vh_idle_grace_ms : 5000;
661 #endif
662 
663 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
664 	context->fic.name = "ctx";
665 	if (info->fic.fi_owner.count)
666 		/*
667 		 * This moves all the lws_fi_t from info->fi to the context fi,
668 		 * leaving it empty, so no injection added to default vhost
669 		 */
670 		lws_fi_import(&context->fic, &info->fic);
671 #endif
672 
673 
674 #if defined(LWS_WITH_SYS_SMD)
675 	context->smd_ttl_us = info->smd_ttl_us ? info->smd_ttl_us :
676 #if defined(LWS_PLAT_FREERTOS)
677 			5000000;
678 #else
679 			2000000;
680 #endif
681 	context->smd_queue_depth = (uint16_t)(info->smd_queue_depth ?
682 						info->smd_queue_depth :
683 #if defined(LWS_PLAT_FREERTOS)
684 						20);
685 #else
686 						40);
687 #endif
688 #endif
689 
690 #if defined(LWS_WITH_NETWORK)
691 	context->lcg[LWSLCG_WSI].tag_prefix = "wsi";
692 	context->lcg[LWSLCG_VHOST].tag_prefix = "vh";
693 	context->lcg[LWSLCG_WSI_SERVER].tag_prefix = "wsisrv"; /* adopted */
694 
695 #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
696 	context->lcg[LWSLCG_WSI_MUX].tag_prefix = "mux"; /* a mux child wsi */
697 #endif
698 
699 #if defined(LWS_WITH_CLIENT)
700 	context->lcg[LWSLCG_WSI_CLIENT].tag_prefix = "wsicli";
701 #endif
702 
703 #if defined(LWS_WITH_SECURE_STREAMS)
704 #if defined(LWS_WITH_CLIENT)
705 	context->lcg[LWSLCG_SS_CLIENT].tag_prefix = "SScli";
706 #endif
707 #if defined(LWS_WITH_SERVER)
708 	context->lcg[LWSLCG_SS_SERVER].tag_prefix = "SSsrv";
709 #endif
710 #if defined(LWS_WITH_CLIENT)
711 	context->lcg[LWSLCG_WSI_SS_CLIENT].tag_prefix = "wsiSScli";
712 #endif
713 #if defined(LWS_WITH_SERVER)
714 	context->lcg[LWSLCG_WSI_SS_SERVER].tag_prefix = "wsiSSsrv";
715 #endif
716 #endif
717 #endif
718 
719 #if defined(LWS_WITH_SYS_METRICS)
720 	/*
721 	 * If we're not using secure streams, we can still pass in a linked-
722 	 * list of metrics policies
723 	 */
724 	context->metrics_policies = info->metrics_policies;
725 	context->metrics_prefix = info->metrics_prefix;
726 
727 	context->mt_service = lws_metric_create(context,
728 					LWSMTFL_REPORT_DUTY_WALLCLOCK_US |
729 					LWSMTFL_REPORT_ONLY_GO, "cpu.svc");
730 
731 #if defined(LWS_WITH_CLIENT)
732 
733 	context->mt_conn_dns = lws_metric_create(context,
734 						 LWSMTFL_REPORT_MEAN |
735 						 LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
736 						 "n.cn.dns");
737 	context->mt_conn_tcp = lws_metric_create(context,
738 						 LWSMTFL_REPORT_MEAN |
739 						 LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
740 						 "n.cn.tcp");
741 	context->mt_conn_tls = lws_metric_create(context,
742 						 LWSMTFL_REPORT_MEAN |
743 						 LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
744 						 "n.cn.tls");
745 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
746 	context->mt_http_txn = lws_metric_create(context,
747 						 LWSMTFL_REPORT_MEAN |
748 						 LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
749 						 "n.http.txn");
750 #endif
751 
752 	context->mth_conn_failures = lws_metric_create(context,
753 					LWSMTFL_REPORT_HIST, "n.cn.failures");
754 
755 #if defined(LWS_WITH_SYS_ASYNC_DNS)
756 	context->mt_adns_cache = lws_metric_create(context,
757 						   LWSMTFL_REPORT_MEAN |
758 						   LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
759 						   "n.cn.adns");
760 #endif
761 #if defined(LWS_WITH_SECURE_STREAMS)
762 	context->mth_ss_conn = lws_metric_create(context, LWSMTFL_REPORT_HIST,
763 						 "n.ss.conn");
764 #endif
765 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
766 	context->mt_ss_cliprox_conn = lws_metric_create(context,
767 			LWSMTFL_REPORT_HIST,
768 							"n.ss.cliprox.conn");
769 	context->mt_ss_cliprox_paylat = lws_metric_create(context,
770 							  LWSMTFL_REPORT_MEAN |
771 							  LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
772 							  "n.ss.cliprox.paylat");
773 	context->mt_ss_proxcli_paylat = lws_metric_create(context,
774 							  LWSMTFL_REPORT_MEAN |
775 							  LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
776 							  "n.ss.proxcli.paylat");
777 #endif
778 
779 #endif /* network + metrics + client */
780 
781 #if defined(LWS_WITH_SERVER)
782 	context->mth_srv = lws_metric_create(context,
783 					     LWSMTFL_REPORT_HIST, "n.srv");
784 #endif /* network + metrics + server */
785 
786 #endif /* network + metrics */
787 
788 #endif /* network */
789 
790 #if defined(LWS_WITH_MBEDTLS)
791 	mbedtls_version_get_string(mbedtls_version);
792 #endif
793 
794 #if defined(LWS_WITH_MBEDTLS)
795 	lwsl_cx_notice(context, "LWS: %s, MbedTLS-%s %s%s", library_version, mbedtls_version, opts_str, s);
796 #else
797 	lwsl_cx_notice(context, "LWS: %s, %s%s", library_version, opts_str, s);
798 #endif
799 
800 #if defined(LWS_WITH_NETWORK)
801 	lwsl_cx_info(context, "Event loop: %s", plev->ops->name);
802 #endif
803 
804 	/*
805 	 * Proxy group
806 	 */
807 
808 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
809 #if defined(LWS_WITH_CLIENT)
810 	context->lcg[LWSLCG_SSP_CLIENT].tag_prefix = "SSPcli";
811 #endif
812 #if defined(LWS_WITH_SERVER)
813 	context->lcg[LWSLCG_SSP_ONWARD].tag_prefix = "SSPonw";
814 #endif
815 #if defined(LWS_WITH_CLIENT)
816 	context->lcg[LWSLCG_WSI_SSP_CLIENT].tag_prefix = "wsiSSPcli";
817 #endif
818 #if defined(LWS_WITH_SERVER)
819 	context->lcg[LWSLCG_WSI_SSP_ONWARD].tag_prefix = "wsiSSPonw";
820 #endif
821 #endif
822 
823 
824 #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
825 	/* directly use the user-provided policy object list */
826 	context->pss_policies = info->pss_policies;
827 #endif
828 
829 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT)
830 	context->ss_proxy_bind = info->ss_proxy_bind;
831 	context->ss_proxy_port = info->ss_proxy_port;
832 	context->ss_proxy_address = info->ss_proxy_address;
833 	if (context->ss_proxy_bind && context->ss_proxy_address)
834 		lwsl_cx_notice(context, "ss proxy bind '%s', port %d, ads '%s'",
835 			context->ss_proxy_bind, context->ss_proxy_port,
836 			context->ss_proxy_address);
837 #endif
838 
839 #if defined(LWS_WITH_NETWORK)
840 	context->undestroyed_threads = count_threads;
841 	context->count_threads = count_threads;
842 
843 #if defined(LWS_ROLE_WS) && defined(LWS_WITHOUT_EXTENSIONS)
844         if (info->extensions)
845                 lwsl_cx_warn(context, "WITHOUT_EXTENSIONS but exts ptr set");
846 #endif
847 #endif /* network */
848 
849 #if defined(LWS_WITH_SECURE_STREAMS)
850 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
851 	context->pss_policies_json = info->pss_policies_json;
852 #endif
853 #if defined(LWS_WITH_SSPLUGINS)
854 	context->pss_plugins = info->pss_plugins;
855 #endif
856 #endif
857 
858 	/* if he gave us names, set the uid / gid */
859 	if (lws_plat_drop_app_privileges(context, 0) ||
860 	    lws_fi(&context->fic, "ctx_createfail_privdrop"))
861 		goto free_context_fail2;
862 
863 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
864 #if defined(LWS_WITH_MBEDTLS)
865 	context->tls_ops = &tls_ops_mbedtls;
866 
867 	mbedtls_client_preload_filepath = info->mbedtls_client_preload_filepath;
868 #else
869 	context->tls_ops = &tls_ops_openssl;
870 #endif
871 #endif
872 
873 #if LWS_MAX_SMP > 1
874 	lws_mutex_refcount_init(&context->mr);
875 #endif
876 
877 #if defined(LWS_PLAT_FREERTOS)
878 #if defined(LWS_AMAZON_RTOS)
879 	context->last_free_heap = xPortGetFreeHeapSize();
880 #else
881 	context->last_free_heap = esp_get_free_heap_size();
882 #endif
883 #endif
884 
885 #if defined(LWS_WITH_FILE_OPS)
886 	/* default to just the platform fops implementation */
887 
888 	context->fops_platform.LWS_FOP_OPEN	= _lws_plat_file_open;
889 	context->fops_platform.LWS_FOP_CLOSE	= _lws_plat_file_close;
890 	context->fops_platform.LWS_FOP_SEEK_CUR	= _lws_plat_file_seek_cur;
891 	context->fops_platform.LWS_FOP_READ	= _lws_plat_file_read;
892 	context->fops_platform.LWS_FOP_WRITE	= _lws_plat_file_write;
893 	context->fops_platform.fi[0].sig	= NULL;
894 
895 	/*
896 	 *  arrange a linear linked-list of fops starting from context->fops
897 	 *
898 	 * platform fops
899 	 * [ -> fops_zip (copied into context so .next settable) ]
900 	 * [ -> info->fops ]
901 	 */
902 
903 	context->fops = &context->fops_platform;
904 	prev = (struct lws_plat_file_ops *)context->fops;
905 
906 #if defined(LWS_WITH_ZIP_FOPS)
907 	/* make a soft copy so we can set .next */
908 	context->fops_zip = fops_zip;
909 	prev->next = &context->fops_zip;
910 	prev = (struct lws_plat_file_ops *)prev->next;
911 #endif
912 
913 	/* if user provided fops, tack them on the end of the list */
914 	if (info->fops)
915 		prev->next = info->fops;
916 #endif
917 
918 #if defined(LWS_WITH_SERVER)
919 	context->reject_service_keywords = info->reject_service_keywords;
920 #endif
921 	if (info->external_baggage_free_on_destroy)
922 		context->external_baggage_free_on_destroy =
923 			info->external_baggage_free_on_destroy;
924 #if defined(LWS_WITH_NETWORK)
925 	context->time_up = lws_now_usecs();
926 #endif
927 	context->pcontext_finalize = info->pcontext;
928 
929 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
930 	context->simultaneous_ssl_restriction =
931 			info->simultaneous_ssl_restriction;
932 	context->simultaneous_ssl_handshake_restriction =
933 			info->simultaneous_ssl_handshake_restriction;
934 #endif
935 
936 	context->options = info->options;
937 
938 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE) && !defined(WIN32)
939 	/*
940 	 * If asked, try to set the rlimit / ulimit for process sockets / files.
941 	 * We read the effective limit in a moment, so we will find out the
942 	 * real limit according to system constraints then.
943 	 */
944 	if (info->rlimit_nofile) {
945 		struct rlimit rl;
946 
947 		rl.rlim_cur = (unsigned int)info->rlimit_nofile;
948 		rl.rlim_max = (unsigned int)info->rlimit_nofile;
949 		setrlimit(RLIMIT_NOFILE, &rl);
950 	}
951 #endif
952 
953 #ifndef LWS_NO_DAEMONIZE
954 	if (pid_daemon) {
955 		context->started_with_parent = pid_daemon;
956 		lwsl_cx_info(context, " Started with daemon pid %u",
957 				(unsigned int)pid_daemon);
958 	}
959 #endif
960 #if defined(__ANDROID__)
961 	n = getrlimit(RLIMIT_NOFILE, &rt);
962 	if (n == -1) {
963 		lwsl_cx_err(context, "Get RLIMIT_NOFILE failed!");
964 
965 		goto free_context_fail2;
966 	}
967 	context->max_fds = (unsigned int)rt.rlim_cur;
968 #else
969 #if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS) || defined(LWS_ESP_PLATFORM)
970 	context->max_fds = getdtablesize();
971 #else
972 	{
973 		long l = sysconf(_SC_OPEN_MAX);
974 
975 		context->max_fds = 2560;
976 
977 		if (l > 10000000)
978 			lwsl_cx_warn(context, "unreasonable ulimit -n workaround");
979 		else
980 			if (l != -1l)
981 				context->max_fds = (unsigned int)l;
982 	}
983 #endif
984 	if ((int)context->max_fds < 0 ||
985 	     lws_fi(&context->fic, "ctx_createfail_maxfds")) {
986 		lwsl_cx_err(context, "problem getting process max files");
987 
988 		goto free_context_fail2;
989 	}
990 #endif
991 
992 	/*
993 	 * deal with any max_fds override, if it's reducing (setting it to
994 	 * more than ulimit -n is meaningless).  The platform init will
995 	 * figure out what if this is something it can deal with.
996 	 */
997 	if (info->fd_limit_per_thread) {
998 		unsigned int mf = lpf * context->count_threads;
999 
1000 		if (mf < context->max_fds) {
1001 			context->max_fds_unrelated_to_ulimit = 1;
1002 			context->max_fds = mf;
1003 		}
1004 	}
1005 
1006 #if defined(LWS_WITH_NETWORK)
1007 	context->token_limits = info->token_limits;
1008 #endif
1009 
1010 
1011 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
1012 	time(&context->tls.last_cert_check_s);
1013 	if (info->alpn)
1014 		context->tls.alpn_default = info->alpn;
1015 	else {
1016 		char *p = context->tls.alpn_discovered, first = 1;
1017 
1018 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
1019 			if (ar->alpn) {
1020 				if (!first)
1021 					*p++ = ',';
1022 				p += lws_snprintf(p, (unsigned int)(
1023 					(context->tls.alpn_discovered +
1024 					sizeof(context->tls.alpn_discovered) -
1025 					2) - p), "%s", ar->alpn);
1026 				first = 0;
1027 			}
1028 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
1029 
1030 		context->tls.alpn_default = context->tls.alpn_discovered;
1031 	}
1032 
1033 #endif
1034 #if defined(LWS_WITH_NETWORK)
1035 	if (info->timeout_secs)
1036 		context->timeout_secs = info->timeout_secs;
1037 	else
1038 #endif
1039 		context->timeout_secs = 15;
1040 
1041 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1042 	if (info->max_http_header_data)
1043 		context->max_http_header_data = info->max_http_header_data;
1044 	else
1045 		if (info->max_http_header_data2)
1046 			context->max_http_header_data =
1047 					(unsigned short)info->max_http_header_data2;
1048 		else
1049 			context->max_http_header_data = LWS_DEF_HEADER_LEN;
1050 
1051 	if (info->max_http_header_pool)
1052 		context->max_http_header_pool = info->max_http_header_pool;
1053 	else
1054 		if (info->max_http_header_pool2)
1055 			context->max_http_header_pool =
1056 					(unsigned short)info->max_http_header_pool2;
1057 		else
1058 			context->max_http_header_pool = context->max_fds;
1059 #endif
1060 
1061 	if (info->fd_limit_per_thread)
1062 		context->fd_limit_per_thread = lpf;
1063 	else
1064 		if (context->count_threads)
1065 			context->fd_limit_per_thread = context->max_fds /
1066 							context->count_threads;
1067 
1068 #if defined(LWS_WITH_SYS_SMD)
1069 	lws_mutex_init(context->smd.lock_messages);
1070 	lws_mutex_init(context->smd.lock_peers);
1071 
1072 	/* lws_system smd participant */
1073 
1074 	if (!lws_smd_register(context, context, 0, LWSSMDCL_NETWORK,
1075 			      lws_system_smd_cb)) {
1076 		lwsl_cx_err(context, "early smd register failed");
1077 	}
1078 
1079 	/* user smd participant */
1080 
1081 	if (info->early_smd_cb &&
1082 	    !lws_smd_register(context, info->early_smd_opaque, 0,
1083 			      info->early_smd_class_filter,
1084 			      info->early_smd_cb)) {
1085 		lwsl_cx_err(context, "early smd register failed");
1086 	}
1087 #endif
1088 
1089 	n = 0;
1090 #if defined(LWS_WITH_NETWORK)
1091 
1092 	context->default_retry.retry_ms_table = default_backoff_table;
1093 	context->default_retry.conceal_count =
1094 			context->default_retry.retry_ms_table_count =
1095 					LWS_ARRAY_SIZE(default_backoff_table);
1096 	context->default_retry.jitter_percent = 20;
1097 	context->default_retry.secs_since_valid_ping = 300;
1098 	context->default_retry.secs_since_valid_hangup = 310;
1099 
1100 	if (info->retry_and_idle_policy &&
1101 	    info->retry_and_idle_policy->secs_since_valid_ping) {
1102 		context->default_retry.secs_since_valid_ping =
1103 				info->retry_and_idle_policy->secs_since_valid_ping;
1104 		context->default_retry.secs_since_valid_hangup =
1105 				info->retry_and_idle_policy->secs_since_valid_hangup;
1106 	}
1107 
1108 	/*
1109 	 * Allocate the per-thread storage for scratchpad buffers,
1110 	 * and header data pool
1111 	 */
1112 	u = (uint8_t *)&context[1];
1113 	for (n = 0; n < context->count_threads; n++) {
1114 		context->pt[n].serv_buf = u;
1115 		u += context->pt_serv_buf_size;
1116 
1117 		context->pt[n].context = context;
1118 		context->pt[n].tid = (uint8_t)n;
1119 
1120 #if !defined(LWS_PLAT_FREERTOS)
1121 		/*
1122 		 * We overallocated for a fakewsi (can't compose it in the
1123 		 * pt because size isn't known at that time).  point to it
1124 		 * and zero it down.  Fakewsis are needed to make callbacks work
1125 		 * when the source of the callback is not actually from a wsi
1126 		 * context.
1127 		 */
1128 		context->pt[n].fake_wsi = (struct lws *)u;
1129 		u += sizeof(struct lws);
1130 
1131 		memset(context->pt[n].fake_wsi, 0, sizeof(struct lws));
1132 #endif
1133 
1134 		context->pt[n].evlib_pt = u;
1135 		u += plev->ops->evlib_size_pt;
1136 
1137 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1138 		context->pt[n].http.ah_list = NULL;
1139 		context->pt[n].http.ah_pool_length = 0;
1140 #endif
1141 		lws_pt_mutex_init(&context->pt[n]);
1142 #if defined(LWS_WITH_SEQUENCER)
1143 		lws_seq_pt_init(&context->pt[n]);
1144 #endif
1145 
1146 #if defined(LWS_WITH_CGI)
1147 		if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy))
1148 			(lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)).
1149 				pt_init_destroy(context, info,
1150 						&context->pt[n], 0);
1151 #endif
1152 	}
1153 
1154 	if (!info->ka_interval && info->ka_time > 0) {
1155 		lwsl_cx_err(context, "info->ka_interval can't be 0 if ka_time used");
1156 		goto free_context_fail;
1157 	}
1158 
1159 #if defined(LWS_WITH_PEER_LIMITS)
1160 	/* scale the peer hash table according to the max fds for the process,
1161 	 * so that the max list depth averages 16.  Eg, 1024 fd -> 64,
1162 	 * 102400 fd -> 6400
1163 	 */
1164 
1165 	context->pl_hash_elements =
1166 		(context->count_threads * context->fd_limit_per_thread) / 16;
1167 	context->pl_hash_table = lws_zalloc(sizeof(struct lws_peer *) *
1168 			context->pl_hash_elements, "peer limits hash table");
1169 
1170 	context->ip_limit_ah = info->ip_limit_ah;
1171 	context->ip_limit_wsi = info->ip_limit_wsi;
1172 	context->pl_notify_cb = info->pl_notify_cb;
1173 #endif
1174 
1175 	/*
1176 	 * fds table contains pollfd structs for as many pollfds as we can
1177 	 * handle... spread across as many service threads as we have going
1178 	 */
1179 	n = (int)(sizeof(struct lws_pollfd) * context->count_threads *
1180 	    context->fd_limit_per_thread);
1181 	context->pt[0].fds = lws_zalloc((unsigned int)n, "fds table");
1182 	if (context->pt[0].fds == NULL ||
1183 	    lws_fi(&context->fic, "ctx_createfail_oom_fds")) {
1184 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
1185 		lws_free(context->pt[0].fds);
1186 #endif
1187 		lwsl_cx_err(context, "OOM allocating %d fds\n", context->max_fds);
1188 		goto free_context_fail;
1189 	}
1190 #endif
1191 
1192 	lwsl_cx_info(context, "ctx: %5luB (%ld ctx + pt(%ld thr x %d)), "
1193 		  "pt-fds: %d, fdmap: %d",
1194 		  (long)sizeof(struct lws_context) +
1195 		  (context->count_threads * context->pt_serv_buf_size),
1196 		  (long)sizeof(struct lws_context),
1197 		  (long)context->count_threads,
1198 		  context->pt_serv_buf_size,
1199 		  context->fd_limit_per_thread, n);
1200 
1201 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1202 	lwsl_cx_info(context, " http: ah_data: %u, ah: %lu, max count %u",
1203 		    context->max_http_header_data,
1204 		    (long)sizeof(struct allocated_headers),
1205 		    context->max_http_header_pool);
1206 #endif
1207 
1208 #if defined(LWS_WITH_SERVER)
1209 	if (info->server_string) {
1210 		context->server_string = info->server_string;
1211 		context->server_string_len = (short)
1212 				strlen(context->server_string);
1213 	}
1214 #endif
1215 
1216 #if LWS_MAX_SMP > 1
1217 	/* each thread serves his own chunk of fds */
1218 	for (n = 1; n < (int)context->count_threads; n++)
1219 		context->pt[n].fds = context->pt[n - 1].fds +
1220 				     context->fd_limit_per_thread;
1221 #endif
1222 
1223 
1224 	/*
1225 	 * Past here, we may have added handles to the event lib
1226 	 * loop and if libuv,  have to take care about how to unpick them...
1227 	 */
1228 
1229 	if (lws_plat_init(context, info) ||
1230 	    lws_fi(&context->fic, "ctx_createfail_plat_init"))
1231 		goto bail_libuv_aware;
1232 
1233 #if defined(LWS_WITH_NETWORK)
1234 
1235 	if (lws_fi(&context->fic, "ctx_createfail_evlib_init"))
1236 		goto bail_libuv_aware;
1237 
1238 	if (context->event_loop_ops->init_context)
1239 		if (context->event_loop_ops->init_context(context, info))
1240 			goto bail_libuv_aware;
1241 
1242 	if (lws_fi(&context->fic, "ctx_createfail_evlib_pt"))
1243 		goto bail_libuv_aware;
1244 
1245 	if (context->event_loop_ops->init_pt)
1246 		for (n = 0; n < context->count_threads; n++) {
1247 			void *lp = NULL;
1248 
1249 			if (info->foreign_loops)
1250 				lp = info->foreign_loops[n];
1251 
1252 			if (context->event_loop_ops->init_pt(context, lp, n))
1253 				goto bail_libuv_aware;
1254 		}
1255 
1256 	lws_context_lock(context, __func__);
1257 	n = __lws_create_event_pipes(context);
1258 	lws_context_unlock(context);
1259 	if (n)
1260 		goto bail_libuv_aware;
1261 
1262 	for (n = 0; n < context->count_threads; n++) {
1263 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
1264 			if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
1265 				(lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
1266 					pt_init_destroy(context, info,
1267 							&context->pt[n], 0);
1268 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
1269 	}
1270 #endif
1271 
1272 	lws_context_init_ssl_library(context, info);
1273 
1274 	context->user_space = info->user;
1275 
1276 #if defined(LWS_WITH_SERVER)
1277 	strcpy(context->canonical_hostname, "unknown");
1278 #if defined(LWS_WITH_NETWORK)
1279 	lws_server_get_canonical_hostname(context, info);
1280 #endif
1281 #endif
1282 
1283 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
1284 	memcpy(context->caps, info->caps, sizeof(context->caps));
1285 	context->count_caps = info->count_caps;
1286 #endif
1287 
1288 
1289 #if defined(LWS_WITH_NETWORK)
1290 
1291 #if defined(LWS_WITH_SYS_ASYNC_DNS) || defined(LWS_WITH_SYS_NTPCLIENT) || \
1292 	defined(LWS_WITH_SYS_DHCP_CLIENT)
1293 	{
1294 		/*
1295 		 * system vhost
1296 		 */
1297 
1298 		struct lws_context_creation_info ii;
1299 		const struct lws_protocols *pp[4];
1300 		struct lws_vhost *vh;
1301 #if defined(LWS_WITH_SYS_ASYNC_DNS)
1302 		extern const struct lws_protocols lws_async_dns_protocol;
1303 #endif
1304 #if defined(LWS_WITH_SYS_NTPCLIENT)
1305 		extern const struct lws_protocols lws_system_protocol_ntpc;
1306 #endif
1307 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
1308 		extern const struct lws_protocols lws_system_protocol_dhcpc4;
1309 #endif
1310 
1311 		n = 0;
1312 #if defined(LWS_WITH_SYS_ASYNC_DNS)
1313 		pp[n++] = &lws_async_dns_protocol;
1314 #endif
1315 #if defined(LWS_WITH_SYS_NTPCLIENT)
1316 		pp[n++] = &lws_system_protocol_ntpc;
1317 #endif
1318 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
1319 		pp[n++] = &lws_system_protocol_dhcpc4;
1320 #endif
1321 		pp[n] = NULL;
1322 
1323 		memset(&ii, 0, sizeof(ii));
1324 		ii.vhost_name = "system";
1325 		ii.pprotocols = pp;
1326 		ii.port = CONTEXT_PORT_NO_LISTEN;
1327 
1328 		if (lws_fi(&context->fic, "ctx_createfail_sys_vh"))
1329 			vh = NULL;
1330 		else
1331 			vh = lws_create_vhost(context, &ii);
1332 		if (!vh) {
1333 			lwsl_cx_err(context, "failed to create system vhost");
1334 			goto bail_libuv_aware;
1335 		}
1336 
1337 		context->vhost_system = vh;
1338 
1339 		if (lws_protocol_init_vhost(vh, NULL) ||
1340 		    lws_fi(&context->fic, "ctx_createfail_sys_vh_init")) {
1341 			lwsl_cx_err(context, "failed to init system vhost");
1342 			goto bail_libuv_aware;
1343 		}
1344 #if defined(LWS_WITH_SYS_ASYNC_DNS)
1345 		lws_async_dns_init(context);
1346 			//goto bail_libuv_aware;
1347 #endif
1348 	}
1349 
1350 #endif
1351 
1352 #if defined(LWS_WITH_SYS_STATE)
1353 	/*
1354 	 * init the lws_state mgr for the system state
1355 	 */
1356 
1357 	context->mgr_system.name		= "system";
1358 	context->mgr_system.state		= LWS_SYSTATE_CONTEXT_CREATED;
1359 	context->mgr_system.parent		= context;
1360 #if defined(LWS_WITH_SYS_SMD)
1361 	context->mgr_system.smd_class		= LWSSMDCL_SYSTEM_STATE;
1362 #endif
1363 
1364 	context->protocols_notify.name		= "prot_init";
1365 	context->protocols_notify.notify_cb	= lws_state_notify_protocol_init;
1366 
1367 	lws_state_reg_notifier(&context->mgr_system, &context->protocols_notify);
1368 
1369 	/*
1370 	 * insert user notifiers here so they can participate with vetoing us
1371 	 * trying to jump straight to operational, or at least observe us
1372 	 * reaching 'operational', before we returned from context creation.
1373 	 */
1374 
1375 	lws_state_reg_notifier_list(&context->mgr_system,
1376 				    info->register_notifier_list);
1377 #endif
1378 
1379 	/*
1380 	 * if he's not saying he'll make his own vhosts later then act
1381 	 * compatibly and make a default vhost using the data in the info
1382 	 */
1383 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
1384 		if (!lws_create_vhost(context, info) ||
1385 		    lws_fi(&context->fic, "ctx_createfail_def_vh")) {
1386 			lwsl_cx_err(context, "Failed to create default vhost");
1387 
1388 #if defined(LWS_WITH_PEER_LIMITS)
1389 			lws_free_set_NULL(context->pl_hash_table);
1390 #endif
1391 			goto bail;
1392 		}
1393 	}
1394 
1395 #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
1396 	if (info->http_nsc_filepath) {
1397 		memset(&ci, 0, sizeof(ci));
1398 
1399 		ci.cx			   = context;
1400 		ci.ops			   = &lws_cache_ops_nscookiejar;
1401 		ci.name			   = "NSC";
1402 		ci.u.nscookiejar.filepath  = info->http_nsc_filepath;
1403 
1404 		context->nsc = lws_cache_create(&ci);
1405 		if (!context->nsc)
1406 			goto bail;
1407 
1408 		ci.ops			  = &lws_cache_ops_heap;
1409 		ci.name			  = "L1";
1410 		ci.parent		  = context->nsc;
1411 		ci.max_footprint	  = info->http_nsc_heap_max_footprint;
1412 		ci.max_items		  = info->http_nsc_heap_max_items;
1413 		ci.max_payload		  = info->http_nsc_heap_max_payload;
1414 
1415 		context->l1 = lws_cache_create(&ci);
1416 		if (!context->l1) {
1417 			lwsl_cx_err(context, "Failed to init cookiejar");
1418 			goto bail;
1419 		}
1420 	}
1421 #endif
1422 
1423 #if defined(LWS_WITH_SECURE_STREAMS)
1424 
1425 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
1426 	if (context->pss_policies_json) {
1427 		/*
1428 		 * You must create your context with the explicit vhosts flag
1429 		 * in order to use secure streams
1430 		 */
1431 		assert(lws_check_opt(info->options,
1432 		       LWS_SERVER_OPTION_EXPLICIT_VHOSTS));
1433 
1434 		if (lws_ss_policy_parse_begin(context, 0) ||
1435 		    lws_fi(&context->fic, "ctx_createfail_ss_pol1")) {
1436 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
1437 			lws_ss_policy_parse_abandon(context);
1438 #endif
1439 			goto bail_libuv_aware;
1440 		}
1441 
1442 		n = lws_ss_policy_parse(context,
1443 					(uint8_t *)context->pss_policies_json,
1444 					strlen(context->pss_policies_json));
1445 		if ((n != LEJP_CONTINUE && n < 0) ||
1446 		    lws_fi(&context->fic, "ctx_createfail_ss_pol2")) {
1447 			lws_ss_policy_parse_abandon(context);
1448 			goto bail_libuv_aware;
1449 		}
1450 
1451 		if (lws_ss_policy_set(context, "hardcoded") ||
1452 		    lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
1453 			lwsl_cx_err(context, "policy set failed");
1454 			goto bail_libuv_aware;
1455 		}
1456 	}
1457 #else
1458 	if (context->pss_policies) {
1459 		/* user code set the policy objects directly, no parsing step */
1460 
1461 		if (lws_ss_policy_set(context, "hardcoded") ||
1462 		    lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
1463 			lwsl_cx_err(context, "policy set failed");
1464 			goto bail_libuv_aware;
1465 		}
1466 	}
1467 #endif
1468 #endif
1469 
1470 	lws_context_init_extensions(info, context);
1471 
1472 	lwsl_cx_info(context, " mem: per-conn:        %5lu bytes + protocol rx buf",
1473 		    (unsigned long)sizeof(struct lws));
1474 
1475 	/*
1476 	 * drop any root privs for this process
1477 	 * to listen on port < 1023 we would have needed root, but now we are
1478 	 * listening, we don't want the power for anything else
1479 	 */
1480 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
1481 		if (lws_plat_drop_app_privileges(context, 1) ||
1482 		    lws_fi(&context->fic, "ctx_createfail_privdrop"))
1483 			goto bail_libuv_aware;
1484 
1485 #if defined(LWS_WITH_SYS_STATE)
1486 	/*
1487 	 * We want to move on the syste, state as far as it can go towards
1488 	 * OPERATIONAL now.  But we have to return from here first so the user
1489 	 * code that called us can set its copy of context, which it may be
1490 	 * relying on to perform operations triggered by the state change.
1491 	 *
1492 	 * We set up a sul to come back immediately and do the state change.
1493 	 */
1494 
1495 	lws_sul_schedule(context, 0, &context->sul_system_state,
1496 			 lws_context_creation_completion_cb, 1);
1497 #endif
1498 
1499 	/* expedite post-context init (eg, protocols) */
1500 	lws_cancel_service(context);
1501 #endif
1502 
1503 	return context;
1504 
1505 early_bail:
1506 	lws_fi_destroy(&info->fic);
1507 
1508 	return NULL;
1509 
1510 #if defined(LWS_WITH_NETWORK)
1511 bail:
1512 	lws_fi_destroy(&info->fic);
1513 	lws_context_destroy(context);
1514 
1515 	return NULL;
1516 #endif
1517 
1518 bail_libuv_aware:
1519 	lws_context_destroy(context);
1520 #if defined(LWS_WITH_LIBUV)
1521 	return fatal_exit_defer ? context : NULL;
1522 #else
1523 	return NULL;
1524 #endif
1525 
1526 #if defined(LWS_WITH_NETWORK)
1527 fail_event_libs:
1528 	if (context)
1529 	lwsl_cx_err(context, "Requested event library support not configured");
1530 #endif
1531 
1532 #if defined(LWS_WITH_NETWORK)
1533 free_context_fail:
1534 	if (context) {
1535 #if defined(LWS_WITH_SYS_SMD)
1536 		_lws_smd_destroy(context);
1537 #endif
1538 	}
1539 #endif
1540 free_context_fail2:
1541 	if (context) {
1542 #if defined(LWS_WITH_SYS_METRICS)
1543 		lws_metrics_destroy(context);
1544 #endif
1545 		lws_fi_destroy(&context->fic);
1546 	}
1547 	lws_fi_destroy(&info->fic);
1548 	if (context) {
1549 		lwsl_refcount_cx(context->log_cx, -1);
1550 		lws_free(context);
1551 	}
1552 
1553 	return NULL;
1554 }
1555 
1556 #if defined(LWS_WITH_NETWORK)
1557 int
lws_system_cpd_start(struct lws_context * cx)1558 lws_system_cpd_start(struct lws_context *cx)
1559 {
1560 	cx->captive_portal_detect = LWS_CPD_UNKNOWN;
1561 
1562 	/* if there's a platform implementation, use it */
1563 
1564 	if (lws_system_get_ops(cx) &&
1565 	    lws_system_get_ops(cx)->captive_portal_detect_request)
1566 		return lws_system_get_ops(cx)->captive_portal_detect_request(cx);
1567 
1568 #if defined(LWS_WITH_SECURE_STREAMS)
1569 	/*
1570 	 * Otherwise try to use SS "captive_portal_detect" if that's enabled
1571 	 */
1572 	return lws_ss_sys_cpd(cx);
1573 #else
1574 	return 0;
1575 #endif
1576 }
1577 
1578 static void
lws_system_deferred_cb(lws_sorted_usec_list_t * sul)1579 lws_system_deferred_cb(lws_sorted_usec_list_t *sul)
1580 {
1581 	struct lws_context *cx =
1582 		     lws_container_of(sul, struct lws_context, sul_cpd_defer);
1583 
1584 	lws_system_cpd_start(cx);
1585 }
1586 
1587 void
lws_system_cpd_start_defer(struct lws_context * cx,lws_usec_t defer_us)1588 lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us)
1589 {
1590 	lws_sul_schedule(cx, 0, &cx->sul_cpd_defer,
1591 			 lws_system_deferred_cb, defer_us);
1592 }
1593 
1594 #if (defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_SYS_SMD)) || !defined(LWS_WITH_NO_LOGS)
1595 static const char *cname[] = { "Unknown", "OK", "Captive", "No internet" };
1596 #endif
1597 
1598 void
lws_system_cpd_set(struct lws_context * cx,lws_cpd_result_t result)1599 lws_system_cpd_set(struct lws_context *cx, lws_cpd_result_t result)
1600 {
1601 	if (cx->captive_portal_detect != LWS_CPD_UNKNOWN)
1602 		return;
1603 
1604 #if !defined(LWS_WITH_NO_LOGS)
1605 	lwsl_cx_notice(cx, "setting CPD result %s", cname[result]);
1606 #endif
1607 
1608 	cx->captive_portal_detect = (uint8_t)result;
1609 
1610 #if defined(LWS_WITH_SYS_STATE)
1611 #if defined(LWS_WITH_SYS_SMD)
1612 	lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
1613 			   "{\"type\":\"cpd\",\"result\":\"%s\"}",
1614 			   cname[cx->captive_portal_detect]);
1615 #endif
1616 
1617 	/* if nothing is there to intercept anything, go all the way */
1618 	if (cx->mgr_system.state != LWS_SYSTATE_POLICY_INVALID)
1619 		lws_state_transition_steps(&cx->mgr_system,
1620 					   LWS_SYSTATE_OPERATIONAL);
1621 #endif
1622 }
1623 
1624 lws_cpd_result_t
lws_system_cpd_state_get(struct lws_context * cx)1625 lws_system_cpd_state_get(struct lws_context *cx)
1626 {
1627 	return (lws_cpd_result_t)cx->captive_portal_detect;
1628 }
1629 
1630 #endif
1631 
1632 int
lws_context_is_deprecated(struct lws_context * cx)1633 lws_context_is_deprecated(struct lws_context *cx)
1634 {
1635 	return cx->deprecated;
1636 }
1637 
1638 /*
1639  * When using an event loop, the context destruction is in three separate
1640  * parts.  This is to cover both internal and foreign event loops cleanly.
1641  *
1642  *  - lws_context_destroy() simply starts a soft close of all wsi and
1643  *     related allocations.  The event loop continues.
1644  *
1645  *     As the closes complete in the event loop, reference counting is used
1646  *     to determine when everything is closed.  It then calls
1647  *     lws_context_destroy2().
1648  *
1649  *  - lws_context_destroy2() cleans up the rest of the higher-level logical
1650  *     lws pieces like vhosts.  If the loop was foreign, it then proceeds to
1651  *     lws_context_destroy3().  If it the loop is internal, it stops the
1652  *     internal loops and waits for lws_context_destroy() to be called again
1653  *     outside the event loop (since we cannot destroy the loop from
1654  *     within the loop).  That will cause lws_context_destroy3() to run
1655  *     directly.
1656  *
1657  *  - lws_context_destroy3() destroys any internal event loops and then
1658  *     destroys the context itself, setting what was info.pcontext to NULL.
1659  */
1660 
1661 
1662 #if defined(LWS_WITH_NETWORK)
1663 static void
lws_pt_destroy(struct lws_context_per_thread * pt)1664 lws_pt_destroy(struct lws_context_per_thread *pt)
1665 {
1666 	volatile struct lws_foreign_thread_pollfd *ftp, *next;
1667 	volatile struct lws_context_per_thread *vpt;
1668 #if defined(LWS_WITH_CGI)
1669 	lws_ctx_t ctx = pt->context;
1670 
1671 		if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy))
1672 			(lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)).
1673 				pt_init_destroy(ctx, NULL, pt, 1);
1674 #endif
1675 	vpt = (volatile struct lws_context_per_thread *)pt;
1676 	ftp = vpt->foreign_pfd_list;
1677 	while (ftp) {
1678 		next = ftp->next;
1679 		lws_free((void *)ftp);
1680 		ftp = next;
1681 	}
1682 	vpt->foreign_pfd_list = NULL;
1683 
1684 	lws_pt_lock(pt, __func__);
1685 
1686 	if (pt->pipe_wsi) {
1687 		lws_destroy_event_pipe(pt->pipe_wsi);
1688 		pt->pipe_wsi = NULL;
1689 	}
1690 
1691 	if ((pt->dummy_pipe_fds[0] || pt->dummy_pipe_fds[1])
1692 #if !defined(WIN32)
1693 	    && ((int)pt->dummy_pipe_fds[0] != -1 || (int)pt->dummy_pipe_fds[1] != -1)
1694 #endif
1695 	) {
1696 		struct lws wsi;
1697 
1698 		memset(&wsi, 0, sizeof(wsi));
1699 		wsi.a.context = pt->context;
1700 		wsi.tsi = (char)pt->tid;
1701 		lws_plat_pipe_close(&wsi);
1702 	}
1703 
1704 #if defined(LWS_WITH_SECURE_STREAMS)
1705 	lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_destroy_dll);
1706 
1707 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT)
1708 	lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_destroy_dll);
1709 #endif
1710 
1711 #if defined(LWS_WITH_SEQUENCER)
1712 	lws_seq_destroy_all_on_pt(pt);
1713 #endif
1714 
1715 
1716 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1717 		while (pt->http.ah_list)
1718 			_lws_destroy_ah(pt, pt->http.ah_list);
1719 #endif
1720 
1721 #endif
1722 
1723 	lws_pt_unlock(pt);
1724 	pt->pipe_wsi = NULL;
1725 
1726 }
1727 #endif
1728 
1729 /*
1730  * Context destruction is now a state machine that's aware of SMP pts and
1731  * various event lib approaches.
1732  *
1733  * lws_context_destroy() expects to be called at the end of the user code's
1734  * usage of it.  But it can also be called non-finally, as a way to stop
1735  * service and exit the outer user service loop, and then complete in the
1736  * final call.
1737  *
1738  * For libuv, with async close, it must decide by refcounting the hamdles on
1739  * the loop if it has extricated itself from the loop and can be destroyed.
1740  *
1741  * The various entry states for the staged destroy
1742  *
1743  * LWSCD_NO_DESTROY: begin destroy process
1744  * 	- mark context as starting destroy process
1745  * 	- start vhost destroy
1746  * 	- stop any further user protocol service
1747  *
1748  * LWSCD_PT_WAS_DEFERRED: come back here if any pt inside service
1749  * 	- Check for pts that are inside service loop, mark deferral needed if so
1750  * 	- If not, close all wsi on the pt loop and start logical pt destroy
1751  * 	- If any deferred, set state to LWSCD_PT_WAS_DEFERRED and exit
1752  *
1753  * LWSCD_PT_WAIT_ALL_DESTROYED: come back here for async loop / pt closes
1754  * 	- exit if any pt not marked as unused, or destroyed
1755  * 	- if all pt down, call into evlib to advance context destroy
1756  * 	- finalize vhost destruction
1757  * 	- finalize pt destruction
1758  *	- if foreign loops, set state to LWSCD_FINALIZATION and exit
1759  *
1760  * LWSCD_FINALIZATION: come back here at final lws_destroy_context() call
1761  *	- destroy sundries
1762  *	- destroy and free the actual context
1763  */
1764 
1765 void
lws_context_destroy(struct lws_context * context)1766 lws_context_destroy(struct lws_context *context)
1767 {
1768 	struct lws_context **pcontext_finalize;
1769 #if defined(LWS_WITH_NETWORK)
1770 	struct lws_context_per_thread *pt;
1771 	struct lws_vhost *vh = NULL, *vh1;
1772 	int alive = 0, deferred_pt = 0;
1773 #endif
1774 #if defined(LWS_WITH_PEER_LIMITS)
1775 	uint32_t nu;
1776 #endif
1777 	int n;
1778 
1779 	if (!context || context->inside_context_destroy)
1780 		return;
1781 
1782 	pcontext_finalize = context->pcontext_finalize;
1783 
1784 	lws_context_lock(context, __func__);
1785 	context->inside_context_destroy = 1;
1786 
1787 	lwsl_cx_info(context, "destroy_state %d", context->destroy_state);
1788 
1789 	switch (context->destroy_state) {
1790 	case LWSCD_NO_DESTROY:
1791 		/*
1792 		 * We're getting started
1793 		 */
1794 
1795 		lwsl_cx_info(context, "starting context destroy flow");
1796 		context->being_destroyed = 1;
1797 
1798 #if defined(LWS_WITH_NETWORK)
1799 
1800 		/*
1801 		 * Close any vhost listen wsi
1802 		 *
1803 		 * inform all the protocols that they are done and will have no
1804 		 * more callbacks.
1805 		 *
1806 		 * We can't free things until after the event loop shuts down.
1807 		 */
1808 
1809 		if (context->protocol_init_done)
1810 			vh = context->vhost_list;
1811 
1812 		while (vh) {
1813 			lwsl_vhost_info(vh, "start close");
1814 			vh1 = vh->vhost_next;
1815 			lws_vhost_destroy1(vh);
1816 			vh = vh1;
1817 		}
1818 #endif
1819 
1820 		lws_plat_context_early_destroy(context);
1821 
1822 		context->service_no_longer_possible = 1;
1823 		context->requested_stop_internal_loops = 1;
1824 
1825 		/* fallthru */
1826 
1827 	case LWSCD_PT_WAS_DEFERRED:
1828 
1829 #if defined(LWS_WITH_NETWORK)
1830 
1831 		/*
1832 		 * We want to mark the pts as their destruction having been
1833 		 * initiated, so they will reject any new wsi, and iterate all
1834 		 * existing pt wsi starting to close them.
1835 		 *
1836 		 * If the event loop has async close, we have to return after
1837 		 * this and try again when all the loops stop after all the
1838 		 * refcounted wsi are gone.
1839 		 */
1840 
1841 		pt = context->pt;
1842 		for (n = 0; n < context->count_threads; n++) {
1843 			lws_pt_lock(pt, __func__);
1844 
1845 			/* evlib will realize it needs to destroy pt */
1846 			pt->destroy_self = 1;
1847 
1848 			if (pt->inside_lws_service) {
1849 				pt->event_loop_pt_unused = 1;
1850 				deferred_pt = 1;
1851 				goto next;
1852 			}
1853 
1854 			/*
1855 			 * Close every handle in the fds
1856 			 */
1857 
1858 			while (pt->fds_count) {
1859 				struct lws *wsi = wsi_from_fd(context,
1860 							      pt->fds[0].fd);
1861 
1862 				if (wsi) {
1863 
1864 					lwsl_cx_debug(context,
1865 						"pt %d: closing wsi %p: role %s",
1866 						n, wsi, wsi->role_ops->name);
1867 
1868 					lws_close_free_wsi(wsi,
1869 						LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
1870 						"ctx destroy"
1871 						/* no protocol close */);
1872 
1873 					if (pt->pipe_wsi == wsi)
1874 						pt->pipe_wsi = NULL;
1875 				}
1876 			}
1877 
1878 #if defined(LWS_WITH_CGI)
1879 			(lws_rops_func_fidx(&role_ops_cgi,
1880 					    LWS_ROPS_pt_init_destroy)).
1881 					    pt_init_destroy(context, NULL,
1882 							    pt, 1);
1883 #endif
1884 
1885 			/*
1886 			 * This closes handles that belong to the evlib pt
1887 			 * footprint, eg, timers, idle
1888 			 */
1889 
1890 			if (context->event_loop_ops->destroy_pt) {
1891 				lwsl_cx_info(context,
1892 					     "calling evlib destroy_pt %d\n", n);
1893 				context->event_loop_ops->destroy_pt(context, n);
1894 			}
1895 
1896 next:
1897 			lws_pt_unlock(pt);
1898 
1899 			pt++;
1900 		}
1901 
1902 		if (deferred_pt) {
1903 			context->destroy_state = LWSCD_PT_WAS_DEFERRED;
1904 			lwsl_cx_notice(context, "destroy from inside service");
1905 			lws_cancel_service(context);
1906 			goto bail;
1907 		}
1908 #endif
1909 		context->destroy_state = LWSCD_PT_WAIT_ALL_DESTROYED;
1910 
1911 		/*
1912 		 * We have different needs depending if foreign loop or not.
1913 		 *
1914 		 * 1) If foreign loop, we really want to advance the
1915 		 *    destroy_context() past here, and block only for libuv-
1916 		 *    style async close completion.
1917 		 *
1918 		 * 2a) If poll, and we exited by ourselves and are calling a
1919 		 *     final destroy_context() outside of any service already,
1920 		 *     we want to advance all the way in one step.
1921 		 *
1922 		 * 2b) If poll, and we are reacting to a SIGINT, service
1923 		 *     thread(s) may be in poll wait or servicing.  We can't
1924 		 *     advance the destroy_context() to the point it's freeing
1925 		 *     things; we have to leave that for the final
1926 		 *     destroy_context() after the service thread(s) are
1927 		 *     finished calling for service.
1928 		 */
1929 
1930 #if defined(LWS_WITH_NETWORK)
1931 		if (context->event_loop_ops->destroy_context1) {
1932 			lwsl_cx_info(context, "do evlib destroy_context1 and wait");
1933 			context->event_loop_ops->destroy_context1(context);
1934 
1935 			goto bail;
1936 		}
1937 
1938 		/*
1939 		 * ...if the more typical sync close, we can clean up the pts
1940 		 * now ourselves...
1941 		 */
1942 
1943 		lwsl_cx_info(context, "manually destroying pts");
1944 
1945 		pt = context->pt;
1946 		for (n = 0; n < context->count_threads; n++, pt++) {
1947 			pt->event_loop_pt_unused = 1;
1948 			lws_pt_destroy(pt);
1949 		}
1950 #endif
1951 		/* fallthru */
1952 
1953 	case LWSCD_PT_WAIT_ALL_DESTROYED:
1954 
1955 #if defined(LWS_WITH_NETWORK)
1956 
1957 		for (n = 0; n < context->count_threads; n++)
1958 			if (!context->pt[n].is_destroyed &&
1959 			    !context->pt[n].event_loop_pt_unused)
1960 				alive++;
1961 
1962 		lwsl_cx_info(context, "PT_WAIT_ALL_DESTROYED: %d alive", alive);
1963 
1964 		if (alive)
1965 			break;
1966 
1967 		/*
1968 		 * With foreign loops, removing all our fds from the loop
1969 		 * means there are no more ways for the foreign loop to give
1970 		 * us any further CPU once we leave here... so we must make
1971 		 * sure related service threads are exiting so we can pick up
1972 		 * again at the original app thread and do the context
1973 		 * destroy completion
1974 		 */
1975 
1976 		/*
1977 		 * evlib specific loop destroy?
1978 		 */
1979 		if (context->event_loop_ops->destroy_context2)
1980 			/*
1981 			 * He returns nonzero to indicate the evlib must
1982 			 * continue around the loop before destroy of it is
1983 			 * completed so it can be freed
1984 			 */
1985 			context->event_loop_ops->destroy_context2(context);
1986 		context->requested_stop_internal_loops = 1;
1987 #endif
1988 
1989 		/*
1990 		 * Every pt and wsi that may depend on the logical vhosts
1991 		 * is destroyed.  We can remove the logical vhosts.
1992 		 */
1993 
1994 #if defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_NETWORK)
1995 	lws_state_transition(&context->mgr_system, LWS_SYSTATE_POLICY_INVALID);
1996 #endif
1997 
1998 #if defined(LWS_WITH_NETWORK)
1999 		/*
2000 		 * free all the per-vhost allocations
2001 		 */
2002 
2003 		vh = context->vhost_list;
2004 		while (vh) {
2005 			vh1 = vh->vhost_next;
2006 		//	lwsl_vhost_debug(vh, "vh %s destroy2", vh->name);
2007 			__lws_vhost_destroy2(vh);
2008 			vh = vh1;
2009 		}
2010 
2011 		/* remove ourselves from the pending destruction list */
2012 
2013 		while (context->vhost_pending_destruction_list)
2014 			/* removes itself from list */
2015 			__lws_vhost_destroy2(context->vhost_pending_destruction_list);
2016 #endif
2017 
2018 #if defined(LWS_WITH_NETWORK)
2019 		lws_ssl_context_destroy(context);
2020 #endif
2021 		lws_plat_context_late_destroy(context);
2022 
2023 #if defined(LWS_WITH_PEER_LIMITS)
2024 		if (context->pl_hash_table)
2025 			for (nu = 0; nu < context->pl_hash_elements; nu++)	{
2026 				if (!context->pl_hash_table[nu])
2027 					continue;
2028 				lws_start_foreach_llp(struct lws_peer **, peer,
2029 						      context->pl_hash_table[nu]) {
2030 					struct lws_peer *df = *peer;
2031 					*peer = df->next;
2032 					lws_free(df);
2033 					continue;
2034 				} lws_end_foreach_llp(peer, next);
2035 			}
2036 		lws_free(context->pl_hash_table);
2037 #endif
2038 
2039 #if defined(LWS_WITH_NETWORK)
2040 
2041 		for (n = 0; n < context->count_threads; n++) {
2042 			struct lws_context_per_thread *pt = &context->pt[n];
2043 
2044 			(void)pt;
2045 #if defined(LWS_WITH_SEQUENCER)
2046 			lws_seq_destroy_all_on_pt(pt);
2047 #endif
2048 			LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
2049 				if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
2050 					(lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
2051 						pt_init_destroy(context, NULL, pt, 1);
2052 			} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
2053 
2054 #if defined(LWS_WITH_CGI)
2055 			lws_rops_func_fidx(&role_ops_cgi,
2056 					   LWS_ROPS_pt_init_destroy).
2057 					        pt_init_destroy(context, NULL,
2058 					        		pt, 1);
2059 #endif
2060 
2061 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
2062 			while (pt->http.ah_list)
2063 				_lws_destroy_ah(pt, pt->http.ah_list);
2064 #endif
2065 			lwsl_cx_info(context, "pt destroy %d", n);
2066 			lws_pt_destroy(pt);
2067 		}
2068 #endif /* NETWORK */
2069 
2070 		context->destroy_state = LWSCD_FINALIZATION;
2071 
2072 #if defined(LWS_WITH_NETWORK)
2073 
2074 		if (context->pt[0].event_loop_foreign &&
2075 		    context->event_loop_ops->destroy_context1) {
2076 
2077 			lwsl_cx_info(context,
2078 				    "leaving final context destruction"
2079 					" for final call");
2080 			goto bail;
2081 		}
2082 
2083 		if (context->event_loop_ops->destroy_context1 &&
2084 		    !context->pt[0].event_loop_foreign) {
2085 			lwsl_cx_notice(context, "waiting for internal loop exit");
2086 
2087 			goto bail;
2088 		}
2089 #endif
2090 		/* fallthru */
2091 
2092 	case LWSCD_FINALIZATION:
2093 
2094 #if defined(LWS_WITH_SYS_METRICS)
2095 		lws_metrics_dump(context);
2096 #endif
2097 
2098 		context->evlib_finalize_destroy_after_int_loops_stop = 1;
2099 
2100 #if defined(LWS_WITH_NETWORK)
2101 		if (context->event_loop_ops->destroy_context2)
2102 			context->event_loop_ops->destroy_context2(context);
2103 #if defined(LWS_WITH_SYS_STATE)
2104 		lws_state_transition_steps(&context->mgr_system,
2105 					   LWS_SYSTATE_CONTEXT_DESTROYING);
2106 #endif
2107 		/*
2108 		 * finalize destroy of pt and things hanging off it
2109 		 */
2110 
2111 		for (n = 0; n < context->count_threads; n++) {
2112 			struct lws_context_per_thread *pt = &context->pt[n];
2113 
2114 			/*
2115 			 * Destroy the pt-roles
2116 			 */
2117 
2118 			LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
2119 				if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
2120 					(lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
2121 							pt_init_destroy(context, NULL, pt, 1);
2122 			} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
2123 
2124 		#if defined(LWS_WITH_CGI)
2125 			lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy).
2126 						pt_init_destroy(context, NULL, pt, 1);
2127 		#endif
2128 
2129 			lws_pt_mutex_destroy(pt);
2130 			assert(!pt->is_destroyed);
2131 			pt->destroy_self = 0;
2132 			pt->is_destroyed = 1;
2133 
2134 			lwsl_cx_info(context, "pt %d fully destroyed",
2135 					(int)(pt - pt->context->pt));
2136 		}
2137 
2138 		/*
2139 		 * wsis are gone, pts are gone, vhosts are gone.
2140 		 *
2141 		 * clean up the context and things hanging off it
2142 		 */
2143 
2144 #if defined(LWS_WITH_TLS_JIT_TRUST)
2145 		lws_cache_destroy(&context->trust_cache);
2146 		lws_tls_jit_trust_inflight_destroy_all(context);
2147 #endif
2148 
2149 #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
2150 		lws_cache_destroy(&context->nsc);
2151 		lws_cache_destroy(&context->l1);
2152 #endif
2153 
2154 #if defined(LWS_WITH_SYS_SMD)
2155 		_lws_smd_destroy(context);
2156 #endif
2157 
2158 #if defined(LWS_WITH_SYS_ASYNC_DNS)
2159 		lws_async_dns_deinit(&context->async_dns);
2160 #endif
2161 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
2162 		lws_dhcpc_remove(context, NULL);
2163 #endif
2164 
2165 		if (context->pt[0].fds)
2166 			lws_free_set_NULL(context->pt[0].fds);
2167 #endif
2168 		lws_context_deinit_ssl_library(context);
2169 
2170 #if defined(LWS_WITH_DETAILED_LATENCIES)
2171 		if (context->latencies_fd != -1)
2172 			compatible_close(context->latencies_fd);
2173 #endif
2174 
2175 		for (n = 0; n < LWS_SYSBLOB_TYPE_COUNT; n++)
2176 			lws_system_blob_destroy(
2177 					lws_system_get_blob(context, (lws_system_blob_item_t)n, 0));
2178 
2179 #if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SECURE_STREAMS) && \
2180 	!defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
2181 
2182 		while (context->server_der_list) {
2183 			struct lws_ss_x509 *x = context->server_der_list;
2184 
2185 			context->server_der_list = x->next;
2186 			lws_free((void *)x->ca_der);
2187 		}
2188 
2189 		if (context->ac_policy)
2190 			lwsac_free(&context->ac_policy);
2191 #endif
2192 
2193 		/*
2194 		 * Context lock is about to go away
2195 		 */
2196 
2197 		lws_context_unlock(context);
2198 
2199 #if LWS_MAX_SMP > 1
2200 		lws_mutex_refcount_destroy(&context->mr);
2201 #endif
2202 
2203 #if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_NETWORK)
2204 		lws_metrics_destroy(context);
2205 #endif
2206 
2207 		if (context->external_baggage_free_on_destroy)
2208 			free(context->external_baggage_free_on_destroy);
2209 
2210 #if defined(LWS_PLAT_FREERTOS)
2211 #if defined(LWS_AMAZON_RTOS)
2212 		context->last_free_heap = xPortGetFreeHeapSize();
2213 #else
2214 		context->last_free_heap = esp_get_free_heap_size();
2215 #endif
2216 #endif
2217 
2218 #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
2219 		if (context->evlib_plugin_list)
2220 			lws_plugins_destroy(&context->evlib_plugin_list,
2221 					    NULL, NULL);
2222 #endif
2223 
2224 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
2225 		lws_fi_destroy(&context->fic);
2226 #endif
2227 
2228 		lwsl_refcount_cx(context->log_cx, -1);
2229 
2230 		lws_free(context);
2231 
2232 		if (pcontext_finalize)
2233 			*pcontext_finalize = NULL;
2234 
2235 		return;
2236 	}
2237 
2238 #if defined(LWS_WITH_NETWORK)
2239 bail:
2240 #endif
2241 	lwsl_cx_info(context, "leaving");
2242 	context->inside_context_destroy = 0;
2243 	lws_context_unlock(context);
2244 }
2245 
2246 int
lws_context_is_being_destroyed(struct lws_context * context)2247 lws_context_is_being_destroyed(struct lws_context *context)
2248 {
2249 	return !!context->being_destroyed;
2250 }
2251 
2252 #if defined(LWS_WITH_SYS_STATE)
2253 struct lws_context *
lws_system_context_from_system_mgr(lws_state_manager_t * mgr)2254 lws_system_context_from_system_mgr(lws_state_manager_t *mgr)
2255 {
2256 #if defined(LWS_WITH_NETWORK)
2257 	return mgr->context;
2258 #else
2259 	return NULL;
2260 #endif
2261 }
2262 #endif
2263 
2264 void
lws_log_prepend_context(struct lws_log_cx * cx,void * obj,char ** p,char * e)2265 lws_log_prepend_context(struct lws_log_cx *cx, void *obj, char **p, char *e)
2266 {
2267 	struct lws_context *lcx = (struct lws_context *)obj;
2268 
2269 	if (lcx->name)
2270 		*p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
2271 				   lcx->name);
2272 }
2273 
2274 struct lws_log_cx *
lwsl_context_get_cx(struct lws_context * cx)2275 lwsl_context_get_cx(struct lws_context *cx)
2276 {
2277 	if (!cx)
2278 		return NULL;
2279 
2280 	return cx->log_cx;
2281 }
2282