Coverage Report

Created: 2026-02-26 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/core-net/adopt.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
#include "private-lib-core.h"
26
#include "private-lib-async-dns.h"
27
28
static int
29
lws_get_idlest_tsi(struct lws_context *context)
30
0
{
31
0
  unsigned int lowest = ~0u;
32
0
  int n = 0, hit = -1;
33
34
0
  for (; n < context->count_threads; n++) {
35
0
    lwsl_cx_debug(context, "%d %d\n", context->pt[n].fds_count,
36
0
        context->fd_limit_per_thread - 1);
37
0
    if ((unsigned int)context->pt[n].fds_count !=
38
0
        context->fd_limit_per_thread - 1 &&
39
0
        (unsigned int)context->pt[n].fds_count < lowest) {
40
0
      lowest = context->pt[n].fds_count;
41
0
      hit = n;
42
0
    }
43
0
  }
44
45
0
  return hit;
46
0
}
47
48
struct lws *
49
lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, int group,
50
        const char *desc)
51
0
{
52
0
  struct lws *new_wsi;
53
0
  int n = fixed_tsi;
54
55
0
  if (n < 0)
56
0
    n = lws_get_idlest_tsi(vhost->context);
57
58
0
  if (n < 0) {
59
0
    lwsl_vhost_err(vhost, "no space for new conn");
60
0
    return NULL;
61
0
  }
62
63
0
  lws_context_lock(vhost->context, __func__);
64
0
  new_wsi = __lws_wsi_create_with_role(vhost->context, n, NULL,
65
0
               vhost->lc.log_cx);
66
0
  lws_context_unlock(vhost->context);
67
0
  if (new_wsi == NULL) {
68
0
    lwsl_vhost_err(vhost, "OOM");
69
0
    return NULL;
70
0
  }
71
72
0
  lws_wsi_fault_timedclose(new_wsi);
73
74
0
  __lws_lc_tag(vhost->context, &vhost->context->lcg[group],
75
0
      &new_wsi->lc, "%s|%s", vhost->name, desc);
76
77
0
  new_wsi->wsistate |= LWSIFR_SERVER;
78
0
  new_wsi->tsi = (char)n;
79
0
  lwsl_wsi_debug(new_wsi, "joining vh %s, tsi %d",
80
0
      vhost->name, new_wsi->tsi);
81
82
0
  lws_vhost_bind_wsi(vhost, new_wsi);
83
0
  new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
84
0
  new_wsi->retry_policy = vhost->retry_policy;
85
86
  /* initialize the instance struct */
87
88
0
  lwsi_set_state(new_wsi, LRS_UNCONNECTED);
89
0
  new_wsi->hdr_parsing_completed = 0;
90
91
0
#ifdef LWS_WITH_TLS
92
0
  new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost);
93
0
#endif
94
95
  /*
96
   * these can only be set once the protocol is known
97
   * we set an un-established connection's protocol pointer
98
   * to the start of the supported list, so it can look
99
   * for matching ones during the handshake
100
   */
101
0
  new_wsi->a.protocol = vhost->protocols;
102
0
  new_wsi->user_space = NULL;
103
104
  /*
105
   * outermost create notification for wsi
106
   * no user_space because no protocol selection
107
   */
108
0
  vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL,
109
0
             NULL, 0);
110
111
0
  return new_wsi;
112
0
}
113
114
115
/* if not a socket, it's a raw, non-ssl file descriptor
116
 * req cx lock, acq pt lock, acq vh lock
117
 */
118
119
static struct lws *
120
__lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
121
          const char *vh_prot_name, struct lws *parent,
122
          void *opaque, const char *fi_wsi_name)
123
0
{
124
0
  struct lws_context *context;
125
0
  struct lws_context_per_thread *pt;
126
0
  struct lws *new_wsi;
127
0
  int n;
128
129
  /*
130
   * Notice that in SMP case, the wsi may be being created on an
131
   * entirely different pt / tsi for load balancing.  In that case as
132
   * we initialize it, it may become "live" concurrently unexpectedly...
133
   */
134
135
0
  if (!vh)
136
0
    return NULL;
137
138
0
  context = vh->context;
139
140
0
  lws_context_assert_lock_held(vh->context);
141
142
0
  n = -1;
143
0
  if (parent)
144
0
    n = parent->tsi;
145
0
  new_wsi = lws_create_new_server_wsi(vh, n, LWSLCG_WSI_SERVER, fi_wsi_name);
146
0
  if (!new_wsi)
147
0
    return NULL;
148
149
  /* bring in specific fault injection rules early */
150
0
  lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name);
