Coverage Report

Created: 2025-08-03 06:52

/src/libwebsockets/lib/plat/unix/unix-init.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 - 2019 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
#if !defined(_GNU_SOURCE)
26
#define _GNU_SOURCE
27
#endif
28
#include "private-lib-core.h"
29
30
#include <pwd.h>
31
#include <grp.h>
32
33
#ifdef LWS_WITH_PLUGINS
34
#include <dlfcn.h>
35
#endif
36
#include <dirent.h>
37
38
#if defined(LWS_WITH_NETWORK)
39
static void
40
lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
41
0
{
42
0
  struct lws_context_per_thread *pt =
43
0
    lws_container_of(sul, struct lws_context_per_thread, sul_plat);
44
0
  struct lws_context *context = pt->context;
45
0
  int n = 0, m = 0;
46
47
#if !defined(LWS_NO_DAEMONIZE)
48
  /* if our parent went down, don't linger around */
49
  if (pt->context->started_with_parent &&
50
      kill(pt->context->started_with_parent, 0) < 0)
51
    kill(getpid(), SIGTERM);
52
#endif
53
54
0
  for (n = 0; n < context->count_threads; n++)
55
0
    m = m | (int)pt->fds_count;
56
57
0
  if (context->deprecated && !m) {
58
0
    lwsl_notice("%s: ending deprecated context\n", __func__);
59
0
    kill(getpid(), SIGINT);
60
0
    return;
61
0
  }
62
63
0
#if defined(LWS_WITH_SERVER)
64
0
  lws_context_lock(context, "periodic checks");
65
0
  lws_start_foreach_llp(struct lws_vhost **, pv,
66
0
            context->no_listener_vhost_list) {
67
0
    struct lws_vhost *v = *pv;
68
0
    lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
69
0
    if (_lws_vhost_init_server(NULL, *pv) == 0) {
70
      /* became happy */
71
0
      lwsl_notice("vh %s: became connected\n", v->name);
72
0
      *pv = v->no_listener_vhost_list;
73
0
      v->no_listener_vhost_list = NULL;
74
0
      break;
75
0
    }
76
0
  } lws_end_foreach_llp(pv, no_listener_vhost_list);
77
0
  lws_context_unlock(context);
78
0
#endif
79
80
0
  __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
81
0
          &pt->sul_plat, 30 * LWS_US_PER_SEC);
82
0
}
83
#endif
84
85
#if defined(LWS_WITH_PLUGINS)
86
static int
87
protocol_plugin_cb(struct lws_plugin *pin, void *each_user)
88
{
89
  struct lws_context *context = (struct lws_context *)each_user;
90
  const lws_plugin_protocol_t *plpr =
91
      (const lws_plugin_protocol_t *)pin->hdr;
92
93
  context->plugin_protocol_count = (short)(context->plugin_protocol_count +
94
             plpr->count_protocols);
95
  context->plugin_extension_count = (short)(context->plugin_extension_count +
96
              plpr->count_extensions);
97
98
  return 0;
99
}
100
#endif
101
102
int
103
lws_plat_init(struct lws_context *context,
104
        const struct lws_context_creation_info *info)
105
0
{
106
0
  int fd;
107
0
#if defined(LWS_WITH_NETWORK)
108
  /*
109
   * context has the process-global fd lookup array.  This can be
110
   * done two different ways now; one or the other is done depending on if
111
   * info->fd_limit_per_thread was snonzero
112
   *
113
   *  - default: allocate a worst-case lookup array sized for ulimit -n
114
   *             and use the fd directly as an index into it
115
   *
116
   *  - slow:    allocate context->max_fds entries only (which can be
117
   *             forced at context creation time to be
118
   *             info->fd_limit_per_thread * the number of threads)
119
   *             and search the array to lookup fds
120
   *
121
   * the default way is optimized for server, if you only use one or two
122
   * client wsi the slow way may save a lot of memory.
123
   *
124
   * Both ways allocate an array of struct lws *... one allocates it for
125
   * all possible fd indexes the process could produce and uses it as a
126
   * map, the other allocates for an amount of wsi the lws context is
127
   * expected to use and searches through it to manipulate it.
128
   */
129
130
0
  context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
131
0
           context->max_fds, "lws_lookup");
132
133
0
  if (!context->lws_lookup) {
134
0
    lwsl_cx_err(context, "OOM on alloc lws_lookup array for %d conn",
135
0
       context->max_fds);
136
0
    return 1;
137
0
  }
