summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2020-12-09 17:13:34 +0100
committerPatric Stout <github@truebrain.nl>2020-12-15 15:46:39 +0100
commit8fbf5bef60568cd4dcd56921c37be64b8234d9bb (patch)
treea234d6bea0d739dafe344ab64a2d71742e1eae85
parentd5b9f7ac37c7d27d1ffe50e55aa73361da64189b (diff)
downloadopenttd-8fbf5bef60568cd4dcd56921c37be64b8234d9bb.tar.xz
Fix: workarounds for two emscripten bugs in the network stack
-rw-r--r--src/network/core/address.cpp12
-rw-r--r--src/network/core/os_abstraction.h22
-rw-r--r--src/network/core/tcp_listen.h3
-rw-r--r--src/network/core/udp.cpp3
4 files changed, 40 insertions, 0 deletions
diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp
index 1aaa0b5fb..2e00b5b19 100644
--- a/src/network/core/address.cpp
+++ b/src/network/core/address.cpp
@@ -267,6 +267,18 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
this->address_length = (int)runp->ai_addrlen;
assert(sizeof(this->address) >= runp->ai_addrlen);
memcpy(&this->address, runp->ai_addr, runp->ai_addrlen);
+#ifdef __EMSCRIPTEN__
+ /* Emscripten doesn't zero sin_zero, but as we compare addresses
+ * to see if they are the same address, we need them to be zero'd.
+ * Emscripten is, as far as we know, the only OS not doing this.
+ *
+ * https://github.com/emscripten-core/emscripten/issues/12998
+ */
+ if (this->address.ss_family == AF_INET) {
+ sockaddr_in *address_ipv4 = (sockaddr_in *)&this->address;
+ memset(address_ipv4->sin_zero, 0, sizeof(address_ipv4->sin_zero));
+ }
+#endif
break;
}
diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h
index be8b8f919..8aa072aef 100644
--- a/src/network/core/os_abstraction.h
+++ b/src/network/core/os_abstraction.h
@@ -151,6 +151,28 @@ typedef unsigned long in_addr_t;
#endif /* OS/2 */
+#ifdef __EMSCRIPTEN__
+/**
+ * Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
+ * and recvfrom(), which confuses other functions and causes them to crash.
+ * This function needs to be called after these four functions to make sure
+ * 'addrlen' is patched up.
+ *
+ * https://github.com/emscripten-core/emscripten/issues/12996
+ *
+ * @param address The address returned by those four functions.
+ * @return The correct value for addrlen.
+ */
+static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
+{
+ switch (address.ss_family) {
+ case AF_INET6: return sizeof(struct sockaddr_in6);
+ case AF_INET: return sizeof(struct sockaddr_in);
+ default: NOT_REACHED();
+ }
+}
+#endif
+
/**
* Try to set the socket into non-blocking mode.
* @param d The socket to set the non-blocking more for.
diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h
index d2982363e..1f073aa73 100644
--- a/src/network/core/tcp_listen.h
+++ b/src/network/core/tcp_listen.h
@@ -42,6 +42,9 @@ public:
socklen_t sin_len = sizeof(sin);
SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
if (s == INVALID_SOCKET) return;
+#ifdef __EMSCRIPTEN__
+ sin_len = FixAddrLenForEmscripten(sin);
+#endif
SetNonBlocking(s); // XXX error handling?
diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp
index 57352412b..aa6d39cbb 100644
--- a/src/network/core/udp.cpp
+++ b/src/network/core/udp.cpp
@@ -129,6 +129,9 @@ void NetworkUDPSocketHandler::ReceivePackets()
/* Did we get the bytes for the base header of the packet? */
if (nbytes <= 0) break; // No data, i.e. no packet
if (nbytes <= 2) continue; // Invalid data; try next packet
+#ifdef __EMSCRIPTEN__
+ client_len = FixAddrLenForEmscripten(client_addr);
+#endif
NetworkAddress address(client_addr, client_len);
p.PrepareToRead();