Coverage Report

Created: 2026-02-26 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/plat/unix/unix-sockets.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2023 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
#if defined(LWS_HAVE_LINUX_IPV6_H)
31
#include <linux/ipv6.h>
32
#endif
33
34
#include <sys/ioctl.h>
35
36
#if !defined(LWS_DETECTED_PLAT_IOS)
37
#include <net/route.h>
38
#endif
39
40
#include <net/if.h>
41
42
#include <pwd.h>
43
#include <grp.h>
44
45
#if defined(LWS_WITH_MBEDTLS)
46
#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
47
#include "mbedtls/net_sockets.h"
48
#else
49
#include "mbedtls/net.h"
50
#endif
51
#endif
52
53
#include <netinet/ip.h>
54
55
int
56
lws_send_pipe_choked(struct lws *wsi)
57
0
{
58
0
  struct lws_pollfd fds;
59
0
  struct lws *wsi_eff;
60
61
#if !defined(LWS_WITHOUT_EXTENSIONS)
62
  if (wsi->ws && wsi->ws->tx_draining_ext)
63
    return 1;
64
#endif
65
66
0
#if defined(LWS_WITH_HTTP2)
67
0
  wsi_eff = lws_get_network_wsi(wsi);
68
#else
69
  wsi_eff = wsi;
70
#endif
71
72
  /* the fact we checked implies we avoided back-to-back writes */
73
0
  wsi_eff->could_have_pending = 0;
74
75
  /* treat the fact we got a truncated send pending as if we're choked */
76
0
  if (lws_has_buffered_out(wsi_eff)
77
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
78
      ||wsi->http.comp_ctx.buflist_comp ||
79
      wsi->http.comp_ctx.may_have_more
80
#endif
81
0
      )
82
0
    return 1;
83
84
0
  fds.fd = wsi_eff->desc.sockfd;
85
0
  fds.events = POLLOUT;
86
0
  fds.revents = 0;
87
88
0
  if (poll(&fds, 1, 0) != 1)
89
0
    return 1;
90
91
0
  if ((fds.revents & POLLOUT) == 0)
92
0
    return 1;
93
94
  /* okay to send another packet without blocking */
95
96
0
  return 0;
97
0
}
98
99
int
100
lws_plat_set_nonblocking(lws_sockfd_type fd)
101
0
{
102
0
  return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
103
0
}
104
105
int
106
lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
107
0
{
108
0
  int optval = 1;
109
0
  socklen_t optlen = sizeof(optval);
110
111
#if defined(__APPLE__) || \
112
    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
113
    defined(__NetBSD__) || \
114
    defined(__OpenBSD__) || \
115
    defined(__HAIKU__)
116
  struct protoent *tcp_proto;
117
#endif
118
119
0
  (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
120
121
0
  if (!unix_skt && vhost->ka_time) {
122
    /* enable keepalive on this socket */
123
0
    optval = 1;
124
0
    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
125
0
             (const void *)&optval, optlen) < 0)
126
0
      return 1;
127
128
#if defined(__APPLE__) || \
129
    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
130
    defined(__NetBSD__) || \
131
    defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \
132
    defined(__HAIKU__)
133
134
    /*
135
     * didn't find a way to set these per-socket, need to
136
     * tune kernel systemwide values
137
     */
138
#else
139
    /* set the keepalive conditions we want on it too */
140
141
0
#if defined(LWS_HAVE_TCP_USER_TIMEOUT)
142
0
    optval = 1000 * (vhost->ka_time +
143
0
         (vhost->ka_interval * vhost->ka_probes));
144
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
145
0
             (const void *)&optval, optlen) < 0)
146
0
      return 1;
147
0
#endif
148
0
    optval = vhost->ka_time;
149
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
150
0
             (const void *)&optval, optlen) < 0)
151
0
      return 1;
152
153
0
    optval = vhost->ka_interval;
154
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
155
0
             (const void *)&optval, optlen) < 0)
156
0
      return 1;
157
158
0
    optval = vhost->ka_probes;
159
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
160
0
             (const void *)&optval, optlen) < 0)
161
0
      return 1;
162
0
#endif
163
0
  }
164
165
0
#if defined(SO_BINDTODEVICE)
166
0
  if (!unix_skt && vhost->bind_iface && vhost->iface) {
167
0
    lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
168
0
    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
169
0
        (socklen_t)strlen(vhost->iface)) < 0) {
170
0
      lwsl_warn("Failed to bind to device %s\n", vhost->iface);
171
0
      return 1;
172
0
    }
173
0
  }
174
0
#endif
175
176
  /* Disable Nagle */