138
139
#if defined(LWS_WITH_MBEDTLS)
140
  {
141
    int n;
142
143
    /* initialize platform random through mbedtls */
144
    mbedtls_entropy_init(&context->mec);
145
    mbedtls_ctr_drbg_init(&context->mcdc);
146
147
    n = mbedtls_ctr_drbg_seed(&context->mcdc, mbedtls_entropy_func,
148
            &context->mec, NULL, 0);
149
    if (n)
150
      lwsl_err("%s: mbedtls_ctr_drbg_seed() returned 0x%x\n",
151
         __func__, n);
152
#if 0
153
    else {
154
      uint8_t rtest[16];
155
      lwsl_notice("%s: started drbg\n", __func__);
156
      if (mbedtls_ctr_drbg_random(&context->mcdc, rtest,
157
              sizeof(rtest)))
158
        lwsl_err("%s: get random failed\n", __func__);
159
      else
160
        lwsl_hexdump_notice(rtest, sizeof(rtest));
161
    }
162
#endif
163
  }
164
#endif
165
166
0
  lwsl_cx_info(context, " mem: platform fd map: %5lu B",
167
0
        (unsigned long)(sizeof(struct lws *) * context->max_fds));
168
0
#endif
169
0
#if defined(LWS_WITH_FILE_OPS)
170
0
  fd = lws_open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
171
#else
172
  fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
173
#endif
174
0
  context->fd_random = fd;
175
0
  if (context->fd_random < 0) {
176
0
    lwsl_err("Unable to open random device %s %d, errno %d\n",
177
0
       SYSTEM_RANDOM_FILEPATH, context->fd_random, errno);
178
0
    return 1;
179
0
  }
180
181
0
#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && !defined(__COVERITY__) && \
182
0
    defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
183
0
  {
184
0
    char *klf_env = getenv("SSLKEYLOGFILE");
185
0
    size_t n = 0;
186
187
    /* ... coverity taint with lws_strncpy()... */
188
189
0
    while (klf_env && n < sizeof(context->keylog_file) - 1 &&
190
0
           klf_env[n]) {
191
0
      context->keylog_file[n] = klf_env[n];
192
0
      n++;
193
0
    }
194
0
    context->keylog_file[n] = '\0';
195
0
  }
196
0
#endif
197
198
#if defined(LWS_WITH_PLUGINS) && !defined(LWS_WITH_PLUGINS_BUILTIN)
199
  {
200
    const char *pp[8] = { };
201
    int n = 0;
202
203
    if (info->plugin_dirs) {
204
      int m = 0;
205
206
      while (info->plugin_dirs[m] && n < (int)LWS_ARRAY_SIZE(pp) - 1)
207
        pp[n++] = info->plugin_dirs[m++];
208
    }
209
210
    if (n < (int)LWS_ARRAY_SIZE(pp) - 1)
211
      pp[n++] = LWS_INSTALL_DATADIR"/libwebsockets-test-server/plugins";
212
213
    pp[n] = NULL;
214
215
    /* We'll also look at LD_LIBRARY_PATH first in here */
216
217
    lws_plugins_init(&context->plugin_list, pp,
218
         "lws_protocol_plugin", NULL,
219
         protocol_plugin_cb, context);
220
  }
221
222
#endif
223
#if defined(LWS_BUILTIN_PLUGIN_NAMES) && defined(LWS_WITH_PLUGINS)
224
  lws_plugins_handle_builtin(&context->plugin_list,
225
           protocol_plugin_cb, context);
226
#endif
227
228
229
0
#if defined(LWS_WITH_NETWORK)
230
  /* we only need to do this on pt[0] */
231
232
0
  context->pt[0].sul_plat.cb = lws_sul_plat_unix;
233
0
  __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
234
0
          &context->pt[0].sul_plat, 30 * LWS_US_PER_SEC);
235
0
#endif
236
237
0
  return 0;
238
0
}
239
240
int
241
lws_plat_context_early_init(void)
242
0
{
243
0
#if !defined(LWS_AVOID_SIGPIPE_IGN)
244
0
  signal(SIGPIPE, SIG_IGN);
245
0
#endif
246
247
0
  return 0;
248
0
}
249
250
void
251
lws_plat_context_early_destroy(struct lws_context *context)
252
0
{
253
0
}
254
255
void
256
lws_plat_context_late_destroy(struct lws_context *context)
257
0
{
258
#if defined(LWS_WITH_PLUGINS)
259
  if (context->plugin_list)
260
    lws_plugins_destroy(&context->plugin_list, NULL, NULL);
261
#endif
262
0
#if defined(LWS_WITH_NETWORK)
263
0
  if (context->lws_lookup)
264
0
    lws_free_set_NULL(context->lws_lookup);
265
0
#endif
266
0
  if (!context->fd_random)
267
0
    lwsl_err("ZERO RANDOM FD\n");
268
0
  if (context->fd_random != LWS_INVALID_FILE)
269
0
    close(context->fd_random);
270
271
#if defined(LWS_WITH_MBEDTLS)
272
  mbedtls_entropy_free(&context->mec);
273
  mbedtls_ctr_drbg_free(&context->mcdc);
274
#endif
275
0
}