Compare commits

...
6 Commits
Author SHA1 Message Date
Alug 5973004bb9 i_tcp: reset errno in UDP_Bind and SOCK_Send
on non WINSOCK systems
2025-10-29 20:10:12 +01:00
Alug 599ef7fad7 UDP_Bind: check for network send buffer and attempt to raise its size if its too small
exactly the same as the receive buffer
2025-10-29 20:06:24 +01:00
Alug 3220faac1e UDP_Bind: attempt to set receive buffer to 256kb if smaller
if that fails, try 128k, if that also somehow fails try 64k again
2025-10-29 19:06:45 +01:00
Gustaf Alhäll ea3e23e055 Fix buffer underflow when querying invalid nodes 2025-10-29 19:06:42 +01:00
Alug 112d389dcd SOCK_GetAddr: freeaddrinfo does not need to be called on getaddrinfo failure 2025-10-29 19:06:39 +01:00
Alug 0611d49455 some i_tcp fixes
- SOCK_Get return true when receiving good packet from a lan player
- SOCK_GetAddr fix handling of ipv6 addresses, so ipv6 servers can be found in the serverlist

taken from srb2/classic
2025-10-29 19:06:36 +01:00
2 changed files with 118 additions and 52 deletions

No files matched your search

+2 -3
View File
@@ -1127,9 +1127,7 @@ boolean HGetPacket(void)
while (true)
{
I_NetGet();
if (doomcom->remotenode == -1) // No packet received
if (!I_NetGet()) // No packets received
return false;
getbytes += packetheaderlength + doomcom->datalength; // For stat
@@ -1165,6 +1163,7 @@ boolean HGetPacket(void)
GotAcks();
continue;
}
doomcom->datalength -= BASEPACKETSIZE;
break;
}
+116 -49
View File
@@ -28,14 +28,14 @@
#endif
#ifdef _WIN32
#define USE_WINSOCK
#define USE_WINSOCK
#endif //WIN32 OS
#ifdef USE_WINSOCK
#include <ws2tcpip.h>
#define addrinfo_t ADDRINFOA
#include <ws2tcpip.h>
#define addrinfo_t ADDRINFOA
#else
#define addrinfo_t struct addrinfo
#define addrinfo_t struct addrinfo
#endif
#include "doomdef.h"
@@ -148,16 +148,16 @@ static UINT8 UPNP_support = TRUE;
#define DEFAULTPORT "5029"
#if defined (USE_WINSOCK)
typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR)
#ifdef USE_WINSOCK
typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR)
#else
#if defined (__unix__) || defined (__APPLE__) || defined (__HAIKU__)
typedef int SOCKET_TYPE;
#else
typedef unsigned long SOCKET_TYPE;
#endif
#define ERRSOCKET (-1)
#if defined (__unix__) || defined (__APPLE__) || defined (__HAIKU__)
typedef int SOCKET_TYPE;
#else
typedef unsigned long SOCKET_TYPE;
#endif
#define ERRSOCKET (-1)
#endif
#define IPV6_MULTICAST_ADDRESS "ff15::57e1:1a12"
@@ -345,17 +345,15 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
{
static char s[64]; // 255.255.255.255:65535 or
// [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535
#ifdef HAVE_IPV6
int v6 = (sk->any.sa_family == AF_INET6);
#else
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)
if (sk->any.sa_family == AF_INET)
addr = &sk->ip4.sin_addr;
#ifdef HAVE_IPV6
else if(sk->any.sa_family == AF_INET6)
@@ -364,9 +362,11 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
else
addr = NULL;
if(addr == NULL)
if (addr == NULL)
{
sprintf(s, "No address");
else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL)
}
else if (inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL)
{
e = errno;
sprintf(s, "Unknown family type, error #%u: %s", e, strerror(e));
@@ -381,7 +381,7 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
}
#endif
else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0)
else if (sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0)
strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
return s;
@@ -481,7 +481,6 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
return false;
}
// This is a hack. For some reason, nodes aren't being freed properly.
// This goes through and cleans up what nodes were supposed to be freed.
/** \warning This function causes the file downloading to stop if someone joins.
@@ -636,7 +635,7 @@ static boolean SOCK_Get(void)
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
(void *)&fromaddress, &fromlen);
if (c > 0)
if (c != ERRSOCKET)
{
#ifdef USE_STUN
if (STUN_got_response(doomcom->data, c))
@@ -652,20 +651,21 @@ static boolean SOCK_Get(void)
#endif
// find remote node number
for (j = 1; j <= MAXNETNODES; j++) //include LAN
for (j = 1; j <= MAXNETNODES; j++) // include LAN
{
if (SOCK_cmpaddr(&fromaddress, &clientaddress[j], 0))
{
doomcom->remotenode = (INT16)j; // good packet from a game player
doomcom->datalength = (INT16)c;
nodesocket[j] = mysockets[n];
return false;
return true;
}
}
// not found
// find a free slot
j = getfreenode();
if (j > 0)
{
const time_t curTime = time(NULL);
@@ -746,13 +746,19 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
#define ALLOWEDERROR(x) ((x) == ECONNREFUSED || (x) == EWOULDBLOCK || (x) == EHOSTUNREACH || (x) == ENETUNREACH || (x) == EADDRNOTAVAIL)
// FIXME: maybe retry if this failed somehow?
// windows kinda dies rather often when some other network heavy thing runs besides kart
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
size_t i, j;
if (!nodeconnected[doomcom->remotenode])
#ifndef USE_WINSOCK
errno = 0;
#endif
if (doomcom->remotenode < 0 || !nodeconnected[doomcom->remotenode])
return;
if (doomcom->remotenode == BROADCASTADDR)
@@ -840,6 +846,10 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
mysockaddr_t straddr;
socklen_t len = sizeof(straddr);
#ifndef USE_WINSOCK
errno = 0;
#endif
if (s == (SOCKET_TYPE)ERRSOCKET)
return (SOCKET_TYPE)ERRSOCKET;
@@ -970,30 +980,90 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
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);
CONS_Printf(M_GetText("Network receive buffer: %dKb\n"), opt>>10);
if (opt < 64<<10) // 64k
//if (opt < 64<<10) // 64k minimum
if (opt < 256<<10) // no try 256k first
{
opt = 64<<10;
opts = (socklen_t)sizeof(opt);
rc = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, opts);
if (rc <= -1)
const int buf_sizes[] = {256<<10, 128<<10, 64<<10}; // Try 256k, 128k, then 64k
size_t i;
for (i = 0; i < sizeof(buf_sizes) / sizeof(buf_sizes[0]); i++)
{
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));
opt = buf_sizes[i];
opts = (socklen_t)sizeof(opt);
rc = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, opts);
if (rc <= -1)
{
e = errno;
I_OutputMsg("setting SO_RCVBUF to %dKb failed: #%u, %s\n", opt>>10, e, strerror(e));
continue;
}
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 >= buf_sizes[i])
{
CONS_Printf(M_GetText("Network system receive buffer set to: %dKb\n"), opt>>10);
break;
}
}
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);
CONS_Alert(CONS_WARNING, M_GetText("Can't set receive buffer length to at least 64k, file transfer will be bad\n"));
}
opt = 0;
opts = (socklen_t)sizeof(opt);
rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&opt, &opts);
if (rc <= -1)
{
e = errno;
I_OutputMsg("getting SO_SNDBUF failed: #%u, %s\n", e, strerror(e));
}
CONS_Printf(M_GetText("Network send buffer: %dKb\n"), opt>>10);
//if (opt < 64<<10) // 64k minimum
if (opt < 256<<10) // no try 256k first
{
int buf_sizes[] = {256<<10, 128<<10, 64<<10}; // Try 256k, 128k, then 64k
size_t i;
for (i = 0; i < sizeof(buf_sizes) / sizeof(buf_sizes[0]); i++)
{
opt = buf_sizes[i];
opts = (socklen_t)sizeof(opt);
rc = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&opt, opts);
if (rc <= -1)
{
e = errno;
I_OutputMsg("setting SO_SNDBUF to %dKb failed: #%u, %s\n", opt>>10, e, strerror(e));
continue;
}
opt = 0;
rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&opt, &opts);
if (rc <= -1)
{
e = errno;
I_OutputMsg("getting SO_SNDBUF failed: #%u, %s\n", e, strerror(e));
}
if (opt >= buf_sizes[i])
{
CONS_Printf(M_GetText("Network system send buffer set to: %dKb\n"), opt>>10);
break;
}
}
if (opt < 64<<10)
CONS_Alert(CONS_WARNING, M_GetText("Can't set send buffer length to at least 64k, file transfer will be bad\n"));
}
rc = getsockname(s, &straddr.any, &len);
@@ -1269,9 +1339,9 @@ void I_ShutdownTcpDriver(void)
init_tcp_driver = false;
}
static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const char *port, boolean test)
static boolean SOCK_GetAddr(mysockaddr_t *sin, const char *address, const char *port, boolean test)
{
addrinfo_t *ai = NULL, *runp, hints;
addrinfo_t *ai, *runp, hints;
int gaie;
size_t i;
@@ -1287,10 +1357,7 @@ static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const
gaie = getaddrinfo(address, port, &hints, &ai);
if (gaie != 0)
{
freeaddrinfo(ai);
return false;
}
runp = ai;
@@ -1330,7 +1397,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
if (newnode != -1)
{
if (!SOCK_GetAddr(&clientaddress[newnode].ip4, address, port, true))
if (!SOCK_GetAddr(&clientaddress[newnode], address, port, true))
{
nodeconnected[newnode] = false;
return -1;
@@ -1358,7 +1425,7 @@ static void rendezvous(int size)
if (tic != refreshtic)
{
if (SOCK_GetAddr(&rzv.ip4, host, (port ? port : "7777"), false))
if (SOCK_GetAddr(&rzv, host, (port ? port : "7777"), false))
{
refreshtic = tic;
}