Coverage Report

Created: 2026-09-04 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/core-net/vhost.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2021 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
void
28
lws_tls_session_vh_destroy(struct lws_vhost *vh);
29
30
const struct lws_role_ops *available_roles[] = {
31
#if defined(LWS_ROLE_H2)
32
  &role_ops_h2,
33
#endif
34
#if defined(LWS_ROLE_QUIC)
35
  &role_ops_quic,
36
#endif
37
#if defined(LWS_ROLE_H3)
38
  &role_ops_h3,
39
#endif
40
#if defined(LWS_ROLE_WT)
41
  &role_ops_wt,
42
#endif
43
#if defined(LWS_ROLE_H1)
44
  &role_ops_h1,
45
#endif
46
#if defined(LWS_ROLE_WS)
47
  &role_ops_ws,
48
#endif
49
#if defined(LWS_ROLE_DBUS)
50
  &role_ops_dbus,
51
#endif
52
#if defined(LWS_ROLE_RAW_PROXY)
53
  &role_ops_raw_proxy,
54
#endif
55
#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
56
  &role_ops_mqtt,
57
#endif
58
#if defined(LWS_WITH_NETLINK)
59
  &role_ops_netlink,
60
#endif
61
  NULL
62
};
63
64
#if defined(LWS_WITH_ABSTRACT)
65
const struct lws_protocols *available_abstract_protocols[] = {
66
#if defined(LWS_ROLE_RAW)
67
  &protocol_abs_client_raw_skt,
68
#endif
69
  NULL
70
};
71
#endif
72
73
#if defined(LWS_WITH_SECURE_STREAMS)
74
const struct lws_protocols *available_secstream_protocols[] = {
75
#if defined(LWS_ROLE_H1)
76
  &protocol_secstream_h1,
77
#endif
78
#if defined(LWS_ROLE_H2)
79
  &protocol_secstream_h2,
80
#endif
81
#if defined(LWS_ROLE_WS)
82
  &protocol_secstream_ws,
83
#endif
84
#if defined(LWS_ROLE_MQTT)
85
  &protocol_secstream_mqtt,
86
#endif
87
  &protocol_secstream_raw,
88
  NULL
89
};
90
#endif
91
92
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
93
static const char * const mount_protocols[] = {
94
  "http://",
95
  "https://",
96
  "file://",
97
  "cgi://",
98
  ">http://",
99
  ">https://",
100
  "callback://"
101
};
102
#endif
103
104
const struct lws_role_ops *
105
lws_role_by_name(const char *name)
106
0
{
107
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
108
0
    if (!strcmp(ar->name, name))
109
0
      return ar;
110
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
111
112
0
  if (!strcmp(name, role_ops_raw_skt.name))
113
0
    return &role_ops_raw_skt;
114
115
0
#if defined(LWS_ROLE_RAW_FILE)
116
0
  if (!strcmp(name, role_ops_raw_file.name))
117
0
    return &role_ops_raw_file;
118
0
#endif
119
120
0
  return NULL;
121
0
}
122
123
int
124
lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
125
0
{
126
0
#if defined(LWS_WITH_TLS)
127
0
  int is_quic;
128
129
0
  if (!alpn)
130
0
    return 0;
131
132
0
#if !defined(LWS_ESP_PLATFORM)
133
0
  lwsl_wsi_info(wsi, "'%s'", alpn);
134
0
#endif
135
136
  /*
137
   * A QUIC-transport wsi always hands the negotiated ALPN to its current
138
   * (quic) role for filtering and possible migration to the h3 role, and
139
   * must never be claimed by the by-ALPN-string fallback below: a TCP
140
   * ALPN like "h2" negotiated on top of the UDP transport would
141
   * transition the wsi to the h2 role where it can never make progress.
142
   */
143
0
  is_quic = wsi->role_ops && !strcmp(wsi->role_ops->name, "quic");
144
145
  /* First try the WSI's current role if it matches the ALPN or if it's QUIC */
146
0
  if (wsi->role_ops && lws_rops_fidx(wsi->role_ops, LWS_ROPS_alpn_negotiated) &&
147
0
      (is_quic ||
148
0
       (wsi->role_ops->alpn && !strcmp(wsi->role_ops->alpn, alpn)))) {
149
0
      lwsl_wsi_info(wsi, "lws_role_call_alpn_negotiated: Matched WSI current role: %s", wsi->role_ops->name);
150
0
#if defined(LWS_WITH_SERVER)
151
0
      lws_metrics_tag_wsi_add(wsi, "upg", wsi->role_ops->name);
152
0
#endif
153
0
      return (lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_alpn_negotiated)).
154
0
               alpn_negotiated(wsi, alpn);
155
0
  }
156
157
  /* ... but a QUIC wsi has nowhere else to go: leave the decision to the
158
   * quic role's caller, which should fail the connection */
159
160
0
  if (is_quic)
161
0
    return 0;
162
163
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
164
0
    if (ar->alpn && !strcmp(ar->alpn, alpn) &&
165
0
        lws_rops_fidx(ar, LWS_ROPS_alpn_negotiated)) {
166
      // lwsl_wsi_notice(wsi, "lws_role_call_alpn_negotiated: Matched fallback role: %s", ar->name);
167
0
#if defined(LWS_WITH_SERVER)
168
0
      lws_metrics_tag_wsi_add(wsi, "upg", ar->name);
169
0
#endif
170
0
      return (lws_rops_func_fidx(ar, LWS_ROPS_alpn_negotiated)).
171
0
               alpn_negotiated(wsi, alpn);
172
0
    }
173
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
174
0
#endif
175
0
  return 0;
176
0
}
177
178
int
179
lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
180
0
{
181
0
  int n;
182
183
  /*
184
   * if the vhost is told to bind accepted sockets to a given role,
185
   * then look it up by name and try to bind to the specific role.
186
   */
187
0
  if (lws_check_opt(wsi->a.vhost->options,
188
0
        LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG) &&
189
0
      wsi->a.vhost->listen_accept_role) {
190
0
    const struct lws_role_ops *role =
191
0
      lws_role_by_name(wsi->a.vhost->listen_accept_role);
192
193
0
    if (!prot)
194
0
      prot = wsi->a.vhost->listen_accept_protocol;
195
196
0
    if (!role)
197
0
      lwsl_wsi_err(wsi, "can't find role '%s'",
198
0
            wsi->a.vhost->listen_accept_role);
199
200
0
    if (!strcmp(wsi->a.vhost->listen_accept_role, "raw-proxy"))
201
0
      type |= LWS_ADOPT_FLAG_RAW_PROXY;
202
203
0
    if (role && lws_rops_fidx(role, LWS_ROPS_adoption_bind)) {
204
0
      n = (lws_rops_func_fidx(role, LWS_ROPS_adoption_bind)).
205
0
            adoption_bind(wsi, type, prot);
206
0
      if (n < 0)
207
0
        return -1;
208
0
      if (n) /* did the bind */
209
0
        return 0;
210
0
    }
211
212
0
    if (type & _LWS_ADOPT_FINISH) {
213
0
      lwsl_wsi_debug(wsi, "leaving bound to role %s",
214
0
              wsi->role_ops->name);
215
0
      return 0;
216
0
    }
217
218
0
    lwsl_wsi_warn(wsi, "adoption bind to role '%s', "
219
0
        "protocol '%s', type 0x%x, failed",
220
0
        wsi->a.vhost->listen_accept_role, prot, type);
221
0
  }
222
223
  /*
224
   * Otherwise ask each of the roles in order of preference if they
225
   * want to bind to this accepted socket
226
   */
227
228
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
229
0
    if (lws_rops_fidx(ar, LWS_ROPS_adoption_bind) &&
230
0
        (lws_rops_func_fidx(ar, LWS_ROPS_adoption_bind)).
231
0
              adoption_bind(wsi, type, prot))
232
0
      return 0;
233
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
234
235
  /* fall back to raw socket role if, eg, h1 not configured */
236
237
0
  if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind) &&
238
0
      (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind)).
239
0
            adoption_bind(wsi, type, prot))
240
0
    return 0;
241
242
0
#if defined(LWS_ROLE_RAW_FILE)
243
244
0
  lwsl_wsi_info(wsi, "falling back to raw file role bind");
245
246
  /* fall back to raw file role if, eg, h1 not configured */
247
248
0
  if (lws_rops_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind) &&
249
0
      (lws_rops_func_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind)).
250
0
            adoption_bind(wsi, type, prot))
251
0
    return 0;
252
0
#endif
253
254
0
  return 1;
255
0
}
256
257
#if defined(LWS_WITH_CLIENT)
258
int
259
lws_role_call_client_bind(struct lws *wsi,
260
        const struct lws_client_connect_info *i)
261
0
{
262
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
263
0
    if (lws_rops_fidx(ar, LWS_ROPS_client_bind)) {
264
0
      int m = (lws_rops_func_fidx(ar, LWS_ROPS_client_bind)).
265
0
              client_bind(wsi, i);
266
267
0
      if (m < 0)
268
0
        return m;
269
0
      if (m)
270
0
        return 0;
271
0
    }
272
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
273
274
  /* fall back to raw socket role if, eg, h1 not configured */
275
276
0
  if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind) &&
277
0
      (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind)).
278
0
          client_bind(wsi, i))
279
0
    return 0;
280
281
0
  return 1;
282
0
}
283
#endif
284
285
void *
286
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
287
          const struct lws_protocols *prot, int size)
288
0
{
289
0
  int n = 0;
290
291
0
  if (!vhost || !prot || !vhost->protocols || !prot->name)
292
0
    return NULL;
293
294
  /* allocate the vh priv array only on demand */
295
0
  if (!vhost->protocol_vh_privs) {
296
0
    vhost->protocol_vh_privs = (void **)lws_zalloc(
297
0
        (size_t)vhost->count_protocols * sizeof(void *),
298
0
        "protocol_vh_privs");
299
300
0
    if (!vhost->protocol_vh_privs)
301
0
      return NULL;
302
0
  }
303
304
0
  while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
305
0
    n++;
306
307
0
  if (n == vhost->count_protocols) {
308
0
    n = 0;
309
0
    while (n < vhost->count_protocols) {
310
0
      if (vhost->protocols[n].name &&
311
0
          !strcmp(vhost->protocols[n].name, prot->name))
312
0
        break;
313
0
      n++;
314
0
    }
315
316
0
    if (n == vhost->count_protocols) {
317
0
      lwsl_vhost_err(vhost, "unknown protocol %p", prot);
318
0
      return NULL;
319
0
    }
320
0
  }
321
322
0
  vhost->protocol_vh_privs[n] = lws_zalloc((size_t)size, "vh priv");
323
0
  return vhost->protocol_vh_privs[n];
324
0
}
325
326
void *
327
lws_protocol_vh_priv_get(struct lws_vhost *vhost,
328
       const struct lws_protocols *prot)