151
152
0
  if (lws_fi(&new_wsi->fic, "createfail")) {
153
0
    lws_fi_destroy(&new_wsi->fic);
154
155
0
    return NULL;
156
0
  }
157
158
0
  new_wsi->a.opaque_user_data = opaque;
159
160
0
  pt = &context->pt[(int)new_wsi->tsi];
161
0
  lws_pt_lock(pt, __func__);
162
163
0
  if (parent) {
164
0
    new_wsi->parent = parent;
165
0
    new_wsi->sibling_list = parent->child_list;
166
0
    parent->child_list = new_wsi;
167
0
  }
168
169
0
  if (vh_prot_name) {
170
0
    new_wsi->a.protocol = lws_vhost_name_to_protocol(new_wsi->a.vhost,
171
0
                     vh_prot_name);
172
0
    if (!new_wsi->a.protocol) {
173
0
      lwsl_vhost_err(new_wsi->a.vhost, "Protocol %s not enabled",
174
0
                  vh_prot_name);
175
0
      goto bail;
176
0
    }
177
0
    if (lws_ensure_user_space(new_wsi)) {
178
0
      lwsl_wsi_notice(new_wsi, "OOM");
179
0
      goto bail;
180
0
    }
181
0
  }
182
183
0
  if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
184
0
      !(type & LWS_ADOPT_SOCKET))
185
0
    type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
186
187
0
  if (lws_role_call_adoption_bind(new_wsi, (int)type, vh_prot_name)) {
188
0
    lwsl_wsi_err(new_wsi, "no role for desc type 0x%x", type);
189
0
    goto bail;
190
0
  }
191
192
0
#if defined(LWS_WITH_SERVER)
193
0
  if (new_wsi->role_ops) {
194
0
    lws_metrics_tag_wsi_add(new_wsi, "role", new_wsi->role_ops->name);
195
0
  }
196
0
#endif
197
198
0
  lws_pt_unlock(pt);
199
200
  /*
201
   * We can lose him from the context pre_natal "last resort" bind now,
202
   * because we will list him on a specific vhost
203
   */
204
205
0
  lws_dll2_remove(&new_wsi->pre_natal);
206
207
  /*
208
   * he's an allocated wsi, but he's not on any fds list or child list,
209
   * join him to the vhost's list of these kinds of incomplete wsi until
210
   * he gets another identity (he may do async dns now...)
211
   */
212
0
  lws_vhost_lock(new_wsi->a.vhost);
213
214
0
  lws_dll2_add_head(&new_wsi->vh_awaiting_socket,
215
0
        &new_wsi->a.vhost->vh_awaiting_socket_owner);
216
0
  lws_vhost_unlock(new_wsi->a.vhost);
217
218
0
  return new_wsi;
219
220
0
bail:
221
0
        lws_pt_lock(pt, __func__); /* -------------- pt { */
222
0
        lws_dll2_remove(&new_wsi->pre_natal);
223
0
        lws_pt_unlock(pt); /* } pt --------------- */
224
225
0
  lwsl_wsi_notice(new_wsi, "exiting on bail");
226
0
  if (parent)
227
0
    parent->child_list = new_wsi->sibling_list;
228
0
  if (new_wsi->user_space)
229
0
    lws_free(new_wsi->user_space);
230
231
0
  lws_fi_destroy(&new_wsi->fic);
232
233
0
  lws_pt_unlock(pt);
234
0
  __lws_vhost_unbind_wsi(new_wsi); /* req cx, acq vh lock */
235
236
0
  lws_free(new_wsi);
237
238
0
  return NULL;
239
0
}
240
241
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
242
243
/*
244
 * If the incoming wsi is bound to a vhost that is a ss server, this creates
245
 * an accepted ss bound to the wsi.
246
 *
247
 * For h1 or raw, we can do the binding here, but for muxed protocols like h2
248
 * or mqtt we have to do it not on the nwsi but on the stream.  And for h2 we
249
 * start off bound to h1 role, since we don't know if we will upgrade to h2
250
 * until we meet the server.
251
 *
252
 * 1) No tls is assumed to mean no muxed protocol so can do it at adopt.
253
 *
254
 * 2) After alpn if not muxed we can do it.
255
 *
256
 * 3) For muxed, do it at the nwsi migration and on new stream
257
 */
