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