329
0
{
330
0
  int n = 0;
331
332
0
  if (!vhost || !vhost->protocols ||
333
0
      !vhost->protocol_vh_privs || !prot || !prot->name)
334
0
    return NULL;
335
336
0
  while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
337
0
    n++;
338
339
0
  if (n == vhost->count_protocols) {
340
0
    n = 0;
341
0
    while (n < vhost->count_protocols) {
342
0
      if (vhost->protocols[n].name &&
343
0
          !strcmp(vhost->protocols[n].name, prot->name))
344
0
        break;
345
0
      n++;
346
0
    }
347
348
0
    if (n == vhost->count_protocols) {
349
0
      lwsl_vhost_err(vhost, "unknown protocol %p (%s)", prot, prot->name);
350
0
      return NULL;
351
0
    }
352
0
  }
353
354
0
  return vhost->protocol_vh_privs[n];
355
0
}
356
357
void *
358
lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname,
359
        const char *pvo_name, const char *pvo_value)
360
0
{
361
0
  struct lws_vhost *vh;
362
0
  int n;
363
364
  /* let's go through all the vhosts */
365
366
0
  vh = lws_vhost_first(cx);
367
0
  while (vh) {
368
369
0
    if (vh->protocol_vh_privs) {
370
371
0
    for (n = 0; n < vh->count_protocols; n++) {
372
0
      const struct lws_protocol_vhost_options *pv;
373
374
0
      if (strcmp(vh->protocols[n].name, protname))
375
0
        continue;
376
377
      /* this vh has an instance of the required protocol */
378
379
0
      pv = lws_pvo_search(vh->pvo, protname);
380
0
      if (!pv)
381
0
        continue;
382
383
0
      pv = lws_pvo_search(pv->options, pvo_name);
384
0
      if (!pv)
385
0
        continue;
386
387
      /* ... he also has a pvo of the right name... */
388
0
      if (!strcmp(pv->value, pvo_value))
389
        /*
390
         * ... yes, the pvo has the right value too,
391
         * return a pointer to this vhost-protocol
392
         * private alloc (ie, its "vhd")
393
         */
394
0
        return vh->protocol_vh_privs[n];
395
0
    }
396
0
    } else
397
0
      lwsl_vhost_notice(vh, "no privs yet");
398
0
    vh = lws_vhost_next(vh);
399
0
  }
400
401
0
  return NULL;
402
0
}
403
404
const struct lws_protocol_vhost_options *
405
lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
406
0
{
407
0
  const struct lws_protocol_vhost_options *pvo = vh->pvo;
408
409
0
  if (!name)
410
0
    return NULL;
411
412
0
  while (pvo) {
413
0
    if (!strcmp(pvo->name, name))
414
0
      return pvo;
415
0
    pvo = pvo->next;
416
0
  }
417
418
0
  return NULL;
419
0
}
420
421
int
422
lws_protocol_init_vhost(struct lws_vhost *vh, int *any)
423
0
{
424
0
  const struct lws_protocol_vhost_options *pvo, *pvo1;
425
0
  int n;
426
#if defined(LWS_PLAT_FREERTOS)
427
  struct lws_a _lwsa, *lwsa = &_lwsa;
428
429
  memset(&_lwsa, 0, sizeof(_lwsa));
430
#else
431
#if defined(__COVERITY__)
432
  struct lws _lws = { 0 };
433
#else
434
0
  struct lws _lws;
435
436
0
  memset((void *)&_lws, 0, sizeof(_lws));
437
0
#endif
438
0
  struct lws_a *lwsa = &_lws.a;
439
0
#endif
440
441
0
  lwsa->context = vh->context;
442
0
  lwsa->vhost = vh;
443
444
  /* initialize supported protocols on this vhost */
445
446
  /* Pass 1: init plugins first */
447
448
0
  for (n = vh->plugin_protocol_bind;
449
0
       n < vh->plugin_protocol_bind + vh->plugin_protocol_count; n++) {
450
0
    lwsa->protocol = &vh->protocols[n];
451
0
    if (!vh->protocols[n].name)
452
0
      continue;
453
454
0
    pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
455
0
    if (pvo) {
456
      /*
457
       * linked list of options specific to
458
       * vh + protocol
459
       */
460
0
      pvo1 = pvo;
461
0
      pvo = pvo1->options;
462
463
0
      while (pvo) {
464
0
        lwsl_vhost_debug(vh, "protocol \"%s\", "
465
0
                 "option \"%s\"",
466
0
                 vh->protocols[n].name,
467
0
                 pvo->name);
468
469
0
        if (!strcmp(pvo->name, "default")) {
470
0
          lwsl_vhost_info(vh, "Setting default "
471
0
                   "protocol to %s",
472
0
                   vh->protocols[n].name);
473
0
          vh->default_protocol_index = (unsigned char)n;
474
0
        }
475
0
        if (!strcmp(pvo->name, "raw")) {
476
0
          lwsl_vhost_info(vh, "Setting raw "
477
0
                   "protocol to %s",
478
0
                   vh->protocols[n].name);
479
0
          vh->raw_protocol_index = (unsigned char)n;
480
0
        }
481
0
        pvo = pvo->next;
482
0
      }
483
0
    } else
484
0
      lwsl_vhost_debug(vh, "not instantiating %s",
485
0
               vh->protocols[n].name);
486
487
0
#if defined(LWS_WITH_TLS)
488
0
    if (any)
489
0
      *any |= !!vh->tls.ssl_ctx;
490
0
#endif
491
492
0
    pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
493
494
    /*
495
     * inform all the protocols that they are doing their
496
     * one-time initialization if they want to.
497
     *
498
     * NOTE the fakewsi is garbage, except the key pointers that are
499
     * prepared in case the protocol handler wants to touch them
500
     */
501
502
0
    if (pvo || (vh->options & LWS_SERVER_OPTION_VH_INSTANTIATE_ALL_PROTOCOLS)
503
504
0
#if !defined(LWS_WITH_PROTOCOL_PLUGINS)
505
        /*
506
         * with plugins, you have to explicitly
507
         * instantiate them per-vhost with pvos.
508
         *
509
         * Without plugins, not setting the vhost pvo
510
         * list at creation enables all the protocols
511
         * by default, for backwards compatibility
512
         */
513
0
        || !vh->pvo
514
0
#endif
515
0
    ) {
516
0
      lwsl_vhost_info(vh, "init %s.%s", vh->name,
517
0
          vh->protocols[n].name);
518
0
      if (vh->protocols[n].callback((struct lws *)lwsa,
519
0
          LWS_CALLBACK_PROTOCOL_INIT, NULL,
520
0
          (void *)(pvo ? pvo->options : NULL),
521
0
          0)) {
522
0
        if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) {
523
0
          lws_free(vh->protocol_vh_privs[n]);
524
0
          vh->protocol_vh_privs[n] = NULL;
525
0
        }
526
0
        lwsl_vhost_warn(vh, "protocol %s failed init",
527
0
          vh->protocols[n].name);
528
529
530
0
      } else
531
0
        vh->protocol_init |= 1u << n;
532
0
    }
533
0
  }
534
535
  /* Pass 2: init non-plugins */
536
537
0
  for (n = 0; n < vh->count_protocols; n++) {
538
0
    if (n >= vh->plugin_protocol_bind &&
539
0
        n < vh->plugin_protocol_bind + vh->plugin_protocol_count)
540
0
      continue;
541
542
0
    lwsa->protocol = &vh->protocols[n];
543
0
    if (!vh->protocols[n].name)
544
0
      continue;
545
546
0
    pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
547
0
    if (pvo) {
548
      /*
549
       * linked list of options specific to
550
       * vh + protocol
551
       */
552
0
      pvo1 = pvo;
553
0
      pvo = pvo1->options;
554
555
0
      while (pvo) {
556
0
        lwsl_vhost_debug(vh, "protocol \"%s\", "
557
0
                 "option \"%s\"",
558
0
                 vh->protocols[n].name,
559
0
                 pvo->name);
560
561
0
        if (!strcmp(pvo->name, "default")) {
562
0
          lwsl_vhost_info(vh, "Setting default "
563
0
                   "protocol to %s",
564
0
                   vh->protocols[n].name);
565
0
          vh->default_protocol_index = (unsigned char)n;
566
0
        }
567
0
        if (!strcmp(pvo->name, "raw")) {
568
0
          lwsl_vhost_info(vh, "Setting raw "
569
0
                   "protocol to %s",
570
0
                   vh->protocols[n].name);
571
0
          vh->raw_protocol_index = (unsigned char)n;
572
0
        }
573
0
        pvo = pvo->next;
574
0
      }
575
0
    } else
576
0
      lwsl_vhost_debug(vh, "not instantiating %s",
577
0
               vh->protocols[n].name);
578
579
0
#if defined(LWS_WITH_TLS)
580
0
    if (any)
581
0
      *any |= !!vh->tls.ssl_ctx;
582
0
#endif
583
584
0
    pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
585
586
    /*
587
     * inform all the protocols that they are doing their
588
     * one-time initialization if they want to.
589
     *
590
     * NOTE the fakewsi is garbage, except the key pointers that are
591
     * prepared in case the protocol handler wants to touch them
592
     */
593
594
0
    if (pvo || (vh->options & LWS_SERVER_OPTION_VH_INSTANTIATE_ALL_PROTOCOLS)
595
596
0
#if !defined(LWS_WITH_PROTOCOL_PLUGINS)
597
        /*
598
         * with plugins, you have to explicitly
599
         * instantiate them per-vhost with pvos.
600
         *
601
         * Without plugins, not setting the vhost pvo
602
         * list at creation enables all the protocols
603
         * by default, for backwards compatibility
604
         */
605
0
        || !vh->pvo
606
0
#endif
607
0
    ) {
608
0
      lwsl_vhost_info(vh, "init %s.%s", vh->name,
609
0
          vh->protocols[n].name);
610
0
      if (vh->protocols[n].callback((struct lws *)lwsa,
611
0
          LWS_CALLBACK_PROTOCOL_INIT, NULL,
612
0
          (void *)(pvo ? pvo->options : NULL),
613
0
          0)) {
614
0
        if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) {
615
0
          lws_free(vh->protocol_vh_privs[n]);
616
0
          vh->protocol_vh_privs[n] = NULL;
617
0
        }
618
0
        lwsl_vhost_warn(vh, "protocol %s failed init",
619
0
          vh->protocols[n].name);
620
621
622
0
      } else
623
0
        vh->protocol_init |= 1u << n;
624
0
    }
625
0
  }
626
627
0
  vh->created_vhost_protocols = 1;
628
629
0
  return 0;
630
0
}
631
632
/*
633
 * inform every vhost that hasn't already done it, that
634
 * his protocols are initializing
635
 */