258
259
int
260
lws_adopt_ss_server_accept(struct lws *new_wsi)
261
0
{
262
0
  struct lws_context_per_thread *pt =
263
0
      &new_wsi->a.context->pt[(int)new_wsi->tsi];
264
0
  lws_ss_handle_t *h;
265
0
  void *pv, **ppv;
266
267
0
  if (!new_wsi->a.vhost->ss_handle)
268
0
    return 0;
269
270
0
  pv = (char *)&new_wsi->a.vhost->ss_handle[1];
271
272
  /*
273
   * Yes... the vhost is pointing to its secure stream representing the
274
   * server... we want to create an accepted SS and bind it to new_wsi,
275
   * the info/ssi from the server SS (so the SS callbacks defined there),
276
   * the opaque_user_data of the server object and the policy of it.
277
   */
278
279
0
  ppv = (void **)((char *)pv +
280
0
        new_wsi->a.vhost->ss_handle->info.opaque_user_data_offset);
281
282
  /*
283
   * indicate we are an accepted connection referencing the
284
   * server object
285
   */
286
287
0
  new_wsi->a.vhost->ss_handle->info.flags |= LWSSSINFLAGS_SERVER;
288
289
0
  if (lws_ss_create(new_wsi->a.context, new_wsi->tsi,
290
0
        &new_wsi->a.vhost->ss_handle->info,
291
0
        *ppv, &h, NULL, NULL)) {
292
0
    lwsl_wsi_err(new_wsi, "accept ss creation failed");
293
0
    goto fail1;
294
0
  }
295
296
  /*
297
   * We made a fresh accepted SS conn from the server pieces,
298
   * now bind the wsi... the problem is, this is the nwsi if it's
299
   * h2.
300
   */
301
302
0
  h->wsi = new_wsi;
303
0
  new_wsi->a.opaque_user_data = h;
304
0
  h->info.flags |= LWSSSINFLAGS_ACCEPTED;
305
  /* indicate wsi should invalidate any ss link to it on close */
306
0
  new_wsi->for_ss = 1;
307
308
  // lwsl_wsi_notice(new_wsi, "%s: opaq %p, role %s",
309
  //           new_wsi->a.opaque_user_data,
310
  //           new_wsi->role_ops->name);
311
312
0
  h->policy = new_wsi->a.vhost->ss_handle->policy;
313
314
  /* apply requested socket options */
315
0
  if (lws_plat_set_socket_options_ip(new_wsi->desc.sockfd,
316
0
             h->policy->priority,
317
0
          (LCCSCF_IP_LOW_LATENCY *
318
0
           !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)) |
319
0
          (LCCSCF_IP_HIGH_THROUGHPUT *
320
0
           !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)) |
321
0
          (LCCSCF_IP_HIGH_RELIABILITY *
322
0
           !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)) |
323
0
          (LCCSCF_IP_LOW_COST *
324
0
           !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_COST))))
325
0
    lwsl_wsi_warn(new_wsi, "unable to set ip options");
326
327
  /*
328
   * add us to the list of clients that came in from the server
329
   */
330
331
0
  lws_pt_lock(pt, __func__);
332
0
  lws_dll2_add_tail(&h->cli_list, &new_wsi->a.vhost->ss_handle->src_list);
333
0
  lws_pt_unlock(pt);
334
335
  /*
336
   * Let's give it appropriate state notifications
337
   */
338
339
0
  if (lws_ss_event_helper(h, LWSSSCS_CREATING))
340
0
    goto fail;
341
0
  if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
342
0
    goto fail;
343
344
  /* defer CONNECTED until we see if he is upgrading */
345
346
//  if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
347
//    goto fail;
348
349
  // lwsl_notice("%s: accepted ss complete, pcol %s\n", __func__,
350
  //    new_wsi->a.protocol->name);
351
352
0
  return 0;
353
354
0
fail:
355
0
  lws_ss_destroy(&h);
356
0
fail1:
357
0
  return 1;
358
0
}
359
360
#endif
361
362
363
static struct lws *
364
lws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type,
365
          lws_sock_file_fd_type fd)
