From a203f4e5536e3ec4b4e3c7748897398ba614949c Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sat, 1 Feb 2025 11:00:02 -0500 Subject: [PATCH 1/4] Update i_tcp.c Add checks for return code for ioctl(), setsockopt(), getsockopt() and getsockname() Also show errno and strerror for failed calls --- src/netcode/i_tcp.c | 89 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 19 deletions(-) diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index 256d9992e..89cee2a6c 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2024 by Sonic Team Junior. +// Copyright (C) 1999-2025 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -695,7 +695,7 @@ static void SOCK_Send(void) { int e = errno; // save error code so it can't be modified later if (!ALLOWEDERROR(e)) - I_Error("SOCK_Send, error sending to node %d (%s) #%u: %s", doomcom->remotenode, + I_Error("SOCK_Send, error sending to node %d (%s) #%u, %s", doomcom->remotenode, SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); } } @@ -726,6 +726,8 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen { SOCKET_TYPE s = socket(family, SOCK_DGRAM, IPPROTO_UDP); int opt; + int rc; + int e = 0; // save error code so it can't be modified later code socklen_t opts; #ifdef FIONBIO unsigned long trueval = true; @@ -740,12 +742,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #ifdef USE_WINSOCK2 DWORD dwBytesReturned = 0; BOOL bfalse = FALSE; - WSAIoctl(s, SIO_UDP_CONNRESET, &bfalse, sizeof(bfalse), + rc = WSAIoctl(s, SIO_UDP_CONNRESET, &bfalse, sizeof(bfalse), NULL, 0, &dwBytesReturned, NULL, NULL); #else unsigned long falseval = false; - ioctl(s, SIO_UDP_CONNRESET, &falseval); + rc = ioctl(s, SIO_UDP_CONNRESET, &falseval); #endif + if (rc == -1) + { + e = errno; + I_OutputMsg("SIO_UDP_CONNRESET failed: #%u, %s\n", e, strerror(e)); + } } #endif @@ -758,14 +765,22 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen { opt = true; opts = (socklen_t)sizeof(opt); - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts); + rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts); + if (rc <= -1) + { + e = errno; + I_OutputMsg("setting SO_REUSEADDR failed: #%u, %s\n", e, strerror(e)); + } } // make it broadcastable opt = true; opts = (socklen_t)sizeof(opt); - if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&opt, opts)) + rc = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&opt, opts); + if (rc <= -1) { + e = errno; CONS_Alert(CONS_WARNING, M_GetText("Could not get broadcast rights\n")); // I do not care anymore + I_OutputMsg("setting SO_BROADCAST failed: #%u, %s\n", e, strerror(e)); } } #ifdef HAVE_IPV6 @@ -775,24 +790,34 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen { opt = true; opts = (socklen_t)sizeof(opt); - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts); + rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts); + if (rc <= -1) + { + e = errno; + I_OutputMsg("setting SO_REUSEADDR failed: #%u, %s\n", e, strerror(e)); + } } #ifdef IPV6_V6ONLY // make it IPv6 ony opt = true; opts = (socklen_t)sizeof(opt); - if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts)) + rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts); + if (rc <= -1) { + e = errno; CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore + I_OutputMsg("setting IPV6_V6ONLY failed: #%u, %s\n", e, strerror(e)); } #endif } #endif - if (bind(s, addr, addrlen) == ERRSOCKET) + rc = bind(s, addr, addrlen); + if (rc == ERRSOCKET) { + e = errno; close(s); - I_OutputMsg("Binding failed\n"); + I_OutputMsg("Binding failed: #%u, %s\n", e, strerror(e)); return (SOCKET_TYPE)ERRSOCKET; } @@ -806,9 +831,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen inet_pton(AF_INET6, IPV6_MULTICAST_ADDRESS, &maddr.ipv6mr_multiaddr); maddr.ipv6mr_interface = 0; - if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&maddr, sizeof(maddr)) != 0) + rc = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&maddr, sizeof(maddr)); + if (rc <= -1) { + e = errno; CONS_Alert(CONS_WARNING, M_GetText("Could not register multicast address\n")); + I_OutputMsg("setting IPV6_JOIN_GROUP failed: #%u, %s \n", e, strerror(e)); } } } @@ -816,33 +844,56 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #ifdef FIONBIO // make it non blocking - opt = true; - if (ioctl(s, FIONBIO, &trueval) != 0) + rc = ioctl(s, FIONBIO, &trueval); + if (rc == -1) { + e = errno; close(s); - I_OutputMsg("Seting FIOBIO on failed\n"); + I_OutputMsg("FIOBIO failed: #%u, %s\n", e, strerror(e)); return (SOCKET_TYPE)ERRSOCKET; } #endif + opt = 0; opts = (socklen_t)sizeof(opt); - getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts); + rc = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts); + if (rc <= -1) + { + e = errno; + I_OutputMsg("getting SO_RCVBUF failed: #%u, %s\n", e, strerror(e)); + } CONS_Printf(M_GetText("Network system buffer: %dKb\n"), opt>>10); if (opt < 64<<10) // 64k { opt = 64<<10; opts = (socklen_t)sizeof(opt); - setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, opts); - getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts); - if (opt < 64<<10) + rc = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, opts); + if (rc <= -1) + { + e = errno; + I_OutputMsg("setting SO_RCVBUF failed: #%u, %s\n", e, strerror(e)); + } + opt = 0; + rc = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts); + if (rc <= -1) + { + e = errno; + I_OutputMsg("getting SO_RCVBUF failed: #%u, %s\n", e, strerror(e)); + } + if (opt <= 64<<10) CONS_Alert(CONS_WARNING, M_GetText("Can't set buffer length to 64k, file transfer will be bad\n")); else CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); } - if (getsockname(s, &straddr.any, &len) == -1) + rc = getsockname(s, &straddr.any, &len); + if (rc != 0) + { + e = errno; CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); + I_OutputMsg("getsockname failed: #%u, %s\n", e, strerror(e)); + } else { if (family == AF_INET) From 4596f20b71b10d330cc26cc657741b1b3607f274 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sat, 1 Feb 2025 11:00:44 -0500 Subject: [PATCH 2/4] Check for ENODEV for hosts with IPv6 disabled while running in IPv6 mode --- src/netcode/i_tcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index 89cee2a6c..282b2ce94 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -836,6 +836,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen { e = errno; CONS_Alert(CONS_WARNING, M_GetText("Could not register multicast address\n")); + if (e == ENODEV) + { + close(s); + I_OutputMsg("Binding failed: no IPv6 device\n"); + return (SOCKET_TYPE)ERRSOCKET; + } I_OutputMsg("setting IPV6_JOIN_GROUP failed: #%u, %s \n", e, strerror(e)); } } From 4bb8183e6f915bb0155f647c0c77e8a60277404a Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 2 Feb 2025 12:43:05 -0500 Subject: [PATCH 3/4] Show in log if IPv6 support is disabled fixup --- src/netcode/i_tcp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index 282b2ce94..c0a606ba1 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -936,6 +936,13 @@ static boolean UDP_Socket(void) hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; +#ifdef HAVE_IPV6 + if (!b_ipv6) + I_OutputMsg("Disabling IPv6 support at runtime\n"); +#else + I_OutputMsg("Compiled without IPv6 support\n"); +#endif + if (serverrunning) serv = serverport_name; else From 1ebac1ed40da053fe6bf8e077cbab1b8d135e7d1 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 2 Feb 2025 12:44:35 -0500 Subject: [PATCH 4/4] Avoid calling WSAGetLastError() (via errno/h_error) more then once with Winsock2 --- src/netcode/i_tcp.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index c0a606ba1..58fb921d6 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -386,6 +386,7 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) int v6 = 0; #endif void *addr; + int e = 0; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once if(sk->any.sa_family == AF_INET) addr = &sk->ip4.sin_addr; @@ -399,7 +400,10 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) if(addr == NULL) sprintf(s, "No address"); else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL) - sprintf(s, "Unknown family type, error #%u", errno); + { + e = errno; + sprintf(s, "Unknown family type, error #%u: %s", e, strerror(e)); + } #ifdef HAVE_IPV6 else if(sk->any.sa_family == AF_INET6) { @@ -655,6 +659,7 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr static void SOCK_Send(void) { ssize_t c = ERRSOCKET; + int e = 0; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once if (!nodeconnected[doomcom->remotenode]) return; @@ -668,8 +673,12 @@ static void SOCK_Send(void) if (myfamily[i] == broadcastaddress[j].any.sa_family) { c = SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); - if (c == ERRSOCKET && !ALLOWEDERROR(errno)) - break; + if (c == ERRSOCKET) + { + e = errno; + if (!ALLOWEDERROR(e)) + break; + } } } } @@ -681,8 +690,12 @@ static void SOCK_Send(void) if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) { c = SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); - if (c == ERRSOCKET && !ALLOWEDERROR(errno)) - break; + if (c == ERRSOCKET) + { + e = errno; + if (!ALLOWEDERROR(e)) + break; + } } } } @@ -693,7 +706,6 @@ static void SOCK_Send(void) if (c == ERRSOCKET) { - int e = errno; // save error code so it can't be modified later if (!ALLOWEDERROR(e)) I_Error("SOCK_Send, error sending to node %d (%s) #%u, %s", doomcom->remotenode, SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); @@ -727,7 +739,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen SOCKET_TYPE s = socket(family, SOCK_DGRAM, IPPROTO_UDP); int opt; int rc; - int e = 0; // save error code so it can't be modified later code + int e = 0; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once socklen_t opts; #ifdef FIONBIO unsigned long trueval = true;