636
int
637
lws_protocol_init(struct lws_context *context)
638
0
{
639
0
  struct lws_vhost *vh = lws_vhost_first(context);
640
0
  int any = 0, r = 0, spd = 0;
641
642
0
  if (context->doing_protocol_init)
643
0
    return 0;
644
645
0
  context->doing_protocol_init = 1;
646
647
0
  lwsl_cx_info(context, "\n");
648
649
0
  while (vh) {
650
651
0
    spd |= lws_check_opt(vh->options, LWS_SERVER_OPTION_VH_SKIP_PRIV_DROP);
652
653
    /* only do the protocol init once for a given vhost */
654
0
    if (vh->created_vhost_protocols ||
655
0
        (lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT)))
656
0
      goto next;
657
658
0
    if (lws_protocol_init_vhost(vh, &any)) {
659
0
      lwsl_vhost_warn(vh, "init vhost %s failed", vh->name);
660
0
      r = -1;
661
0
    }
662
0
next:
663
0
    vh = lws_vhost_next(vh);
664
0
  }
665
666
0
  context->doing_protocol_init = 0;
667
668
0
  if (r)
669
0
    lwsl_cx_warn(context, "some protocols did not init");
670
671
0
  if (!context->protocol_init_done) {
672
673
0
    context->protocol_init_done = 1;
674
0
    if (!spd)
675
0
      lws_finalize_startup(context, __func__);
676
677
0
    return 0;
678
0
  }
679
680
0
#if defined(LWS_WITH_SERVER)
681
0
  if (any) {
682
0
    lws_tls_check_all_cert_lifetimes(context);
683
0
  }
684
0
#endif
685
686
0
  return 0;
687
0
}
688
689
690
/* list of supported protocols and callbacks */
691
692
static const struct lws_protocols protocols_dummy[] = {
693
  /* first protocol must always be HTTP handler */
694
695
  {
696
    "http-only",      /* name */
697
    lws_callback_http_dummy,  /* callback */
698
    0,        /* per_session_data_size */
699
    0,        /* rx_buffer_size */
700
    0,        /* id */
701
    NULL,       /* user */
702
    0       /* tx_packet_size */
703
  },
704
  /*
705
   * the other protocols are provided by lws plugins
706
   */
707
  { NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
708
};
709
710
711
#ifdef LWS_PLAT_OPTEE
712
#undef LWS_HAVE_GETENV
713
#endif
714
715
struct lws_vhost *
716
lws_create_vhost(struct lws_context *context,
717
     const struct lws_context_creation_info *info)
718
0
{
719
0
  struct lws_vhost *vh;
720
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
721
0
  const struct lws_http_mount *mounts;
722
0
#endif
723
0
  const struct lws_protocols *pcols = info->protocols;
724
#if defined(LWS_WITH_PROTOCOL_PLUGINS)
725
  struct lws_plugin *plugin = context->plugin_list;
726
#endif
727
0
  struct lws_protocols *lwsp;
728
0
  int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0, dht_count = 0;
729
0
  const char *name = "default";
730
0
  char buf[96];
731
0
  char *p;
732
#if defined(LWS_WITH_SYS_ASYNC_DNS)
733
  extern struct lws_protocols lws_async_dns_protocol;
734
#endif
735
#if defined(LWS_WITH_DHT)
736
  extern const struct lws_protocols lws_dht_protocol;
737
#endif
738
0
#if defined(LWS_WITH_CLIENT)
739
0
  extern const struct lws_protocols lws_async_ipc_protocol;
740
0
#endif
741
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
742
  extern const struct lws_protocols lws_sspc_protocols[];
743
#endif
744
0
  int n;
745
746
747
0
  if (!pcols && context->protocols_copy)
748
0
    pcols = context->protocols_copy;
749
750
0
  if (info->vhost_name)
751
0
    name = info->vhost_name;
752
753
0
  if (lws_fi(&info->fic, "vh_create_oom"))
754
0
    vh = NULL;
755
0
  else
756
0
    vh = lws_zalloc(sizeof(*vh) + strlen(name) + 1
757
#if defined(LWS_WITH_EVENT_LIBS)
758
      + context->event_loop_ops->evlib_size_vh
759
#endif
760
0
      , __func__);
761
0
  if (!vh)
762
0
    goto early_bail;
763
764
0
  if (info->log_cx)
765
0
    vh->lc.log_cx = info->log_cx;
766
0
  else
767
0
    vh->lc.log_cx = &log_cx;
768
769
#if defined(LWS_WITH_EVENT_LIBS)
770
  vh->evlib_vh = (void *)&vh[1];
771
  vh->name = (const char *)vh->evlib_vh +
772
      context->event_loop_ops->evlib_size_vh;
773
#else
774
0
  vh->name = (const char *)&vh[1];
775
0
#endif
776
0
  memcpy((char *)vh->name, name, strlen(name) + 1);
777
778
#if LWS_MAX_SMP > 1
779
  lws_mutex_refcount_init(&vh->mr);
780
#endif
781
782
0
  if (!pcols && !info->pprotocols)
783
0
    pcols = &protocols_dummy[0];
784
785
0
  vh->context = context;
786
0
  {
787
0
    char *end = buf + sizeof(buf) - 1;
788
0
    p = buf;
789
790
0
    p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", vh->name);
791
0
    if (info->iface)
792
0
      p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%s", info->iface);
793
0
    if (info->port && !(info->port & 0xffff))
794
0
      p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%u", info->port);
795
0
  }
796
797
0
  __lws_lc_tag(context, &context->lcg[LWSLCG_VHOST], &vh->lc, "%s|%s|%d",
798
0
         buf, info->iface ? info->iface : "", info->port);
799
800
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
801
  vh->fic.name = "vh";
802
  if (lws_dll2_count(&info->fic.fi_owner))
803
    /*
804
     * This moves all the lws_fi_t from info->fi to the vhost fi,
805
     * leaving it empty
806
     */
807
    lws_fi_import(&vh->fic, &info->fic);
808
809
  lws_fi_inherit_copy(&vh->fic, &context->fic, "vh", vh->name);
810
  if (lws_fi(&vh->fic, "vh_create_oom"))
811
    goto bail;
812
#endif
813
814
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
815
0
  vh->http.error_document_404 = info->error_document_404;
816
0
#endif
817
818
0
  if (lws_check_opt(info->options, LWS_SERVER_OPTION_ONLY_RAW))
819
0
    lwsl_vhost_info(vh, "set to only support RAW");
820
821
0
  vh->iface = info->iface;
822
0
#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
823
0
  vh->bind_iface = info->bind_iface;
824
0
#endif
825
0
#if defined(LWS_WITH_CLIENT)
826
0
  if (info->connect_timeout_secs)
827
0
    vh->connect_timeout_secs = (int)info->connect_timeout_secs;
828
0
  else
829
0
    vh->connect_timeout_secs = 20;
830
0
#endif
831
  /* apply the context default lws_retry */
832
833
0
  if (info->retry_and_idle_policy)
834
0
    vh->retry_policy = info->retry_and_idle_policy;
835
0
  else
836
0
    vh->retry_policy = &context->default_retry;
837
838
  /*
839
   * let's figure out how many protocols the user is handing us, using the
840
   * old or new way depending on what he gave us
841
   */
842
843
0
  if (!pcols) {
844
0
    for (vh->count_protocols = 0;
845
0
      info->pprotocols[vh->count_protocols];
846
0
      vh->count_protocols++)
847
0
        ;
848
849
0
  } else
850
0
    for (vh->count_protocols = 0;
851
0
      pcols[vh->count_protocols].callback;
852
0
      vh->count_protocols++)
853
0
        ;
854
855
0
  vh->options                     = info->options;
856
0
  vh->quic_preferred_addresses    = info->quic_preferred_addresses;
857
0
  vh->pvo                         = info->pvo;
858
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
859
0
  vh->headers     = info->headers;
860
0
#endif
861
0
  vh->user      = info->user;
862
0
  vh->finalize      = info->finalize;
863
0
  vh->finalize_arg    = info->finalize_arg;
864
0
  vh->listen_accept_role    = info->listen_accept_role;
865
0
  vh->listen_accept_protocol  = info->listen_accept_protocol;
866
0
  vh->unix_socket_perms   = info->unix_socket_perms;
867
0
  vh->fo_listen_queue   = info->fo_listen_queue;
868
0
  vh->max_http_body_size    = info->max_http_body_size;
869
870
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
871
0
  if (lws_rops_fidx(ar, LWS_ROPS_init_vhost) &&
872
0
      (lws_rops_func_fidx(ar, LWS_ROPS_init_vhost)).init_vhost(vh, info))
873
0
    return NULL;
874
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
875
876
877
0
  if (info->keepalive_timeout)
878
0
    vh->keepalive_timeout = info->keepalive_timeout;
879
0
  else
880
0
    vh->keepalive_timeout = 5;
881
882
0
  if (info->timeout_secs_ah_idle)
883
0
    vh->timeout_secs_ah_idle = (int)info->timeout_secs_ah_idle;
884
0
  else
885
0
    vh->timeout_secs_ah_idle = 10;
886
887
0
#if defined(LWS_WITH_TLS)
888
889
0
  vh->tls.alpn = info->alpn;
890
0
  vh->tls.ssl_info_event_mask = info->ssl_info_event_mask;
891
892
0
  if (info->ecdh_curve)
893
0
    vh->tls.cfg_ecdh_curve = lws_strdup(info->ecdh_curve);
894
0
#if defined(LWS_WITH_CLIENT)
895
0
  if (info->client_ecdh_curve)
896
0
    vh->tls.cfg_client_ecdh_curve =
897
0
          lws_strdup(info->client_ecdh_curve);
898
0
#endif
899
900
0
  if (info->ssl_cipher_list)
901
0
    vh->tls.cfg_ssl_cipher_list = lws_strdup(info->ssl_cipher_list);
902
0
  if (info->tls1_3_plus_cipher_list)
903
0
    vh->tls.cfg_tls1_3_plus_cipher_list = lws_strdup(info->tls1_3_plus_cipher_list);
904
0
#if defined(LWS_WITH_CLIENT)
905
0
        if (info->client_ssl_cipher_list)
906
0
                vh->tls.cfg_tls_client_cipher_list = lws_strdup(info->client_ssl_cipher_list);
907
0
#endif
908
0
  if (info->tls_ciphers_iana)
909
0
    vh->tls.cfg_tls_ciphers_iana = lws_strdup(info->tls_ciphers_iana);
910
0
  if (info->ssl_ca_filepath)
911
0
    vh->tls.cfg_ssl_ca_filepath = lws_strdup(info->ssl_ca_filepath);
912
913
0
  vh->tls.cfg_server_ssl_cert_mem = info->server_ssl_cert_mem;
914
0
  vh->tls.cfg_server_ssl_cert_mem_len = info->server_ssl_cert_mem_len;
915
0
  vh->tls.cfg_server_ssl_privkey_mem = info->server_ssl_private_key_mem;
916
0
  vh->tls.cfg_server_ssl_privkey_mem_len = info->server_ssl_private_key_mem_len;
917
0
  vh->tls.cfg_server_ssl_ca_mem = info->server_ssl_ca_mem;
918
0
  vh->tls.cfg_server_ssl_ca_mem_len = info->server_ssl_ca_mem_len;
919
920
0
#if defined(LWS_WITH_CLIENT)
921
0
  vh->tls.cfg_client_ssl_ca_mem = info->client_ssl_ca_mem;
922
0
  vh->tls.cfg_client_ssl_ca_mem_len = info->client_ssl_ca_mem_len;
923
0
  vh->tls.cfg_client_ssl_cert_mem = info->client_ssl_cert_mem;
924
0
  vh->tls.cfg_client_ssl_cert_mem_len = info->client_ssl_cert_mem_len;
925
0
  vh->tls.cfg_client_ssl_key_mem = info->client_ssl_key_mem;
926
0
  vh->tls.cfg_client_ssl_key_mem_len = info->client_ssl_key_mem_len;
927
0
#endif
928
929
0
  vh->tls.ssl_options_set = info->ssl_options_set;
930
0
  vh->tls.ssl_options_clear = info->ssl_options_clear;
931
932
  /* carefully allocate and take a copy of cert + key paths if present */
933
0
  n = 0;
934
0
  if (info->ssl_cert_filepath)
935
0
    n += (int)strlen(info->ssl_cert_filepath) + 1;
936
0
  if (info->ssl_private_key_filepath)
937
0
    n += (int)strlen(info->ssl_private_key_filepath) + 1;
938
939
0
  if (n) {
940
0
    vh->tls.cfg_key_path = vh->tls.cfg_alloc_cert_path =
941
0
          lws_malloc((unsigned int)n, "vh paths");
942
0
    if (!vh->tls.cfg_alloc_cert_path)
943
0
      goto bail;
944
0
    if (info->ssl_cert_filepath) {
945
0
      n = (int)strlen(info->ssl_cert_filepath) + 1;
946
0
      memcpy(vh->tls.cfg_alloc_cert_path,
947
0
             info->ssl_cert_filepath, (unsigned int)n);
948
0
      vh->tls.cfg_key_path += n;
949
0
    }
950
0
    if (info->ssl_private_key_filepath)
951
0
      memcpy(vh->tls.cfg_key_path, info->ssl_private_key_filepath,
952
0
             strlen(info->ssl_private_key_filepath) + 1);
953
0
  }
954
0
#endif
955
956
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
957
  fx = 1;
958
#endif
959
#if defined(LWS_WITH_ABSTRACT)
960
  abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1;
961
#endif
962
0
#if defined(LWS_WITH_SECURE_STREAMS)
963
0
  sec_pcol_count = (int)LWS_ARRAY_SIZE(available_secstream_protocols) - 1;
964
0
#endif
965
#if defined(LWS_WITH_DHT)
966
  dht_count = 1;
967
#endif
968
969
  /*
970
   * give the vhost a unified list of protocols including:
971
   *
972
   * - internal, async_dns if enabled (first vhost only)
973
   * - internal, abstracted ones
974
   * - the ones that came from plugins
975
   * - his user protocols
976
   */
977
978
0
  if (lws_fi(&vh->fic, "vh_create_pcols_oom"))
979
0
    lwsp = NULL;
980
0
  else
981
0
    lwsp = lws_zalloc(sizeof(struct lws_protocols) *
982
0
        ((unsigned int)vh->count_protocols +
983
0
           (unsigned int)abs_pcol_count +
984
0
           (unsigned int)sec_pcol_count +
985
0
           (unsigned int)dht_count +
986
0
#if defined(LWS_WITH_CLIENT)
987
0
           1 +
988
0
#endif
989
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
990
           1 +
991
#endif
992
0
           (unsigned int)context->plugin_protocol_count +
993
0
           (unsigned int)fx + 1), "vh plugin table");
994
0
  if (!lwsp) {
995
0
    lwsl_err("OOM\n");
996
0
    goto bail;
997
0
  }
998
999
  /*
1000
   * 1: user protocols (from pprotocols or protocols)
1001
   */
1002
1003
0
  m = vh->count_protocols;
1004
0
  if (!pcols) {
1005
0
    for (n = 0; n < m; n++)
1006
0
      memcpy(&lwsp[n], info->pprotocols[n], sizeof(lwsp[0]));
1007
0
  } else
1008
0
    memcpy(lwsp, pcols, sizeof(struct lws_protocols) * (unsigned int)m);
1009
1010
  /*
1011
   * 2: abstract protocols
1012
   */
1013
#if defined(LWS_WITH_ABSTRACT)
1014
  for (n = 0; n < abs_pcol_count; n++) {
1015
    memcpy(&lwsp[m++], available_abstract_protocols[n],
1016
           sizeof(*lwsp));
1017
    vh->count_protocols++;
1018
  }
1019
#endif
1020
  /*
1021
   * 3: async dns protocol (first vhost only)
1022
   */
1023
#if defined(LWS_WITH_SYS_ASYNC_DNS)
1024
  if(lws_dll2_is_empty(&context->vhost_list_owner)) {
1025
    uint8_t seen = 0;
1026
1027
    for (n = 0; n < m; n++)
1028
      if (lwsp[n].name && !strcmp(lwsp[n].name, lws_async_dns_protocol.name)) {
1029
        /* Already defined */
1030
        seen = 1;
1031
        break;
1032
      }
1033
1034
    if (!seen) {
1035
      memcpy(&lwsp[m++], &lws_async_dns_protocol,
1036
             sizeof(struct lws_protocols));
1037
      vh->count_protocols++;
1038
    }
1039
  }
1040
#endif
1041
1042
0
#if defined(LWS_WITH_SECURE_STREAMS)
1043
0
  for (n = 0; n < sec_pcol_count; n++) {
1044
0
    memcpy(&lwsp[m++], available_secstream_protocols[n],
1045
0
           sizeof(*lwsp));
1046
0
    vh->count_protocols++;
1047
0
  }
1048
0
#endif
1049
1050
#if defined(LWS_WITH_DHT)
1051
  memcpy(&lwsp[m], &lws_dht_protocol, sizeof(*lwsp));
1052
  m++;
1053
  vh->count_protocols++;
1054
#endif
1055
1056
0
#if defined(LWS_WITH_CLIENT)
1057
0
  memcpy(&lwsp[m], &lws_async_ipc_protocol, sizeof(*lwsp));
1058
0
  m++;
1059
0
  vh->count_protocols++;
1060
0
#endif
1061
1062
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
1063
  memcpy(&lwsp[m], &lws_sspc_protocols[0], sizeof(*lwsp));
1064
  m++;
1065
  vh->count_protocols++;
1066
#endif
1067
1068
1069
  /*
1070
   * 3: For compatibility, all protocols enabled on vhost if only
1071
   * the default vhost exists.  Otherwise only vhosts who ask
1072
   * for a protocol get it enabled.
1073
   */
1074
1075
0
  if ((context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) &&
1076
0
      !(vh->options & LWS_SERVER_OPTION_VH_INSTANTIATE_ALL_PROTOCOLS))
1077
0
    f = 0;
1078
0
  (void)f;
1079
#if defined(LWS_WITH_PROTOCOL_PLUGINS)
1080
  if (plugin) {
1081
    vh->plugin_protocol_bind = m;
1082
    while (plugin) {
1083
      const lws_plugin_protocol_t *plpr =
1084
        (const lws_plugin_protocol_t *)plugin->hdr;
1085
1086
      for (n = 0; n < plpr->count_protocols; n++) {
1087
        /*
1088
         * for compatibility's sake, no pvo implies
1089
         * allow all protocols
1090
         */
1091
        if (f || lws_vhost_protocol_options(vh,
1092
            plpr->protocols[n].name)) {
1093
          memcpy(&lwsp[m],
1094
                 &plpr->protocols[n],
1095
                 sizeof(struct lws_protocols));
1096
          m++;
1097
          vh->count_protocols++;
1098
          vh->plugin_protocol_count++;
1099
        }
1100
      }
1101
      plugin = plugin->list;
1102
    }
1103
  }
1104
#endif
1105
1106
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
1107
  memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(*lwsp));
1108
  vh->count_protocols++;
1109
#endif
1110
1111
0
  vh->protocols = lwsp;
1112
0
  vh->allocated_vhost_protocols = 1;
1113
1114
0
  vh->same_vh_protocol_owner = (struct lws_dll2_owner *)
1115
0
      lws_zalloc(sizeof(struct lws_dll2_owner) *
1116
0
           (unsigned int)vh->count_protocols, "same vh list");
1117
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1118
0
  vh->http.mount_list = info->mounts;
1119
0
#endif
1120
1121
#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
1122
  {
1123
    char *end = buf + sizeof(buf) - 1;
1124
    p = buf;
1125
1126
    p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "vh.%s", vh->name);
1127
    if (info->iface)
1128
      p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%s", info->iface);
1129
    if (info->port && !(info->port & 0xffff))
1130
      p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%u", info->port);
1131
    p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".rx");