366
0
{
367
0
  struct lws_context_per_thread *pt =
368
0
      &new_wsi->a.context->pt[(int)new_wsi->tsi];
369
0
  int n;
370
371
  /* enforce that every fd is nonblocking */
372
373
0
  if (type & LWS_ADOPT_SOCKET) {
374
0
    if (lws_plat_set_nonblocking(fd.sockfd)) {
375
0
      lwsl_wsi_err(new_wsi, "unable to set sockfd %d nonblocking",
376
0
             fd.sockfd);
377
0
      goto fail;
378
0
    }
379
0
  }
380
0
#if !defined(WIN32)
381
0
  else
382
0
    if (lws_plat_set_nonblocking(fd.filefd)) {
383
0
      lwsl_wsi_err(new_wsi, "unable to set filefd nonblocking");
384
0
      goto fail;
385
0
    }
386
0
#endif
387
388
0
  new_wsi->desc = fd;
389
390
0
  if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
391
0
      !(type & LWS_ADOPT_SOCKET))
392
0
    type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
393
394
  /*
395
   * A new connection was accepted. Give the user a chance to
396
   * set properties of the newly created wsi. There's no protocol
397
   * selected yet so we issue this to the vhosts's default protocol,
398
   * itself by default protocols[0]
399
   */
400
0
  new_wsi->wsistate |= LWSIFR_SERVER;
401
0
  n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
402
0
  if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
403
0
    n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
404
405
0
  if (new_wsi->a.context->event_loop_ops->sock_accept)
406
0
    if (new_wsi->a.context->event_loop_ops->sock_accept(new_wsi))
407
0
      goto fail;
408
409
0
  {
410
0
          struct lws *nwsi = lws_get_network_wsi(new_wsi);
411
0
    char ta[64];
412
413
0
          if (nwsi->sa46_peer.sa4.sin_family)
414
0
                  lws_sa46_write_numeric_address(&nwsi->sa46_peer, ta, sizeof(ta));
415
0
          else
416
0
                  strncpy(ta, "unknown", sizeof(ta));
417
0
    __lws_lc_tag_append(&new_wsi->lc, ta);
418
0
  }
419
420
#if LWS_MAX_SMP > 1
421
  /*
422
   * Caution: after this point the wsi is live on its service thread
423
   * which may be concurrent to this.  We mark the wsi as still undergoing
424
   * init in another pt so the assigned pt leaves it alone.
425
   */
426
  new_wsi->undergoing_init_from_other_pt = 1;
427
#endif
428
429
0
  if (!(type & LWS_ADOPT_ALLOW_SSL)) {
430
0
    lws_pt_lock(pt, __func__);
431
0
    if (__insert_wsi_socket_into_fds(new_wsi->a.context, new_wsi)) {
432
0
      lws_pt_unlock(pt);
433
0
      lwsl_wsi_err(new_wsi, "fail inserting socket");
434
0
      goto fail;
435
0
    }
436
0
    lws_pt_unlock(pt);
437
0
  }
438
0
#if defined(LWS_WITH_SERVER)
439
0
   else
440
0
    if (lws_server_socket_service_ssl(new_wsi, fd.sockfd, 0)) {
441
0
      lwsl_wsi_info(new_wsi, "fail ssl negotiation");
442
443
0
      goto fail;
444
0
    }
445
0
#endif
446
447
0
  lws_vhost_lock(new_wsi->a.vhost);
448
  /* he has fds visibility now, remove from vhost orphan list */
449
0
  lws_dll2_remove(&new_wsi->vh_awaiting_socket);
450
0
  lws_vhost_unlock(new_wsi->a.vhost);
451
452
  /*
453
   *  by deferring callback to this point, after insertion to fds,
454
   * lws_callback_on_writable() can work from the callback
455
   */
456
0
  if ((new_wsi->a.protocol->callback)(new_wsi, (enum lws_callback_reasons)n, new_wsi->user_space,
457
0
            NULL, 0))
458
0
    goto fail;
459
460
  /* role may need to do something after all adoption completed */
461
462
0
  lws_role_call_adoption_bind(new_wsi, (int)type | _LWS_ADOPT_FINISH,
463
0
            new_wsi->a.protocol->name);