177
0
  optval = 1;
178
#if defined (__sun) || defined(__QNX__) || defined(__NuttX__)
179
  if (!unix_skt && setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
180
    return 1;
181
#elif !defined(__APPLE__) && \
182
      !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) &&        \
183
      !defined(__NetBSD__) && \
184
      !defined(__OpenBSD__) && \
185
      !defined(__HAIKU__)
186
0
  if (!unix_skt && setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
187
0
    return 1;
188
#else
189
  tcp_proto = getprotobyname("TCP");
190
  if (!unix_skt && setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
191
    return 1;
192
#endif
193
194
0
  return lws_plat_set_nonblocking(fd);
195
0
}
196
197
#if !defined(__NuttX__)
198
static const int ip_opt_lws_flags[] = {
199
  LCCSCF_IP_LOW_LATENCY, LCCSCF_IP_HIGH_THROUGHPUT
200
#if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__)
201
  , LCCSCF_IP_HIGH_RELIABILITY
202
  , LCCSCF_IP_LOW_COST
203
#endif
204
}, ip_opt_val[] = {
205
  IPTOS_LOWDELAY, IPTOS_THROUGHPUT
206
#if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__)
207
  , IPTOS_RELIABILITY
208
  , IPTOS_MINCOST
209
#endif
210
};
211
#if !defined(LWS_WITH_NO_LOGS)
212
static const char *ip_opt_names[] = {
213
  "LOWDELAY", "THROUGHPUT"
214
#if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__)
215
  , "RELIABILITY"
216
  , "MINCOST"
217
#endif
218
};
219
#endif
220
#endif
221
222
int
223
lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
224
0
{
225
0
  int optval = (int)pri, ret = 0, n;
226
0
  socklen_t optlen = sizeof(optval);
227
0
#if (_LWS_ENABLED_LOGS & LLL_WARN)
228
0
  int en;
229
0
#endif
230
231
#if 0
232
#if defined(TCP_FASTOPEN_CONNECT)
233
  optval = 1;
234
  if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval,
235
           sizeof(optval)))
236
    lwsl_warn("%s: FASTOPEN_CONNECT failed\n", __func__);
237
  optval = (int)pri;
238
#endif
239
#endif
240
241
0
#if !defined(__APPLE__) && \
242
0
      !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) &&        \
243
0
      !defined(__NetBSD__) && \
244
0
      !defined(__OpenBSD__) && \
245
0
      !defined(__sun) && \
246
0
      !defined(__HAIKU__) && \
247
0
      !defined(__CYGWIN__) && \
248
0
      !defined(__QNX__) && \
249
0
      !defined(__NuttX__)
250
251
  /* the BSDs don't have SO_PRIORITY */
252
253
0
  if (pri) { /* 0 is the default already */
254
0
    if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
255
0
        (const void *)&optval, optlen) < 0) {
256
0
#if (_LWS_ENABLED_LOGS & LLL_WARN)
257
0
      en = errno;
258
0
      lwsl_warn("%s: unable to set socket pri %d: errno %d\n",
259
0
          __func__, (int)pri, en);
260
0
#endif
261
0
      ret = 1;
262
0
    } else
263
0
      lwsl_notice("%s: set pri %u\n", __func__, pri);
264
0
  }
265
0
#endif
266
267
0
  if (lws_flags & LCCSCF_ALLOW_REUSE_ADDR) {
268
0
    optval = 1;
269
0
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
270
0
          (const void *)&optval, optlen) < 0) { 
271
0
#if (_LWS_ENABLED_LOGS & LLL_WARN)
272
0
      en = errno;
273
0
      lwsl_warn("%s: unable to reuse local addresses: errno %d\n",
274
0
        __func__, en);
275
0
#endif
276
0
      ret = 1;
277
0
    } else
278
0
      lwsl_notice("%s: set reuse addresses\n", __func__);
279
0
  }
280
281
282
0
  if (lws_flags & LCCSCF_IPV6_PREFER_PUBLIC_ADDR) {
283
0
#if defined(LWS_WITH_IPV6) && defined(IPV6_PREFER_SRC_PUBLIC)
284
0
    optval = IPV6_PREFER_SRC_PUBLIC;
285
286
0
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
287
0
            (const void *)&optval, optlen) < 0) {
288
0
        #if (_LWS_ENABLED_LOGS & LLL_WARN)
289
0
          en = errno;
290
0
          lwsl_warn("%s: unable to set IPV6_PREFER_SRC_PUBLIC: errno %d\n",
291
0
            __func__, en);
292
0
        #endif
293
0
        ret = 1;
294
0
    } else