1132
    vh->mt_traffic_rx = lws_metric_create(context, 0, buf);
1133
    p[-2] = 't';
1134
    vh->mt_traffic_tx = lws_metric_create(context, 0, buf);
1135
  }
1136
#endif
1137
1138
0
#ifdef LWS_WITH_UNIX_SOCK
1139
0
  if (LWS_UNIX_SOCK_ENABLED(vh)) {
1140
0
    lwsl_vhost_info(vh, "Creating '%s' path \"%s\", %d protocols",
1141
0
        vh->name, vh->iface, vh->count_protocols);
1142
0
  } else
1143
0
#endif
1144
0
  {
1145
0
    switch(info->port) {
1146
0
    case CONTEXT_PORT_NO_LISTEN:
1147
0
      strcpy(buf, "(serving disabled)");
1148
0
      break;
1149
0
    case CONTEXT_PORT_NO_LISTEN_SERVER:
1150
0
      strcpy(buf, "(no listener)");
1151
0
      break;
1152
0
    default:
1153
0
      lws_snprintf(buf, sizeof(buf), "port %u", info->port);
1154
0
      break;
1155
0
    }
1156
0
    lwsl_vhost_info(vh, "Creating Vhost '%s' %s, %d protocols, IPv6 %s",
1157
0
          vh->name, buf, vh->count_protocols,
1158
0
          LWS_IPV6_ENABLED(vh) ? "on" : "off");
1159
0
  }
1160
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1161
0
  mounts = info->mounts;
1162
0
  while (mounts) {
1163
0
    (void)mount_protocols[0];
1164
0
    lwsl_vhost_info(vh, "   mounting %s%s to %s",
1165
0
        mount_protocols[mounts->origin_protocol],
1166
0
        mounts->origin ? mounts->origin : "none",
1167
0
        mounts->mountpoint);
1168
1169
0
    mounts = mounts->mount_next;
1170
0
  }
