summaryrefslogtreecommitdiff
path: root/drivers/unix
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/unix')
-rw-r--r--drivers/unix/SCsub2
-rw-r--r--drivers/unix/dir_access_unix.cpp2
-rw-r--r--drivers/unix/net_socket_posix.cpp106
-rw-r--r--drivers/unix/net_socket_posix.h4
-rw-r--r--drivers/unix/os_unix.cpp47
-rw-r--r--drivers/unix/os_unix.h2
-rw-r--r--drivers/unix/socket_helpers.h156
7 files changed, 141 insertions, 178 deletions
diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub
index ada8255580..4888f56099 100644
--- a/drivers/unix/SCsub
+++ b/drivers/unix/SCsub
@@ -5,5 +5,3 @@ Import('env')
env.add_source_files(env.drivers_sources, "*.cpp")
env["check_c_headers"] = [ [ "mntent.h", "HAVE_MNTENT" ] ]
-
-Export('env')
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 81861f8c7b..a5a9258c4a 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -60,7 +60,7 @@ Error DirAccessUnix::list_dir_begin() {
//char real_current_dir_name[2048]; //is this enough?!
//getcwd(real_current_dir_name,2048);
- //chdir(curent_path.utf8().get_data());
+ //chdir(current_path.utf8().get_data());
dir_stream = opendir(current_dir.utf8().get_data());
//chdir(real_current_dir_name);
if (!dir_stream)
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index ea19b6a700..3f03175403 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -68,29 +68,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 +126,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) {
@@ -150,9 +154,24 @@ NetSocket *NetSocketPosix::_create_func() {
}
void NetSocketPosix::make_default() {
+#if defined(WINDOWS_ENABLED)
+ if (_create == NULL) {
+ WSADATA data;
+ WSAStartup(MAKEWORD(2, 2), &data);
+ }
+#endif
_create = _create_func;
}
+void NetSocketPosix::cleanup() {
+#if defined(WINDOWS_ENABLED)
+ if (_create != NULL) {
+ WSACleanup();
+ }
+ _create = NULL;
+#endif
+}
+
NetSocketPosix::NetSocketPosix() {
_sock = SOCK_EMPTY;
_ip_type = IP::TYPE_NONE;
@@ -169,10 +188,11 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() {
if (err == WSAEISCONN)
return ERR_NET_IS_CONNECTED;
- if (err == WSAEINPROGRESS || errno == WSAEALREADY)
+ if (err == WSAEINPROGRESS || err == WSAEALREADY)
return ERR_NET_IN_PROGRESS;
if (err == WSAEWOULDBLOCK)
return ERR_NET_WOULD_BLOCK;
+ ERR_PRINTS("Socket error: " + itos(err));
return ERR_NET_OTHER;
#else
if (errno == EISCONN)
@@ -181,6 +201,7 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() {
return ERR_NET_IN_PROGRESS;
if (errno == EAGAIN || errno == EWOULDBLOCK)
return ERR_NET_WOULD_BLOCK;
+ ERR_PRINTS("Socket error: " + itos(errno));
return ERR_NET_OTHER;
#endif
}
@@ -243,6 +264,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;
}
@@ -314,10 +350,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;
@@ -334,14 +418,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) {
@@ -473,7 +559,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) {
@@ -526,7 +612,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);
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index ee178136f3..010f2ea6e0 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -39,6 +39,7 @@
#define SOCKET_TYPE SOCKET
#else
+#include <sys/socket.h>
#define SOCKET_TYPE int
#endif
@@ -67,6 +68,9 @@ protected:
public:
static void make_default();
+ static void cleanup();
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port);
+ 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);
virtual Error open(Type p_sock_type, IP::Type &ip_type);
virtual void close();
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 1225d00aad..6c70934bc6 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -45,6 +45,7 @@
#ifdef __APPLE__
#include <mach-o/dyld.h>
+#include <mach/mach_time.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -64,6 +65,32 @@
#include <sys/wait.h>
#include <unistd.h>
+/// Clock Setup function (used by get_ticks_usec)
+static uint64_t _clock_start = 0;
+#if defined(__APPLE__)
+static double _clock_scale = 0;
+static void _setup_clock() {
+ mach_timebase_info_data_t info;
+ kern_return_t ret = mach_timebase_info(&info);
+ ERR_EXPLAIN("OS CLOCK IS NOT WORKING!");
+ ERR_FAIL_COND(ret != 0);
+ _clock_scale = ((double)info.numer / (double)info.denom) / 1000.0;
+ _clock_start = mach_absolute_time() * _clock_scale;
+}
+#else
+#if defined(CLOCK_MONOTONIC_RAW) && !defined(JAVASCRIPT_ENABLED) // This is a better clock on Linux.
+#define GODOT_CLOCK CLOCK_MONOTONIC_RAW
+#else
+#define GODOT_CLOCK CLOCK_MONOTONIC
+#endif
+static void _setup_clock() {
+ struct timespec tv_now = { 0, 0 };
+ ERR_EXPLAIN("OS CLOCK IS NOT WORKING!");
+ ERR_FAIL_COND(clock_gettime(GODOT_CLOCK, &tv_now) != 0);
+ _clock_start = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L;
+}
+#endif
+
void OS_Unix::debug_break() {
assert(false);
@@ -126,8 +153,7 @@ void OS_Unix::initialize_core() {
IP_Unix::make_default();
#endif
- ticks_start = 0;
- ticks_start = get_ticks_usec();
+ _setup_clock();
struct sigaction sa;
sa.sa_handler = &handle_sigchld;
@@ -139,6 +165,8 @@ void OS_Unix::initialize_core() {
}
void OS_Unix::finalize_core() {
+
+ NetSocketPosix::cleanup();
}
void OS_Unix::alert(const String &p_alert, const String &p_title) {
@@ -244,11 +272,16 @@ void OS_Unix::delay_usec(uint32_t p_usec) const {
}
uint64_t OS_Unix::get_ticks_usec() const {
- struct timeval tv_now;
- gettimeofday(&tv_now, NULL);
-
- uint64_t longtime = (uint64_t)tv_now.tv_usec + (uint64_t)tv_now.tv_sec * 1000000L;
- longtime -= ticks_start;
+#if defined(__APPLE__)
+ uint64_t longtime = mach_absolute_time() * _clock_scale;
+#else
+ // Unchecked return. Static analyzers might complain.
+ // If _setup_clock() succeded, we assume clock_gettime() works.
+ struct timespec tv_now = { 0, 0 };
+ clock_gettime(GODOT_CLOCK, &tv_now);
+ uint64_t longtime = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L;
+#endif
+ longtime -= _clock_start;
return longtime;
}
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index f4abfa2dd4..b702454603 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -42,8 +42,6 @@
class OS_Unix : public OS {
- uint64_t ticks_start;
-
protected:
// UNIX only handles the core functions.
// inheriting platforms under unix (eg. X11) should handle the rest
diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h
deleted file mode 100644
index 5b42c13eae..0000000000
--- a/drivers/unix/socket_helpers.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*************************************************************************/
-/* socket_helpers.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef SOCKET_HELPERS_H
-#define SOCKET_HELPERS_H
-
-#include <string.h>
-
-#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4)
-// Workaround for mingw-w64 < 4.0
-#ifndef IPV6_V6ONLY
-#define IPV6_V6ONLY 27
-#endif
-#endif
-
-// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this
-
-static size_t _set_sockaddr(struct sockaddr_storage *p_addr, const IP_Address &p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) {
-
- memset(p_addr, 0, sizeof(struct sockaddr_storage));
-
- ERR_FAIL_COND_V(!p_ip.is_valid(), 0);
-
- // IPv6 socket
- if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) {
-
- // IPv6 only socket with IPv4 address
- ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0);
-
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
- addr6->sin6_family = AF_INET6;
- addr6->sin6_port = htons(p_port);
- copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
- return sizeof(sockaddr_in6);
-
- } else { // IPv4 socket
-
- // IPv4 socket with IPv6 address
- ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0);
-
- struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- addr4->sin_family = AF_INET;
- addr4->sin_port = htons(p_port); // short, network byte order
- copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16);
- return sizeof(sockaddr_in);
- };
-};
-
-static size_t _set_listen_sockaddr(struct sockaddr_storage *p_addr, int p_port, IP::Type p_sock_type, const IP_Address p_bind_address) {
-
- memset(p_addr, 0, sizeof(struct sockaddr_storage));
- if (p_sock_type == IP::TYPE_IPV4) {
- struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- addr4->sin_family = AF_INET;
- addr4->sin_port = htons(p_port);
- if (p_bind_address.is_valid()) {
- copymem(&addr4->sin_addr.s_addr, p_bind_address.get_ipv4(), 4);
- } else {
- addr4->sin_addr.s_addr = INADDR_ANY;
- }
- return sizeof(sockaddr_in);
- } else {
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
-
- addr6->sin6_family = AF_INET6;
- addr6->sin6_port = htons(p_port);
- if (p_bind_address.is_valid()) {
- copymem(&addr6->sin6_addr.s6_addr, p_bind_address.get_ipv6(), 16);
- } else {
- addr6->sin6_addr = in6addr_any;
- }
- return sizeof(sockaddr_in6);
- };
-};
-
-static int _socket_create(IP::Type &p_type, int type, int protocol) {
-
- ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
-
- int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
- int sockfd = socket(family, type, protocol);
-
- if (sockfd == -1 && p_type == IP::TYPE_ANY) {
- // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
- // in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
- p_type = IP::TYPE_IPV4;
- family = AF_INET;
- sockfd = socket(family, type, protocol);
- }
-
- ERR_FAIL_COND_V(sockfd == -1, -1);
-
- if (family == AF_INET6) {
- // Select IPv4 over IPv6 mapping
- int opt = p_type != IP::TYPE_ANY;
- if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)) != 0) {
- WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6");
- }
- }
- if (protocol == IPPROTO_UDP && p_type != IP::TYPE_IPV6) {
- // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option).
- int broadcast = 1;
- if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)) != 0) {
- WARN_PRINT("Error when enabling broadcasting");
- }
- }
-
- return sockfd;
-}
-
-static void _set_ip_addr_port(IP_Address &r_ip, int &r_port, struct sockaddr_storage *p_addr) {
-
- if (p_addr->ss_family == AF_INET) {
-
- struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
-
- r_port = ntohs(addr4->sin_port);
-
- } else if (p_addr->ss_family == AF_INET6) {
-
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
- r_ip.set_ipv6(addr6->sin6_addr.s6_addr);
-
- r_port = ntohs(addr6->sin6_port);
- };
-};
-
-#endif