Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/drivers/unix/net_socket_unix.cpp
20897 views
1
/**************************************************************************/
2
/* net_socket_unix.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
// Some proprietary Unix-derived platforms don't expose Unix sockets
32
// so this allows skipping this file to reimplement this API differently.
33
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
34
35
#include "net_socket_unix.h"
36
37
#include <fcntl.h>
38
#include <netdb.h>
39
#include <netinet/in.h>
40
#include <netinet/tcp.h>
41
#include <poll.h>
42
#include <sys/ioctl.h>
43
#include <sys/socket.h>
44
#include <sys/stat.h>
45
#include <sys/types.h>
46
#include <unistd.h>
47
#include <cerrno>
48
#include <cstdio>
49
#include <cstdlib>
50
51
#ifdef WEB_ENABLED
52
#include <arpa/inet.h>
53
#endif
54
55
// BSD calls this flag IPV6_JOIN_GROUP
56
#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
57
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
58
#endif
59
#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP)
60
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
61
#endif
62
63
size_t NetSocketUnix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
64
memset(p_addr, 0, sizeof(struct sockaddr_storage));
65
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket.
66
67
// IPv6 only socket with IPv4 address.
68
ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0);
69
70
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
71
addr6->sin6_family = AF_INET6;
72
addr6->sin6_port = htons(p_port);
73
if (p_ip.is_valid()) {
74
memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
75
} else {
76
addr6->sin6_addr = in6addr_any;
77
}
78
return sizeof(sockaddr_in6);
79
} else { // IPv4 socket.
80
81
// IPv4 socket with IPv6 address.
82
ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0);
83
84
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
85
addr4->sin_family = AF_INET;
86
addr4->sin_port = htons(p_port); // Short, network byte order.
87
88
if (p_ip.is_valid()) {
89
memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
90
} else {
91
addr4->sin_addr.s_addr = INADDR_ANY;
92
}
93
94
return sizeof(sockaddr_in);
95
}
96
}
97
98
socklen_t NetSocketUnix::_unix_set_sockaddr(struct sockaddr_un *p_addr, const CharString &p_path) {
99
memset(p_addr, 0, sizeof(struct sockaddr_un));
100
p_addr->sun_family = AF_UNIX;
101
102
// Path must not exceed maximum path length for Unix domain socket
103
size_t path_len = p_path.length();
104
ERR_FAIL_COND_V(path_len >= sizeof(p_addr->sun_path) - 1, 0);
105
106
// Regular file system socket
107
memcpy(p_addr->sun_path, p_path.get_data(), path_len);
108
p_addr->sun_path[path_len] = '\0';
109
return sizeof(struct sockaddr_un);
110
}
111
112
void NetSocketUnix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
113
if (p_addr->ss_family == AF_INET) {
114
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
115
if (r_ip) {
116
r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
117
}
118
if (r_port) {
119
*r_port = ntohs(addr4->sin_port);
120
}
121
} else if (p_addr->ss_family == AF_INET6) {
122
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
123
if (r_ip) {
124
r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
125
}
126
if (r_port) {
127
*r_port = ntohs(addr6->sin6_port);
128
}
129
}
130
}
131
132
NetSocket *NetSocketUnix::_create_func() {
133
return memnew(NetSocketUnix);
134
}
135
136
void NetSocketUnix::make_default() {
137
_create = _create_func;
138
}
139
140
void NetSocketUnix::cleanup() {
141
}
142
143
NetSocketUnix::NetSocketUnix() {
144
}
145
146
NetSocketUnix::~NetSocketUnix() {
147
close();
148
}
149
150
// Silence a warning reported in GH-27594.
151
// EAGAIN and EWOULDBLOCK have the same value on most platforms, but it's not guaranteed.
152
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wlogical-op")
153
154
NetSocketUnix::NetError NetSocketUnix::_get_socket_error() const {
155
if (errno == EISCONN) {
156
return ERR_NET_IS_CONNECTED;
157
}
158
if (errno == EINPROGRESS || errno == EALREADY) {
159
return ERR_NET_IN_PROGRESS;
160
}
161
if (errno == EAGAIN || errno == EWOULDBLOCK) {
162
return ERR_NET_WOULD_BLOCK;
163
}
164
if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) {
165
return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
166
}
167
if (errno == EACCES) {
168
return ERR_NET_UNAUTHORIZED;
169
}
170
if (errno == ENOBUFS) {
171
return ERR_NET_BUFFER_TOO_SMALL;
172
}
173
print_verbose("Socket error: " + itos(errno) + ".");
174
return ERR_NET_OTHER;
175
}
176
177
GODOT_GCC_WARNING_POP
178
179
bool NetSocketUnix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
180
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
181
return false;
182
} else if (!p_for_bind && !p_ip.is_valid()) {
183
return false;
184
}
185
// Check if socket support this IP type.
186
IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
187
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
188
}
189
190
bool NetSocketUnix::_can_use_path(const CharString &p_path) const {
191
// Path must not exceed maximum path length for Unix domain socket
192
return !p_path.is_empty() && (size_t)p_path.length() < sizeof(((sockaddr_un *)0)->sun_path);
193
}
194
195
_FORCE_INLINE_ Error NetSocketUnix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
196
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
197
ERR_FAIL_COND_V(_family != Family::INET, ERR_UNAVAILABLE);
198
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
199
200
// Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4.
201
IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
202
// This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
203
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
204
int ret = -1;
205
206
IPAddress if_ip;
207
uint32_t if_v6id = 0;
208
HashMap<String, IP::Interface_Info> if_info;
209
IP::get_singleton()->get_local_interfaces(&if_info);
210
for (KeyValue<String, IP::Interface_Info> &E : if_info) {
211
IP::Interface_Info &c = E.value;
212
if (c.name != p_if_name) {
213
continue;
214
}
215
216
if_v6id = (uint32_t)c.index.to_int();
217
if (type == IP::TYPE_IPV6) {
218
break; // IPv6 uses index.
219
}
220
221
for (const IPAddress &F : c.ip_addresses) {
222
if (!F.is_ipv4()) {
223
continue; // Wrong IP type.
224
}
225
if_ip = F;
226
break;
227
}
228
break;
229
}
230
231
if (level == IPPROTO_IP) {
232
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
233
struct ip_mreq greq;
234
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
235
memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
236
memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
237
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
238
} else {
239
struct ipv6_mreq greq;
240
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
241
memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
242
greq.ipv6mr_interface = if_v6id;
243
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
244
}
245
ERR_FAIL_COND_V(ret != 0, FAILED);
246
247
return OK;
248
}
249
250
void NetSocketUnix::_set_socket(int p_sock, IP::Type p_ip_type, bool p_is_stream) {
251
_sock = p_sock;
252
_ip_type = p_ip_type;
253
_is_stream = p_is_stream;
254
// Disable descriptor sharing with subprocesses.
255
_set_close_exec_enabled(true);
256
}
257
258
void NetSocketUnix::_set_close_exec_enabled(bool p_enabled) {
259
// Enable close on exec to avoid sharing with subprocesses. Off by default on Windows.
260
int opts = fcntl(_sock, F_GETFD);
261
fcntl(_sock, F_SETFD, opts | FD_CLOEXEC);
262
}
263
264
Error NetSocketUnix::_inet_open(Type p_sock_type, IP::Type &r_ip_type) {
265
ERR_FAIL_COND_V(r_ip_type > IP::TYPE_ANY || r_ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
266
267
#if defined(__OpenBSD__)
268
// OpenBSD does not support dual stacking, fallback to IPv4 only.
269
if (r_ip_type == IP::TYPE_ANY) {
270
r_ip_type = IP::TYPE_IPV4;
271
}
272
#endif
273
274
int family = r_ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
275
int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP;
276
int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM;
277
_sock = socket(family, type, protocol);
278
279
if (_sock == -1 && r_ip_type == IP::TYPE_ANY) {
280
// Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
281
// in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
282
r_ip_type = IP::TYPE_IPV4;
283
family = AF_INET;
284
_sock = socket(family, type, protocol);
285
}
286
287
ERR_FAIL_COND_V(_sock == -1, FAILED);
288
_ip_type = r_ip_type;
289
_family = Family::INET;
290
291
if (family == AF_INET6) {
292
// Select IPv4 over IPv6 mapping.
293
set_ipv6_only_enabled(r_ip_type != IP::TYPE_ANY);
294
}
295
296
if (protocol == IPPROTO_UDP) {
297
// Make sure to disable broadcasting for UDP sockets.
298
// Depending on the OS, this option might or might not be enabled by default. Let's normalize it.
299
set_broadcasting_enabled(false);
300
}
301
302
_is_stream = p_sock_type == TYPE_TCP;
303
304
// Disable descriptor sharing with subprocesses.
305
_set_close_exec_enabled(true);
306
307
#if defined(SO_NOSIGPIPE)
308
// Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS).
309
int par = 1;
310
if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, &par, sizeof(int)) != 0) {
311
print_verbose("Unable to turn off SIGPIPE on socket.");
312
}
313
#endif
314
return OK;
315
}
316
317
Error NetSocketUnix::_unix_open() {
318
_sock = socket(AF_UNIX, SOCK_STREAM, 0);
319
ERR_FAIL_COND_V(_sock == -1, FAILED);
320
321
_family = Family::UNIX;
322
323
_set_close_exec_enabled(true);
324
325
#if defined(SO_NOSIGPIPE)
326
// Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS).
327
int par = 1;
328
if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, &par, sizeof(int)) != 0) {
329
print_verbose("Unable to turn off SIGPIPE on socket.");
330
}
331
#endif
332
333
return OK;
334
}
335
336
Error NetSocketUnix::open(NetSocket::Family p_family, NetSocket::Type p_sock_type, IP::Type &r_ip_type) {
337
ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE);
338
339
switch (p_family) {
340
case Family::INET:
341
return _inet_open(p_sock_type, r_ip_type);
342
case Family::UNIX:
343
return _unix_open();
344
case Family::NONE:
345
default:
346
return ERR_INVALID_PARAMETER;
347
}
348
}
349
350
void NetSocketUnix::close() {
351
if (_sock != -1) {
352
::close(_sock);
353
354
if (_family == Family::UNIX) {
355
if (_unlink_on_close) {
356
::unlink(_unix_path.get_data());
357
_unlink_on_close = false;
358
_unix_path = CharString();
359
}
360
}
361
}
362
363
_sock = -1;
364
_family = Family::NONE;
365
_ip_type = IP::TYPE_NONE;
366
_is_stream = false;
367
}
368
369
Error NetSocketUnix::_inet_bind(IPAddress p_addr, uint16_t p_port) {
370
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
371
372
sockaddr_storage addr;
373
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
374
375
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
376
NetError err = _get_socket_error();
377
print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
378
close();
379
return ERR_UNAVAILABLE;
380
}
381
382
return OK;
383
}
384
385
Error NetSocketUnix::_unix_bind(const CharString &p_path) {
386
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
387
388
struct sockaddr_un addr;
389
socklen_t addr_size = _unix_set_sockaddr(&addr, p_path);
390
ERR_FAIL_COND_V(addr_size == 0, ERR_INVALID_PARAMETER);
391
392
// If the socket file exists, attempt to remove it.
393
if (access(p_path.get_data(), F_OK) == 0) {
394
// Check if it's a socket
395
struct stat st;
396
if (stat(p_path.get_data(), &st) == 0) {
397
if (S_ISSOCK(st.st_mode)) {
398
// It is a socket, try to remove it.
399
if (unlink(p_path.get_data()) != 0) {
400
// Failed to remove existing socket file.
401
return FAILED;
402
}
403
} else {
404
// It's not a socket, don't remove it.
405
return ERR_ALREADY_EXISTS;
406
}
407
}
408
}
409
410
_unlink_on_close = true;
411
412
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
413
NetError err = _get_socket_error();
414
print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
415
close();
416
switch (err) {
417
case ERR_NET_UNAUTHORIZED:
418
return ERR_UNAUTHORIZED;
419
default:
420
return ERR_UNAVAILABLE;
421
}
422
}
423
424
return OK;
425
}
426
427
Error NetSocketUnix::bind(NetSocket::Address p_addr) {
428
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
429
ERR_FAIL_COND_V(_family != p_addr.get_family(), ERR_INVALID_PARAMETER);
430
switch (p_addr.get_family()) {
431
case Family::INET: {
432
return _inet_bind(p_addr.ip(), p_addr.port());
433
}
434
case Family::UNIX: {
435
_unix_path = p_addr.get_path();
436
return _unix_bind(_unix_path);
437
}
438
case Family::NONE:
439
default:
440
return ERR_INVALID_PARAMETER;
441
}
442
}
443
444
Error NetSocketUnix::listen(int p_max_pending) {
445
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
446
447
if (::listen(_sock, p_max_pending) != 0) {
448
_get_socket_error();
449
print_verbose("Failed to listen from socket.");
450
close();
451
return FAILED;
452
}
453
454
return OK;
455
}
456
457
Error NetSocketUnix::_inet_connect_to_host(IPAddress p_host, uint16_t p_port) {
458
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
459
460
struct sockaddr_storage addr;
461
size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type);
462
463
if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
464
NetError err = _get_socket_error();
465
466
switch (err) {
467
// We are already connected.
468
case ERR_NET_IS_CONNECTED:
469
return OK;
470
// Still waiting to connect, try again in a while.
471
case ERR_NET_WOULD_BLOCK:
472
case ERR_NET_IN_PROGRESS:
473
return ERR_BUSY;
474
default:
475
print_verbose("Connection to remote host failed.");
476
close();
477
return FAILED;
478
}
479
}
480
481
return OK;
482
}
483
484
Error NetSocketUnix::_unix_connect_to_host(const CharString &p_path) {
485
ERR_FAIL_COND_V(!_can_use_path(p_path), ERR_INVALID_PARAMETER);
486
487
struct sockaddr_un addr;
488
socklen_t addr_size = _unix_set_sockaddr(&addr, p_path);
489
ERR_FAIL_COND_V(addr_size == 0, ERR_INVALID_PARAMETER);
490
491
if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
492
NetError err = _get_socket_error();
493
switch (err) {
494
case ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE:
495
return ERR_INVALID_PARAMETER;
496
// Still waiting to connect, try again in a while.
497
case ERR_NET_WOULD_BLOCK:
498
case ERR_NET_IN_PROGRESS:
499
return ERR_BUSY;
500
case ERR_NET_UNAUTHORIZED:
501
return ERR_UNAUTHORIZED;
502
default:
503
print_verbose("Connection to host failed.");
504
close();
505
return FAILED;
506
}
507
}
508
509
return OK;
510
}
511
512
Error NetSocketUnix::connect_to_host(NetSocket::Address p_addr) {
513
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
514
ERR_FAIL_COND_V(_family != p_addr.get_family(), ERR_INVALID_PARAMETER);
515
516
switch (p_addr.get_family()) {
517
case Family::INET:
518
return _inet_connect_to_host(p_addr.ip(), p_addr.port());
519
case Family::UNIX:
520
return _unix_connect_to_host(p_addr.get_path());
521
case Family::NONE:
522
default:
523
return ERR_INVALID_PARAMETER;
524
}
525
}
526
527
Error NetSocketUnix::poll(PollType p_type, int p_timeout) const {
528
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
529
530
struct pollfd pfd;
531
pfd.fd = _sock;
532
pfd.events = POLLIN;
533
pfd.revents = 0;
534
535
switch (p_type) {
536
case POLL_TYPE_IN:
537
pfd.events = POLLIN;
538
break;
539
case POLL_TYPE_OUT:
540
pfd.events = POLLOUT;
541
break;
542
case POLL_TYPE_IN_OUT:
543
pfd.events = POLLOUT | POLLIN;
544
}
545
546
int ret = ::poll(&pfd, 1, p_timeout);
547
548
if (ret < 0 || pfd.revents & POLLERR) {
549
_get_socket_error();
550
print_verbose("Error when polling socket.");
551
return FAILED;
552
}
553
554
if (ret == 0) {
555
return ERR_BUSY;
556
}
557
558
return OK;
559
}
560
561
Error NetSocketUnix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
562
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
563
564
r_read = ::recv(_sock, p_buffer, p_len, 0);
565
566
if (r_read < 0) {
567
NetError err = _get_socket_error();
568
if (err == ERR_NET_WOULD_BLOCK) {
569
return ERR_BUSY;
570
}
571
572
if (err == ERR_NET_BUFFER_TOO_SMALL) {
573
return ERR_OUT_OF_MEMORY;
574
}
575
576
return FAILED;
577
}
578
579
return OK;
580
}
581
582
Error NetSocketUnix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
583
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
584
ERR_FAIL_COND_V(_family != Family::INET, ERR_UNAVAILABLE);
585
586
struct sockaddr_storage from;
587
socklen_t len = sizeof(struct sockaddr_storage);
588
memset(&from, 0, len);
589
590
r_read = ::recvfrom(_sock, p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
591
592
if (r_read < 0) {
593
NetError err = _get_socket_error();
594
if (err == ERR_NET_WOULD_BLOCK) {
595
return ERR_BUSY;
596
}
597
598
if (err == ERR_NET_BUFFER_TOO_SMALL) {
599
return ERR_OUT_OF_MEMORY;
600
}
601
602
return FAILED;
603
}
604
605
if (from.ss_family == AF_INET) {
606
struct sockaddr_in *sin_from = (struct sockaddr_in *)&from;
607
r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr);
608
r_port = ntohs(sin_from->sin_port);
609
} else if (from.ss_family == AF_INET6) {
610
struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from;
611
r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr);
612
r_port = ntohs(s6_from->sin6_port);
613
} else {
614
// Unsupported socket family, should never happen.
615
ERR_FAIL_V(FAILED);
616
}
617
618
return OK;
619
}
620
621
Error NetSocketUnix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
622
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
623
624
int flags = 0;
625
#ifdef MSG_NOSIGNAL
626
if (_is_stream || _family == Family::UNIX) {
627
flags = MSG_NOSIGNAL;
628
}
629
#endif
630
r_sent = ::send(_sock, p_buffer, p_len, flags);
631
632
if (r_sent < 0) {
633
NetError err = _get_socket_error();
634
if (err == ERR_NET_WOULD_BLOCK) {
635
return ERR_BUSY;
636
}
637
if (err == ERR_NET_BUFFER_TOO_SMALL) {
638
return ERR_OUT_OF_MEMORY;
639
}
640
641
return FAILED;
642
}
643
644
return OK;
645
}
646
647
Error NetSocketUnix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
648
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
649
ERR_FAIL_COND_V(_family != Family::INET, ERR_UNAVAILABLE);
650
651
struct sockaddr_storage addr;
652
size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type);
653
r_sent = ::sendto(_sock, p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
654
655
if (r_sent < 0) {
656
NetError err = _get_socket_error();
657
if (err == ERR_NET_WOULD_BLOCK) {
658
return ERR_BUSY;
659
}
660
if (err == ERR_NET_BUFFER_TOO_SMALL) {
661
return ERR_OUT_OF_MEMORY;
662
}
663
664
return FAILED;
665
}
666
667
return OK;
668
}
669
670
Error NetSocketUnix::set_broadcasting_enabled(bool p_enabled) {
671
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
672
// IPv6 has no broadcast support.
673
if (_ip_type == IP::TYPE_IPV6) {
674
return ERR_UNAVAILABLE;
675
}
676
677
int par = p_enabled ? 1 : 0;
678
if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, &par, sizeof(int)) != 0) {
679
WARN_PRINT("Unable to change broadcast setting.");
680
return FAILED;
681
}
682
return OK;
683
}
684
685
void NetSocketUnix::set_blocking_enabled(bool p_enabled) {
686
ERR_FAIL_COND(!is_open());
687
688
int ret = 0;
689
int opts = fcntl(_sock, F_GETFL);
690
if (p_enabled) {
691
ret = fcntl(_sock, F_SETFL, opts & ~O_NONBLOCK);
692
} else {
693
ret = fcntl(_sock, F_SETFL, opts | O_NONBLOCK);
694
}
695
696
if (ret != 0) {
697
WARN_PRINT("Unable to change non-block mode.");
698
}
699
}
700
701
void NetSocketUnix::set_ipv6_only_enabled(bool p_enabled) {
702
ERR_FAIL_COND(!is_open());
703
// This option is only available in IPv6 sockets.
704
ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4);
705
706
int par = p_enabled ? 1 : 0;
707
if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, &par, sizeof(int)) != 0) {
708
WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option.");
709
}
710
}
711
712
void NetSocketUnix::set_tcp_no_delay_enabled(bool p_enabled) {
713
ERR_FAIL_COND(!is_open());
714
ERR_FAIL_COND(!_is_stream); // Not TCP.
715
716
int par = p_enabled ? 1 : 0;
717
if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &par, sizeof(int)) < 0) {
718
WARN_PRINT("Unable to set TCP no delay option.");
719
}
720
}
721
722
void NetSocketUnix::set_reuse_address_enabled(bool p_enabled) {
723
ERR_FAIL_COND(!is_open());
724
725
int par = p_enabled ? 1 : 0;
726
if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, &par, sizeof(int)) < 0) {
727
WARN_PRINT("Unable to set socket REUSEADDR option.");
728
}
729
}
730
731
bool NetSocketUnix::is_open() const {
732
return _sock != -1;
733
}
734
735
int NetSocketUnix::get_available_bytes() const {
736
ERR_FAIL_COND_V(!is_open(), -1);
737
738
int len;
739
int ret = ioctl(_sock, FIONREAD, &len);
740
if (ret == -1) {
741
_get_socket_error();
742
print_verbose("Error when checking available bytes on socket.");
743
return -1;
744
}
745
return len;
746
}
747
748
Error NetSocketUnix::_inet_get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
749
struct sockaddr_storage saddr;
750
socklen_t len = sizeof(saddr);
751
if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
752
_get_socket_error();
753
print_verbose("Error when reading local socket address.");
754
return FAILED;
755
}
756
_set_ip_port(&saddr, r_ip, r_port);
757
return OK;
758
}
759
760
Error NetSocketUnix::get_socket_address(NetSocket::Address *r_addr) const {
761
ERR_FAIL_COND_V(!is_open(), FAILED);
762
switch (_family) {
763
case Family::INET: {
764
IPAddress ip;
765
uint16_t port = 0;
766
Error res = _inet_get_socket_address(&ip, &port);
767
ERR_FAIL_COND_V(res != OK, res);
768
if (r_addr) {
769
Address addr(ip, port);
770
*r_addr = addr;
771
}
772
} break;
773
case Family::UNIX: {
774
if (r_addr) {
775
*r_addr = Address(_unix_path);
776
}
777
} break;
778
case Family::NONE:
779
default:
780
return FAILED;
781
}
782
783
return OK;
784
}
785
786
Ref<NetSocket> NetSocketUnix::_inet_accept(IPAddress &r_ip, uint16_t &r_port) {
787
struct sockaddr_storage their_addr;
788
socklen_t size = sizeof(their_addr);
789
int fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
790
if (fd == -1) {
791
_get_socket_error();
792
print_verbose("Error when accepting socket connection.");
793
return Ref<NetSocket>();
794
}
795
796
_set_ip_port(&their_addr, &r_ip, &r_port);
797
798
NetSocketUnix *ns = memnew(NetSocketUnix);
799
ns->_set_socket(fd, _ip_type, _is_stream);
800
ns->set_blocking_enabled(false);
801
return Ref<NetSocket>(ns);
802
}
803
804
Ref<NetSocket> NetSocketUnix::_unix_accept() {
805
struct sockaddr_un addr;
806
socklen_t addr_len = sizeof(addr);
807
808
int fd = ::accept(_sock, (struct sockaddr *)&addr, &addr_len);
809
if (fd == -1) {
810
_get_socket_error();
811
print_verbose("Error when accepting socket connection.");
812
return Ref<NetSocket>();
813
}
814
815
NetSocketUnix *ret = memnew(NetSocketUnix);
816
ret->_sock = fd;
817
ret->_family = _family;
818
ret->_unix_path = _unix_path;
819
ret->set_blocking_enabled(false);
820
return Ref<NetSocket>(ret);
821
}
822
823
Ref<NetSocket> NetSocketUnix::accept(NetSocket::Address &r_addr) {
824
Ref<NetSocket> out;
825
ERR_FAIL_COND_V(!is_open(), out);
826
827
switch (_family) {
828
case Family::INET: {
829
IPAddress ip;
830
uint16_t port;
831
out = _inet_accept(ip, port);
832
if (out.is_valid()) {
833
r_addr = Address(ip, port);
834
}
835
} break;
836
case Family::UNIX: {
837
out = _unix_accept();
838
} break;
839
case Family::NONE:
840
default:
841
break;
842
}
843
return out;
844
}
845
846
Error NetSocketUnix::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
847
return _change_multicast_group(p_multi_address, p_if_name, true);
848
}
849
850
Error NetSocketUnix::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
851
return _change_multicast_group(p_multi_address, p_if_name, false);
852
}
853
854
#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
855
856