1171
0
#endif
1172
1173
0
  vh->listen_port = info->port;
1174
1175
#if defined(LWS_WITH_SOCKS5)
1176
  vh->socks_proxy_port = 0;
1177
  vh->socks_proxy_address[0] = '\0';
1178
#endif
1179
1180
0
#if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING)
1181
  /* either use proxy from info, or try get it from env var */
1182
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1183
0
  vh->http.http_proxy_port = 0;
1184
0
  vh->http.http_proxy_address[0] = '\0';
1185
  /* http proxy */
1186
0
  if (info->http_proxy_address) {
1187
    /* override for backwards compatibility */
1188
0
    if (info->http_proxy_port)
1189
0
      vh->http.http_proxy_port = info->http_proxy_port;
1190
0
    lws_set_proxy(vh, info->http_proxy_address);
1191
0
  } else
1192
0
#endif
1193
0
  {
1194
0
#ifdef LWS_HAVE_GETENV
1195
#if defined(__COVERITY__)
1196
    p = NULL;
1197
#else
1198
0
    p = getenv("http_proxy"); /* coverity[tainted_scalar] */
1199
0
    if (p) {
1200
0
      lws_strncpy(buf, p, sizeof(buf));
1201
0
      lws_set_proxy(vh, buf);
1202
0
    }
1203
0
#endif
1204
0
#endif
1205
0
  }
1206
0
#endif
1207
#if defined(LWS_WITH_SOCKS5)
1208
  lws_socks5c_ads_server(vh, info);
1209
#endif
1210
1211
0
  vh->ka_time = info->ka_time;
1212
0
  vh->ka_interval = info->ka_interval;
1213
1214
0
  vh->quic_mtu = info->quic_mtu ? info->quic_mtu : 1280;
1215
0
  vh->ka_probes = info->ka_probes;
1216
1217
0
  if (vh->options & LWS_SERVER_OPTION_STS)
1218
0
    lwsl_vhost_notice(vh, "   STS enabled");
1219
1220
#ifdef LWS_WITH_ACCESS_LOG
1221
  if (info->log_filepath) {
1222
    if (lws_fi(&vh->fic, "vh_create_access_log_open_fail"))
1223
      vh->log_fd = (int)LWS_INVALID_FILE;
1224
    else
1225
      vh->log_fd = lws_open(info->log_filepath,
1226
          O_CREAT | O_APPEND | O_RDWR, 0600);
1227
    if (vh->log_fd == (int)LWS_INVALID_FILE) {
1228
      lwsl_vhost_err(vh, "unable to open log filepath %s",
1229
             info->log_filepath);
1230
      goto bail;
1231
    }
1232
#ifndef WIN32
1233
    if (context->uid != (uid_t)-1)
1234
      if (chown(info->log_filepath, context->uid,
1235
          context->gid) == -1)
1236
        lwsl_vhost_err(vh, "unable to chown log file %s",
1237
               info->log_filepath);
1238
#endif
1239
  } else
1240
    vh->log_fd = (int)LWS_INVALID_FILE;
1241
#endif
1242
0
  if (lws_fi(&vh->fic, "vh_create_ssl_srv") ||
1243
0
      lws_context_init_server_ssl(info, vh)) {
1244
0
    lwsl_vhost_err(vh, "lws_context_init_server_ssl failed");
1245
0
    goto bail1;
1246
0
  }
1247
0
#if defined(LWS_WITH_CLIENT)
1248
0
  if (lws_fi(&vh->fic, "vh_create_ssl_cli") ||
1249
0
      lws_context_init_client_ssl(info, vh)) {
1250
0
    lwsl_vhost_err(vh, "lws_context_init_client_ssl failed");
1251
0
    goto bail1;
1252
0
  }
1253
0
#endif
1254
0
#if defined(LWS_WITH_SERVER)
1255
0
  lws_context_lock(context, __func__);
1256
0
  if (lws_fi(&vh->fic, "vh_create_srv_init"))
1257
0
    n = -1;
1258
0
  else
1259
0
    n = _lws_vhost_init_server(info, vh);
1260
0
  lws_context_unlock(context);
1261
0
  if (n < 0) {
1262
0
    lwsl_vhost_err(vh, "init server failed\n");
1263
0
    goto bail1;
1264
0
  }
1265
0
#endif
1266
1267
#if defined(LWS_WITH_SYS_ASYNC_DNS)
1268
  n = !!lws_dll2_get_head(&context->vhost_list_owner);
1269
#endif
1270
1271
0
  lws_dll2_add_tail(&vh->vhost_list, &context->vhost_list_owner);
1272
1273
#if defined(LWS_WITH_SYS_ASYNC_DNS)
1274
  if (!n)
1275
    lws_async_dns_init(context);
1276
#endif
1277
1278
  /* for the case we are adding a vhost much later, after server init */
1279
1280
0
  if (context->protocol_init_done)
1281
0
    if (lws_fi(&vh->fic, "vh_create_protocol_init") ||
1282
0
        lws_protocol_init(context)) {
1283
0
      lwsl_vhost_err(vh, "lws_protocol_init failed");
1284
0
      goto bail1;
1285
0
    }
1286
1287
0
  return vh;
1288
1289
0
bail1:
1290
0
  lws_vhost_destroy(vh);
1291
1292
0
  return NULL;
1293
1294
0
bail:
1295
0
  __lws_lc_untag(vh->context, &vh->lc);
1296
0
  lws_fi_destroy(&vh->fic);
1297
0
  lws_free(vh);
1298
1299
0
early_bail:
1300
0
  lws_fi_destroy(&info->fic);
1301
1302
0
  return NULL;
1303
0
}
1304
1305
void
1306
lws_vhost_set_mounts(struct lws_vhost *vh, const struct lws_http_mount *mounts)
1307
0
{
1308
0
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1309
0
        vh->http.mount_list = mounts;
1310
0
#endif
1311
0
}
1312
1313
int
1314
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
1315
        struct lws_vhost *vhost)
1316
0
{
1317
0
  struct lws_context_creation_info i;
1318
1319
0
  memcpy(&i, info, sizeof(i));
1320
0
  i.port = CONTEXT_PORT_NO_LISTEN;
1321
1322
0
  return lws_context_init_client_ssl(&i, vhost);
1323
0
}
1324
1325
void
1326
lws_cancel_service_pt(struct lws *wsi)
1327
0
{
1328
0
  lws_plat_pipe_signal(wsi->a.context, wsi->tsi);
1329
0
}
1330
1331
void
1332
lws_cancel_service(struct lws_context *context)
1333
0
{
1334
0
  struct lws_context_per_thread *pt = &context->pt[0];
1335
0
  unsigned short m;
1336
1337
0
  if (context->service_no_longer_possible)
1338
0
    return;
1339
1340
0
  lwsl_cx_debug(context, "\n");
1341
1342
0
  for (m = 0; m < context->count_threads; m++) {
1343
0
    if (pt->pipe_wsi)
1344
0
      lws_plat_pipe_signal(pt->context, m);
1345
0
    pt++;
1346
0
  }
1347
0
}
1348
1349
int
1350
__lws_create_event_pipes(struct lws_context *context)
1351
0
{
1352
0
  struct lws_context_per_thread *pt;
1353
0
  struct lws *wsi;
1354
0
  int n;
1355
1356
  /*
1357
   * Create the pt event pipes... these are unique in that they are
1358
   * not bound to a vhost or protocol (both are NULL)
1359
   */
1360
1361
#if LWS_MAX_SMP > 1
1362
  for (n = 0; n < context->count_threads; n++) {
1363
#else
1364
0
  n = 0;
1365
0
  {
1366
0
#endif
1367
0
    pt = &context->pt[n];
1368
1369
0
    if (pt->pipe_wsi)
1370
0
      return 0;
1371
1372
0
    wsi = __lws_wsi_create_with_role(context, n, &role_ops_pipe,
1373
0
              NULL);
1374
0
    if (!wsi)
1375
0
      return 1;
1376
1377
0
    __lws_lc_tag(context, &context->lcg[LWSLCG_WSI], &wsi->lc,
1378
0
        "pipe");
1379
1380
0
    wsi->event_pipe = 1;
1381
0
    pt->pipe_wsi = wsi;
1382
1383
0
    if (!lws_plat_pipe_create(wsi)) {
1384
      /*
1385
       * platform code returns 0 if it actually created pipes
1386
       * and initialized pt->dummy_pipe_fds[].  If it used
1387
       * some other mechanism outside of signaling in the
1388
       * normal event loop, we skip treating the pipe as
1389
       * related to dummy_pipe_fds[], adding it to the fds,
1390
       * etc.
1391
       */
1392
1393
0
      wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
1394
      // lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
1395
1396
0
      if (lws_wsi_inject_to_loop(pt, wsi))
1397
0
          goto bail;
1398
0
    }
1399
0
  }
1400
1401
0
  return 0;
1402
1403
0
bail:
1404
1405
0
  return 1;
1406
0
}
1407
1408
void
1409
lws_destroy_event_pipe(struct lws *wsi)
1410
0
{
1411
0
  int n;
1412
1413
0
  lwsl_wsi_info(wsi, "in");
1414
1415
0
  n = lws_wsi_extract_from_loop(wsi);
1416
0
  lws_plat_pipe_close(wsi);
1417
0
  if (!n)
1418
0
    lws_free(wsi);
1419
0
}
1420
1421
/*
1422
 * Start close process for any wsi bound to this vhost that belong to the
1423
 * service thread we are called from.  Because of async event lib close, or
1424
 * protocol staged close on wsi, latency with pts joining in closing their
1425
 * wsi on the vhost, this may take some time.
1426
 *
1427
 * When the wsi count bound to the vhost (from all pts) drops to zero, the
1428
 * vhost destruction will be finalized.
1429
 */
1430
1431
void
1432
__lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh)
1433
0
{
1434
#if LWS_MAX_SMP > 1
1435
  /* calling pt thread has done its wsi dieback */
1436
  int tsi = lws_pthread_self_to_tsi(vh->context);
1437
#else
1438
0
  int tsi = 0;
1439
0
#endif
1440
0
  struct lws_context *ctx = vh->context;
1441
0
  struct lws_context_per_thread *pt = &ctx->pt[tsi];
1442
0
  unsigned int n;
1443
1444
#if LWS_MAX_SMP > 1
1445
  if (vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)])
1446
    /* this pt has already done its bit */
1447
    return;
1448
#endif
1449
1450
0
#if defined(LWS_WITH_CLIENT)
1451
  /*
1452
   * destroy any wsi that are associated with us but have no socket
1453
   * (and will otherwise be missed for destruction)
1454
   */
