• 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 " " LWS_BUILD_HASH;
32 
33 #if defined(LWS_WITH_NETWORK)
34 /* in ms */
35 static uint32_t default_backoff_table[] = { 1000, 3000, 9000, 17000 };
36 #endif
37 
38 /**
39  * lws_get_library_version: get version and git hash library built from
40  *
41  *	returns a const char * to a string like "1.1 178d78c"
42  *	representing the library version followed by the git head hash it
43  *	was built from
44  */
45 const char *
lws_get_library_version(void)46 lws_get_library_version(void)
47 {
48 	return library_version;
49 }
50 
51 #if defined(LWS_WITH_STATS)
52 static void
lws_sul_stats_cb(lws_sorted_usec_list_t * sul)53 lws_sul_stats_cb(lws_sorted_usec_list_t *sul)
54 {
55 	struct lws_context_per_thread *pt = lws_container_of(sul,
56 			struct lws_context_per_thread, sul_stats);
57 
58 	lws_stats_log_dump(pt->context);
59 
60 	__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_stats, 10 * LWS_US_PER_SEC);
61 }
62 #endif
63 #if defined(LWS_WITH_PEER_LIMITS)
64 static void
lws_sul_peer_limits_cb(lws_sorted_usec_list_t * sul)65 lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
66 {
67 	struct lws_context_per_thread *pt = lws_container_of(sul,
68 			struct lws_context_per_thread, sul_peer_limits);
69 
70 	lws_peer_cull_peer_wait_list(pt->context);
71 
72 	__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_peer_limits, 10 * LWS_US_PER_SEC);
73 }
74 #endif
75 
76 #if defined(LWS_WITH_NETWORK)
77 
78 #if defined(_DEBUG)
79 static const char * system_state_names[] = {
80 	"undef",
81 	"CONTEXT_CREATED",
82 	"INITIALIZED",
83 	"IFACE_COLDPLUG",
84 	"DHCP",
85 	"TIME_VALID",
86 	"POLICY_VALID",
87 	"REGISTERED",
88 	"AUTH1",
89 	"AUTH2",
90 	"OPERATIONAL",
91 	"POLICY_INVALID"
92 };
93 #endif
94 
95 /*
96  * Handle provoking protocol init when we pass through the right system state
97  */
98 
99 static int
lws_state_notify_protocol_init(struct lws_state_manager * mgr,struct lws_state_notify_link * link,int current,int target)100 lws_state_notify_protocol_init(struct lws_state_manager *mgr,
101 			       struct lws_state_notify_link *link, int current,
102 			       int target)
103 {
104 	struct lws_context *context = lws_container_of(mgr, struct lws_context,
105 						       mgr_system);
106 	int n;
107 
108 	/*
109 	 * Deal with any attachments that were waiting for the right state
110 	 * to come along
111 	 */
112 
113 	for (n = 0; n < context->count_threads; n++)
114 		lws_system_do_attach(&context->pt[n]);
115 
116 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
117 	if (target == LWS_SYSTATE_DHCP) {
118 		/*
119 		 * Don't let it past here until at least one iface has been
120 		 * configured for operation with DHCP
121 		 */
122 
123 		if (!lws_dhcpc_status(context, NULL))
124 			return 1;
125 	}
126 #endif
127 
128 #if defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
129 	/*
130 	 * Skip this if we are running something without the policy for it
131 	 *
132 	 * If root token is empty, skip too.
133 	 */
134 	if (target == LWS_SYSTATE_AUTH1 &&
135 	    context->pss_policies &&
136 	    !lws_system_blob_get_size(lws_system_get_blob(context,
137 						          LWS_SYSBLOB_TYPE_AUTH,
138 						          0)) &&
139 	    lws_system_blob_get_size(lws_system_get_blob(context,
140 						          LWS_SYSBLOB_TYPE_AUTH,
141 						          1))) {
142 		lwsl_info("%s: AUTH1 state triggering api.amazon.com auth\n", __func__);
143 		/*
144 		 * Start trying to acquire it if it's not already in progress
145 		 * returns nonzero if we determine it's not needed
146 		 */
147 		if (!lws_ss_sys_auth_api_amazon_com(context))
148 			return 1;
149 	}
150 #endif
151 
152 #if defined(LWS_WITH_SECURE_STREAMS)
153 	/*
154 	 * Skip this if we are running something without the policy for it
155 	 */
156 	if (target == LWS_SYSTATE_POLICY_VALID &&
157 	    context->pss_policies && !context->policy_updated) {
158 		/*
159 		 * Start trying to acquire it if it's not already in progress
160 		 * returns nonzero if we determine it's not needed
161 		 */
162 		if (!lws_ss_sys_fetch_policy(context))
163 			return 1;
164 	}
165 #endif
166 
167 	/* protocol part */
168 
169 	if (context->protocol_init_done)
170 		return 0;
171 
172 	if (target != LWS_SYSTATE_POLICY_VALID)
173 		return 0;
174 
175 	lwsl_info("%s: doing protocol init on POLICY_VALID\n", __func__);
176 	lws_protocol_init(context);
177 
178 	return 0;
179 }
180 
181 static void
lws_context_creation_completion_cb(lws_sorted_usec_list_t * sul)182 lws_context_creation_completion_cb(lws_sorted_usec_list_t *sul)
183 {
184 	struct lws_context *context = lws_container_of(sul, struct lws_context,
185 						       sul_system_state);
186 
187 	/* if nothing is there to intercept anything, go all the way */
188 	lws_state_transition_steps(&context->mgr_system,
189 				   LWS_SYSTATE_OPERATIONAL);
190 }
191 #endif
192 
193 struct lws_context *
lws_create_context(const struct lws_context_creation_info * info)194 lws_create_context(const struct lws_context_creation_info *info)
195 {
196 	struct lws_context *context = NULL;
197 #if defined(LWS_WITH_FILE_OPS)
198 	struct lws_plat_file_ops *prev;
199 #endif
200 #ifndef LWS_NO_DAEMONIZE
201 	pid_t pid_daemon = get_daemonize_pid();
202 #endif
203 #if defined(LWS_WITH_NETWORK)
204 	int n, count_threads = 1;
205 	uint8_t *u;
206 #endif
207 #if defined(__ANDROID__)
208 	struct rlimit rt;
209 #endif
210 	size_t s1 = 4096, size = sizeof(struct lws_context);
211 	int lpf = info->fd_limit_per_thread;
212 
213 	if (lpf) {
214 		lpf+= 2;
215 #if defined(LWS_WITH_SYS_ASYNC_DNS)
216 		lpf++;
217 #endif
218 #if defined(LWS_WITH_SYS_NTPCLIENT)
219 		lpf++;
220 #endif
221 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
222 		lpf++;
223 #endif
224 	}
225 
226 	lwsl_info("Initial logging level %d\n", log_level);
227 	lwsl_info("Libwebsockets version: %s\n", library_version);
228 
229 #ifdef LWS_WITH_IPV6
230 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
231 		lwsl_info("IPV6 compiled in and enabled\n");
232 	else
233 		lwsl_info("IPV6 compiled in but disabled\n");
234 #else
235 	lwsl_info("IPV6 not compiled in\n");
236 #endif
237 
238 	lwsl_info(" LWS_DEF_HEADER_LEN    : %u\n", LWS_DEF_HEADER_LEN);
239 	lwsl_info(" LWS_MAX_SMP           : %u\n", LWS_MAX_SMP);
240 	lwsl_info(" sizeof (*info)        : %ld\n", (long)sizeof(*info));
241 #if defined(LWS_WITH_STATS)
242 	lwsl_info(" LWS_WITH_STATS        : on\n");
243 #endif
244 	lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
245 #if defined(LWS_WITH_HTTP2)
246 	lwsl_info(" HTTP2 support         : available\n");
247 #else
248 	lwsl_info(" HTTP2 support         : not configured\n");
249 #endif
250 	if (lws_plat_context_early_init())
251 		return NULL;
252 
253 #if defined(LWS_WITH_NETWORK)
254 	if (info->count_threads)
255 		count_threads = info->count_threads;
256 
257 	if (count_threads > LWS_MAX_SMP)
258 		count_threads = LWS_MAX_SMP;
259 
260 	if (info->pt_serv_buf_size)
261 		s1 = info->pt_serv_buf_size;
262 
263 	/* pt fakewsi and the pt serv buf allocations ride after the context */
264 	size += count_threads * (s1 + sizeof(struct lws));
265 #endif
266 
267 	context = lws_zalloc(size, "context");
268 	if (!context) {
269 		lwsl_err("No memory for websocket context\n");
270 		return NULL;
271 	}
272 
273 	context->uid = info->uid;
274 	context->gid = info->gid;
275 	context->username = info->username;
276 	context->groupname = info->groupname;
277 	context->system_ops = info->system_ops;
278 	context->pt_serv_buf_size = (unsigned int)s1;
279 	context->udp_loss_sim_tx_pc = info->udp_loss_sim_tx_pc;
280 	context->udp_loss_sim_rx_pc = info->udp_loss_sim_rx_pc;
281 
282 	if (context->udp_loss_sim_tx_pc || context->udp_loss_sim_rx_pc)
283 		lwsl_warn("%s: simulating udp loss tx: %d%%, rx: %d%%\n",
284 			  __func__, context->udp_loss_sim_tx_pc,
285 			  context->udp_loss_sim_rx_pc);
286 
287 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
288 	context->ss_proxy_bind = info->ss_proxy_bind;
289 	context->ss_proxy_port = info->ss_proxy_port;
290 	context->ss_proxy_address = info->ss_proxy_address;
291 	lwsl_notice("%s: using ss proxy bind '%s', port %d, ads '%s'\n",
292 			__func__, context->ss_proxy_bind, context->ss_proxy_port,
293 			context->ss_proxy_address);
294 #endif
295 
296 #if defined(LWS_WITH_NETWORK)
297 	context->count_threads = count_threads;
298 #if defined(LWS_WITH_DETAILED_LATENCY)
299 	context->detailed_latency_cb = info->detailed_latency_cb;
300 	context->detailed_latency_filepath = info->detailed_latency_filepath;
301 	context->latencies_fd = -1;
302 #endif
303 #if defined(LWS_WITHOUT_EXTENSIONS)
304         if (info->extensions)
305                 lwsl_warn("%s: LWS_WITHOUT_EXTENSIONS but extensions ptr set\n", __func__);
306 #endif
307 #endif
308 
309 #if defined(LWS_WITH_SECURE_STREAMS)
310 	context->pss_policies_json = info->pss_policies_json;
311 	context->pss_plugins = info->pss_plugins;
312 #endif
313 
314 	/* if he gave us names, set the uid / gid */
315 	if (lws_plat_drop_app_privileges(context, 0))
316 		goto bail;
317 
318 	lwsl_info("context created\n");
319 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
320 #if defined(LWS_WITH_MBEDTLS)
321 	context->tls_ops = &tls_ops_mbedtls;
322 #else
323 	context->tls_ops = &tls_ops_openssl;
324 #endif
325 #endif
326 
327 #if LWS_MAX_SMP > 1
328 	lws_mutex_refcount_init(&context->mr);
329 #endif
330 
331 #if defined(LWS_PLAT_FREERTOS)
332 #if defined(LWS_AMAZON_RTOS)
333 	context->last_free_heap = xPortGetFreeHeapSize();
334 #else
335 	context->last_free_heap = esp_get_free_heap_size();
336 #endif
337 #endif
338 
339 #if defined(LWS_WITH_FILE_OPS)
340 	/* default to just the platform fops implementation */
341 
342 	context->fops_platform.LWS_FOP_OPEN	= _lws_plat_file_open;
343 	context->fops_platform.LWS_FOP_CLOSE	= _lws_plat_file_close;
344 	context->fops_platform.LWS_FOP_SEEK_CUR	= _lws_plat_file_seek_cur;
345 	context->fops_platform.LWS_FOP_READ	= _lws_plat_file_read;
346 	context->fops_platform.LWS_FOP_WRITE	= _lws_plat_file_write;
347 	context->fops_platform.fi[0].sig	= NULL;
348 
349 	/*
350 	 *  arrange a linear linked-list of fops starting from context->fops
351 	 *
352 	 * platform fops
353 	 * [ -> fops_zip (copied into context so .next settable) ]
354 	 * [ -> info->fops ]
355 	 */
356 
357 	context->fops = &context->fops_platform;
358 	prev = (struct lws_plat_file_ops *)context->fops;
359 
360 #if defined(LWS_WITH_ZIP_FOPS)
361 	/* make a soft copy so we can set .next */
362 	context->fops_zip = fops_zip;
363 	prev->next = &context->fops_zip;
364 	prev = (struct lws_plat_file_ops *)prev->next;
365 #endif
366 
367 	/* if user provided fops, tack them on the end of the list */
368 	if (info->fops)
369 		prev->next = info->fops;
370 #endif
371 
372 #if defined(LWS_WITH_SERVER)
373 	context->reject_service_keywords = info->reject_service_keywords;
374 #endif
375 	if (info->external_baggage_free_on_destroy)
376 		context->external_baggage_free_on_destroy =
377 			info->external_baggage_free_on_destroy;
378 #if defined(LWS_WITH_NETWORK)
379 	context->time_up = lws_now_usecs();
380 #endif
381 	context->pcontext_finalize = info->pcontext;
382 
383 	context->simultaneous_ssl_restriction =
384 			info->simultaneous_ssl_restriction;
385 
386 	context->options = info->options;
387 
388 #ifndef LWS_NO_DAEMONIZE
389 	if (pid_daemon) {
390 		context->started_with_parent = pid_daemon;
391 		lwsl_info(" Started with daemon pid %u\n", (unsigned int)pid_daemon);
392 	}
393 #endif
394 #if defined(__ANDROID__)
395 	n = getrlimit(RLIMIT_NOFILE, &rt);
396 	if (n == -1) {
397 		lwsl_err("Get RLIMIT_NOFILE failed!\n");
398 
399 		return NULL;
400 	}
401 	context->max_fds = rt.rlim_cur;
402 #else
403 #if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS)
404 	context->max_fds = getdtablesize();
405 #else
406 	context->max_fds = sysconf(_SC_OPEN_MAX);
407 #endif
408 	if (context->max_fds < 0) {
409 		lwsl_err("%s: problem getting process max files\n",
410 			 __func__);
411 
412 		return NULL;
413 	}
414 #endif
415 
416 	/*
417 	 * deal with any max_fds override, if it's reducing (setting it to
418 	 * more than ulimit -n is meaningless).  The platform init will
419 	 * figure out what if this is something it can deal with.
420 	 */
421 	if (info->fd_limit_per_thread) {
422 		int mf = lpf * context->count_threads;
423 
424 		if (mf < context->max_fds) {
425 			context->max_fds_unrelated_to_ulimit = 1;
426 			context->max_fds = mf;
427 		}
428 	}
429 
430 	context->token_limits = info->token_limits;
431 
432 #if defined(LWS_WITH_NETWORK)
433 
434 	/*
435 	 * set the context event loops ops struct
436 	 *
437 	 * after this, all event_loop actions use the generic ops
438 	 */
439 
440 #if defined(LWS_WITH_POLL)
441 	context->event_loop_ops = &event_loop_ops_poll;
442 #endif
443 
444 	if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
445 #if defined(LWS_WITH_LIBUV)
446 		context->event_loop_ops = &event_loop_ops_uv;
447 #else
448 		goto fail_event_libs;
449 #endif
450 
451 	if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV))
452 #if defined(LWS_WITH_LIBEV)
453 		context->event_loop_ops = &event_loop_ops_ev;
454 #else
455 		goto fail_event_libs;
456 #endif
457 
458 	if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
459 #if defined(LWS_WITH_LIBEVENT)
460 		context->event_loop_ops = &event_loop_ops_event;
461 #else
462 		goto fail_event_libs;
463 #endif
464 
465 	if (lws_check_opt(context->options, LWS_SERVER_OPTION_GLIB))
466 #if defined(LWS_WITH_GLIB)
467 		context->event_loop_ops = &event_loop_ops_glib;
468 #else
469 		goto fail_event_libs;
470 #endif
471 
472 	if (!context->event_loop_ops)
473 		goto fail_event_libs;
474 
475 	lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
476 #endif
477 
478 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
479 	time(&context->tls.last_cert_check_s);
480 	if (info->alpn)
481 		context->tls.alpn_default = info->alpn;
482 	else {
483 		char *p = context->tls.alpn_discovered, first = 1;
484 
485 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
486 			if (ar->alpn) {
487 				if (!first)
488 					*p++ = ',';
489 				p += lws_snprintf(p,
490 					context->tls.alpn_discovered +
491 					sizeof(context->tls.alpn_discovered) -
492 					2 - p, "%s", ar->alpn);
493 				first = 0;
494 			}
495 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
496 
497 		context->tls.alpn_default = context->tls.alpn_discovered;
498 	}
499 
500 	lwsl_info("Default ALPN advertisment: %s\n", context->tls.alpn_default);
501 #endif
502 
503 	if (info->timeout_secs)
504 		context->timeout_secs = info->timeout_secs;
505 	else
506 		context->timeout_secs = AWAITING_TIMEOUT;
507 
508 	context->ws_ping_pong_interval = info->ws_ping_pong_interval;
509 
510 	lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
511 
512 	if (info->max_http_header_data)
513 		context->max_http_header_data = info->max_http_header_data;
514 	else
515 		if (info->max_http_header_data2)
516 			context->max_http_header_data =
517 					info->max_http_header_data2;
518 		else
519 			context->max_http_header_data = LWS_DEF_HEADER_LEN;
520 
521 	if (info->max_http_header_pool)
522 		context->max_http_header_pool = info->max_http_header_pool;
523 	else
524 		if (info->max_http_header_pool2)
525 			context->max_http_header_pool =
526 					info->max_http_header_pool2;
527 		else
528 			context->max_http_header_pool = context->max_fds;
529 
530 
531 	if (info->fd_limit_per_thread)
532 		context->fd_limit_per_thread = lpf;
533 	else
534 		if (context->count_threads)
535 			context->fd_limit_per_thread = context->max_fds /
536 							context->count_threads;
537 
538 #if defined(LWS_WITH_NETWORK)
539 
540 	context->default_retry.retry_ms_table = default_backoff_table;
541 	context->default_retry.conceal_count =
542 			context->default_retry.retry_ms_table_count =
543 					LWS_ARRAY_SIZE(default_backoff_table);
544 	context->default_retry.jitter_percent = 20;
545 	context->default_retry.secs_since_valid_ping = 300;
546 	context->default_retry.secs_since_valid_hangup = 310;
547 
548 	if (info->retry_and_idle_policy &&
549 	    info->retry_and_idle_policy->secs_since_valid_ping) {
550 		context->default_retry.secs_since_valid_ping =
551 				info->retry_and_idle_policy->secs_since_valid_ping;
552 		context->default_retry.secs_since_valid_hangup =
553 				info->retry_and_idle_policy->secs_since_valid_hangup;
554 	}
555 
556 	/*
557 	 * Allocate the per-thread storage for scratchpad buffers,
558 	 * and header data pool
559 	 */
560 	u = (uint8_t *)&context[1];
561 	for (n = 0; n < context->count_threads; n++) {
562 		context->pt[n].serv_buf = u;
563 		u += context->pt_serv_buf_size;
564 
565 		context->pt[n].context = context;
566 		context->pt[n].tid = n;
567 
568 		/*
569 		 * We overallocated for a fakewsi (can't compose it in the
570 		 * pt because size isn't known at that time).  point to it
571 		 * and zero it down.  Fakewsis are needed to make callbacks work
572 		 * when the source of the callback is not actually from a wsi
573 		 * context.
574 		 */
575 		context->pt[n].fake_wsi = (struct lws *)u;
576 		u += sizeof(struct lws);
577 
578 		memset(context->pt[n].fake_wsi, 0, sizeof(struct lws));
579 
580 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
581 		context->pt[n].http.ah_list = NULL;
582 		context->pt[n].http.ah_pool_length = 0;
583 #endif
584 		lws_pt_mutex_init(&context->pt[n]);
585 #if defined(LWS_WITH_SEQUENCER)
586 		lws_seq_pt_init(&context->pt[n]);
587 #endif
588 
589 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
590 			if (ar->pt_init_destroy)
591 				ar->pt_init_destroy(context, info,
592 						    &context->pt[n], 0);
593 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
594 
595 #if defined(LWS_WITH_CGI)
596 		role_ops_cgi.pt_init_destroy(context, info, &context->pt[n], 0);
597 #endif
598 	}
599 
600 	lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
601 		    context->fd_limit_per_thread);
602 
603 	if (!info->ka_interval && info->ka_time > 0) {
604 		lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
605 		return NULL;
606 	}
607 
608 #if defined(LWS_WITH_PEER_LIMITS)
609 	/* scale the peer hash table according to the max fds for the process,
610 	 * so that the max list depth averages 16.  Eg, 1024 fd -> 64,
611 	 * 102400 fd -> 6400
612 	 */
613 
614 	context->pl_hash_elements =
615 		(context->count_threads * context->fd_limit_per_thread) / 16;
616 	context->pl_hash_table = lws_zalloc(sizeof(struct lws_peer *) *
617 			context->pl_hash_elements, "peer limits hash table");
618 
619 	context->ip_limit_ah = info->ip_limit_ah;
620 	context->ip_limit_wsi = info->ip_limit_wsi;
621 #endif
622 
623 	lwsl_info(" mem: context:         %5lu B (%ld ctx + (%ld thr x %d))\n",
624 		  (long)sizeof(struct lws_context) +
625 		  (context->count_threads * context->pt_serv_buf_size),
626 		  (long)sizeof(struct lws_context),
627 		  (long)context->count_threads,
628 		  context->pt_serv_buf_size);
629 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
630 	lwsl_info(" mem: http hdr size:   (%u + %lu), max count %u\n",
631 		    context->max_http_header_data,
632 		    (long)sizeof(struct allocated_headers),
633 		    context->max_http_header_pool);
634 #endif
635 
636 	/*
637 	 * fds table contains pollfd structs for as many pollfds as we can
638 	 * handle... spread across as many service threads as we have going
639 	 */
640 	n = sizeof(struct lws_pollfd) * context->count_threads *
641 	    context->fd_limit_per_thread;
642 	context->pt[0].fds = lws_zalloc(n, "fds table");
643 	if (context->pt[0].fds == NULL) {
644 		lwsl_err("OOM allocating %d fds\n", context->max_fds);
645 		goto bail;
646 	}
647 	lwsl_info(" mem: pollfd map:      %5u B\n", n);
648 #endif
649 #if defined(LWS_WITH_SERVER)
650 	if (info->server_string) {
651 		context->server_string = info->server_string;
652 		context->server_string_len = (short)
653 				strlen(context->server_string);
654 	}
655 #endif
656 
657 #if LWS_MAX_SMP > 1
658 	/* each thread serves his own chunk of fds */
659 	for (n = 1; n < (int)context->count_threads; n++)
660 		context->pt[n].fds = context->pt[n - 1].fds +
661 				     context->fd_limit_per_thread;
662 #endif
663 
664 	if (lws_plat_init(context, info))
665 		goto bail;
666 
667 #if defined(LWS_WITH_NETWORK)
668 	if (context->event_loop_ops->init_context)
669 		if (context->event_loop_ops->init_context(context, info))
670 			goto bail;
671 
672 
673 	if (context->event_loop_ops->init_pt)
674 		for (n = 0; n < context->count_threads; n++) {
675 			void *lp = NULL;
676 
677 			if (info->foreign_loops)
678 				lp = info->foreign_loops[n];
679 
680 			if (context->event_loop_ops->init_pt(context, lp, n))
681 				goto bail;
682 		}
683 
684 	if (lws_create_event_pipes(context))
685 		goto bail;
686 #endif
687 
688 	lws_context_init_ssl_library(info);
689 
690 	context->user_space = info->user;
691 
692 #if defined(LWS_WITH_SERVER)
693 	strcpy(context->canonical_hostname, "unknown");
694 #if defined(LWS_WITH_NETWORK)
695 	lws_server_get_canonical_hostname(context, info);
696 #endif
697 #endif
698 
699 #if defined(LWS_WITH_STATS)
700 	context->pt[0].sul_stats.cb = lws_sul_stats_cb;
701 	__lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_stats,
702 			 10 * LWS_US_PER_SEC);
703 #endif
704 #if defined(LWS_WITH_PEER_LIMITS)
705 	context->pt[0].sul_peer_limits.cb = lws_sul_peer_limits_cb;
706 	__lws_sul_insert(&context->pt[0].pt_sul_owner,
707 			 &context->pt[0].sul_peer_limits, 10 * LWS_US_PER_SEC);
708 #endif
709 
710 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
711 	memcpy(context->caps, info->caps, sizeof(context->caps));
712 	context->count_caps = info->count_caps;
713 #endif
714 
715 
716 #if defined(LWS_WITH_NETWORK)
717 
718 #if defined(LWS_WITH_SYS_ASYNC_DNS) || defined(LWS_WITH_SYS_NTPCLIENT) || \
719 	defined(LWS_WITH_SYS_DHCP_CLIENT)
720 	{
721 		/*
722 		 * system vhost
723 		 */
724 
725 		struct lws_context_creation_info ii;
726 		const struct lws_protocols *pp[4];
727 		struct lws_vhost *vh;
728 #if defined(LWS_WITH_SYS_ASYNC_DNS)
729 		extern const struct lws_protocols lws_async_dns_protocol;
730 #endif
731 #if defined(LWS_WITH_SYS_NTPCLIENT)
732 		extern const struct lws_protocols lws_system_protocol_ntpc;
733 #endif
734 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
735 		extern const struct lws_protocols lws_system_protocol_dhcpc;
736 #endif
737 
738 		n = 0;
739 #if defined(LWS_WITH_SYS_ASYNC_DNS)
740 		pp[n++] = &lws_async_dns_protocol;
741 #endif
742 #if defined(LWS_WITH_SYS_NTPCLIENT)
743 		pp[n++] = &lws_system_protocol_ntpc;
744 #endif
745 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
746 		pp[n++] = &lws_system_protocol_dhcpc;
747 #endif
748 		pp[n] = NULL;
749 
750 		memset(&ii, 0, sizeof(ii));
751 		ii.vhost_name = "system";
752 		ii.pprotocols = pp;
753 
754 		vh = lws_create_vhost(context, &ii);
755 		if (!vh) {
756 			lwsl_err("%s: failed to create system vhost\n",
757 				 __func__);
758 			goto bail;
759 		}
760 
761 		context->vhost_system = vh;
762 
763 		if (lws_protocol_init_vhost(vh, NULL)) {
764 			lwsl_err("%s: failed to init system vhost\n", __func__);
765 			goto bail;
766 		}
767 #if defined(LWS_WITH_SYS_ASYNC_DNS)
768 		if (lws_async_dns_init(context))
769 			goto bail;
770 #endif
771 	}
772 #endif
773 
774 	/*
775 	 * init the lws_state mgr for the system state
776 	 */
777 #if defined(_DEBUG)
778 	context->mgr_system.state_names = system_state_names;
779 #endif
780 	context->mgr_system.name = "system";
781 	context->mgr_system.state = LWS_SYSTATE_CONTEXT_CREATED;
782 	context->mgr_system.parent = context;
783 
784 	context->protocols_notify.name = "prot_init";
785 	context->protocols_notify.notify_cb = lws_state_notify_protocol_init;
786 
787 	lws_state_reg_notifier(&context->mgr_system, &context->protocols_notify);
788 
789 	/*
790 	 * insert user notifiers here so they can participate with vetoing us
791 	 * trying to jump straight to operational, or at least observe us
792 	 * reaching 'operational', before we returned from context creation.
793 	 */
794 
795 	lws_state_reg_notifier_list(&context->mgr_system,
796 				    info->register_notifier_list);
797 
798 	/*
799 	 * if he's not saying he'll make his own vhosts later then act
800 	 * compatibly and make a default vhost using the data in the info
801 	 */
802 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
803 		if (!lws_create_vhost(context, info)) {
804 			lwsl_err("Failed to create default vhost\n");
805 
806 #if defined(LWS_WITH_PEER_LIMITS)
807 			lws_free_set_NULL(context->pl_hash_table);
808 #endif
809 			goto fail_clean_pipes;
810 		}
811 
812 #if defined(LWS_WITH_SECURE_STREAMS)
813 
814 	if (context->pss_policies_json) {
815 		/*
816 		 * You must create your context with the explicit vhosts flag
817 		 * in order to use secure streams
818 		 */
819 		assert(lws_check_opt(info->options,
820 		       LWS_SERVER_OPTION_EXPLICIT_VHOSTS));
821 
822 		if (lws_ss_policy_parse_begin(context))
823 			goto bail;
824 
825 		n = lws_ss_policy_parse(context,
826 					(uint8_t *)context->pss_policies_json,
827 					strlen(context->pss_policies_json));
828 		if (n != LEJP_CONTINUE && n < 0)
829 			goto bail;
830 
831 		if (lws_ss_policy_set(context, "hardcoded")) {
832 			lwsl_err("%s: policy set failed\n", __func__);
833 			goto bail;
834 		}
835 	} else
836 		lws_create_vhost(context, info);
837 #endif
838 
839 	lws_context_init_extensions(info, context);
840 
841 	lwsl_info(" mem: per-conn:        %5lu bytes + protocol rx buf\n",
842 		    (unsigned long)sizeof(struct lws));
843 
844 	/*
845 	 * drop any root privs for this process
846 	 * to listen on port < 1023 we would have needed root, but now we are
847 	 * listening, we don't want the power for anything else
848 	 */
849 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
850 		if (lws_plat_drop_app_privileges(context, 1))
851 			goto bail;
852 
853 	/*
854 	 * We want to move on the syste, state as far as it can go towards
855 	 * OPERATIONAL now.  But we have to return from here first so the user
856 	 * code that called us can set its copy of context, which it may be
857 	 * relying on to perform operations triggered by the state change.
858 	 *
859 	 * We set up a sul to come back immediately and do the state change.
860 	 */
861 
862 	lws_sul_schedule(context, 0, &context->sul_system_state,
863 			 lws_context_creation_completion_cb, 1);
864 
865 	/* expedite post-context init (eg, protocols) */
866 	lws_cancel_service(context);
867 #endif
868 
869 	return context;
870 
871 #if defined(LWS_WITH_NETWORK)
872 fail_clean_pipes:
873 	for (n = 0; n < context->count_threads; n++)
874 		lws_destroy_event_pipe(context->pt[n].pipe_wsi);
875 
876 	lws_free_set_NULL(context->pt[0].fds);
877 	lws_plat_context_late_destroy(context);
878 	lws_free_set_NULL(context);
879 
880 	return NULL;
881 #endif
882 
883 bail:
884 	lws_context_destroy(context);
885 
886 	return NULL;
887 
888 #if defined(LWS_WITH_NETWORK)
889 fail_event_libs:
890 	lwsl_err("Requested event library support not configured, available:\n");
891 	{
892 		extern const struct lws_event_loop_ops *available_event_libs[];
893 		const struct lws_event_loop_ops **elops = available_event_libs;
894 
895 		while (*elops) {
896 			lwsl_err("  - %s\n", (*elops)->name);
897 			elops++;
898 		}
899 	}
900 #endif
901 	lws_free(context);
902 
903 	return NULL;
904 }
905 
906 int
lws_context_is_deprecated(struct lws_context * context)907 lws_context_is_deprecated(struct lws_context *context)
908 {
909 	return context->deprecated;
910 }
911 
912 /*
913  * When using an event loop, the context destruction is in three separate
914  * parts.  This is to cover both internal and foreign event loops cleanly.
915  *
916  *  - lws_context_destroy() simply starts a soft close of all wsi and
917  *     related allocations.  The event loop continues.
918  *
919  *     As the closes complete in the event loop, reference counting is used
920  *     to determine when everything is closed.  It then calls
921  *     lws_context_destroy2().
922  *
923  *  - lws_context_destroy2() cleans up the rest of the higher-level logical
924  *     lws pieces like vhosts.  If the loop was foreign, it then proceeds to
925  *     lws_context_destroy3().  If it the loop is internal, it stops the
926  *     internal loops and waits for lws_context_destroy() to be called again
927  *     outside the event loop (since we cannot destroy the loop from
928  *     within the loop).  That will cause lws_context_destroy3() to run
929  *     directly.
930  *
931  *  - lws_context_destroy3() destroys any internal event loops and then
932  *     destroys the context itself, setting what was info.pcontext to NULL.
933  */
934 
935 /*
936  * destroy the actual context itself
937  */
938 
939 static void
lws_context_destroy3(struct lws_context * context)940 lws_context_destroy3(struct lws_context *context)
941 {
942 	struct lws_context **pcontext_finalize = context->pcontext_finalize;
943 	int n;
944 
945 #if defined(LWS_WITH_NETWORK)
946 
947 	context->finalize_destroy_after_internal_loops_stopped = 1;
948 	if (context->event_loop_ops->destroy_context2)
949 		context->event_loop_ops->destroy_context2(context);
950 
951 	for (n = 0; n < context->count_threads; n++) {
952 		struct lws_context_per_thread *pt = &context->pt[n];
953 		(void)pt;
954 #if defined(LWS_WITH_SEQUENCER)
955 		lws_seq_destroy_all_on_pt(pt);
956 #endif
957 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
958 			if (ar->pt_init_destroy)
959 				ar->pt_init_destroy(context, NULL, pt, 1);
960 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
961 
962 #if defined(LWS_WITH_CGI)
963 		role_ops_cgi.pt_init_destroy(context, NULL, pt, 1);
964 #endif
965 #if 0
966 		if (context->event_loop_ops->destroy_pt)
967 			context->event_loop_ops->destroy_pt(context, n);
968 #endif
969 
970 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
971 		while (pt->http.ah_list)
972 			_lws_destroy_ah(pt, pt->http.ah_list);
973 #endif
974 	}
975 
976 #if defined(LWS_WITH_SYS_ASYNC_DNS)
977 	lws_async_dns_deinit(&context->async_dns);
978 #endif
979 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
980 	lws_dhcpc_remove(context, NULL);
981 #endif
982 
983 	if (context->pt[0].fds)
984 		lws_free_set_NULL(context->pt[0].fds);
985 #endif
986 	lws_context_deinit_ssl_library(context);
987 
988 #if defined(LWS_WITH_DETAILED_LATENCIES)
989 	if (context->latencies_fd != -1)
990 		compatible_close(context->latencies_fd);
991 #endif
992 
993 	for (n = 0; n < LWS_SYSBLOB_TYPE_COUNT; n++)
994 		lws_system_blob_destroy(
995 				lws_system_get_blob(context, n, 0));
996 
997 	lws_free(context);
998 	lwsl_info("%s: ctx %p freed\n", __func__, context);
999 
1000 	if (pcontext_finalize)
1001 		*pcontext_finalize = NULL;
1002 }
1003 
1004 /*
1005  * really start destroying things
1006  */
1007 
1008 void
lws_context_destroy2(struct lws_context * context)1009 lws_context_destroy2(struct lws_context *context)
1010 {
1011 #if defined(LWS_WITH_NETWORK)
1012 	struct lws_vhost *vh = NULL, *vh1;
1013 	int n;
1014 #endif
1015 #if defined(LWS_WITH_PEER_LIMITS)
1016 	uint32_t nu;
1017 #endif
1018 
1019 	lwsl_info("%s: ctx %p\n", __func__, context);
1020 
1021 	lws_context_lock(context, "context destroy 2"); /* ------ context { */
1022 
1023 	context->being_destroyed2 = 1;
1024 #if defined(LWS_WITH_NETWORK)
1025 
1026 	/*
1027 	 * We're going to trash things like vhost-protocols
1028 	 * So we need to finish dealing with wsi close that
1029 	 * might make callbacks first
1030 	 */
1031 	for (n = 0; n < context->count_threads; n++) {
1032 		struct lws_context_per_thread *pt = &context->pt[n];
1033 
1034 		(void)pt;
1035 
1036 #if defined(LWS_WITH_SECURE_STREAMS)
1037 		lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_destroy_dll);
1038 		if (context->ac_policy)
1039 			lwsac_free(&context->ac_policy);
1040 #endif
1041 
1042 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
1043 		lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_destroy_dll);
1044 #endif
1045 
1046 #if defined(LWS_WITH_SEQUENCER)
1047 		lws_seq_destroy_all_on_pt(pt);
1048 #endif
1049 		LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
1050 			if (ar->pt_init_destroy)
1051 				ar->pt_init_destroy(context, NULL, pt, 1);
1052 		} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
1053 
1054 #if defined(LWS_WITH_CGI)
1055 		role_ops_cgi.pt_init_destroy(context, NULL, pt, 1);
1056 #endif
1057 
1058 		if (context->event_loop_ops->destroy_pt)
1059 			context->event_loop_ops->destroy_pt(context, n);
1060 
1061 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1062 		while (pt->http.ah_list)
1063 			_lws_destroy_ah(pt, pt->http.ah_list);
1064 #endif
1065 	}
1066 
1067 	/*
1068 	 * free all the per-vhost allocations
1069 	 */
1070 
1071 	vh = context->vhost_list;
1072 	while (vh) {
1073 		vh1 = vh->vhost_next;
1074 		__lws_vhost_destroy2(vh);
1075 		vh = vh1;
1076 	}
1077 
1078 	lwsl_debug("%p: post vh listl\n", __func__);
1079 
1080 	/* remove ourselves from the pending destruction list */
1081 
1082 	while (context->vhost_pending_destruction_list)
1083 		/* removes itself from list */
1084 		__lws_vhost_destroy2(context->vhost_pending_destruction_list);
1085 #endif
1086 
1087 	lwsl_debug("%p: post pdl\n", __func__);
1088 
1089 	lws_stats_log_dump(context);
1090 #if defined(LWS_WITH_NETWORK)
1091 	lws_ssl_context_destroy(context);
1092 #endif
1093 	lws_plat_context_late_destroy(context);
1094 
1095 #if defined(LWS_WITH_PEER_LIMITS)
1096 	for (nu = 0; nu < context->pl_hash_elements; nu++)	{
1097 		lws_start_foreach_llp(struct lws_peer **, peer,
1098 				      context->pl_hash_table[nu]) {
1099 			struct lws_peer *df = *peer;
1100 			*peer = df->next;
1101 			lws_free(df);
1102 			continue;
1103 		} lws_end_foreach_llp(peer, next);
1104 	}
1105 	lws_free(context->pl_hash_table);
1106 #endif
1107 
1108 	lwsl_debug("%p: baggage\n", __func__);
1109 
1110 	if (context->external_baggage_free_on_destroy)
1111 		free(context->external_baggage_free_on_destroy);
1112 
1113 #if defined(LWS_WITH_NETWORK)
1114 	lws_check_deferred_free(context, 0, 1);
1115 #endif
1116 
1117 	lws_context_unlock(context); /* } context ------ */
1118 
1119 #if defined(LWS_WITH_NETWORK)
1120 	if (context->event_loop_ops->destroy_context2)
1121 		if (context->event_loop_ops->destroy_context2(context)) {
1122 			context->finalize_destroy_after_internal_loops_stopped = 1;
1123 			return;
1124 		}
1125 
1126 	lwsl_debug("%p: post dc2\n", __func__);
1127 
1128 	if (!context->pt[0].event_loop_foreign) {
1129 		int n;
1130 		for (n = 0; n < context->count_threads; n++)
1131 			if (context->pt[n].inside_service) {
1132 				lwsl_debug("%p: bailing as inside service\n", __func__);
1133 				return;
1134 			}
1135 	}
1136 #endif
1137 
1138 	lws_context_destroy3(context);
1139 }
1140 
1141 #if defined(LWS_WITH_NETWORK)
1142 static void
lws_pt_destroy(struct lws_context_per_thread * pt)1143 lws_pt_destroy(struct lws_context_per_thread *pt)
1144 {
1145 	volatile struct lws_foreign_thread_pollfd *ftp, *next;
1146 	volatile struct lws_context_per_thread *vpt;
1147 
1148 	assert(!pt->is_destroyed);
1149 	pt->destroy_self = 0;
1150 
1151 	vpt = (volatile struct lws_context_per_thread *)pt;
1152 	ftp = vpt->foreign_pfd_list;
1153 	while (ftp) {
1154 		next = ftp->next;
1155 		lws_free((void *)ftp);
1156 		ftp = next;
1157 	}
1158 	vpt->foreign_pfd_list = NULL;
1159 
1160 	if (pt->pipe_wsi)
1161 		lws_destroy_event_pipe(pt->pipe_wsi);
1162 	pt->pipe_wsi = NULL;
1163 
1164 	while (pt->fds_count) {
1165 		struct lws *wsi = wsi_from_fd(pt->context, pt->fds[0].fd);
1166 
1167 		if (!wsi)
1168 			break;
1169 
1170 		lws_close_free_wsi(wsi,
1171 				LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
1172 				"ctx destroy"
1173 				/* no protocol close */);
1174 	}
1175 	lws_pt_mutex_destroy(pt);
1176 
1177 	pt->is_destroyed = 1;
1178 
1179 	lwsl_info("%s: pt destroyed\n", __func__);
1180 }
1181 #endif
1182 
1183 /*
1184  * Begin the context takedown
1185  */
1186 
1187 void
lws_context_destroy(struct lws_context * context)1188 lws_context_destroy(struct lws_context *context)
1189 {
1190 #if defined(LWS_WITH_NETWORK)
1191 	struct lws_vhost *vh = NULL;
1192 	int m, deferred_pt = 0;
1193 #endif
1194 
1195 	if (!context || context->inside_context_destroy)
1196 		return;
1197 
1198 	context->inside_context_destroy = 1;
1199 
1200 #if defined(LWS_WITH_NETWORK)
1201 	if (context->finalize_destroy_after_internal_loops_stopped) {
1202 		if (context->event_loop_ops->destroy_context2)
1203 			context->event_loop_ops->destroy_context2(context);
1204 		lws_context_destroy3(context);
1205 		/* context is invalid, no need to reset inside flag */
1206 		return;
1207 	}
1208 #endif
1209 	if (context->being_destroyed1) {
1210 		if (!context->being_destroyed2) {
1211 			lws_context_destroy2(context);
1212 
1213 			return;
1214 		}
1215 		lwsl_info("%s: ctx %p: already being destroyed\n",
1216 			    __func__, context);
1217 
1218 		lws_context_destroy3(context);
1219 		/* context is invalid, no need to reset inside flag */
1220 		return;
1221 	}
1222 
1223 	lwsl_info("%s: ctx %p\n", __func__, context);
1224 
1225 	context->being_destroyed = 1;
1226 
1227 #if defined(LWS_WITH_NETWORK)
1228 	lws_state_transition(&context->mgr_system, LWS_SYSTATE_POLICY_INVALID);
1229 	m = context->count_threads;
1230 
1231 	while (m--) {
1232 		struct lws_context_per_thread *pt = &context->pt[m];
1233 
1234 		if (pt->is_destroyed)
1235 			continue;
1236 
1237 		if (pt->inside_lws_service) {
1238 			pt->destroy_self = 1;
1239 			deferred_pt = 1;
1240 			continue;
1241 		}
1242 
1243 		lws_pt_destroy(pt);
1244 	}
1245 
1246 	if (deferred_pt) {
1247 		lwsl_info("%s: waiting for deferred pt close\n", __func__);
1248 		lws_cancel_service(context);
1249 		goto out;
1250 	}
1251 
1252 	context->being_destroyed1 = 1;
1253 	context->requested_kill = 1;
1254 
1255 	/*
1256 	 * inform all the protocols that they are done and will have no more
1257 	 * callbacks.
1258 	 *
1259 	 * We can't free things until after the event loop shuts down.
1260 	 */
1261 	if (context->protocol_init_done)
1262 		vh = context->vhost_list;
1263 	while (vh) {
1264 		struct lws_vhost *vhn = vh->vhost_next;
1265 		lws_vhost_destroy1(vh);
1266 		vh = vhn;
1267 	}
1268 #endif
1269 
1270 	lws_plat_context_early_destroy(context);
1271 
1272 #if defined(LWS_WITH_NETWORK)
1273 
1274 	/*
1275 	 * We face two different needs depending if foreign loop or not.
1276 	 *
1277 	 * 1) If foreign loop, we really want to advance the destroy_context()
1278 	 *    past here, and block only for libuv-style async close completion.
1279 	 *
1280 	 * 2a) If poll, and we exited by ourselves and are calling a final
1281 	 *     destroy_context() outside of any service already, we want to
1282 	 *     advance all the way in one step.
1283 	 *
1284 	 * 2b) If poll, and we are reacting to a SIGINT, service thread(s) may
1285 	 *     be in poll wait or servicing.  We can't advance the
1286 	 *     destroy_context() to the point it's freeing things; we have to
1287 	 *     leave that for the final destroy_context() after the service
1288 	 *     thread(s) are finished calling for service.
1289 	 */
1290 
1291 	if (context->event_loop_ops->destroy_context1) {
1292 		context->event_loop_ops->destroy_context1(context);
1293 
1294 		goto out;
1295 	}
1296 #endif
1297 
1298 #if defined(LWS_PLAT_FREERTOS)
1299 #if defined(LWS_AMAZON_RTOS)
1300 	context->last_free_heap = xPortGetFreeHeapSize();
1301 #else
1302 	context->last_free_heap = esp_get_free_heap_size();
1303 #endif
1304 #endif
1305 
1306 	context->inside_context_destroy = 0;
1307 	lws_context_destroy2(context);
1308 
1309 	return;
1310 
1311 #if defined(LWS_WITH_NETWORK)
1312 out:
1313 	context->inside_context_destroy = 0;
1314 #endif
1315 }
1316 
1317 struct lws_context *
lws_system_context_from_system_mgr(lws_state_manager_t * mgr)1318 lws_system_context_from_system_mgr(lws_state_manager_t *mgr)
1319 {
1320 #if defined(LWS_WITH_NETWORK)
1321 	return lws_container_of(mgr, struct lws_context, mgr_system);
1322 #else
1323 	return NULL;
1324 #endif
1325 }
1326