Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/drivers/windows/net_socket_winsock.cpp
20849 views
1
/**************************************************************************/
2
/* net_socket_winsock.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
#ifdef WINDOWS_ENABLED
32
33
#include "net_socket_winsock.h"
34
35
#include <winsock2.h>
36
#include <ws2tcpip.h>
37
38
#include <mswsock.h>
39
// Workaround missing flag in MinGW
40
#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
41
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
42
#endif
43
44
size_t NetSocketWinSock::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
45
memset(p_addr, 0, sizeof(struct sockaddr_storage));
46
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket.
47
48
// IPv6 only socket with IPv4 address.
49
ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0);
50
51
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
52
addr6->sin6_family = AF_INET6;
53
addr6->sin6_port = htons(p_port);
54
if (p_ip.is_valid()) {
55
memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
56
} else {
57
addr6->sin6_addr = in6addr_any;
58
}
59
return sizeof(sockaddr_in6);
60
} else { // IPv4 socket.
61
62
// IPv4 socket with IPv6 address.
63
ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0);
64
65
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
66
addr4->sin_family = AF_INET;
67
addr4->sin_port = htons(p_port); // Short, network byte order.
68
69
if (p_ip.is_valid()) {
70
memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
71
} else {
72
addr4->sin_addr.s_addr = INADDR_ANY;
73
}
74
75
return sizeof(sockaddr_in);
76
}
77
}
78
79
void NetSocketWinSock::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
80
if (p_addr->ss_family == AF_INET) {
81
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
82
if (r_ip) {
83
r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
84
}
85
if (r_port) {
86
*r_port = ntohs(addr4->sin_port);
87
}
88
} else if (p_addr->ss_family == AF_INET6) {
89
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
90
if (r_ip) {
91
r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
92
}
93
if (r_port) {
94
*r_port = ntohs(addr6->sin6_port);
95
}
96
}
97
}
98
99
NetSocket *NetSocketWinSock::_create_func() {
100
return memnew(NetSocketWinSock);
101
}
102
103
void NetSocketWinSock::make_default() {
104
ERR_FAIL_COND(_create != nullptr);
105
106
WSADATA data;
107
WSAStartup(MAKEWORD(2, 2), &data);
108
_create = _create_func;
109
}
110
111
void NetSocketWinSock::cleanup() {
112
ERR_FAIL_COND(_create == nullptr);
113
114
WSACleanup();
115
_create = nullptr;
116
}
117
118
NetSocketWinSock::NetSocketWinSock() {
119
}
120
121
NetSocketWinSock::~NetSocketWinSock() {
122
close();
123
}
124
125
NetSocketWinSock::NetError NetSocketWinSock::_get_socket_error() const {
126
int err = WSAGetLastError();
127
if (err == WSAEISCONN) {
128
return ERR_NET_IS_CONNECTED;
129
}
130
if (err == WSAEINPROGRESS || err == WSAEALREADY) {
131
return ERR_NET_IN_PROGRESS;
132
}
133
if (err == WSAEWOULDBLOCK) {
134
return ERR_NET_WOULD_BLOCK;
135
}
136
if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
137
return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
138
}
139
if (err == WSAEACCES) {
140
return ERR_NET_UNAUTHORIZED;
141
}
142
if (err == WSAEMSGSIZE || err == WSAENOBUFS) {
143
return ERR_NET_BUFFER_TOO_SMALL;
144
}
145
print_verbose("Socket error: " + itos(err) + ".");
146
return ERR_NET_OTHER;
147
}
148
149
bool NetSocketWinSock::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
150
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
151
return false;
152
} else if (!p_for_bind && !p_ip.is_valid()) {
153
return false;
154
}
155
// Check if socket support this IP type.
156
IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
157
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
158
}
159
160
_FORCE_INLINE_ Error NetSocketWinSock::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
161
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
162
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
163
164
// Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4.
165
IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
166
// This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
167
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
168
int ret = -1;
169
170
IPAddress if_ip;
171
uint32_t if_v6id = 0;
172
HashMap<String, IP::Interface_Info> if_info;
173
IP::get_singleton()->get_local_interfaces(&if_info);
174
for (KeyValue<String, IP::Interface_Info> &E : if_info) {
175
IP::Interface_Info &c = E.value;
176
if (c.name != p_if_name) {
177
continue;
178
}
179
180
if_v6id = (uint32_t)c.index.to_int();
181
if (type == IP::TYPE_IPV6) {
182
break; // IPv6 uses index.
183
}
184
185
for (const IPAddress &F : c.ip_addresses) {
186
if (!F.is_ipv4()) {
187
continue; // Wrong IP type.
188
}
189
if_ip = F;
190
break;
191
}
192
break;
193
}
194
195
if (level == IPPROTO_IP) {
196
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
197
struct ip_mreq greq;
198
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
199
memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
200
memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
201
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
202
} else {
203
struct ipv6_mreq greq;
204
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
205
memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
206
greq.ipv6mr_interface = if_v6id;
207
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
208
}
209
ERR_FAIL_COND_V(ret != 0, FAILED);
210
211
return OK;
212
}
213
214
void NetSocketWinSock::_set_socket(SOCKET p_sock, IP::Type p_ip_type, bool p_is_stream) {
215
_sock = p_sock;
216
_ip_type = p_ip_type;
217
_is_stream = p_is_stream;
218
}
219
220
Error NetSocketWinSock::open(Family p_family, Type p_sock_type, IP::Type &ip_type) {
221
ERR_FAIL_COND_V(p_family != Family::INET, ERR_UNAVAILABLE);
222
ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE);
223
ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
224
225
int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
226
int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP;
227
int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM;
228
_sock = socket(family, type, protocol);
229
230
if (_sock == INVALID_SOCKET && ip_type == IP::TYPE_ANY) {
231
// Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
232
// in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
233
ip_type = IP::TYPE_IPV4;
234
family = AF_INET;
235
_sock = socket(family, type, protocol);
236
}
237
238
ERR_FAIL_COND_V(_sock == INVALID_SOCKET, FAILED);
239
_ip_type = ip_type;
240
241
if (family == AF_INET6) {
242
// Select IPv4 over IPv6 mapping.
243
set_ipv6_only_enabled(ip_type != IP::TYPE_ANY);
244
}
245
246
if (protocol == IPPROTO_UDP) {
247
// Make sure to disable broadcasting for UDP sockets.
248
// Depending on the OS, this option might or might not be enabled by default. Let's normalize it.
249
set_broadcasting_enabled(false);
250
}
251
252
_is_stream = p_sock_type == TYPE_TCP;
253
254
if (!_is_stream) {
255
// Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
256
// recv/recvfrom and an ICMP reply was received from a previous send/sendto.
257
unsigned long disable = 0;
258
if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
259
print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows.");
260
}
261
if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
262
// This feature seems not to be supported on wine.
263
print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows.");
264
}
265
}
266
return OK;
267
}
268
269
void NetSocketWinSock::close() {
270
if (_sock != INVALID_SOCKET) {
271
closesocket(_sock);
272
}
273
274
_sock = INVALID_SOCKET;
275
_ip_type = IP::TYPE_NONE;
276
_is_stream = false;
277
}
278
279
Error NetSocketWinSock::bind(Address p_addr) {
280
ERR_FAIL_COND_V(!p_addr.is_inet(), ERR_UNAVAILABLE);
281
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
282
ERR_FAIL_COND_V(!_can_use_ip(p_addr.ip(), true), ERR_INVALID_PARAMETER);
283
284
sockaddr_storage addr;
285
size_t addr_size = _set_addr_storage(&addr, p_addr.ip(), p_addr.port(), _ip_type);
286
287
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
288
NetError err = _get_socket_error();
289
print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
290
close();
291
return ERR_UNAVAILABLE;
292
}
293
294
return OK;
295
}
296
297
Error NetSocketWinSock::listen(int p_max_pending) {
298
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
299
300
if (::listen(_sock, p_max_pending) != 0) {
301
_get_socket_error();
302
print_verbose("Failed to listen from socket.");
303
close();
304
return FAILED;
305
}
306
307
return OK;
308
}
309
310
Error NetSocketWinSock::connect_to_host(Address p_addr) {
311
ERR_FAIL_COND_V(!p_addr.is_inet(), ERR_UNAVAILABLE);
312
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
313
ERR_FAIL_COND_V(!_can_use_ip(p_addr.ip(), false), ERR_INVALID_PARAMETER);
314
315
struct sockaddr_storage addr;
316
size_t addr_size = _set_addr_storage(&addr, p_addr.ip(), p_addr.port(), _ip_type);
317
318
if (::WSAConnect(_sock, (struct sockaddr *)&addr, addr_size, nullptr, nullptr, nullptr, nullptr) != 0) {
319
NetError err = _get_socket_error();
320
321
switch (err) {
322
// We are already connected.
323
case ERR_NET_IS_CONNECTED:
324
return OK;
325
// Still waiting to connect, try again in a while.
326
case ERR_NET_WOULD_BLOCK:
327
case ERR_NET_IN_PROGRESS:
328
return ERR_BUSY;
329
default:
330
print_verbose("Connection to remote host failed.");
331
close();
332
return FAILED;
333
}
334
}
335
336
return OK;
337
}
338
339
Error NetSocketWinSock::poll(PollType p_type, int p_timeout) const {
340
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
341
342
bool ready = false;
343
fd_set rd, wr, ex;
344
fd_set *rdp = nullptr;
345
fd_set *wrp = nullptr;
346
FD_ZERO(&rd);
347
FD_ZERO(&wr);
348
FD_ZERO(&ex);
349
FD_SET(_sock, &ex);
350
struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
351
// For blocking operation, pass nullptr timeout pointer to select.
352
struct timeval *tp = nullptr;
353
if (p_timeout >= 0) {
354
// If timeout is non-negative, we want to specify the timeout instead.
355
tp = &timeout;
356
}
357
358
switch (p_type) {
359
case POLL_TYPE_IN:
360
FD_SET(_sock, &rd);
361
rdp = &rd;
362
break;
363
case POLL_TYPE_OUT:
364
FD_SET(_sock, &wr);
365
wrp = &wr;
366
break;
367
case POLL_TYPE_IN_OUT:
368
FD_SET(_sock, &rd);
369
FD_SET(_sock, &wr);
370
rdp = &rd;
371
wrp = &wr;
372
}
373
// WSAPoll is broken: https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/.
374
int ret = select(1, rdp, wrp, &ex, tp);
375
376
if (ret == SOCKET_ERROR) {
377
return FAILED;
378
}
379
380
if (ret == 0) {
381
return ERR_BUSY;
382
}
383
384
if (FD_ISSET(_sock, &ex)) {
385
_get_socket_error();
386
print_verbose("Exception when polling socket.");
387
return FAILED;
388
}
389
390
if (rdp && FD_ISSET(_sock, rdp)) {
391
ready = true;
392
}
393
if (wrp && FD_ISSET(_sock, wrp)) {
394
ready = true;
395
}
396
397
return ready ? OK : ERR_BUSY;
398
}
399
400
Error NetSocketWinSock::recv(uint8_t *p_buffer, int p_len, int &r_read) {
401
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
402
403
r_read = ::recv(_sock, (char *)p_buffer, p_len, 0);
404
405
if (r_read < 0) {
406
NetError err = _get_socket_error();
407
if (err == ERR_NET_WOULD_BLOCK) {
408
return ERR_BUSY;
409
}
410
411
if (err == ERR_NET_BUFFER_TOO_SMALL) {
412
return ERR_OUT_OF_MEMORY;
413
}
414
415
return FAILED;
416
}
417
418
return OK;
419
}
420
421
Error NetSocketWinSock::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
422
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
423
424
struct sockaddr_storage from;
425
socklen_t len = sizeof(struct sockaddr_storage);
426
memset(&from, 0, len);
427
428
r_read = ::recvfrom(_sock, (char *)p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
429
430
if (r_read < 0) {
431
NetError err = _get_socket_error();
432
if (err == ERR_NET_WOULD_BLOCK) {
433
return ERR_BUSY;
434
}
435
436
if (err == ERR_NET_BUFFER_TOO_SMALL) {
437
return ERR_OUT_OF_MEMORY;
438
}
439
440
return FAILED;
441
}
442
443
if (from.ss_family == AF_INET) {
444
struct sockaddr_in *sin_from = (struct sockaddr_in *)&from;
445
r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr);
446
r_port = ntohs(sin_from->sin_port);
447
} else if (from.ss_family == AF_INET6) {
448
struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from;
449
r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr);
450
r_port = ntohs(s6_from->sin6_port);
451
} else {
452
// Unsupported socket family, should never happen.
453
ERR_FAIL_V(FAILED);
454
}
455
456
return OK;
457
}
458
459
Error NetSocketWinSock::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
460
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
461
462
int flags = 0;
463
r_sent = ::send(_sock, (const char *)p_buffer, p_len, flags);
464
465
if (r_sent < 0) {
466
NetError err = _get_socket_error();
467
if (err == ERR_NET_WOULD_BLOCK) {
468
return ERR_BUSY;
469
}
470
if (err == ERR_NET_BUFFER_TOO_SMALL) {
471
return ERR_OUT_OF_MEMORY;
472
}
473
474
return FAILED;
475
}
476
477
return OK;
478
}
479
480
Error NetSocketWinSock::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
481
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
482
483
struct sockaddr_storage addr;
484
size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type);
485
r_sent = ::sendto(_sock, (const char *)p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
486
487
if (r_sent < 0) {
488
NetError err = _get_socket_error();
489
if (err == ERR_NET_WOULD_BLOCK) {
490
return ERR_BUSY;
491
}
492
if (err == ERR_NET_BUFFER_TOO_SMALL) {
493
return ERR_OUT_OF_MEMORY;
494
}
495
496
return FAILED;
497
}
498
499
return OK;
500
}
501
502
Error NetSocketWinSock::set_broadcasting_enabled(bool p_enabled) {
503
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
504
// IPv6 has no broadcast support.
505
if (_ip_type == IP::TYPE_IPV6) {
506
return ERR_UNAVAILABLE;
507
}
508
509
int par = p_enabled ? 1 : 0;
510
if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, (const char *)&par, sizeof(int)) != 0) {
511
WARN_PRINT("Unable to change broadcast setting.");
512
return FAILED;
513
}
514
return OK;
515
}
516
517
void NetSocketWinSock::set_blocking_enabled(bool p_enabled) {
518
ERR_FAIL_COND(!is_open());
519
520
int ret = 0;
521
unsigned long par = p_enabled ? 0 : 1;
522
ret = ioctlsocket(_sock, FIONBIO, &par);
523
if (ret != 0) {
524
WARN_PRINT("Unable to change non-block mode.");
525
}
526
}
527
528
void NetSocketWinSock::set_ipv6_only_enabled(bool p_enabled) {
529
ERR_FAIL_COND(!is_open());
530
// This option is only available in IPv6 sockets.
531
ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4);
532
533
int par = p_enabled ? 1 : 0;
534
if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&par, sizeof(int)) != 0) {
535
WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option.");
536
}
537
}
538
539
void NetSocketWinSock::set_tcp_no_delay_enabled(bool p_enabled) {
540
ERR_FAIL_COND(!is_open());
541
ERR_FAIL_COND(!_is_stream); // Not TCP.
542
543
int par = p_enabled ? 1 : 0;
544
if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&par, sizeof(int)) < 0) {
545
WARN_PRINT("Unable to set TCP no delay option.");
546
}
547
}
548
549
void NetSocketWinSock::set_reuse_address_enabled(bool p_enabled) {
550
ERR_FAIL_COND(!is_open());
551
552
// On Windows, enabling SO_REUSEADDR actually would also enable reuse port, very bad on TCP. Denying...
553
// Windows does not have this option, SO_REUSEADDR in this magical world means SO_REUSEPORT
554
}
555
556
bool NetSocketWinSock::is_open() const {
557
return _sock != INVALID_SOCKET;
558
}
559
560
int NetSocketWinSock::get_available_bytes() const {
561
ERR_FAIL_COND_V(!is_open(), -1);
562
563
unsigned long len;
564
int ret = ioctlsocket(_sock, FIONREAD, &len);
565
if (ret == -1) {
566
_get_socket_error();
567
print_verbose("Error when checking available bytes on socket.");
568
return -1;
569
}
570
return len;
571
}
572
573
Error NetSocketWinSock::get_socket_address(Address *r_addr) const {
574
ERR_FAIL_COND_V(!is_open(), FAILED);
575
576
struct sockaddr_storage saddr;
577
socklen_t len = sizeof(saddr);
578
if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
579
_get_socket_error();
580
print_verbose("Error when reading local socket address.");
581
return FAILED;
582
}
583
IPAddress ip;
584
uint16_t port = 0;
585
_set_ip_port(&saddr, &ip, &port);
586
if (r_addr) {
587
*r_addr = Address(ip, port);
588
}
589
return OK;
590
}
591
592
Ref<NetSocket> NetSocketWinSock::accept(Address &r_addr) {
593
Ref<NetSocket> out;
594
ERR_FAIL_COND_V(!is_open(), out);
595
596
struct sockaddr_storage their_addr;
597
socklen_t size = sizeof(their_addr);
598
SOCKET fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
599
if (fd == INVALID_SOCKET) {
600
_get_socket_error();
601
print_verbose("Error when accepting socket connection.");
602
return out;
603
}
604
605
IPAddress ip;
606
uint16_t port = 0;
607
_set_ip_port(&their_addr, &ip, &port);
608
r_addr = Address(ip, port);
609
610
NetSocketWinSock *ns = memnew(NetSocketWinSock);
611
ns->_set_socket(fd, _ip_type, _is_stream);
612
ns->set_blocking_enabled(false);
613
return Ref<NetSocket>(ns);
614
}
615
616
Error NetSocketWinSock::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
617
return _change_multicast_group(p_multi_address, p_if_name, true);
618
}
619
620
Error NetSocketWinSock::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
621
return _change_multicast_group(p_multi_address, p_if_name, false);
622
}
623
624
#endif // WINDOWS_ENABLED
625
626