summaryrefslogtreecommitdiff
path: root/drivers/unix/net_socket_posix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/unix/net_socket_posix.cpp')
-rw-r--r--drivers/unix/net_socket_posix.cpp93
1 files changed, 79 insertions, 14 deletions
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 9dcc6038ab..f981be66ce 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -42,12 +42,8 @@
#include <sys/types.h>
#include <unistd.h>
#ifndef NO_FCNTL
-#ifdef __HAIKU__
#include <fcntl.h>
#else
-#include <sys/fcntl.h>
-#endif
-#else
#include <sys/ioctl.h>
#endif
#include <netinet/in.h>
@@ -59,7 +55,7 @@
#include <netinet/tcp.h>
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(__APPLE__)
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
@@ -68,29 +64,33 @@
#define SOCK_BUF(x) x
#define SOCK_CBUF(x) x
#define SOCK_IOCTL ioctl
-#define SOCK_POLL ::poll
#define SOCK_CLOSE ::close
/* Windows */
#elif defined(WINDOWS_ENABLED)
#include <winsock2.h>
#include <ws2tcpip.h>
+
+#include <mswsock.h>
// Some custom defines to minimize ifdefs
#define SOCK_EMPTY INVALID_SOCKET
#define SOCK_BUF(x) (char *)(x)
#define SOCK_CBUF(x) (const char *)(x)
#define SOCK_IOCTL ioctlsocket
-#define SOCK_POLL WSAPoll
#define SOCK_CLOSE closesocket
// Windows doesn't have this flag
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
+// Workaround missing flag in MinGW
+#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
+#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
+#endif
#endif
-static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket
@@ -122,12 +122,12 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres
addr4->sin_addr.s_addr = INADDR_ANY;
}
- copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16);
+ copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
return sizeof(sockaddr_in);
}
}
-static void _set_ip_port(IP_Address &r_ip, uint16_t &r_port, struct sockaddr_storage *p_addr) {
+void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) {
if (p_addr->ss_family == AF_INET) {
@@ -260,6 +260,21 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
}
_is_stream = p_sock_type == TYPE_TCP;
+
+#if defined(WINDOWS_ENABLED)
+ if (!_is_stream) {
+ // Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
+ // recv/recvfrom and an ICMP reply was received from a previous send/sendto.
+ unsigned long disable = 0;
+ if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
+ print_verbose("Unable to turn off UDP WSAECONNRESET behaviour on Windows");
+ }
+ if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
+ // This feature seems not to be supported on wine.
+ print_verbose("Unable to turn off UDP WSAENETRESET behaviour on Windows");
+ }
+ }
+#endif
return OK;
}
@@ -331,10 +346,58 @@ Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) {
return OK;
}
-Error NetSocketPosix::poll(PollType p_type, int timeout) const {
+Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+#if defined(WINDOWS_ENABLED)
+ bool ready = false;
+ fd_set rd, wr, ex;
+ fd_set *rdp = NULL;
+ fd_set *wrp = NULL;
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(_sock, &ex);
+ struct timeval timeout = { p_timeout, 0 };
+ // For blocking operation, pass NULL timeout pointer to select.
+ struct timeval *tp = NULL;
+ if (p_timeout >= 0) {
+ // If timeout is non-negative, we want to specify the timeout instead.
+ tp = &timeout;
+ }
+
+ switch (p_type) {
+ case POLL_TYPE_IN:
+ FD_SET(_sock, &rd);
+ rdp = &rd;
+ break;
+ case POLL_TYPE_OUT:
+ FD_SET(_sock, &wr);
+ wrp = &wr;
+ break;
+ case POLL_TYPE_IN_OUT:
+ FD_SET(_sock, &rd);
+ FD_SET(_sock, &wr);
+ rdp = &rd;
+ wrp = &wr;
+ }
+ int ret = select(1, rdp, wrp, &ex, tp);
+
+ ERR_FAIL_COND_V(ret == SOCKET_ERROR, FAILED);
+
+ if (ret == 0)
+ return ERR_BUSY;
+
+ ERR_FAIL_COND_V(FD_ISSET(_sock, &ex), FAILED);
+
+ if (rdp && FD_ISSET(_sock, rdp))
+ ready = true;
+ if (wrp && FD_ISSET(_sock, wrp))
+ ready = true;
+
+ return ready ? OK : ERR_BUSY;
+#else
struct pollfd pfd;
pfd.fd = _sock;
pfd.events = POLLIN;
@@ -351,14 +414,16 @@ Error NetSocketPosix::poll(PollType p_type, int timeout) const {
pfd.events = POLLOUT || POLLIN;
}
- int ret = SOCK_POLL(&pfd, 1, timeout);
+ int ret = ::poll(&pfd, 1, p_timeout);
ERR_FAIL_COND_V(ret < 0, FAILED);
+ ERR_FAIL_COND_V(pfd.revents & POLLERR, FAILED);
if (ret == 0)
return ERR_BUSY;
return OK;
+#endif
}
Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
@@ -490,7 +555,7 @@ void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) {
void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
- ERR_FAIL_COND(_ip_type != TYPE_TCP);
+ ERR_FAIL_COND(!_is_stream); // Not TCP
int par = p_enabled ? 1 : 0;
if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) {
@@ -543,7 +608,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
ERR_FAIL_COND_V(fd == SOCK_EMPTY, out);
- _set_ip_port(r_ip, r_port, &their_addr);
+ _set_ip_port(&their_addr, r_ip, r_port);
NetSocketPosix *ns = memnew(NetSocketPosix);
ns->_set_socket(fd, _ip_type, _is_stream);