Coverage Report

Created: 2026-07-16 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/plat/unix/unix-fds.c
Line
Count
Source
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
struct lws *
31
wsi_from_fd(const struct lws_context *context, int fd)
32
0
{
33
0
  struct lws **p, **done;
34
35
0
  if (!context->max_fds_unrelated_to_ulimit)
36
0
    return context->lws_lookup[fd - lws_plat_socket_offset()];
37
38
  /* slow fds handling */
39
40
0
  p = context->lws_lookup;
41
0
  done = &p[context->max_fds];
42
43
0
  while (p != done) {
44
0
    if (*p) {
45
0
      if ((*p)->desc.sockfd == fd)
46
0
        return *p;
47
0
#if defined(LWS_WITH_CLIENT)
48
0
      for (int j = 0; j < (*p)->parallel_count; j++) {
49
0
        if ((*p)->parallel_conns[j].is_valid && (*p)->parallel_conns[j].desc.sockfd == fd)
50
0
          return *p;
51
0
      }
52
0
#endif
53
0
    }
54
0
    p++;
55
0
  }
56
57
0
  return NULL;
58
0
}
59
60
#if defined(_DEBUG)
61
int
62
sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi)
63
0
{
64
0
  struct lws **p, **done;
65
0
  int occurrences = 0;
66
0
  int expected = 0;
67
68
0
#if defined(LWS_WITH_CLIENT)
69
0
  if (lws_socket_is_valid(wsi->desc.sockfd))
70
0
    expected++;
71
0
  for (int i = 0; i < wsi->parallel_count; i++)
72
0
    if (wsi->parallel_conns[i].is_valid)
73
0
      expected++;
74
0
#endif
75
76
0
  if (!context->max_fds_unrelated_to_ulimit)
77
    /* can't tell */
78
0
    return 0;
79
80
  /* slow fds handling */
81
82
0
  p = context->lws_lookup;
83
0
  done = &p[context->max_fds];
84
85
  /* count occurrences of wsi in lookup table */
86
87
0
  while (p != done) {
88
0
    if (*p == wsi)
89
0
      occurrences++;
90
0
    p++;
91
0
  }
92
93
0
  if (occurrences <= expected)
94
0
    return 0;
95
96
0
  assert(0); /* this wsi is still mentioned inside lws too many times */
97
98
0
  return 1;
99
0
}
100
101
int
102
sanity_assert_no_sockfd_traces(const struct lws_context *context,
103
             lws_sockfd_type sfd)