1455
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1456
0
            lws_dll2_get_head(&vh->vh_awaiting_socket_owner)) {
1457
0
    struct lws *w =
1458
0
      lws_container_of(d, struct lws, vh_awaiting_socket);
1459
1460
0
    if (w->tsi == tsi) {
1461
1462
0
      lwsl_vhost_debug(vh, "closing aso");
1463
0
      lws_wsi_close(w, LWS_TO_KILL_ASYNC);
1464
0
    }
1465
1466
0
  } lws_end_foreach_dll_safe(d, d1);
1467
0
#endif
1468
1469
  /*
1470
   * Close any wsi on this pt bound to the vhost
1471
   */
1472
1473
0
  n = 0;
1474
0
  while (n < pt->fds_count) {
1475
0
    struct lws *wsi = wsi_from_fd(ctx, pt->fds[n].fd);
1476
1477
0
    if (wsi && wsi->tsi == tsi && wsi->a.vhost == vh) {
1478
1479
0
      lwsl_wsi_debug(wsi, "pt %d: closin, role %s", tsi,
1480
0
              wsi->role_ops->name);
1481
1482
0
      lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
1483
1484
0
      if (pt->pipe_wsi == wsi)
1485
0
        pt->pipe_wsi = NULL;
1486
0
    }
1487
0
    n++;
1488
0
  }
1489
1490
#if LWS_MAX_SMP > 1
1491
  /* calling pt thread has done its wsi dieback */
1492
  vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)] = 1;
1493
#endif
1494
0
}
1495
1496
#if defined(LWS_WITH_NETWORK)
1497
1498
/* returns nonzero if v1 and v2 can share listen sockets */
1499
int
1500
lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2)
1501
0
{
1502
0
  return ((!v1->iface && !v2->iface) ||
1503
0
     (v1->iface && v2->iface && !strcmp(v1->iface, v2->iface))) &&
1504
0
    v1->listen_port == v2->listen_port;
1505
0
}
1506
1507
/* helper to interate every listen socket on any vhost and call cb on it */
1508
int
1509
lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg,
1510
           lws_dll2_foreach_cb_t cb)
1511
0
{
1512
0
  struct lws_vhost *v = lws_vhost_first(cx);
1513
0
  int n;
1514
1515
0
  while (v) {
1516
1517
0
    n = lws_dll2_foreach_safe(&v->listen_wsi, arg, cb);
1518
0
    if (n)
1519
0
      return n;
1520
1521
0
    v = lws_vhost_next(v);
1522
0
  }
1523
1524
0
  return 0;
1525
0
}
1526
1527
#endif
1528
1529
/*
1530
 * Mark the vhost as being destroyed, so things trying to use it abort.
1531
 *
1532
 * Dispose of the listen socket.
1533
 */
1534
1535
void
1536
lws_vhost_destroy1(struct lws_vhost *vh)
1537
0
{
1538
0
  struct lws_context *context = vh->context;
1539
0
  int n;
1540
1541
0
  lwsl_vhost_info(vh, "\n");
1542
1543
0
  lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */
1544
1545
0
  if (vh->being_destroyed)
1546
0
    goto out;
1547
1548
  /*
1549
   * let's lock all the pts, to enforce pt->vh order... pt is refcounted
1550
   * so it's OK if we acquire it later inside this
1551
   */
1552
1553
0
  for (n = 0; n < context->count_threads; n++)
1554
0
    lws_pt_lock((&context->pt[n]), __func__);
1555
1556
0
  lws_vhost_lock(vh); /* -------------- vh { */
1557
1558
0
#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_TLS)
1559
0
  lws_tls_session_vh_destroy(vh);
1560
0
#endif
1561
1562
0
  vh->being_destroyed = 1;
1563
0
  vh->count_bound_wsi++; /* protect from opportunistic destroy */
1564
0
  lws_dll2_add_tail(&vh->vh_being_destroyed_list,
1565
0
        &context->owner_vh_being_destroyed);
1566
1567
0
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SERVER)
1568
  /*
1569
   * PHASE 1: take down or reassign any listen wsi
1570
   *
1571
   * Are there other vhosts that are piggybacking on our listen sockets?
1572
   * If so we need to hand each listen socket off to one of the others
1573
   * so it will remain open.
1574
   *
1575
   * If not, close the listen socket now.
1576
   *
1577
   * Either way the listen socket response to the vhost close is
1578
   * immediately performed.
1579
   */
1580
1581
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1582
0
            lws_dll2_get_head(&vh->listen_wsi)) {
1583
0
    struct lws *wsi = lws_container_of(d, struct lws, listen_list);
1584
1585
    /*
1586
     * For each of our listen sockets, check every other vhost to
1587
     * see if another vhost should be given our listen socket.
1588
     *
1589
     * ipv4 and ipv6 sockets will both match and be migrated.
1590
     */
1591
1592
0
    lws_start_foreach_vhost(v, context) {
1593
0
      if (v != vh && !v->being_destroyed &&
1594
0
          lws_vhost_compare_listen(v, vh)) {
1595
        /*
1596
         * this can only be a listen wsi, which is
1597
         * restricted... it has no protocol or other
1598
         * bindings or states.  So we can simply
1599
         * swap it to a vhost that has the same
1600
         * iface + port, but is not closing.
1601
         */
1602
1603
0
        lwsl_vhost_notice(vh, "listen skt migrate -> %s",
1604
0
                  lws_vh_tag(v));
1605
1606
0
        lws_dll2_remove(&wsi->listen_list);
1607
0
        lws_dll2_add_tail(&wsi->listen_list,
1608
0
              &v->listen_wsi);
1609
1610
        /* req cx + vh lock */
1611
        /*
1612
         * If the vhost sees it's being destroyed and
1613
         * in the unbind the number of wsis bound to
1614
         * it falls to zero, it will destroy the
1615
         * vhost opportunistically before we can
1616
         * complete the transfer.  Add a fake wsi
1617
         * bind temporarily to disallow this...
1618
         */
1619
0
        v->count_bound_wsi++;
1620
0
        __lws_vhost_unbind_wsi(wsi);
1621
0
        lws_vhost_bind_wsi(v, wsi);
1622
        /*
1623
         * ... remove the fake wsi bind
1624
         */
1625
0
        v->count_bound_wsi--;
1626
0
        break;
1627
0
      }
1628
0
    } lws_end_foreach_vhost(v);
1629
1630
0
  } lws_end_foreach_dll_safe(d, d1);
1631
1632
  /*
1633
   * If any listen wsi left we couldn't pass to other vhosts, close them
1634
   */
1635
1636
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1637
0
                 lws_dll2_get_head(&vh->listen_wsi)) {
1638
0
    struct lws *wsi = lws_container_of(d, struct lws, listen_list);
1639
1640
0
    lws_dll2_remove(&wsi->listen_list);
1641
0
    lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
1642
1643
0
  } lws_end_foreach_dll_safe(d, d1);
1644
1645
0
#endif
1646
#if defined(LWS_WITH_TLS_JIT_TRUST)
1647
  lws_sul_cancel(&vh->sul_unref);
1648
#endif
1649
1650
0
  vh->count_bound_wsi--;
1651
0
  lws_vhost_unlock(vh); /* } vh -------------- */
1652
1653
0
  for (n = 0; n < context->count_threads; n++)
1654
0
    lws_pt_unlock((&context->pt[n]));
1655
1656
0
out:
1657
0
  lws_context_unlock(context); /* --------------------------- context { */
1658
0
}
1659
1660
#if defined(LWS_WITH_ABSTRACT)
1661
static int
1662
destroy_ais(struct lws_dll2 *d, void *user)
1663
{
1664
  lws_abs_t *ai = lws_container_of(d, lws_abs_t, abstract_instances);
1665
1666
  lws_abs_destroy_instance(&ai);
1667
1668
  return 0;
1669
}
1670
#endif
1671
1672
/*
1673
 * Either start close or destroy any wsi on the vhost that belong to this pt,
1674
 * if SMP mark the vh that we have done it for
1675
 *
1676
 * Must not have lock on vh
1677
 */
1678
1679
void
1680
__lws_vhost_destroy2(struct lws_vhost *vh)
1681
0
{
1682
0
  const struct lws_protocols *protocol = NULL;
1683
#if defined(__COVERITY__)
1684
  struct lws wsi = { 0 };
1685
#else
1686
0
  struct lws wsi;
1687
0
#endif
1688
0
  int n;
1689
1690
0
  vh->being_destroyed = 0;
1691
1692
  // lwsl_info("%s: %s\n", __func__, vh->name);
1693
1694
  /*
1695
   * remove ourselves from the defer binding list.  Vhosts that bound
1696
   * their listener normally (or never had one, like the internal
1697
   * system vhost) were never on it; that is the common case and not
1698
   * an error.
1699
   */
1700
0
  if (!lws_dll2_is_detached(&vh->no_listener_vlist)) {
1701
0
    lwsl_debug("deferred iface: removing vh %s\n", vh->name);
1702
0
    lws_dll2_remove(&vh->no_listener_vlist);
1703
0
  }
1704
1705
  /*
1706
   * let the protocols destroy the per-vhost protocol objects
1707
   */
1708
1709
0
#if !defined(__COVERITY__)
1710
0
  memset((void *)&wsi, 0, sizeof(wsi));
1711
0
#endif
1712
0
  wsi.a.context = vh->context;
1713
0
  wsi.a.vhost = vh; /* not a real bound wsi */
1714
1715
#if defined(LWS_WITH_DHT)
1716
  lws_dht_destroy_all_on_vhost(vh);
1717
#endif
1718
1719
0
  protocol = vh->protocols;
1720
0
  if (protocol && vh->created_vhost_protocols) {
1721
0
    n = 0;
1722
0
    while (n < vh->count_protocols) {
1723
0
      wsi.a.protocol = protocol;
1724
1725
0
      if (protocol->callback && (vh->protocol_init & (1u << n))) {
1726
0
        lwsl_vhost_debug(vh, "protocol %s destroy", protocol->name);
1727
0
        protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
1728
0
             NULL, NULL, 0);
1729
0
      }
1730
0
      protocol++;
1731
0
      n++;
1732
0
    }
1733
0
  }
1734
1735
0
#if defined(LWS_WITH_STUB)
1736
  /*
1737
   * Destroy stubs spawned on this vhost that are still alive, eg,
1738
   * because PROTOCOL_DESTROY was never delivered for their parent
1739
   * protocol to clean them up (in a plugins build, vhost protocols
1740
   * that were never instantiated with pvos get no protocol
1741
   * callbacks at all).  This is done after the explicit protocol
1742
   * destroys above, so those have already taken down their stubs
1743
   * and removed them from the tracking list.
1744
   */
1745
0
  lws_stub_destroy_all_on_vhost(vh);
1746
0
#endif
1747
1748
  /*
1749
   * remove vhost from context list of vhosts
1750
   */
1751
1752
0
  lws_dll2_remove(&vh->vhost_list);
1753
1754
  /* add ourselves to the pending destruction list */
1755
1756
0
  if (lws_dll2_is_detached(&vh->vhost_list))