464
465
0
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
466
  /*
467
   * Did we come from an accepted client connection to a ss server?
468
   *
469
   * !!! For mux protocols, this will cause an additional inactive ss
470
   * representing the nwsi.  Doing that allows us to support both h1
471
   * (here) and h2 (at __lws_wsi_server_new())
472
   */
473
474
0
  lwsl_wsi_info(new_wsi, "vhost %s", new_wsi->a.vhost->lc.gutag);
475
476
0
  if (lws_adopt_ss_server_accept(new_wsi))
477
0
    goto fail;
478
0
#endif
479
480
#if LWS_MAX_SMP > 1
481
  /* its actual pt can service it now */
482
483
  new_wsi->undergoing_init_from_other_pt = 0;
484
#endif
485
486
0
  lws_cancel_service_pt(new_wsi);
487
488
0
  return new_wsi;
489
490
0
fail:
491
0
  if (type & LWS_ADOPT_SOCKET)
492
0
    lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS,
493
0
           "adopt skt fail");
494
495
0
  return NULL;
496
0
}
497
498
499
/* if not a socket, it's a raw, non-ssl file descriptor */
500
501
struct lws *
502
lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
503
         lws_sock_file_fd_type fd, const char *vh_prot_name,
504
         struct lws *parent)
505
0
{
506
0
  lws_adopt_desc_t info;
507
508
0
  memset(&info, 0, sizeof(info));
509
510
0
  info.vh = vh;
511
0
  info.type = type;
512
0
  info.fd = fd;
513
0
  info.vh_prot_name = vh_prot_name;
514
0
  info.parent = parent;
515
516
0
  return lws_adopt_descriptor_vhost_via_info(&info);
517
0
}
518
519
struct lws *
520
lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
521
0
{
522
0
  socklen_t slen = sizeof(lws_sockaddr46);
523
0
  struct lws *new_wsi;
524
525
#if defined(LWS_WITH_PEER_LIMITS)
526
  struct lws_peer *peer = NULL;
527
528
  if (info->type & LWS_ADOPT_SOCKET) {
529
    peer = lws_get_or_create_peer(info->vh, info->fd.sockfd);
530
531
    if (peer && info->vh->context->ip_limit_wsi &&
532
        peer->count_wsi >= info->vh->context->ip_limit_wsi) {
533
      lwsl_info("Peer reached wsi limit %d\n",
534
          info->vh->context->ip_limit_wsi);
535
      if (info->vh->context->pl_notify_cb)
536
        info->vh->context->pl_notify_cb(
537
              info->vh->context,
538
              info->fd.sockfd,
539
              &peer->sa46);
540
      compatible_close(info->fd.sockfd);
541
      return NULL;
542
    }
543
  }
544
#endif
545
546
0
  lws_context_lock(info->vh->context, __func__);
547
548
0
  new_wsi = __lws_adopt_descriptor_vhost1(info->vh, info->type,
549
0
                info->vh_prot_name, info->parent,
550
0
                info->opaque, info->fi_wsi_name);
551
0
  if (!new_wsi) {
552
0
    if (info->type & LWS_ADOPT_SOCKET)
553
0
      compatible_close(info->fd.sockfd);
554
0
    goto bail;
555
0
  }
556
557
0
  if (info->type & LWS_ADOPT_SOCKET &&
558
0
      getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer,
559
0
                    &slen) < 0)
560
0
    lwsl_info("%s: getpeername failed\n", __func__);
561
562
#if defined(LWS_WITH_PEER_LIMITS)
563
  if (peer)
564
    lws_peer_add_wsi(info->vh->context, peer, new_wsi);
565
#endif
566
567
0
  new_wsi = lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
568
569
0
bail:
570
0
  lws_context_unlock(info->vh->context);
571
572
0
  return new_wsi;
573
0
}
574
575
struct lws *
576
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
577
0
{
578
0
  lws_sock_file_fd_type fd;
579
580
0
  fd.sockfd = accept_fd;
581
0
  return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
582
0
      LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
583
0
}
584
585
struct lws *
586
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
587
0
{
588
0
  return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
589
0
}
590
591
/* Common read-buffer adoption for lws_adopt_*_readbuf */
592
static struct lws*
593
adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
594
0
{
595
0
  struct lws_context_per_thread *pt;
596
0
  struct lws_pollfd *pfd;
597
0
  int n;
598
599
0
  if (!wsi)
600
0
    return NULL;
601
602
0
  if (!readbuf || len == 0)
603
0
    return wsi;
604
605
0
  if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
606
0
    return wsi;
607
608
0
  pt = &wsi->a.context->pt[(int)wsi->tsi];
609
610
0
  n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
611
0
               len);
