Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/os_network.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2026 The TokTok team.
3
 * Copyright © 2013 Tox project.
4
 */
5
6
#ifdef __APPLE__
7
#define _DARWIN_C_SOURCE
8
#endif /* __APPLE__ */
9
10
// For Solaris.
11
#ifdef __sun
12
#define __EXTENSIONS__ 1
13
#endif /* __sun */
14
15
// For Linux (and some BSDs).
16
#ifndef _XOPEN_SOURCE
17
#define _XOPEN_SOURCE 700
18
#endif /* _XOPEN_SOURCE */
19
20
#include "os_network.h"
21
22
#if defined(_WIN32) && defined(_WIN32_WINNT) && defined(_WIN32_WINNT_WINXP) && _WIN32_WINNT >= _WIN32_WINNT_WINXP
23
#undef _WIN32_WINNT
24
#define _WIN32_WINNT  0x501
25
#endif /* defined(_WIN32) && defined(_WIN32_WINNT) && defined(_WIN32_WINNT_WINXP) && _WIN32_WINNT >= _WIN32_WINNT_WINXP */
26
27
#if !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
28
#define OS_WIN32
29
#endif /* !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) */
30
31
#if defined(OS_WIN32) && !defined(WINVER)
32
// Windows XP
33
#define WINVER 0x0501
34
#endif /* defined(OS_WIN32) && !defined(WINVER) */
35
36
#ifdef OS_WIN32
37
#include <winsock2.h>
38
#include <windows.h>
39
#include <ws2tcpip.h>
40
#endif /* OS_WIN32 */
41
42
#if !defined(OS_WIN32)
43
#include <arpa/inet.h>
44
#include <errno.h>
45
#include <fcntl.h>
46
#include <netdb.h>
47
#include <netinet/in.h>
48
#include <sys/ioctl.h>
49
#include <sys/socket.h>
50
#include <sys/time.h>
51
#include <sys/types.h>
52
#include <unistd.h>
53
54
#ifdef __sun
55
#include <stropts.h>
56
#include <sys/filio.h>
57
#endif /* __sun */
58
59
#else
60
#ifndef IPV6_V6ONLY
61
#define IPV6_V6ONLY 27
62
#endif /* IPV6_V6ONLY */
63
#endif /* !defined(OS_WIN32) */
64
65
#include <assert.h>
66
#include <stdio.h>
67
#include <stdlib.h>
68
#include <string.h>
69
70
#include "attributes.h"
71
#include "ccompat.h"
72
#include "mem.h"
73
#include "net.h"
74
75
// Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD
76
#if !defined(MSG_NOSIGNAL)
77
#define MSG_NOSIGNAL 0
78
#endif /* !defined(MSG_NOSIGNAL) */
79
80
static int make_proto(int proto)
81
570
{
82
570
    switch (proto) {
83
100
        case TOX_PROTO_TCP:
84
100
            return IPPROTO_TCP;
85
86
460
        case TOX_PROTO_UDP:
87
460
            return IPPROTO_UDP;
88
89
10
        default:
90
10
            return proto;
91
570
    }
92
570
}
93
94
static int make_socktype(int type)
95
588
{
96
588
    switch (type) {
97
110
        case TOX_SOCK_STREAM:
98
110
            return SOCK_STREAM;
99
100
465
        case TOX_SOCK_DGRAM:
101
465
            return SOCK_DGRAM;
102
103
13
        default:
104
13
            return type;
105
588
    }
106
588
}
107
108
static int make_family(int family_value)
109
588
{
110
588
    switch (family_value) {
111
544
        case TOX_AF_INET:
112
544
        case TCP_INET:
113
544
            return AF_INET;
114
115
36
        case TOX_AF_INET6:
116
36
        case TCP_INET6:
117
36
            return AF_INET6;
118
119
8
        case TOX_AF_UNSPEC:
120
8
            return AF_UNSPEC;
121
122
0
        default:
123
0
            return family_value;
124
588
    }
125
588
}
126
127
static void get_ip4(IP4 *_Nonnull result, const struct in_addr *_Nonnull addr)
128
478k
{
129
478k
    static_assert(sizeof(result->uint32) == sizeof(addr->s_addr),
130
478k
                  "Tox and operating system don't agree on size of IPv4 addresses");
131
478k
    result->uint32 = addr->s_addr;
132
478k
}
133
134
static void get_ip6(IP6 *_Nonnull result, const struct in6_addr *_Nonnull addr)
135
40.1k
{
136
40.1k
    static_assert(sizeof(result->uint8) == sizeof(addr->s6_addr),
137
40.1k
                  "Tox and operating system don't agree on size of IPv6 addresses");
138
40.1k
    memcpy(result->uint8, addr->s6_addr, sizeof(result->uint8));
139
40.1k
}
140
141
static void fill_addr4(const IP4 *_Nonnull ip, struct in_addr *_Nonnull addr)
142
2.08M
{
143
2.08M
    addr->s_addr = ip->uint32;
144
2.08M
}
145
146
static void fill_addr6(const IP6 *_Nonnull ip, struct in6_addr *_Nonnull addr)
147
42.6k
{
148
42.6k
    memcpy(addr->s6_addr, ip->uint8, sizeof(ip->uint8));
149
42.6k
}
150
151
#ifndef OS_WIN32
152
2.38k
#define INVALID_SOCKET (-1)
153
#endif /* OS_WIN32 */
154
155
typedef struct Network_Addr {
156
    struct sockaddr_storage addr;
157
    size_t size;
158
} Network_Addr;
159
160
static void ip_port_to_network_addr(const IP_Port *_Nonnull ip_port, Network_Addr *_Nonnull addr)
161
553k
{
162
553k
    addr->size = 0;
163
553k
    if (net_family_is_ipv4(ip_port->ip.family)) {
164
512k
        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr->addr;
165
512k
        addr->size = sizeof(struct sockaddr_in);
166
512k
        addr4->sin_family = AF_INET;
167
512k
        fill_addr4(&ip_port->ip.ip.v4, &addr4->sin_addr);
168
512k
        addr4->sin_port = ip_port->port;
169
512k
    } else if (net_family_is_ipv6(ip_port->ip.family)) {
170
40.8k
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr->addr;
171
40.8k
        addr->size = sizeof(struct sockaddr_in6);
172
40.8k
        addr6->sin6_family = AF_INET6;
173
40.8k
        fill_addr6(&ip_port->ip.ip.v6, &addr6->sin6_addr);
174
40.8k
        addr6->sin6_port = ip_port->port;
175
40.8k
        addr6->sin6_flowinfo = 0;
176
40.8k
        addr6->sin6_scope_id = 0;
177
40.8k
    }
178
553k
}
179
180
static bool network_addr_to_ip_port(const Network_Addr *_Nonnull addr, IP_Port *_Nonnull ip_port)
181
489k
{
182
489k
    if (addr->addr.ss_family == AF_INET) {
183
449k
        const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr->addr;
184
449k
        ip_port->ip.family = net_family_ipv4();
185
449k
        get_ip4(&ip_port->ip.ip.v4, &addr_in->sin_addr);
186
449k
        ip_port->port = addr_in->sin_port;
187
449k
        return true;
188
449k
    } else if (addr->addr.ss_family == AF_INET6) {
189
40.1k
        const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr->addr;
190
40.1k
        ip_port->ip.family = net_family_ipv6();
191
40.1k
        get_ip6(&ip_port->ip.ip.v6, &addr_in6->sin6_addr);
192
40.1k
        ip_port->port = addr_in6->sin6_port;
193
40.1k
        return true;
194
40.1k
    }
195
78
    return false;
196
489k
}
197
198
#if !defined(OS_WIN32)
199
200
static bool should_ignore_recv_error(int err)
201
102k
{
202
102k
    return err == EWOULDBLOCK;
203
102k
}
204
205
static bool should_ignore_connect_error(int err)
206
77
{
207
77
    return err == EWOULDBLOCK || err == EINPROGRESS;
208
77
}
209
210
static const char *_Nullable inet_ntop4(const struct in_addr *_Nonnull addr, char *_Nonnull buf, size_t bufsize)
211
1.57M
{
212
1.57M
    return inet_ntop(AF_INET, addr, buf, bufsize);
213
1.57M
}
214
215
static const char *_Nullable inet_ntop6(const struct in6_addr *_Nonnull addr, char *_Nonnull buf, size_t bufsize)
216
1.73k
{
217
1.73k
    return inet_ntop(AF_INET6, addr, buf, bufsize);
218
1.73k
}
219
220
static int inet_pton4(const char *_Nonnull addr_string, struct in_addr *_Nonnull addrbuf)
221
28.6k
{
222
28.6k
    return inet_pton(AF_INET, addr_string, addrbuf);
223
28.6k
}
224
225
static int inet_pton6(const char *_Nonnull addr_string, struct in6_addr *_Nonnull addrbuf)
226
5
{
227
5
    return inet_pton(AF_INET6, addr_string, addrbuf);
228
5
}
229
230
#else
231
232
static bool should_ignore_recv_error(int err)
233
{
234
    // We ignore WSAECONNRESET as Windows helpfully* sends that error if a
235
    // previously sent UDP packet wasn't delivered.
236
    return err == WSAEWOULDBLOCK || err == WSAECONNRESET;
237
}
238
239
static bool should_ignore_connect_error(int err)
240
{
241
    return err == WSAEWOULDBLOCK || err == WSAEINPROGRESS;
242
}
243
244
static const char *_Nullable inet_ntop4(const struct in_addr *_Nonnull addr, char *_Nonnull buf, size_t bufsize)
245
{
246
    struct sockaddr_in saddr = {0};
247
248
    saddr.sin_family = AF_INET;
249
    saddr.sin_addr = *addr;
250
251
    DWORD len = (DWORD)bufsize;
252
253
    if (WSAAddressToStringA((LPSOCKADDR)&saddr, sizeof(saddr), nullptr, buf, &len)) {
254
        return nullptr;
255
    }
256
257
    return buf;
258
}
259
260
static const char *_Nullable inet_ntop6(const struct in6_addr *_Nonnull addr, char *_Nonnull buf, size_t bufsize)
261
{
262
    struct sockaddr_in6 saddr = {0};
263
264
    saddr.sin6_family = AF_INET6;
265
    saddr.sin6_addr = *addr;
266
267
    DWORD len = (DWORD)bufsize;
268
269
    if (WSAAddressToStringA((LPSOCKADDR)&saddr, sizeof(saddr), nullptr, buf, &len)) {
270
        return nullptr;
271
    }
272
273
    return buf;
274
}
275
276
static int inet_pton4(const char *_Nonnull addrString, struct in_addr *_Nonnull addrbuf)
277
{
278
    struct sockaddr_in saddr = {0};
279
280
    INT len = sizeof(saddr);
281
282
    if (WSAStringToAddressA((LPSTR)addrString, AF_INET, nullptr, (LPSOCKADDR)&saddr, &len)) {
283
        return 0;
284
    }
285
286
    *addrbuf = saddr.sin_addr;
287
288
    return 1;
289
}
290
291
static int inet_pton6(const char *_Nonnull addrString, struct in6_addr *_Nonnull addrbuf)
292
{
293
    struct sockaddr_in6 saddr = {0};
294
295
    INT len = sizeof(saddr);
296
297
    if (WSAStringToAddressA((LPSTR)addrString, AF_INET6, nullptr, (LPSOCKADDR)&saddr, &len)) {
298
        return 0;
299
    }
300
301
    *addrbuf = saddr.sin6_addr;
302
303
    return 1;
304
}
305
306
#endif /* !defined(OS_WIN32) */
307
308
const char *net_inet_ntop4(const IP4 *addr, char *buf, size_t bufsize)
309
1.57M
{
310
1.57M
    struct in_addr a;
311
1.57M
    fill_addr4(addr, &a);
312
1.57M
    return inet_ntop4(&a, buf, bufsize);
313
1.57M
}
314
315
const char *net_inet_ntop6(const IP6 *addr, char *buf, size_t bufsize)
316
1.73k
{
317
1.73k
    struct in6_addr a;
318
1.73k
    fill_addr6(addr, &a);
319
1.73k
    return inet_ntop6(&a, buf, bufsize);
320
1.73k
}
321
322
int net_inet_pton4(const char *addr_string, IP4 *addrbuf)
323
28.6k
{
324
28.6k
    struct in_addr a;
325
28.6k
    const int ret = inet_pton4(addr_string, &a);
326
28.6k
    if (ret == 1) {
327
28.6k
        get_ip4(addrbuf, &a);
328
28.6k
    }
329
28.6k
    return ret;
330
28.6k
}
331
332
int net_inet_pton6(const char *addr_string, IP6 *addrbuf)
333
5
{
334
5
    struct in6_addr a;
335
5
    const int ret = inet_pton6(addr_string, &a);
336
5
    if (ret == 1) {
337
0
        get_ip6(addrbuf, &a);
338
0
    }
339
5
    return ret;
340
5
}
341
342
bool net_should_ignore_recv_error(int err)
343
102k
{
344
102k
    return should_ignore_recv_error(err);
345
102k
}
346
347
bool net_should_ignore_connect_error(int err)
348
77
{
349
77
    return should_ignore_connect_error(err);
350
77
}
351
352
static int sys_close(void *_Nullable obj, Socket sock)
353
525
{
354
#if defined(OS_WIN32)
355
    return closesocket(net_socket_to_native(sock));
356
#else  // !OS_WIN32
357
525
    return close(net_socket_to_native(sock));
358
525
#endif /* OS_WIN32 */
359
525
}
360
361
static Socket sys_accept(void *_Nullable obj, Socket sock)
362
88
{
363
88
    return net_socket_from_native(accept(net_socket_to_native(sock), nullptr, nullptr));
364
88
}
365
366
static int sys_bind(void *_Nullable obj, Socket sock, const IP_Port *_Nonnull addr)
367
31.4k
{
368
31.4k
    Network_Addr naddr;
369
31.4k
    ip_port_to_network_addr(addr, &naddr);
370
31.4k
    if (naddr.size == 0) {
371
0
        return -1;
372
0
    }
373
31.4k
    return bind(net_socket_to_native(sock), (const struct sockaddr *)&naddr.addr, (socklen_t)naddr.size);
374
31.4k
}
375
376
static int sys_listen(void *_Nullable obj, Socket sock, int backlog)
377
19
{
378
19
    return listen(net_socket_to_native(sock), backlog);
379
19
}
380
381
static int sys_connect(void *_Nullable obj, Socket sock, const IP_Port *_Nonnull addr)
382
81
{
383
81
    Network_Addr naddr;
384
81
    ip_port_to_network_addr(addr, &naddr);
385
81
    if (naddr.size == 0) {
386
0
        return -1;
387
0
    }
388
81
    return connect(net_socket_to_native(sock), (const struct sockaddr *)&naddr.addr, (socklen_t)naddr.size);
389
81
}
390
391
static int sys_recvbuf(void *_Nullable obj, Socket sock)
392
77.1k
{
393
#ifdef OS_WIN32
394
    u_long count = 0;
395
    ioctlsocket(net_socket_to_native(sock), FIONREAD, &count);
396
#else
397
77.1k
    int count = 0;
398
77.1k
    ioctl(net_socket_to_native(sock), FIONREAD, &count);
399
77.1k
#endif /* OS_WIN32 */
400
401
77.1k
    return count;
402
77.1k
}
403
404
static int sys_recv(void *_Nullable obj, Socket sock, uint8_t *_Nonnull buf, size_t len)
405
33.3k
{
406
33.3k
    return recv(net_socket_to_native(sock), (char *)buf, len, MSG_NOSIGNAL);
407
33.3k
}
408
409
static int sys_send(void *_Nullable obj, Socket sock, const uint8_t *_Nonnull buf, size_t len)
410
17.5k
{
411
17.5k
    return send(net_socket_to_native(sock), (const char *)buf, len, MSG_NOSIGNAL);
412
17.5k
}
413
414
static int sys_sendto(void *_Nullable obj, Socket sock, const uint8_t *_Nonnull buf, size_t len, const IP_Port *_Nonnull addr)
415
521k
{
416
521k
    Network_Addr naddr;
417
521k
    ip_port_to_network_addr(addr, &naddr);
418
521k
    if (naddr.size == 0) {
419
0
        return -1;
420
0
    }
421
521k
    return sendto(net_socket_to_native(sock), (const char *)buf, len, 0, (const struct sockaddr *)&naddr.addr, (socklen_t)naddr.size);
422
521k
}
423
424
static int sys_recvfrom(void *_Nullable obj, Socket sock, uint8_t *_Nonnull buf, size_t len, IP_Port *_Nonnull addr)
425
584k
{
426
584k
    Network_Addr naddr = {{0}};
427
584k
    socklen_t addrlen = sizeof(naddr.addr);
428
584k
    const int ret = recvfrom(net_socket_to_native(sock), (char *)buf, len, 0, (struct sockaddr *)&naddr.addr, &addrlen);
429
584k
    naddr.size = addrlen;
430
584k
    if (ret >= 0) {
431
489k
        if (!network_addr_to_ip_port(&naddr, addr)) {
432
            // Ignore packets from unknown families
433
0
            return -1;
434
0
        }
435
489k
    }
436
584k
    return ret;
437
584k
}
438
439
static Socket sys_socket(void *_Nullable obj, int domain, int type, int proto)
440
570
{
441
570
    const int platform_domain = make_family(domain);
442
570
    const int platform_type = make_socktype(type);
443
570
    const int platform_prot = make_proto(proto);
444
570
    return net_socket_from_native(socket(platform_domain, platform_type, platform_prot));
445
570
}
446
447
static int sys_socket_nonblock(void *_Nullable obj, Socket sock, bool nonblock)
448
619
{
449
#ifdef OS_WIN32
450
    u_long mode = nonblock ? 1 : 0;
451
    return ioctlsocket(net_socket_to_native(sock), FIONBIO, &mode);
452
#else
453
619
    const int fd = net_socket_to_native(sock);
454
619
    int flags = fcntl(fd, F_GETFL, 0);
455
619
    if (flags == -1) {
456
0
        return -1;
457
0
    }
458
619
    if (nonblock) {
459
619
        flags |= O_NONBLOCK;
460
619
    } else {
461
0
        flags &= ~O_NONBLOCK;
462
0
    }
463
619
    return fcntl(fd, F_SETFL, flags);
464
619
#endif /* OS_WIN32 */
465
619
}
466
467
static int sys_getsockopt(void *_Nullable obj, Socket sock, int level, int optname, void *_Nonnull optval, size_t *_Nonnull optlen)
468
32
{
469
32
    socklen_t len = (socklen_t) * optlen;
470
32
    const int ret = getsockopt(net_socket_to_native(sock), level, optname, (char *)optval, &len);
471
32
    *optlen = len;
472
32
    return ret;
473
32
}
474
475
static int sys_setsockopt(void *_Nullable obj, Socket sock, int level, int optname, const void *_Nonnull optval, size_t optlen)
476
1.42k
{
477
#ifdef EMSCRIPTEN
478
    return 0;
479
#else
480
1.42k
    return setsockopt(net_socket_to_native(sock), level, optname, (const char *)optval, (socklen_t)optlen);
481
1.42k
#endif /* EMSCRIPTEN */
482
1.42k
}
483
484
static int sys_getaddrinfo(void *_Nullable obj, const Memory *_Nonnull mem, const char *_Nonnull address, int family, int sock_type, IP_Port *_Nullable *_Nonnull addrs)
485
18
{
486
18
    assert(addrs != nullptr);
487
488
18
    struct addrinfo hints = {0};
489
18
    hints.ai_family = make_family(family);
490
18
    hints.ai_socktype = make_socktype(sock_type);
491
492
18
    struct addrinfo *infos = nullptr;
493
494
18
    const int rc = getaddrinfo(address, nullptr, &hints, &infos);
495
496
18
    if (rc != 0) {
497
0
        return 0;
498
0
    }
499
500
18
    const int32_t max_count = INT32_MAX / sizeof(IP_Port);
501
502
18
    int result = 0;
503
85
    for (struct addrinfo *walker = infos; walker != nullptr && result < max_count; walker = walker->ai_next) {
504
67
        if (walker->ai_family == hints.ai_family || hints.ai_family == AF_UNSPEC) {
505
67
            ++result;
506
67
        }
507
67
    }
508
509
18
    assert(max_count >= result);
510
511
18
    IP_Port *tmp_addrs = (IP_Port *)mem_valloc(mem, result, sizeof(IP_Port));
512
18
    if (tmp_addrs == nullptr) {
513
0
        freeaddrinfo(infos);
514
0
        return 0;
515
0
    }
516
517
18
    int i = 0;
518
85
    for (struct addrinfo *walker = infos; walker != nullptr; walker = walker->ai_next) {
519
67
        if (walker->ai_family == hints.ai_family || hints.ai_family == AF_UNSPEC) {
520
67
            Network_Addr naddr;
521
67
            naddr.size = walker->ai_addrlen;
522
67
            memcpy(&naddr.addr, walker->ai_addr, walker->ai_addrlen);
523
524
67
            if (network_addr_to_ip_port(&naddr, &tmp_addrs[i])) {
525
67
                ++i;
526
67
            }
527
67
        }
528
67
    }
529
530
18
    result = i;
531
18
    freeaddrinfo(infos);
532
18
    *addrs = tmp_addrs;
533
534
18
    return result;
535
18
}
536
537
static int sys_freeaddrinfo(void *_Nullable obj, const Memory *_Nonnull mem, IP_Port *_Nullable addrs)
538
13
{
539
13
    if (addrs == nullptr) {
540
0
        return 0;
541
0
    }
542
543
13
    mem_delete(mem, addrs);
544
545
13
    return 0;
546
13
}
547
548
static const Network_Funcs os_network_funcs = {
549
    sys_close,
550
    sys_accept,
551
    sys_bind,
552
    sys_listen,
553
    sys_connect,
554
    sys_recvbuf,
555
    sys_recv,
556
    sys_recvfrom,
557
    sys_send,
558
    sys_sendto,
559
    sys_socket,
560
    sys_socket_nonblock,
561
    sys_getsockopt,
562
    sys_setsockopt,
563
    sys_getaddrinfo,
564
    sys_freeaddrinfo,
565
};
566
const Network os_network_obj = {&os_network_funcs, nullptr};
567
568
const Network *os_network(void)
569
2.02k
{
570
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
571
1.47k
    if ((true)) {
572
1.47k
        return nullptr;
573
1.47k
    }
574
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
575
#ifdef OS_WIN32
576
    WSADATA wsaData;
577
578
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) {
579
        return nullptr;
580
    }