1757
0
    lws_dll2_add_head(&vh->vhost_list,
1758
0
          &vh->context->vhost_pending_destruction_owner);
1759
1760
  //lwsl_debug("%s: do dfl '%s'\n", __func__, vh->name);
1761
1762
  /* remove ourselves from the pending destruction list */
1763
1764
0
  lws_dll2_remove(&vh->vhost_list);
1765
1766
  /*
1767
   * Free all the allocations associated with the vhost
1768
   */
1769
1770
0
  protocol = vh->protocols;
1771
0
  if (protocol) {
1772
0
    n = 0;
1773
0
    while (n < vh->count_protocols) {
1774
0
      if (vh->protocol_vh_privs &&
1775
0
          vh->protocol_vh_privs[n]) {
1776
0
        lws_free(vh->protocol_vh_privs[n]);
1777
0
        vh->protocol_vh_privs[n] = NULL;
1778
0
      }
1779
0
      protocol++;
1780
0
      n++;
1781
0
    }
1782
0
  }
1783
0
  if (vh->protocol_vh_privs)
1784
0
    lws_free(vh->protocol_vh_privs);
1785
0
#if defined(LWS_WITH_SERVER)
1786
0
  lws_tls_ctx_ref_destroy_all(vh);
1787
0
#endif
1788
0
  lws_ssl_SSL_CTX_destroy(vh);
1789
0
  lws_free(vh->same_vh_protocol_owner);
1790
1791
0
  if (
1792
#if defined(LWS_WITH_PROTOCOL_PLUGINS)
1793
    vh->context->plugin_list ||
1794
#endif
1795
0
      vh->allocated_vhost_protocols)
1796
0
    lws_free((void *)vh->protocols);
1797
0
#if defined(LWS_WITH_NETWORK)
1798
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
1799
0
  if (lws_rops_fidx(ar, LWS_ROPS_destroy_vhost))
1800
0
    lws_rops_func_fidx(ar, LWS_ROPS_destroy_vhost).
1801
0
              destroy_vhost(vh);
1802
0
  LWS_FOR_EVERY_AVAILABLE_ROLE_END;
1803
0
#endif
1804
1805
#ifdef LWS_WITH_ACCESS_LOG
1806
  if (vh->log_fd != (int)LWS_INVALID_FILE)
1807
    close(vh->log_fd);
1808
#endif
1809
1810
0
#if defined (LWS_WITH_TLS)
1811
0
  lws_free_set_NULL(vh->tls.cfg_alloc_cert_path);
1812
0
  lws_free_set_NULL(vh->tls.cfg_ssl_cipher_list);
1813
0
  lws_free_set_NULL(vh->tls.cfg_tls1_3_plus_cipher_list);
1814
0
  lws_free_set_NULL(vh->tls.cfg_tls_client_cipher_list);
1815
0
  lws_free_set_NULL(vh->tls.cfg_tls_ciphers_iana);
1816
0
  lws_free_set_NULL(vh->tls.cfg_ssl_ca_filepath);
1817
0
  lws_free_set_NULL(vh->tls.cfg_ecdh_curve);
1818
0
#if defined(LWS_WITH_CLIENT)
1819
0
  lws_free_set_NULL(vh->tls.cfg_client_ecdh_curve);
1820
0
#endif
1821
0
  vh->tls.cfg_key_path = NULL;
1822
0
#endif
1823
1824
#if LWS_MAX_SMP > 1
1825
  lws_mutex_refcount_destroy(&vh->mr);
1826
#endif
1827
1828
0
#if defined(LWS_WITH_UNIX_SOCK)
1829
0
  if (LWS_UNIX_SOCK_ENABLED(vh)) {
1830
0
    n = unlink(vh->iface);
1831
0
    if (n)
1832
0
      lwsl_vhost_info(vh, "Closing unix socket %s: errno %d\n",
1833
0
          vh->iface, errno);
1834
0
  }
1835
0
#endif
1836
  /*
1837
   * although async event callbacks may still come for wsi handles with
1838
   * pending close in the case of asycn event library like libuv,
1839
   * they do not refer to the vhost.  So it's safe to free.
1840
   */
1841
1842
0
  if (vh->finalize)
1843
0
    vh->finalize(vh, vh->finalize_arg);
1844
1845
#if defined(LWS_WITH_ABSTRACT)
1846
  /*
1847
   * abstract instances
1848
   */
1849
1850
  lws_dll2_foreach_safe(&vh->abstract_instances_owner, NULL, destroy_ais);
1851
#endif
1852
1853
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SYS_METRICS)
1854
  lws_metric_destroy(&vh->mt_traffic_rx, 0);
1855
  lws_metric_destroy(&vh->mt_traffic_tx, 0);
1856
#endif
1857
1858
0
  lws_dll2_remove(&vh->vh_being_destroyed_list);
1859
1860
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
1861
  lws_fi_destroy(&vh->fic);
1862
#endif
1863
#if defined(LWS_WITH_TLS_JIT_TRUST)
1864
  lws_sul_cancel(&vh->sul_unref);
1865
#endif
1866
1867
0
  __lws_lc_untag(vh->context, &vh->lc);
1868
1869
0
  memset(vh, 0, sizeof(*vh));
1870
0
  lws_free(vh);
1871
0
}
1872
1873
/*
1874
 * Starts the vhost destroy process
1875
 *
1876
 * Vhosts are not simple to deal with because they are an abstraction that
1877
 * crosses SMP thread boundaries, a wsi on any pt can bind to any vhost.  If we
1878
 * want another pt to do something to its wsis safely, we have to asynchronously
1879
 * ask it to do it.
1880
 *
1881
 * In addition, with event libs, closing any handles (which are bound to vhosts
1882
 * in their wsi) can happens asynchronously, so we can't just linearly do some
1883
 * cleanup flow and free it in one step.
1884
 *
1885
 * The vhost destroy is cut into two pieces:
1886
 *
1887
 * 1) dispose of the listen socket, either by passing it on to another vhost
1888
 *    that was already sharing it, or just closing it.
1889
 *
1890
 *    If any wsi bound to the vhost, mark the vhost as in the process of being
1891
 *    destroyed, triggering each pt to close all wsi bound to the vhost next
1892
 *    time around the event loop.  Call lws_cancel_service() so all the pts wake
1893
 *    to deal with this without long poll waits making delays.
1894
 *
1895
 * 2) When the number of wsis bound to the vhost reaches zero, do the final
1896
 *    vhost destroy flow, this can be triggered from any pt.
1897
 */
1898
1899
void
1900
lws_vhost_destroy(struct lws_vhost *vh)
1901
0
{
1902
0
  struct lws_context *context = vh->context;
1903
1904
0
  lws_context_lock(context, __func__); /* ------ context { */
1905
1906
  /* dispose of the listen socket one way or another */
1907
0
  lws_vhost_destroy1(vh);
1908
1909
0
  vh->count_bound_wsi++; /* protect from opportunistic destroy */
1910
  /* start async closure of all wsi on this pt thread attached to vh */
1911
0
  __lws_vhost_destroy_pt_wsi_dieback_start(vh);
1912
0
  vh->count_bound_wsi--;
1913
1914
0
  lwsl_vhost_info(vh, "count_bound_wsi %d", vh->count_bound_wsi);
1915
1916
  /* if there are none, finalize now since no further chance */
1917
0
  if (!vh->count_bound_wsi) {
1918
0
    __lws_vhost_destroy2(vh);
1919
1920
0
    goto out;
1921
0
  }
1922
1923
  /*
1924
   * We have some wsi bound to this vhost, we have to wait for these to
1925
   * complete close and unbind before progressing the vhost removal.
1926
   *
1927
   * When the last bound wsi on this vh is destroyed we will auto-call
1928
   * __lws_vhost_destroy2() to finalize vh destruction
1929
   */
1930
1931
#if LWS_MAX_SMP > 1
1932
  /* alert other pts they also need to do dieback flow for their wsi */
1933
  lws_cancel_service(context);
1934
#endif
1935
1936
0
out:
1937
0
  lws_context_unlock(context); /* } context ------------------- */
1938
0
}
1939
1940
1941
void *
1942
lws_vhost_user(struct lws_vhost *vhost)
1943
0
{
1944
0
  return vhost->user;
1945
0
}
1946
1947
int
1948
lws_get_vhost_listen_port(struct lws_vhost *vhost)
1949
0
{
1950
0
  return vhost->listen_port;
1951
0
}
1952
1953
#if defined(LWS_WITH_SERVER)
1954
void
1955
lws_context_deprecate(struct lws_context *cx, lws_reload_func cb)
1956
0
{
1957
0
  struct lws_vhost *vh = lws_vhost_first(cx);
1958
1959
  /*
1960
   * "deprecation" means disable the cx from accepting any new
1961
   * connections and free up listen sockets to be used by a replacement
1962
   * cx.
1963
   *
1964
   * Otherwise the deprecated cx remains operational, until its
1965
   * number of connected sockets falls to zero, when it is deleted.
1966
   *
1967
   * So, for each vhost, close his listen sockets
1968
   */
1969
1970
0
  while (vh) {
1971
1972
0
    lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1973
0
             lws_dll2_get_head(&vh->listen_wsi)) {
1974
0
      struct lws *wsi = lws_container_of(d, struct lws,
1975
0
                 listen_list);
1976
1977
0
      wsi->socket_is_permanently_unusable = 1;
1978
0
      lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
1979
0
             __func__);
1980
0
      cx->deprecation_pending_listen_close_count++;
1981
1982
0
    } lws_end_foreach_dll_safe(d, d1);
1983
1984
0
    vh = lws_vhost_next(vh);
1985
0
  }
1986
1987
0
  cx->deprecated = 1;
1988
0
  cx->deprecation_cb = cb;
1989
0
}
1990
#endif
1991
1992
#if defined(LWS_WITH_NETWORK)
1993
1994
struct lws_vhost *
1995
lws_get_vhost_by_name(struct lws_context *context, const char *name)
1996
0
{
1997
0
  lws_start_foreach_vhost(v, context) {
1998
0
    if (!v->being_destroyed && !strcmp(v->name, name))
1999
0
      return v;
2000
2001
0
  } lws_end_foreach_vhost(v);
2002
2003
0
  return NULL;
2004
0
}
2005
2006
2007
#if defined(LWS_WITH_CLIENT)
2008
/*
2009
 * This is the logic checking to see if the new connection wsi should have a
2010
 * pipelining or muxing relationship with an existing "active connection" to
2011
 * the same endpoint under the same conditions.
2012
 *
2013
 * This was originally in the client code but since the list is held on the
2014
 * vhost (to ensure the same client tls ctx is involved) it's cleaner in vhost.c
2015
 *
2016
 * ACTIVE_CONNS_QUEUED: We're queued on an active connection, set *nwsi to that
2017
 * ACTIVE_CONNS_MUXED: We are joining an active mux conn *nwsi as a child
2018
 * ACTIVE_CONNS_SOLO: There's no existing conn to join either way
2019
 */