612
0
  if (n < 0)
613
0
    goto bail;
614
0
  if (n)
615
0
    lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
616
617
  /*
618
   * we can't process the initial read data until we can attach an ah.
619
   *
620
   * if one is available, get it and place the data in his ah rxbuf...
621
   * wsi with ah that have pending rxbuf get auto-POLLIN service.
622
   *
623
   * no autoservice because we didn't get a chance to attach the
624
   * readbuf data to wsi or ah yet, and we will do it next if we get
625
   * the ah.
626
   */
627
0
  if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
628
629
0
    lwsl_notice("%s: calling service on readbuf ah\n", __func__);
630
631
    /*
632
     * unlike a normal connect, we have the headers already
633
     * (or the first part of them anyway).
634
     * libuv won't come back and service us without a network
635
     * event, so we need to do the header service right here.
636
     */
637
0
    pfd = &pt->fds[wsi->position_in_fds_table];
638
0
    pfd->revents |= LWS_POLLIN;
639
0
    lwsl_err("%s: calling service\n", __func__);
640
0
    if (lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi))
641
      /* service closed us */
642
0
      return NULL;
643
644
0
    return wsi;
645
0
  }
646
0
  lwsl_err("%s: deferring handling ah\n", __func__);
647
648
0
  return wsi;
649
650
0
bail:
651
0
  lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
652
0
         "adopt skt readbuf fail");
653
654
0
  return NULL;
655
0
}
656
657
#if defined(LWS_WITH_UDP)
658
#if defined(LWS_WITH_CLIENT)
659
660
/*
661
 * This is the ASYNC_DNS callback target for udp client, it's analogous to
662
 * connect3()
663
 */
664
665
static struct lws *
666
lws_create_adopt_udp2(struct lws *wsi, const char *ads,
667
          const struct addrinfo *r, int n, void *opaque)
668
0
{
669
0
  lws_sock_file_fd_type sock;
670
0
  int bc = 1, m;
671
672
0
  assert(wsi);
673
674
0
  if (ads && (n < 0 || !r)) {
675
    /*
676
     * DNS lookup failed: there are no usable results.  Fail the
677
     * overall connection request.
678
     */
679
0
    lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
680
681
0
    goto bail;
682
0
  }
683
684
0
  m = lws_sort_dns(wsi, r);
685
#if defined(LWS_WITH_SYS_ASYNC_DNS)
686
  lws_async_dns_freeaddrinfo(&r);
687
#else
688
0
  freeaddrinfo((struct addrinfo *)r);
689
0
#endif
690
0
  if (m)
691
0
    goto bail;
692
693
0
  while (lws_dll2_get_head(&wsi->dns_sorted_list)) {
694
0
    lws_dns_sort_t *s = lws_container_of(
695
0
        lws_dll2_get_head(&wsi->dns_sorted_list),
696
0
        lws_dns_sort_t, list);
697
698
    /*
699
     * Remove it from the head, but don't free it yet... we are
700
     * taking responsibility to free it
701
     */
702
0
    lws_dll2_remove(&s->list);
703
704
    /*
705
     * We have done the dns lookup, identify the result we want
706
     * if any, and then complete the adoption by binding wsi to
707
     * socket opened on it.
708
     *
709
     * Ignore the weak assumptions about protocol driven by port
710
     * number and force to DGRAM / UDP since that's what this
711
     * function is for.
712
     */
713
714
#if !defined(__linux__)
715
    sock.sockfd = socket(s->dest.sa4.sin_family,
716
             SOCK_DGRAM, IPPROTO_UDP);
717
#else
718
    /* PF_PACKET is linux-only */
719
0
    sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
720
0
            s->dest.sa4.sin_family,
721
0
             SOCK_DGRAM, wsi->pf_packet ?
722
0
          htons(0x800) : IPPROTO_UDP);
723
0
#endif
724
0
    if (sock.sockfd == LWS_SOCK_INVALID)
725
0
      goto resume;
726
727
    /* ipv6 udp!!! */
728
729
0
    if (s->af == AF_INET)
730
0
      s->dest.sa4.sin_port = htons(wsi->c_port);
731
0
#if defined(LWS_WITH_IPV6)
732
0
    else
733
0
      s->dest.sa6.sin6_port = htons(wsi->c_port);
734
0
#endif
735
736
0
    if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR,
737
0
             (const char *)&bc, sizeof(bc)) < 0)
