Hole punching

This commit is contained in:
James R 2020-11-12 17:07:19 -08:00
parent 52879a7632
commit ba5b6aa7af
6 changed files with 161 additions and 23 deletions

View file

@ -1908,6 +1908,8 @@ static void SendAskInfo(INT32 node)
// now allowed traffic from the host to us in, so once the MS relays
// our address to the host, it'll be able to speak to us.
HSendPacket(node, false, 0, sizeof (askinfo_pak));
I_NetRequestHolePunch();
}
serverelem_t serverlist[MAXSERVERLIST];
@ -5725,6 +5727,19 @@ static void UpdatePingTable(void)
}
}
static void RenewHolePunch(void)
{
static time_t past;
const time_t now = time(NULL);
if ((now - past) > 20)
{
I_NetRegisterHolePunch();
past = now;
}
}
// Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void)
{
@ -5759,6 +5774,11 @@ FILESTAMP
MasterClient_Ticker();
#endif
if (serverrunning)
{
RenewHolePunch();
}
if (client)
{
// send keep alive
@ -5818,6 +5838,11 @@ FILESTAMP
MasterClient_Ticker(); // Acking the Master Server
#endif
if (serverrunning)
{
RenewHolePunch();
}
if (client)
{
if (!resynch_local_inprogress)

View file

@ -49,6 +49,8 @@ tic_t connectiontimeout = (10*TICRATE);
doomcom_t *doomcom = NULL;
/// \brief network packet data, points inside doomcom
doomdata_t *netbuffer = NULL;
/// \brief hole punching packet, also points inside doomcom
holepunch_t *holepunchpacket = NULL;
#ifdef DEBUGFILE
FILE *debugfile = NULL; // put some net info in a file during the game
@ -72,6 +74,8 @@ boolean (*I_NetCanGet)(void) = NULL;
void (*I_NetCloseSocket)(void) = NULL;
void (*I_NetFreeNodenum)(INT32 nodenum) = NULL;
SINT8 (*I_NetMakeNodewPort)(const char *address, const char* port) = NULL;
void (*I_NetRequestHolePunch)(void) = NULL;
void (*I_NetRegisterHolePunch)(void) = NULL;
boolean (*I_NetOpenSocket)(void) = NULL;
boolean (*I_Ban) (INT32 node) = NULL;
void (*I_ClearBans)(void) = NULL;
@ -1335,6 +1339,7 @@ boolean D_CheckNetGame(void)
I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES);
netbuffer = (doomdata_t *)(void *)&doomcom->data;
holepunchpacket = (holepunch_t *)(void *)&doomcom->data;
#ifdef DEBUGFILE
#ifdef _arch_dreamcast

View file

@ -77,11 +77,19 @@ typedef struct
char data[MAXPACKETLENGTH];
} ATTRPACK doomcom_t;
typedef struct
{
INT32 magic;
INT32 addr;
INT16 port;
} ATTRPACK holepunch_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
extern doomcom_t *doomcom;
extern holepunch_t *holepunchpacket;
/** \brief return packet in doomcom struct
*/
@ -140,6 +148,15 @@ extern boolean (*I_NetOpenSocket)(void);
extern void (*I_NetCloseSocket)(void);
/** \brief send a hole punching request
*/
extern void (*I_NetRequestHolePunch)(void);
/** \brief register this machine on the hole punching server
*/
extern void (*I_NetRegisterHolePunch)(void);
extern boolean (*I_Ban) (INT32 node);
extern void (*I_ClearBans)(void);
extern const char *(*I_GetNodeAddress) (INT32 node);

View file

@ -241,6 +241,7 @@ static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
static const INT32 hole_punch_magic = MSBF_LONG (0x52eb11);
#endif
static size_t numbans = 0;
@ -597,6 +598,27 @@ void Command_Numnodes(void)
#endif
#ifndef NONET
static boolean hole_punch(ssize_t c)
{
if (c == 10 && holepunchpacket->magic == hole_punch_magic)
{
mysockaddr_t addr;
addr.ip4.sin_family = AF_INET;
addr.ip4.sin_addr.s_addr = holepunchpacket->addr;
addr.ip4.sin_port = holepunchpacket->port;
sendto(mysockets[0], NULL, 0, 0, &addr.any, sizeof addr.ip4);
CONS_Debug(DBG_NETPLAY,
"hole punching request from %s\n", SOCK_AddrToStr(&addr));
return true;
}
else
{
return false;
}
}
// Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{
@ -620,6 +642,11 @@ static boolean SOCK_Get(void)
}
#endif
if (hole_punch(c))
{
return false;
}
// find remote node number
for (j = 1; j <= MAXNETNODES; j++) //include LAN
{
@ -1319,17 +1346,14 @@ void I_ShutdownTcpDriver(void)
}
#ifndef NONET
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const char *port, boolean test)
{
SINT8 newnode = -1;
struct my_addrinfo *ai = NULL, *runp, hints;
int gaie;
if (!port || !port[0])
if (!port || !port[0])
port = DEFAULTPORT;
DEBFILE(va("Creating new node: %s@%s\n", address, port));
memset (&hints, 0x00, sizeof (hints));
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC;
@ -1337,30 +1361,91 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
hints.ai_protocol = IPPROTO_UDP;
gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0)
{
newnode = getfreenode();
}
if (newnode == -1)
if (gaie != 0)
{
I_freeaddrinfo(ai);
return -1;
return false;
}
runp = ai;
if (test)
{
while (runp != NULL)
{
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
break;
runp = runp->ai_next;
}
}
if (runp != NULL)
memcpy(sin, runp->ai_addr, runp->ai_addrlen);
I_freeaddrinfo(ai);
return (runp != NULL);
}
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
{
SINT8 newnode = getfreenode();
DEBFILE(va("Creating new node: %s@%s\n", address, port));
if (newnode != -1)
{
if (!SOCK_GetAddr(&clientaddress[newnode].ip4, address, port, true))
{
nodeconnected[newnode] = false;
return -1;
}
}
return newnode;
}
static void rendezvous(int size)
{
char *addrs = strdup(cv_rendezvousserver.string);
char *host = strtok(addrs, ":");
char *port = strtok(NULL, ":");
mysockaddr_t rzv;
if (SOCK_GetAddr(&rzv.ip4, host, (port ? port : "7777"), false))
{
holepunchpacket->magic = hole_punch_magic;
sendto(mysockets[0], doomcom->data, size, 0, &rzv.any, sizeof rzv.ip4);
}
else
runp = ai;
while (runp != NULL)
{
// find ip of the server
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
{
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
break;
}
runp = runp->ai_next;
CONS_Alert(CONS_ERROR, "Failed to contact rendezvous server (%s).\n",
cv_rendezvousserver.string);
}
I_freeaddrinfo(ai);
return newnode;
free(addrs);
}
static void SOCK_RequestHolePunch(void)
{
mysockaddr_t * addr = &clientaddress[doomcom->remotenode];
holepunchpacket->addr = addr->ip4.sin_addr.s_addr;
holepunchpacket->port = addr->ip4.sin_port;
CONS_Debug(DBG_NETPLAY,
"requesting hole punch to node %s\n", SOCK_AddrToStr(addr));
rendezvous(10);
}
static void SOCK_RegisterHolePunch(void)
{
rendezvous(4);
}
#endif
@ -1387,6 +1472,9 @@ static boolean SOCK_OpenSocket(void)
I_NetCanGet = SOCK_CanGet;
#endif
I_NetRequestHolePunch = SOCK_RequestHolePunch;
I_NetRegisterHolePunch = SOCK_RegisterHolePunch;
// build the socket but close it first
SOCK_CloseSocket();
return UDP_Socket();

View file

@ -68,6 +68,7 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
};
consvar_t cv_masterserver = {"masterserver", "https://ms.kartkrew.org/ms/api", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_rendezvousserver = {"rendezvousserver", "jart-dev.jameds.org", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_servername = {"servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_server_contact = {"server_contact", "", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
@ -99,6 +100,7 @@ void AddMServCommands(void)
CV_RegisterVar(&cv_masterserver_debug);
CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_advertise);
CV_RegisterVar(&cv_rendezvousserver);
CV_RegisterVar(&cv_servername);
CV_RegisterVar(&cv_server_contact);
#ifdef MASTERSERVER

View file

@ -58,6 +58,7 @@ extern consvar_t cv_masterserver_update_rate;
extern consvar_t cv_masterserver_timeout;
extern consvar_t cv_masterserver_debug;
extern consvar_t cv_masterserver_token;
extern consvar_t cv_rendezvousserver;
extern consvar_t cv_advertise;