Coverage Report

Created: 2024-09-08 06:10

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