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
31static const char *library_version = LWS_LIBRARY_VERSION;
32
33#if defined(LWS_WITH_MBEDTLS)
34extern 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 */
44static 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 */
54const char *
55lws_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
64static 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
87static int
88lws_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
230static void
231lws_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)
243static int
244lws_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
297static 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)
350static 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};
361static 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
368struct lws_context *
369lws_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
1505early_bail:
1506	lws_fi_destroy(&info->fic);
1507
1508	return NULL;
1509
1510#if defined(LWS_WITH_NETWORK)
1511bail:
1512	lws_fi_destroy(&info->fic);
1513	lws_context_destroy(context);
1514
1515	return NULL;
1516#endif
1517
1518bail_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)
1527fail_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)
1533free_context_fail:
1534	if (context) {
1535#if defined(LWS_WITH_SYS_SMD)
1536		_lws_smd_destroy(context);
1537#endif
1538	}
1539#endif
1540free_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)
1557int
1558lws_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
1578static void
1579lws_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
1587void
1588lws_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)
1595static const char *cname[] = { "Unknown", "OK", "Captive", "No internet" };
1596#endif
1597
1598void
1599lws_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
1624lws_cpd_result_t
1625lws_system_cpd_state_get(struct lws_context *cx)
1626{
1627	return (lws_cpd_result_t)cx->captive_portal_detect;
1628}
1629
1630#endif
1631
1632int
1633lws_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)
1663static void
1664lws_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
1765void
1766lws_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
1896next:
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)
2239bail:
2240#endif
2241	lwsl_cx_info(context, "leaving");
2242	context->inside_context_destroy = 0;
2243	lws_context_unlock(context);
2244}
2245
2246int
2247lws_context_is_being_destroyed(struct lws_context *context)
2248{
2249	return !!context->being_destroyed;
2250}
2251
2252#if defined(LWS_WITH_SYS_STATE)
2253struct lws_context *
2254lws_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
2264void
2265lws_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
2274struct lws_log_cx *
2275lwsl_context_get_cx(struct lws_context *cx)
2276{
2277	if (!cx)
2278		return NULL;
2279
2280	return cx->log_cx;
2281}
2282