738
0
      lwsl_err("%s: failed to set reuse\n", __func__);
739
740
0
    if (wsi->do_broadcast &&
741
0
        setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST,
742
0
             (const char *)&bc, sizeof(bc)) < 0)
743
0
      lwsl_err("%s: failed to set broadcast\n", __func__);
744
745
    /* Bind the udp socket to a particular network interface */
746
747
0
    if (opaque &&
748
0
        lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
749
0
      goto resume;
750
751
0
    if (wsi->do_bind &&
752
0
        bind(sock.sockfd, sa46_sockaddr(&s->dest),
753
#if defined(_WIN32)
754
       (int)sa46_socklen(&s->dest)
755
#else
756
0
       sizeof(struct sockaddr)
757
0
#endif
758
0
    ) == -1) {
759
0
      lwsl_err("%s: bind failed\n", __func__);
760
0
      goto resume;
761
0
    }
762
763
0
    if (!wsi->do_bind && !wsi->pf_packet) {
764
0
#if !defined(__APPLE__)
765
0
      if (connect(sock.sockfd, sa46_sockaddr(&s->dest),
766
0
            sa46_socklen(&s->dest)) == -1 &&
767
0
          errno != EADDRNOTAVAIL /* openbsd */ ) {
768
0
        lwsl_err("%s: conn fd %d fam %d %s:%u failed "
769
0
           "errno %d\n", __func__, sock.sockfd,
770
0
           s->dest.sa4.sin_family,
771
0
           ads ? ads : "null", wsi->c_port,
772
0
           LWS_ERRNO);
773
0
        compatible_close(sock.sockfd);
774
0
        goto resume;
775
0
      }
776
0
#endif
777
0
    }
778
779
0
    if (wsi->udp)
780
0
      wsi->udp->sa46 = s->dest;
781
0
    wsi->sa46_peer = s->dest;
782
783
    /* we connected: complete the udp socket adoption flow */
784
785
#if defined(LWS_WITH_SYS_ASYNC_DNS)
786
    {
787
      lws_async_dns_server_t *asds =
788
          __lws_async_dns_server_find_wsi(
789
            &wsi->a.context->async_dns, wsi);
790
      if (asds)
791
        asds->dns_server_connected = 1;
792
    }
793
#endif
794
795
0
    lws_free(s);
796
0
    lws_addrinfo_clean(wsi);
797
0
    return lws_adopt_descriptor_vhost2(wsi,
798
0
            LWS_ADOPT_RAW_SOCKET_UDP, sock);
799
800
0
resume:
801
0
    lws_free(s);
802
0
  }
803
804
0
  lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
805
0
  lws_addrinfo_clean(wsi);
806
807
#if defined(LWS_WITH_SYS_ASYNC_DNS)
808
  {
809
    lws_async_dns_server_t *asds = __lws_async_dns_server_find_wsi(
810
          &wsi->a.context->async_dns, wsi);
811
    if (asds)
812
      lws_async_dns_drop_server(asds);
813
  }
814
#endif
815
816
0
bail:
817
818
  /* caller must close */
819
820
0
  return NULL;
821
0
}
822
823
struct lws *
824
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
825
         int flags, const char *protocol_name, const char *ifname,
826
         struct lws *parent_wsi, void *opaque,
827
         const lws_retry_bo_t *retry_policy, const char *fi_wsi_name)
828
0
{
829
0
#if !defined(LWS_PLAT_OPTEE)
830
0
  struct lws *wsi;
831
0
  int n;
832
833
0
  lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
834
835
  /* create the logical wsi without any valid fd */
836
837
0
  lws_context_lock(vhost->context, __func__);
838
839
0
  wsi = __lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET |
840
0
             LWS_ADOPT_RAW_SOCKET_UDP,
841
0
            protocol_name, parent_wsi, opaque,
842
0
            fi_wsi_name);
843
844
0
  lws_context_unlock(vhost->context);
