/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 | } 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 | } |
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 */ |