diff options
Diffstat (limited to 'drivers/unix/net_socket_posix.cpp')
| -rw-r--r-- | drivers/unix/net_socket_posix.cpp | 93 |
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 = ≀ + break; + case POLL_TYPE_IN_OUT: + FD_SET(_sock, &rd); + FD_SET(_sock, &wr); + rdp = &rd; + wrp = ≀ + } + 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); |