104
0
{
105
#if LWS_MAX_SMP > 1
106
  /*
107
   * We can't really do this test... another thread can accept and
108
   * reuse the closed fd
109
   */
110
  return 0;
111
#else
112
0
  struct lws **p, **done;
113
114
0
  if (sfd == LWS_SOCK_INVALID || !context->lws_lookup)
115
0
    return 0;
116
117
0
  if (!context->max_fds_unrelated_to_ulimit &&
118
0
      context->lws_lookup[sfd - lws_plat_socket_offset()]) {
119
0
    assert(0); /* the fd is still in use */
120
0
    return 1;
121
0
  }
122
123
  /* slow fds handling */
124
125
0
  p = context->lws_lookup;
126
0
  done = &p[context->max_fds];
127
128
  /* confirm the sfd not already in use */
129
130
0
  while (p != done) {
131
0
    if (*p && (*p)->desc.sockfd == sfd) {
132
0
#if defined(LWS_WITH_CLIENT)
133
0
      if ((*p)->parallel_count > 0) {
134
0
        p++;
135
0
        continue;
136
0
      }
137
0
#endif
138
0
      break;
139
0
    }
140
0
    p++;
141
0
  }
142
143
0
  if (p == done)
144
0
    return 0;
145
146
0
  assert(0); /* this fd is still in the tables */
147
148
0
  return 1;
149
0
#endif
150
0
}
151
#endif
152
153
154
int
155
insert_wsi(const struct lws_context *context, struct lws *wsi)
156
0
{
157
0
  struct lws **p, **done;
158
159
0
  if (sanity_assert_no_wsi_traces(context, wsi))
160
0
    return 0;
161
162
0
  if (!context->max_fds_unrelated_to_ulimit) {
163
0
    assert(context->lws_lookup[wsi->desc.sockfd -
164
0
                               lws_plat_socket_offset()] == 0);
165
166
0
    context->lws_lookup[wsi->desc.sockfd - \
167
0
          lws_plat_socket_offset()] = wsi;
168
169
0
    return 0;
170
0
  }
171
172
  /* slow fds handling */
173
174
0
  p = context->lws_lookup;
175
0
  done = &p[context->max_fds];
176
177
  /* confirm fd isn't already in use by a wsi */
178
179
0
  if (sanity_assert_no_sockfd_traces(context, wsi->desc.sockfd))
180
0
    return 0;
181
182
0
  p = context->lws_lookup;
183
184
  /* find an empty slot */
185
186
0
  while (p != done && *p)
187
0
    p++;
188
189
0
  if (p == done) {
190
0
    lwsl_err("%s: reached max fds\n", __func__);
191
0
    return 1;
192
0
  }
193
194
0
  *p = wsi;
195
196
0
  return 0;
197
0
}
198
199
200
201
void
202
delete_from_fd(const struct lws_context *context, int fd)
203
0
{
204
205
0
  struct lws **p, **done;
206
207
0
  if (!context->max_fds_unrelated_to_ulimit) {
208
0
    if (context->lws_lookup) {
209
0
      assert((int)context->max_fds > fd - lws_plat_socket_offset());
210
0
      context->lws_lookup[fd - lws_plat_socket_offset()] = NULL;
211
0
    }
212
213
0
    return;
214
0
  }
215
216
  /* slow fds handling */
217
218
0
  p = context->lws_lookup;
219
0
  assert(p);
220
221
0
  done = &p[context->max_fds];
222
223
  /* find the match */
224
225
0
  while (p != done && (!*p || (*p)->desc.sockfd != fd))
226
0
    p++;
227
228
0
  if (p != done)
229
0
    *p = NULL;
230
231
0
#if defined(_DEBUG)
232
0
  p = context->lws_lookup;
233
0
  while (p != done) {
234
0
    if (*p && (*p)->desc.sockfd == fd) {
235
0
#if defined(LWS_WITH_CLIENT)
236
0
      if ((*p)->parallel_count > 0) {
237
0
        p++;
238
0
        continue;
239
0
      }
240
0
#endif
241
0
      break;
242
0
    }
243
0
    p++;
244
0
  }
245
246
0
  if (p != done) {
247
0
    lwsl_err("%s: fd %d in lws_lookup again at %d\n", __func__,
248
0
        fd, (int)(p - context->lws_lookup));
249
0
    assert(0);
250
0
  }
251
0
#endif
252
0
}
253
254
void
255
delete_from_fdwsi(const struct lws_context *context, struct lws *wsi)
256
0
{
257
258
0
  struct lws **p, **done;
259
260
0
  if (!context->max_fds_unrelated_to_ulimit)
261
0
    return;
262
263
264
  /* slow fds handling */
265
266
0
  p = context->lws_lookup;
267
0
  done = &p[context->max_fds];
268
269
  /* find the match */
270
271
0
  while (p != done && (!*p || (*p) != wsi))
272
0
    p++;
273
274
0
  if (p != done)
275
0
    *p = NULL;
276
0
}
277
278
void
279
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
280
0
{
281
0
  struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
282
283
0
  if (context->event_loop_ops->io || context->event_loop_ops->io_parallel)
284
0
    _lws_event_loop_ops_io(wsi, LWS_EV_START | LWS_EV_READ);
285
286
0
  pt->fds[pt->fds_count++].revents = 0;
287
0
}
288
289
void
290
lws_plat_delete_socket_from_fds(struct lws_context *context,
291
            struct lws *wsi, int m)
292
0
{
293
0
  struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
294
295
0
  if (context->event_loop_ops->io || context->event_loop_ops->io_parallel)
296
0
    _lws_event_loop_ops_io(wsi,
297
0
        LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
298
299
0
  pt->fds_count--;
300
0
}
301
302
int
303
lws_plat_change_pollfd(struct lws_context *context,
304
          struct lws *wsi, struct lws_pollfd *pfd)
305
0
{
306
0
  return 0;
307
0
}