Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/drivers/windows/net_socket_winsock.cpp
9903 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(Type p_sock_type, IP::Type &ip_type) {
221
ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE);
222
ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
223
224
int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
225
int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP;
226
int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM;
227
_sock = socket(family, type, protocol);
228
229
if (_sock == INVALID_SOCKET && ip_type == IP::TYPE_ANY) {
230
// Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
231
// in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
232
ip_type = IP::TYPE_IPV4;
233
family = AF_INET;
234
_sock = socket(family, type, protocol);
235
}
236
237
ERR_FAIL_COND_V(_sock == INVALID_SOCKET, FAILED);
238
_ip_type = ip_type;
239
240
if (family == AF_INET6) {
241
// Select IPv4 over IPv6 mapping.
242
set_ipv6_only_enabled(ip_type != IP::TYPE_ANY);
243
}
244
245
if (protocol == IPPROTO_UDP) {
246
// Make sure to disable broadcasting for UDP sockets.
247
// Depending on the OS, this option might or might not be enabled by default. Let's normalize it.
248
set_broadcasting_enabled(false);
249
}
250
251
_is_stream = p_sock_type == TYPE_TCP;
252
253
if (!_is_stream) {
254
// Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
255
// recv/recvfrom and an ICMP reply was received from a previous send/sendto.
256
unsigned long disable = 0;
257
if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
258
print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows.");
259
}
260
if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
261
// This feature seems not to be supported on wine.
262
print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows.");
263
}
264
}
265
return OK;
266
}
267
268
void NetSocketWinSock::close() {
269
if (_sock != INVALID_SOCKET) {
270
closesocket(_sock);
271
}
272
273
_sock = INVALID_SOCKET;
274
_ip_type = IP::TYPE_NONE;
275
_is_stream = false;
276
}
277
278
Error NetSocketWinSock::bind(IPAddress p_addr, uint16_t p_port) {
279
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
280
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
281
282
sockaddr_storage addr;
283
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
284
285
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
286
NetError err = _get_socket_error();
287
print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
288
close();
289
return ERR_UNAVAILABLE;
290
}
291
292
return OK;
293
}
294
295
Error NetSocketWinSock::listen(int p_max_pending) {
296
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
297
298
if (::listen(_sock, p_max_pending) != 0) {
299
_get_socket_error();
300
print_verbose("Failed to listen from socket.");
301
close();
302
return FAILED;
303
}
304
305
return OK;
306
}
307
308
Error NetSocketWinSock::connect_to_host(IPAddress p_host, uint16_t p_port) {
309
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
310
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
311
312
struct sockaddr_storage addr;
313
size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type);
314
315
if (::WSAConnect(_sock, (struct sockaddr *)&addr, addr_size, nullptr, nullptr, nullptr, nullptr) != 0) {
316
NetError err = _get_socket_error();
317
318
switch (err) {
319
// We are already connected.
320
case ERR_NET_IS_CONNECTED:
321
return OK;
322
// Still waiting to connect, try again in a while.
323
case ERR_NET_WOULD_BLOCK:
324
case ERR_NET_IN_PROGRESS:
325
return ERR_BUSY;
326
default:
327
print_verbose("Connection to remote host failed.");
328
close();
329
return FAILED;
330
}
331
}
332
333
return OK;
334
}
335
336
Error NetSocketWinSock::poll(PollType p_type, int p_timeout) const {
337
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
338
339
bool ready = false;
340
fd_set rd, wr, ex;
341
fd_set *rdp = nullptr;
342
fd_set *wrp = nullptr;
343
FD_ZERO(&rd);
344
FD_ZERO(&wr);
345
FD_ZERO(&ex);
346
FD_SET(_sock, &ex);
347
struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
348
// For blocking operation, pass nullptr timeout pointer to select.
349
struct timeval *tp = nullptr;
350
if (p_timeout >= 0) {
351
// If timeout is non-negative, we want to specify the timeout instead.
352
tp = &timeout;
353
}
354
355
switch (p_type) {
356
case POLL_TYPE_IN:
357
FD_SET(_sock, &rd);
358
rdp = &rd;
359
break;
360
case POLL_TYPE_OUT:
361
FD_SET(_sock, &wr);
362
wrp = &wr;
363
break;
364
case POLL_TYPE_IN_OUT:
365
FD_SET(_sock, &rd);
366
FD_SET(_sock, &wr);
367
rdp = &rd;
368
wrp = &wr;
369
}
370
// WSAPoll is broken: https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/.
371
int ret = select(1, rdp, wrp, &ex, tp);
372
373
if (ret == SOCKET_ERROR) {
374
return FAILED;
375
}
376
377
if (ret == 0) {
378
return ERR_BUSY;
379
}
380
381
if (FD_ISSET(_sock, &ex)) {
382
_get_socket_error();
383
print_verbose("Exception when polling socket.");
384
return FAILED;
385
}
386
387
if (rdp && FD_ISSET(_sock, rdp)) {
388
ready = true;
389
}
390
if (wrp && FD_ISSET(_sock, wrp)) {
391
ready = true;
392
}
393
394
return ready ? OK : ERR_BUSY;
395
}
396
397
Error NetSocketWinSock::recv(uint8_t *p_buffer, int p_len, int &r_read) {
398
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
399
400
r_read = ::recv(_sock, (char *)p_buffer, p_len, 0);
401
402
if (r_read < 0) {
403
NetError err = _get_socket_error();
404
if (err == ERR_NET_WOULD_BLOCK) {
405
return ERR_BUSY;
406
}
407
408
if (err == ERR_NET_BUFFER_TOO_SMALL) {
409
return ERR_OUT_OF_MEMORY;
410
}
411
412
return FAILED;
413
}
414
415
return OK;
416
}
417
418
Error NetSocketWinSock::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
419
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
420
421
struct sockaddr_storage from;
422
socklen_t len = sizeof(struct sockaddr_storage);
423
memset(&from, 0, len);
424
425
r_read = ::recvfrom(_sock, (char *)p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
426
427
if (r_read < 0) {
428
NetError err = _get_socket_error();
429
if (err == ERR_NET_WOULD_BLOCK) {
430
return ERR_BUSY;
431
}
432
433
if (err == ERR_NET_BUFFER_TOO_SMALL) {
434
return ERR_OUT_OF_MEMORY;
435
}
436
437
return FAILED;
438
}
439
440
if (from.ss_family == AF_INET) {
441
struct sockaddr_in *sin_from = (struct sockaddr_in *)&from;
442
r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr);
443
r_port = ntohs(sin_from->sin_port);
444
} else if (from.ss_family == AF_INET6) {
445
struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from;
446
r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr);
447
r_port = ntohs(s6_from->sin6_port);
448
} else {
449
// Unsupported socket family, should never happen.
450
ERR_FAIL_V(FAILED);
451
}
452
453
return OK;
454
}
455
456
Error NetSocketWinSock::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
457
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
458
459
int flags = 0;
460
r_sent = ::send(_sock, (const char *)p_buffer, p_len, flags);
461
462
if (r_sent < 0) {
463
NetError err = _get_socket_error();
464
if (err == ERR_NET_WOULD_BLOCK) {
465
return ERR_BUSY;
466
}
467
if (err == ERR_NET_BUFFER_TOO_SMALL) {
468
return ERR_OUT_OF_MEMORY;
469
}
470
471
return FAILED;
472
}
473
474
return OK;
475
}
476
477
Error NetSocketWinSock::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
478
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
479
480
struct sockaddr_storage addr;
481
size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type);
482
r_sent = ::sendto(_sock, (const char *)p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
483
484
if (r_sent < 0) {
485
NetError err = _get_socket_error();
486
if (err == ERR_NET_WOULD_BLOCK) {
487
return ERR_BUSY;
488
}
489
if (err == ERR_NET_BUFFER_TOO_SMALL) {
490
return ERR_OUT_OF_MEMORY;
491
}
492
493
return FAILED;
494
}
495
496
return OK;
497
}
498
499
Error NetSocketWinSock::set_broadcasting_enabled(bool p_enabled) {
500
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
501
// IPv6 has no broadcast support.
502
if (_ip_type == IP::TYPE_IPV6) {
503
return ERR_UNAVAILABLE;
504
}
505
506
int par = p_enabled ? 1 : 0;
507
if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, (const char *)&par, sizeof(int)) != 0) {
508
WARN_PRINT("Unable to change broadcast setting.");
509
return FAILED;
510
}
511
return OK;
512
}
513
514
void NetSocketWinSock::set_blocking_enabled(bool p_enabled) {
515
ERR_FAIL_COND(!is_open());
516
517
int ret = 0;
518
unsigned long par = p_enabled ? 0 : 1;
519
ret = ioctlsocket(_sock, FIONBIO, &par);
520
if (ret != 0) {
521
WARN_PRINT("Unable to change non-block mode.");
522
}
523
}
524
525
void NetSocketWinSock::set_ipv6_only_enabled(bool p_enabled) {
526
ERR_FAIL_COND(!is_open());
527
// This option is only available in IPv6 sockets.
528
ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4);
529
530
int par = p_enabled ? 1 : 0;
531
if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&par, sizeof(int)) != 0) {
532
WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option.");
533
}
534
}
535
536
void NetSocketWinSock::set_tcp_no_delay_enabled(bool p_enabled) {
537
ERR_FAIL_COND(!is_open());
538
ERR_FAIL_COND(!_is_stream); // Not TCP.
539
540
int par = p_enabled ? 1 : 0;
541
if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&par, sizeof(int)) < 0) {
542
WARN_PRINT("Unable to set TCP no delay option.");
543
}
544
}
545
546
void NetSocketWinSock::set_reuse_address_enabled(bool p_enabled) {
547
ERR_FAIL_COND(!is_open());
548
549
// On Windows, enabling SO_REUSEADDR actually would also enable reuse port, very bad on TCP. Denying...
550
// Windows does not have this option, SO_REUSEADDR in this magical world means SO_REUSEPORT
551
}
552
553
bool NetSocketWinSock::is_open() const {
554
return _sock != INVALID_SOCKET;
555
}
556
557
int NetSocketWinSock::get_available_bytes() const {
558
ERR_FAIL_COND_V(!is_open(), -1);
559
560
unsigned long len;
561
int ret = ioctlsocket(_sock, FIONREAD, &len);
562
if (ret == -1) {
563
_get_socket_error();
564
print_verbose("Error when checking available bytes on socket.");
565
return -1;
566
}
567
return len;
568
}
569
570
Error NetSocketWinSock::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
571
ERR_FAIL_COND_V(!is_open(), FAILED);
572
573
struct sockaddr_storage saddr;
574
socklen_t len = sizeof(saddr);
575
if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
576
_get_socket_error();
577
print_verbose("Error when reading local socket address.");
578
return FAILED;
579
}
580
_set_ip_port(&saddr, r_ip, r_port);
581
return OK;
582
}
583
584
Ref<NetSocket> NetSocketWinSock::accept(IPAddress &r_ip, uint16_t &r_port) {
585
Ref<NetSocket> out;
586
ERR_FAIL_COND_V(!is_open(), out);
587
588
struct sockaddr_storage their_addr;
589
socklen_t size = sizeof(their_addr);
590
SOCKET fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
591
if (fd == INVALID_SOCKET) {
592
_get_socket_error();
593
print_verbose("Error when accepting socket connection.");
594
return out;
595
}
596
597
_set_ip_port(&their_addr, &r_ip, &r_port);
598
599
NetSocketWinSock *ns = memnew(NetSocketWinSock);
600
ns->_set_socket(fd, _ip_type, _is_stream);
601
ns->set_blocking_enabled(false);
602
return Ref<NetSocket>(ns);
603
}
604
605
Error NetSocketWinSock::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
606
return _change_multicast_group(p_multi_address, p_if_name, true);
607
}
608
609
Error NetSocketWinSock::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
610
return _change_multicast_group(p_multi_address, p_if_name, false);
611
}
612
613
#endif // WINDOWS_ENABLED
614
615