295
0
      lwsl_notice("%s: set IPV6_PREFER_SRC_PUBLIC\n", __func__);
296
#else
297
    lwsl_err("%s: IPV6_PREFER_SRC_PUBLIC UNIMPLEMENTED on this platform\n", __func__);
298
#endif
299
0
  }
300
301
302
0
#if !defined(__NuttX__)
303
  /* array size differs by platform */
304
0
  for (n = 0; n < (int)LWS_ARRAY_SIZE(ip_opt_lws_flags); n++) {
305
0
    if (!(lws_flags & ip_opt_lws_flags[n]))
306
0
      continue;
307
308
0
    optval = (int)ip_opt_val[n];
309
0
    if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *)&optval,
310
0
             optlen) < 0) {
311
0
#if !defined(LWS_WITH_NO_LOGS)
312
0
      en = errno;
313
0
      lwsl_warn("%s: unable to set %s: errno %d\n", __func__,
314
0
          ip_opt_names[n], en);
315
0
#endif
316
0
      ret = 1;
317
0
    } else
318
0
      lwsl_notice("%s: set ip flag %s\n", __func__,
319
0
            ip_opt_names[n]);
320
0
  }
321
0
#endif
322
323
0
  return ret;
324
0
}
325
326
/* cast a struct sockaddr_in6 * into addr for ipv6 */
327
328
enum {
329
  IP_SCORE_NONE,
330
  IP_SCORE_NONNATIVE,
331
  IP_SCORE_IPV6_SCOPE_BASE,
332
  /* ipv6 scopes */
333
  IP_SCORE_GLOBAL_NATIVE = 18
334
};
335
336
int
337
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
338
        size_t addrlen)
339
0
{
340
0
  int rc = LWS_ITOSA_NOT_EXIST;
341
342
0
  struct ifaddrs *ifr;
343
0
  struct ifaddrs *ifc;
344
0
#if defined(LWS_WITH_IPV6)
345
0
  struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
346
0
  unsigned long sco = IP_SCORE_NONE;
347
0
  unsigned long ts;
348
0
  const uint8_t *p;
349
0
#endif
350
351
0
  if (getifaddrs(&ifr)) {
352
0
    lwsl_err("%s: unable to getifaddrs: errno %d\n", __func__, errno);
353
354
0
    return LWS_ITOSA_USABLE;
355
0
  }
356
0
  for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
357
0
    if (!ifc->ifa_addr || !ifc->ifa_name)
358
0
      continue;
359
360
0
    lwsl_debug(" interface %s vs %s (fam %d) ipv6 %d\n",
361
0
         ifc->ifa_name, ifname,
362
0
         ifc->ifa_addr->sa_family, ipv6);
363
364
0
    if (strcmp(ifc->ifa_name, ifname))
365
0
      continue;
366
367
0
    switch (ifc->ifa_addr->sa_family) {
368
0
#if defined(AF_PACKET)
369
0
    case AF_PACKET:
370
      /* interface exists but is not usable */
371
0
      if (rc == LWS_ITOSA_NOT_EXIST)
372
0
        rc = LWS_ITOSA_NOT_USABLE;
373
0
      continue;
374
0
#endif
375
376
0
    case AF_INET:
377
0
#if defined(LWS_WITH_IPV6)
378
0
      if (ipv6) {
379
        /* any existing solution is better than this */
380
0
        if (sco != IP_SCORE_NONE)
381
0
          break;
382
0
        sco = IP_SCORE_NONNATIVE;
383
0
        rc = LWS_ITOSA_USABLE;
384
        /* map IPv4 to IPv6 */
385
0
        memset((char *)&addr6->sin6_addr, 0,
386
0
            sizeof(struct in6_addr));
387
0
        addr6->sin6_addr.s6_addr[10] = 0xff;
388
0
        addr6->sin6_addr.s6_addr[11] = 0xff;
389
0
        memcpy(&addr6->sin6_addr.s6_addr[12],
390
0
               &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
391
0
              sizeof(struct in_addr));
392
0
        lwsl_debug("%s: uplevelling ipv4 bind to ipv6\n", __func__);
393
0
        break;
394
0
      }
395
396
0
      sco = IP_SCORE_GLOBAL_NATIVE;
397
0
#endif
398
0
      rc = LWS_ITOSA_USABLE;
399
0
      memcpy(addr, (struct sockaddr_in *)ifc->ifa_addr,
400
0
                sizeof(struct sockaddr_in));
401
0
      break;
402
0
#if defined(LWS_WITH_IPV6)
403
0
    case AF_INET6:
404
0
      p = (const uint8_t *)
405
0
        &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr;
406
0
      ts = IP_SCORE_IPV6_SCOPE_BASE;
407
0
      if (p[0] == 0xff)
408
0
        ts = (unsigned long)(IP_SCORE_IPV6_SCOPE_BASE + (p[1] & 0xf));
409
410
0
      if (sco >= ts)
411
0
        break;
412
413
0
      sco = ts;
414
0
      rc = LWS_ITOSA_USABLE;
415
416
0
      memcpy(&addr6->sin6_addr,
417
0
           &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
418
0
                   sizeof(struct in6_addr));
419
0
      break;
420
0
#endif
421
0
    default:
422
0
      break;
423
0
    }
424
0
  }
