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