845
0
  if (!wsi) {
846
0
    lwsl_err("%s: udp wsi creation failed\n", __func__);
847
0
    goto bail;
848
0
  }
849
850
  // lwsl_notice("%s: role %s\n", __func__, wsi->role_ops->name);
851
852
0
  wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
853
0
  wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
854
0
  wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
855
0
  wsi->c_port = (uint16_t)(unsigned int)port;
856
0
  if (retry_policy)
857
0
    wsi->retry_policy = retry_policy;
858
0
  else
859
0
    wsi->retry_policy = vhost->retry_policy;
860
861
0
#if !defined(LWS_WITH_SYS_ASYNC_DNS)
862
0
  {
863
0
    struct addrinfo *r, h;
864
0
    char buf[16];
865
866
0
    memset(&h, 0, sizeof(h));
867
0
    h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
868
0
    h.ai_socktype = SOCK_DGRAM;
869
0
    h.ai_protocol = IPPROTO_UDP;
870
0
#if defined(AI_PASSIVE)
871
0
    h.ai_flags = AI_PASSIVE;
872
0
#endif
873
0
#ifdef AI_ADDRCONFIG
874
0
    h.ai_flags |= AI_ADDRCONFIG;
875
0
#endif
876
877
    /* if the dns lookup is synchronous, do the whole thing now */
878
0
    lws_snprintf(buf, sizeof(buf), "%u", port);
879
0
    n = getaddrinfo(ads, buf, &h, &r);
880
0
    if (n) {
881
0
#if !defined(LWS_PLAT_FREERTOS)
882
0
      lwsl_cx_info(vhost->context, "getaddrinfo error: %d", n);
883
#else
884
#if (_LWS_ENABLED_LOGS & LLL_INFO)
885
      char t16[16];
886
      lwsl_cx_info(vhost->context, "getaddrinfo error: %s",
887
        lws_errno_describe(LWS_ERRNO, t16, sizeof(t16)));
888
#endif
889
#endif
890
      //freeaddrinfo(r);
891
0
      goto bail1;
892
0
    }
893
    /*
894
     * With synchronous dns, complete it immediately after the
895
     * blocking dns lookup finished... free r when connect either
896
     * completed or failed
897
     */
898
0
    wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
899
900
0
    return wsi;
901
0
  }
902
#else
903
  if (ads) {
904
    /*
905
     * with async dns, use the wsi as the point about which to do
906
     * the dns lookup and have it call the second part when it's
907
     * done.
908
     *
909
     * Keep a refcount on the results and free it when we connected
910
     * or definitively failed.
911
     *
912
     * Notice wsi has no socket at this point (we don't know what
913
     * kind to ask for until we get the dns back).  But it is bound
914
     * to a vhost and can be cleaned up from that at vhost destroy.
915
     */
916
    n = lws_async_dns_query(vhost->context, 0, ads,
917
          LWS_ADNS_RECORD_A,
918
          lws_create_adopt_udp2, wsi,
919
          (void *)ifname, NULL);
920
    // lwsl_notice("%s: dns query returned %d\n", __func__, n);
921
    if (n == LADNS_RET_FAILED) {
922
      lwsl_err("%s: async dns failed\n", __func__);
923
      wsi = NULL;
924
      /*
925
       * It was already closed by calling callback with error
926
       * from lws_async_dns_query()
927
       */
928
      goto bail;
929
    }
930
  } else {
931
    lwsl_debug("%s: udp adopt has no ads\n", __func__);
932
    wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
933
  }
934
935
  /* dns lookup is happening asynchronously */
936
937
  // lwsl_notice("%s: returning wsi %p\n", __func__, wsi);
938
939
  return wsi;
940
#endif
941
0
#if !defined(LWS_WITH_SYS_ASYNC_DNS)
942
0
bail1:
943
0
  lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
944
0
  wsi = NULL;
945
0
#endif
946
0
bail:
947
0
  return wsi;
948
#else
949
  return NULL;
950
#endif
951
0
}
952
#endif
953
#endif
954
955
struct lws *
956
lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
957
       const char *readbuf, size_t len)
958
0
{
959
0
        return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
960
0
            readbuf, len);
961
0
}
962
963
struct lws *
964
lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
965
             lws_sockfd_type accept_fd,
966
             const char *readbuf, size_t len)
967
0
{
968
0
        return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
969
0
            readbuf, len);
970
0
}