581
#endif /* OS_WIN32 */
582
0
    return &os_network_obj;
583
2.02k
}
os_network
Line
Count
Source
569
1.47k
{
570
1.47k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
571
1.47k
    if ((true)) {
572
1.47k
        return nullptr;
573
1.47k
    }
574
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
575
#ifdef OS_WIN32
576
    WSADATA wsaData;
577
578
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) {
579
        return nullptr;
580
    }
581
#endif /* OS_WIN32 */
582
0
    return &os_network_obj;
583
1.47k
}
os_network
Line
Count
Source
569
546
{
570
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
571
    if ((true)) {
572
        return nullptr;
573
    }
574
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
575
#ifdef OS_WIN32
576
    WSADATA wsaData;
577
578
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) {
579
        return nullptr;
580
    }
581
#endif /* OS_WIN32 */
582
546
    return &os_network_obj;
583
546
}
584
585
Socket net_invalid_socket(void)
586
2.38k
{
587
2.38k
    return net_socket_from_native(INVALID_SOCKET);
588
2.38k
}
589
590
uint32_t net_htonl(uint32_t hostlong)
591
1.07M
{
592
1.07M
    return htonl(hostlong);
593
1.07M
}
594
595
uint16_t net_htons(uint16_t hostshort)
596
248k
{
597
248k
    return htons(hostshort);
598
248k
}
599
600
uint32_t net_ntohl(uint32_t hostlong)
601
806k
{
602
806k
    return ntohl(hostlong);
603
806k
}
604
605
uint16_t net_ntohs(uint16_t hostshort)
606
2.82M
{
607
2.82M
    return ntohs(hostshort);
608
2.82M
}
609
610
#if !defined(INADDR_LOOPBACK)
611
#define INADDR_LOOPBACK 0x7f000001
612
#endif /* !defined(INADDR_LOOPBACK) */
613
614
IP4 net_get_ip4_broadcast(void)
615
31
{
616
31
    const IP4 ip4_broadcast = {INADDR_BROADCAST};
617
31
    return ip4_broadcast;
618
31
}
619
620
IP6 net_get_ip6_broadcast(void)
621
132
{
622
132
    const IP6 ip6_broadcast = {
623
132
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
624
132
    };
625
132
    return ip6_broadcast;
626
132
}
627
628
IP4 net_get_ip4_loopback(void)
629
155
{
630
155
    IP4 loopback;
631
155
    loopback.uint32 = htonl(INADDR_LOOPBACK);
632
155
    return loopback;
633
155
}
634
635
IP6 net_get_ip6_loopback(void)
636
3
{
637
    /* in6addr_loopback isn't available everywhere, so we do it ourselves. */
638
3
    IP6 loopback = {{0}};
639
3
    loopback.uint8[15] = 1;
640
3
    return loopback;
641
3
}
642
643
#ifndef IPV6_ADD_MEMBERSHIP
644
#ifdef IPV6_JOIN_GROUP
645
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
646
#endif /* IPV6_JOIN_GROUP */
647
#endif /* IPV6_ADD_MEMBERSHIP */
648
649
bool net_join_multicast(const Network *ns, Socket sock, Family family)
650
1.47k
{
651
1.47k
#ifndef ESP_PLATFORM
652
1.47k
    if (net_family_is_ipv6(family)) {
653
        /* multicast local nodes */
654
1.47k
        struct ipv6_mreq mreq = {{{{0}}}};
655
1.47k
        mreq.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
656
1.47k
        mreq.ipv6mr_multiaddr.s6_addr[1] = 0x02;
657
1.47k
        mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
658
1.47k
        mreq.ipv6mr_interface = 0;
659
660
1.47k
        return ns_setsockopt(ns, sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0;
661
1.47k
    }
662
0
#endif /* ESP_PLATFORM */
663
0
    return false;
664
1.47k
}
665
666
bool net_set_socket_nonblock(const Network *ns, Socket sock)
667
2.21k
{
668
2.21k
    return ns_socket_nonblock(ns, sock, true) == 0;
669
2.21k
}
670
671
bool net_set_socket_nosigpipe(const Network *ns, Socket sock)
672
2.17k
{
673
#if defined(__APPLE__)
674
    int set = 1;
675
    return ns_setsockopt(ns, sock, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == 0;
676
#else
677
2.17k
    return true;
678
2.17k
#endif /* __APPLE__ */
679
2.17k
}
680
681
bool net_set_socket_reuseaddr(const Network *ns, Socket sock)
682
34
{
683
34
    int set = 1;
684
#if defined(OS_WIN32)
685
    return ns_setsockopt(ns, sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &set, sizeof(set)) == 0;
686
#else
687
34
    return ns_setsockopt(ns, sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == 0;
688
34
#endif /* OS_WIN32 */
689
34
}
690
691
bool net_set_socket_dualstack(const Network *ns, Socket sock)
692
1.49k
{
693
1.49k
    int ipv6only = 0;
694
1.49k
    size_t optsize = sizeof(ipv6only);
695
1.49k
    const int res = ns_getsockopt(ns, sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize);
696
697
1.49k
    if ((res == 0) && (ipv6only == 0)) {
698
1.48k
        return true;
699
1.48k
    }
700
701
1
    ipv6only = 0;
702
1
    return ns_setsockopt(ns, sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0;
703
1.49k
}
704
705
bool net_set_socket_buffer_size(const Network *ns, Socket sock, int size)
706
2.00k
{
707
2.00k
    bool ok = true;
708
709
2.00k
    if (ns_setsockopt(ns, sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
710
3
        ok = false;
711
3
    }
712
713
2.00k
    if (ns_setsockopt(ns, sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
714
3
        ok = false;
715
3
    }
716
717
2.00k
    return ok;
718
2.00k
}
719
720
bool net_set_socket_broadcast(const Network *ns, Socket sock)
721
2.00k
{
722
2.00k
    int broadcast = 1;
723
2.00k
    return ns_setsockopt(ns, sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == 0;
724
2.00k
}
725
726
int net_error(void)
727
105k
{
728
#ifdef OS_WIN32
729
    return WSAGetLastError();
730
#else
731
105k
    return errno;
732
105k
#endif /* OS_WIN32 */
733
105k
}
734
735
void net_clear_error(void)
736
2.08k
{
737
#ifdef OS_WIN32
738
    WSASetLastError(0);
739
#else
740
2.08k
    errno = 0;
741
2.08k
#endif /* OS_WIN32 */
742
2.08k
}
743
744
#ifdef OS_WIN32
745
char *net_strerror(int error, Net_Strerror *buf)
746
{
747
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
748
                   error, 0, buf->data, NET_STRERROR_SIZE, nullptr);
749
    return buf->data;
750
}
751
#else
752
#if defined(_GNU_SOURCE) && defined(__GLIBC__)
753
static const char *_Nonnull net_strerror_r(int error, char *_Nonnull tmp, size_t tmp_size)
754
{
755
    const char *retstr = strerror_r(error, tmp, tmp_size);
756
757
    if (errno != 0) {
758
        snprintf(tmp, tmp_size, "error %d (strerror_r failed with errno %d)", error, errno);
759
    }
760
761
    return retstr;
762
}
763
#else
764
static const char *_Nonnull net_strerror_r(int error, char *_Nonnull tmp, size_t tmp_size)
765
2.24k
{
766
2.24k
    const int fmt_error = strerror_r(error, tmp, tmp_size);
767
768
2.24k
    if (fmt_error != 0) {
769
0
        snprintf(tmp, tmp_size, "error %d (strerror_r failed with error %d, errno %d)", error, fmt_error, errno);
770
0
    }
771
772
2.24k
    return tmp;
773
2.24k
}
774
#endif /* GNU */
775
char *net_strerror(int error, Net_Strerror *buf)
776
2.24k
{
777
2.24k
    errno = 0;
778
779
2.24k
    const char *retstr = net_strerror_r(error, buf->data, NET_STRERROR_SIZE);
780
2.24k
    const size_t retstr_len = strlen(retstr);
781
2.24k
    assert(retstr_len < NET_STRERROR_SIZE);
782
2.24k
    buf->size = (uint16_t)retstr_len;
783
784
2.24k
    return buf->data;
785
2.24k
}
786
#endif /* OS_WIN32 */