Coverage Report

Created: 2025-12-16 08:26

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