From 65c5a647191a9a10a532bb9d67da6938f5eace1b Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Tue, 27 Apr 2021 10:50:28 +0200 Subject: Fix: [Network] errno and strerror do not handle network errors on Windows --- src/network/core/address.cpp | 14 +++++++------- src/network/core/core.cpp | 17 +++++++++++++++++ src/network/core/os_abstraction.h | 25 ++++++++++++++++++++++--- src/network/core/tcp.cpp | 6 +++--- src/network/core/tcp_http.cpp | 2 +- src/network/core/tcp_listen.h | 4 ++-- src/network/core/udp.cpp | 4 ++-- 7 files changed, 54 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 8c6909438..fc19439e0 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -316,7 +316,7 @@ static SOCKET ConnectLoopProc(addrinfo *runp) SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, strerror(errno)); + DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkGetLastErrorString()); return INVALID_SOCKET; } @@ -331,7 +331,7 @@ static SOCKET ConnectLoopProc(addrinfo *runp) if (err != 0) #endif { - DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno)); + DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } @@ -369,7 +369,7 @@ static SOCKET ListenLoopProc(addrinfo *runp) SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, NetworkGetLastErrorString()); return INVALID_SOCKET; } @@ -380,24 +380,24 @@ static SOCKET ListenLoopProc(addrinfo *runp) int on = 1; /* The (const char*) cast is needed for windows!! */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, NetworkGetLastErrorString()); } #ifndef __OS2__ if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, NetworkGetLastErrorString()); } #endif if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { - DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) { - DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index 0aeb9c65c..8c5c5c229 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -13,6 +13,7 @@ #include "../../debug.h" #include "os_abstraction.h" #include "packet.h" +#include "../../string_func.h" #include "../../safeguards.h" @@ -48,6 +49,22 @@ void NetworkCoreShutdown() #endif } +#if defined(_WIN32) +/** + * Return the string representation of the given error from the OS's network functions. + * @param error The error number (from \c NetworkGetLastError()). + * @return The error message, potentially an empty string but never \c nullptr. + */ +const char *NetworkGetErrorString(int error) +{ + static char buffer[512]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) { + seprintf(buffer, lastof(buffer), "Unknown error %d", error); + } + return buffer; +} +#endif /* defined(_WIN32) */ /** * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 836cfeae8..a015c4374 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -23,9 +23,17 @@ #include #include -#define GET_LAST_ERROR() WSAGetLastError() +/** + * Get the last error code from any of the OS's network functions. + * What it returns and when it is reset, is implementation defined. + * @return The last error code. + */ +#define NetworkGetLastError() WSAGetLastError() #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK + +const char *NetworkGetErrorString(int error); + /* Windows has some different names for some types */ typedef unsigned long in_addr_t; @@ -51,7 +59,8 @@ typedef unsigned long in_addr_t; # define INVALID_SOCKET -1 # define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (errno) +# define NetworkGetLastError() (errno) +# define NetworkGetErrorString(error) (strerror(error)) /* Need this for FIONREAD on solaris */ # define BSD_COMP @@ -101,7 +110,8 @@ typedef unsigned long in_addr_t; # define INVALID_SOCKET -1 # define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (sock_errno()) +# define NetworkGetLastError() (sock_errno()) +# define NetworkGetErrorString(error) (strerror(error)) /* Includes needed for OS/2 systems */ # include @@ -173,6 +183,15 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address } #endif +/** + * Return the string representation of the last error from the OS's network functions. + * @return The error message, potentially an empty string but never \c nullptr. + */ +static inline const char *NetworkGetLastErrorString() +{ + return NetworkGetErrorString(NetworkGetLastError()); +} + /** * 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.cpp b/src/network/core/tcp.cpp index 72e66a0b5..b9ba33f00 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -86,7 +86,7 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) while ((p = this->packet_queue) != nullptr) { res = p->TransferOut(send, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { /* Something went wrong.. close client! */ if (!closing_down) { @@ -136,7 +136,7 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); @@ -164,7 +164,7 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index d88ea711d..04bc6a03a 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -228,7 +228,7 @@ int NetworkHTTPSocketHandler::Receive() for (;;) { ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 53a3d57cc..c11727ba7 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -64,7 +64,7 @@ public: DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str()); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + DEBUG(net, 0, "send failed with error %d", NetworkGetLastError()); } closesocket(s); break; @@ -81,7 +81,7 @@ public: p.PrepareToSend(); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + DEBUG(net, 0, "send failed with error %d", NetworkGetLastError()); } closesocket(s); diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index e8299f7b6..abbb1bbdb 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -94,7 +94,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a /* Enable broadcast */ unsigned long val = 1; if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { - DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR()); + DEBUG(net, 1, "[udp] setting broadcast failed with: %i", NetworkGetLastError()); } } @@ -103,7 +103,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString().c_str()); /* Check for any errors, but ignore it otherwise */ - if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString().c_str(), GET_LAST_ERROR()); + if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString().c_str(), NetworkGetLastError()); if (!all) break; } -- cgit v1.2.3-54-g00ecf