2020
2021
int
2022
lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin)
2023
0
{
2024
0
#if defined(LWS_WITH_TLS)
2025
0
#if defined(LWS_ROLE_H1)
2026
0
  const char *my_alpn = lws_wsi_client_stash_item(wsi, CIS_ALPN,
2027
0
              _WSI_TOKEN_CLIENT_ALPN);
2028
0
#endif
2029
0
#endif
2030
0
#if defined(LWS_WITH_TLS)
2031
0
#if defined(LWS_ROLE_H1)
2032
0
  char newconn_cannot_use_h1 = 0;
2033
2034
0
  if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) &&
2035
0
      my_alpn && !(char *)strstr(my_alpn, "http/1.1"))
2036
    /*
2037
     * new guy wants to use tls, he specifies the alpn and he does
2038
     * not list h1 as a choice ==> he can't bind to existing h1
2039
     */
2040
0
    newconn_cannot_use_h1 = 1;
2041
0
#endif
2042
0
#endif
2043
2044
0
  if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
2045
0
    struct lws *w = lws_dll2_owner_container(&wsi->dll2_cli_txn_queue, struct lws,
2046
0
        dll2_cli_txn_queue_owner);
2047
0
    *nwsi = w;
2048
2049
0
    return ACTIVE_CONNS_QUEUED;
2050
0
  }
2051
2052
0
#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
2053
0
  if (wsi->mux.parent_wsi) {
2054
    /*
2055
     * We already decided...
2056
     */
2057
2058
0
    *nwsi = wsi->mux.parent_wsi;
2059
2060
0
    return ACTIVE_CONNS_MUXED;
2061
0
  }
2062
0
#endif
2063
2064
0
  lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
2065
0
  lws_vhost_lock(wsi->a.vhost); /* ----------------------------------- { */
2066
2067
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
2068
0
           lws_dll2_get_head(&wsi->a.vhost->dll_cli_active_conns_owner)) {
2069
0
    struct lws *w = lws_container_of(d, struct lws,
2070
0
             dll_cli_active_conns);
2071
2072
0
    lwsl_wsi_debug(wsi, "check %s %s %s %d %d",
2073
0
            lws_wsi_tag(w), adsin,
2074
0
            w->cli_hostname_copy ? w->cli_hostname_copy :
2075
0
                  "null",
2076
0
            wsi->c_port, w->c_port);
2077
2078
0
    if (w != wsi &&
2079
        /*
2080
         * "same internet protocol"... this is a bit tricky,
2081
         * since h2 start out as h1, and may stay at h1.
2082
         *
2083
         * But an idle h1 connection cannot be used by a connection
2084
         * request that doesn't have http/1.1 in its alpn list...
2085
         */
2086
0
        (w->role_ops == wsi->role_ops ||
2087
0
         (lwsi_role_http(w) && lwsi_role_http(wsi))) &&
2088
         /* ... same role, or at least both some kind of http */
2089
0
        w->cli_hostname_copy && !strcmp(adsin, w->cli_hostname_copy) &&
2090
        /* same endpoint hostname */
2091
0
#if defined(LWS_WITH_TLS)
2092
0
#if defined(LWS_ROLE_H1)
2093
0
       !(newconn_cannot_use_h1 && w->role_ops == &role_ops_h1) &&
2094
0
#endif
2095
       /* if we can't use h1, old guy must not be h1 */
2096
0
        (wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
2097
0
         (w->tls.use_ssl & LCCSCF_USE_SSL) &&
2098
         /* must both agree on tls use or not */
2099
0
#endif
2100
0
        wsi->c_port == w->c_port) {
2101
      /* same endpoint port */
2102
2103
      /*
2104
       * There's already an active connection.
2105
       *
2106
       * The server may have told the existing active
2107
       * connection that it doesn't support pipelining...
2108
       */
2109
0
      if (w->keepalive_rejected) {
2110
0
        lwsl_wsi_notice(w, "defeating pipelining");
2111
0
        goto solo;
2112
0
      }
2113
2114
0
#if defined(LWS_WITH_HTTP2)
2115
      /*
2116
       * h2: if in usable state already: just use it without
2117
       *     going through the queue
2118
       */
2119
0
      if (lwsi_role_h2(w) && w->client_h2_alpn && w->client_mux_migrated &&
2120
0
          (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
2121
0
           lwsi_state(w) == LRS_ESTABLISHED ||
2122
0
           lwsi_state(w) == LRS_IDLING)) {
2123
2124
0
        lwsl_wsi_info(w, "just join h2 directly 0x%x",
2125
0
               lwsi_state(w));
2126
2127
0
        if (lwsi_state(w) == LRS_IDLING) {
2128
0
          _lws_generic_transaction_completed_active_conn(&w, 0);
2129
2130
          /*
2131
           * The connection was kept warm in
2132
           * LRS_IDLING, which does not carry
2133
           * LWSIFS_POCB, so its POLLOUT is never
2134
           * serviced (lwsi_state_can_handle_POLLOUT()
2135
           * is false).  If we adopt the new stream
2136
           * while the network wsi is still IDLING, the
2137
           * child-walking POLLOUT loop never runs, the
2138
           * new stream's HEADERS are never sent
2139
           * (lws_h2_client_handshake() is never
2140
           * reached) and its response would not be read
2141
           * either.  Put it back into the same
2142
           * LRS_ESTABLISHED state it uses while actively
2143
           * muxing, and drop the keep-warm idle timeout
2144
           * since it is no longer idle.
2145
           */
2146
0
          lwsi_set_state(w, LRS_ESTABLISHED);
2147
0
          lws_set_timeout(w, NO_PENDING_TIMEOUT, 0);
2148
0
        }
2149
2150
0
        wsi->client_h2_alpn = 1;
2151
0
        lws_wsi_h2_adopt(w, wsi);
2152
0
        lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
2153
0
        lws_context_unlock(wsi->a.context); /* -------------- cx { */
2154
2155
0
        *nwsi = w;
2156
2157
0
        return ACTIVE_CONNS_MUXED;
2158
0
      }
2159
0
#endif
2160
2161
#if defined(LWS_ROLE_H3)
2162
      /*
2163
       * h3: if in usable state already: just use it without
2164
       *     going through the queue
2165
       */
2166
      if ((w->role_ops && !strcmp(w->role_ops->name, "quic")) && w->client_h2_alpn && w->client_mux_migrated &&
2167
          (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
2168
           lwsi_state(w) == LRS_ESTABLISHED ||
2169
           lwsi_state(w) == LRS_IDLING)) {
2170
2171
        lwsl_wsi_info(w, "just join h3 directly 0x%x",
2172
               lwsi_state(w));
2173
2174
2175
        if (lwsi_state(w) == LRS_IDLING) {
2176
          _lws_generic_transaction_completed_active_conn(&w, 0);
2177
2178
          /* See the h2 branch above: a revived idle
2179
           * mux connection must leave LRS_IDLING so its
2180
           * POLLOUT is serviced and the new stream's
2181
           * headers get sent. */
2182
          lwsi_set_state(w, LRS_ESTABLISHED);
2183
          lws_set_timeout(w, NO_PENDING_TIMEOUT, 0);
2184
        }
2185
2186
        wsi->client_h2_alpn = 1;
2187
        if (lws_wsi_h3_adopt(w, wsi)) {
2188
          lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
2189
          lws_context_unlock(wsi->a.context); /* -------------- cx { */
2190
2191
          *nwsi = w;
2192
2193
          return ACTIVE_CONNS_MUXED;
2194
        }
2195
      }
2196
#endif
2197
2198
#if defined(LWS_ROLE_MQTT)
2199
      /*
2200
       * MQTT: if in usable state already: just use it without
2201
       *   going through the queue
2202
       */
2203
2204
      if (lwsi_role_mqtt(wsi) && w->client_mux_migrated &&
2205
          lwsi_state(w) == LRS_ESTABLISHED) {
2206
2207
        if (lws_wsi_mqtt_adopt(w, wsi)) {
2208
          lwsl_wsi_notice(w, "join mqtt directly");
2209
          lws_dll2_remove(&wsi->dll2_cli_txn_queue);
2210
          wsi->client_mux_substream = 1;
2211
2212
          lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
2213
          lws_context_unlock(wsi->a.context); /* -------------- cx { */
2214
2215
          return ACTIVE_CONNS_MUXED;
2216
        }
2217
      }
2218
#endif
2219
2220
      /*
2221
       * If the connection is viable but not yet in a usable
2222
       * state, let's attach ourselves to it and wait for it
2223
       * to get there or fail.
2224
       */
2225
2226
0
      lwsl_wsi_info(wsi, "apply txn queue %s, state 0x%lx",
2227
0
               lws_wsi_tag(w),
2228
0
               (unsigned long)w->wsistate);
2229
      /*
2230
       * ...let's add ourselves to his transaction queue...
2231
       * we are adding ourselves at the TAIL
2232
       */
2233
0
      lws_dll2_add_tail(&wsi->dll2_cli_txn_queue,
2234
0
            &w->dll2_cli_txn_queue_owner);
2235
2236
0
      if (lwsi_state(w) == LRS_IDLING)
2237
0
        _lws_generic_transaction_completed_active_conn(&w, 0);
2238
2239
      /*
2240
       * For eg, h1 next we'd pipeline our headers out on him,
2241
       * and wait for our turn at client transaction_complete
2242
       * to take over parsing the rx.
2243
       */
2244
0
      lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
2245
0
      lws_context_unlock(wsi->a.context); /* -------------- cx { */
2246
2247
0
      *nwsi = w;
2248
2249
0
      return ACTIVE_CONNS_QUEUED;
2250
0
    }
2251
2252
0
  } lws_end_foreach_dll_safe(d, d1);
2253
2254
0
solo:
2255
0
  lws_vhost_unlock(wsi->a.vhost); /* } ---------------------------------- */
2256
0
  lws_context_unlock(wsi->a.context); /* -------------- cx { */
2257
2258
  /* there is nobody already connected in the same way */
2259
2260
0
  return ACTIVE_CONNS_SOLO;
2261
0
}
2262
#endif
2263
#endif
2264
2265
const char *
2266
lws_vh_tag(struct lws_vhost *vh)
2267
0
{
2268
0
  return lws_lc_tag(&vh->lc);
2269
0
}
2270
2271
struct lws_log_cx *
2272
lwsl_vhost_get_cx(struct lws_vhost *vh)
2273
0
{
2274
0
  if (!vh)
2275
0
    return NULL;
2276
2277
0
  return vh->lc.log_cx;
2278
0
}
2279
2280
void
2281
lws_log_prepend_vhost(struct lws_log_cx *cx, void *obj, char **p, char *e)
2282
0
{
2283
0
  struct lws_vhost *vh = (struct lws_vhost *)obj;
2284
2285
0
  *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
2286
0
              lws_vh_tag(vh));
2287
0
}