425
426
0
  freeifaddrs(ifr);
427
428
0
  if (rc &&
429
0
      !lws_sa46_parse_numeric_address(ifname, (lws_sockaddr46 *)addr))
430
0
    rc = LWS_ITOSA_USABLE;
431
432
0
  return rc;
433
0
}
434
435
436
const char *
437
lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
438
0
{
439
0
  return inet_ntop(af, src, dst, cnt);
440
0
}
441
442
int
443
lws_plat_inet_pton(int af, const char *src, void *dst)
444
0
{
445
0
  return inet_pton(af, src, dst);
446
0
}
447
448
int
449
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
450
0
{
451
0
#if defined(__linux__)
452
0
  struct ifreq i;
453
454
0
  memset(&i, 0, sizeof(i));
455
0
  lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name));
456
457
0
  if (ioctl(fd, SIOCGIFHWADDR, &i) < 0)
458
0
    return -1;
459
460
0
  memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6);
461
462
0
  return 6;
463
#else
464
  lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
465
466
  return -1;
467
#endif
468
0
}
469
470
int
471
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
472
        size_t n, int fd, const char *iface)
473
0
{
474
0
#if defined(__linux__)
475
0
  struct sockaddr_ll sll;
476
0
  uint16_t *p16 = (uint16_t *)p;
477
0
  uint32_t ucs = 0;
478
479
0
  memcpy(p, canned, canned_len);
480
481
0
  p[2] = (uint8_t)(n >> 8);
482
0
  p[3] = (uint8_t)(n);
483
484
0
  while (p16 < (uint16_t *)(p + 20))
485
0
    ucs = ucs + (uint32_t)(ntohs((uint16_t)(*p16++)));
486
487
0
  ucs += ucs >> 16;
488
0
  ucs ^= 0xffff;
489
490
0
  p[10] = (uint8_t)(ucs >> 8);
491
0
  p[11] = (uint8_t)(ucs);
492
0
  p[24] = (uint8_t)((n - 20) >> 8);
493
0
  p[25] = (uint8_t)((n - 20));
494
495
0
  memset(&sll, 0, sizeof(sll));
496
0
  sll.sll_family = AF_PACKET;
497
0
  sll.sll_protocol = (uint16_t)(htons((uint16_t)0x800));
498
0
  sll.sll_halen = 6;
499
0
  sll.sll_ifindex = (int)if_nametoindex(iface);
500
0
  memset(sll.sll_addr, 0xff, 6);
501
502
0
  return (int)sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll));
503
#else
504
  lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
505
506
  return -1;
507
#endif
508
0
}
509
510
int
511
lws_plat_if_up(const char *ifname, int fd, int up)
512
0
{
513
0
#if defined(__linux__)
514
0
  struct ifreq ifr;
515
516
0
  memset(&ifr, 0, sizeof(ifr));
517
0
  lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
518
519
0
  if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
520
0
    lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__);
521
0
    return 1;
522
0
  }
523
524
0
  if (up)
525
0
    ifr.ifr_flags |= IFF_UP;
526
0
  else
527
0
    ifr.ifr_flags &= ~IFF_UP;
528
529
0
  if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
530
0
    lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__);
531
0
    return 1;
532
0
  }
533
534
0
  return 0;
535
#else
536
  lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
537
538
  return -1;
539
#endif
540
0
}
541
542
int
543
lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
544
0
{
545
0
#if defined(__linux__)
546
0
  struct ifreq i;
547
548
0
  memset(&i, 0, sizeof(i));
549
0
  i.ifr_addr.sa_family = AF_INET;
550
0
  lws_strncpy(i.ifr_ifrn.ifrn_name, ifname,
551
0
        sizeof(i.ifr_ifrn.ifrn_name));
552
0
  if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) {
553
0
    lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO);
554
0
    return 1;
555
0
  }
556
557
0
  return 0;
558
#else
559
  lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
560
561
  return -1;
562
#endif
563
0
}
564
565
int
566
lws_plat_ifconfig(int fd, lws_dhcpc_ifstate_t *is)
567
0
{
568
0
#if defined(__linux__)
569
0
  struct rtentry route;
570
0
  struct ifreq ifr;
571
572
0
  memset(&ifr, 0, sizeof(ifr));
573
0
  memset(&route, 0, sizeof(route));
574
575
0
  lws_strncpy(ifr.ifr_name, is->ifname, IFNAMSIZ);
576
577
0
  lws_plat_if_up(is->ifname, fd, 0);
578
579
0
  memcpy(&ifr.ifr_addr, &is->sa46[LWSDH_SA46_IP], sizeof(struct sockaddr));
580
0
  if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
581
0
    lwsl_err("%s: SIOCSIFADDR fail\n", __func__);
582
0
    return 1;
583
0
  }
584
585
0
  if (is->sa46[LWSDH_SA46_IP].sa4.sin_family == AF_INET) {
586
0
    struct sockaddr_in sin;
587
588
0
    memset(&sin, 0, sizeof(sin));
589
0
    sin.sin_family = AF_INET;
590
0
    sin.sin_addr.s_addr = *(uint32_t *)&is->nums[LWSDH_IPV4_SUBNET_MASK];
591
0
    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
592
0
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
593
0
      lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__);
594
0
      return 1;
595
0
    }
596
597
0
    lws_plat_if_up(is->ifname, fd, 1);
598
599
0
    memcpy(&route.rt_gateway,
600
0
           &is->sa46[LWSDH_SA46_IPV4_ROUTER].sa4,
601
0
           sizeof(struct sockaddr));
602
603
0
    sin.sin_addr.s_addr = 0;
604
0
    memcpy(&route.rt_dst, &sin, sizeof(struct sockaddr));
605
0
    memcpy(&route.rt_genmask, &sin, sizeof(struct sockaddr));
606
607
0
    route.rt_flags = RTF_UP | RTF_GATEWAY;
608
0
    route.rt_metric = 100;
609
0
    route.rt_dev = (char *)is->ifname;
610
611
0
    if (ioctl(fd, SIOCADDRT, &route) < 0) {
612
0
      lwsl_err("%s: SIOCADDRT 0x%x fail: %d\n", __func__,
613
0
        (unsigned int)htonl(*(uint32_t *)&is->
614
0
          sa46[LWSDH_SA46_IPV4_ROUTER].
615
0
            sa4.sin_addr.s_addr), LWS_ERRNO);
616
0
      return 1;
617
0
    }
618
0
  } else
619
0
    lws_plat_if_up(is->ifname, fd, 1);
620
621
0
  return 0;
622
#else
623
  lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
624
625
  return -1;
626
#endif
627
0
}
628
629
int
630
lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
631
0
{
632
0
  return 0;
633
0
}
634
635
#if defined(LWS_WITH_MBEDTLS)
636
int
637
lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
638
{
639
  int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd);
640
  int ret;
641
642
  if (fd < 0)
643
    return MBEDTLS_ERR_NET_INVALID_CONTEXT;
644
645
  ret = (int)write(fd, buf, len);
646
  if (ret >= 0)
647
    return ret;
648
649
  if (errno == EAGAIN || errno == EWOULDBLOCK)
650
    return MBEDTLS_ERR_SSL_WANT_WRITE;
651
652
  if (errno == EPIPE || errno == ECONNRESET)
653
    return MBEDTLS_ERR_NET_CONN_RESET;
654
655
  if( errno == EINTR )
656
    return MBEDTLS_ERR_SSL_WANT_WRITE;
657
658
  return MBEDTLS_ERR_NET_SEND_FAILED;
659
}
660
661
int
662
lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
663
{
664
  int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd);
665
  int ret;
666
667
  if (fd < 0)
668
    return MBEDTLS_ERR_NET_INVALID_CONTEXT;
669
670
  ret = (int)read(fd, buf, len);
671
  if (ret >= 0)
672
    return ret;
673
674
  if (errno == EAGAIN || errno == EWOULDBLOCK)
675
    return MBEDTLS_ERR_SSL_WANT_READ;
676
677
  if (errno == EPIPE || errno == ECONNRESET)
678
    return MBEDTLS_ERR_NET_CONN_RESET;
679
680
  if (errno == EINTR)
681
    return MBEDTLS_ERR_SSL_WANT_READ;
682
683
  return MBEDTLS_ERR_NET_RECV_FAILED;
684
}
685
#endif