From 43b691dbc5af8ae7302a767c354f12a1bf540aee Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Tue, 18 Jun 2024 14:31:43 -0400 Subject: [PATCH] add support for PXO's NAT hole punch --- netcon/mtclient/mtgametrack.cpp | 34 +++++++++++++++++++++++++++++++++ netcon/mtclient/mtgametrack.h | 14 ++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/netcon/mtclient/mtgametrack.cpp b/netcon/mtclient/mtgametrack.cpp index 0a7c8fffb..dd73f889a 100644 --- a/netcon/mtclient/mtgametrack.cpp +++ b/netcon/mtclient/mtgametrack.cpp @@ -139,6 +139,9 @@ extern nw_RegisterCallback_fp DLLnw_RegisterCallback; typedef int (*nw_DoReceiveCallbacks_fp)(); extern nw_DoReceiveCallbacks_fp DLLnw_DoReceiveCallbacks; +typedef int (*nw_SendWithID_fp)(uint8_t id, uint8_t *data, int len, network_address *who_to); +extern nw_SendWithID_fp DLLnw_SendWithID; + #if (defined(LOGGER) && (!defined(RELEASE))) #define DLLmprintf(...) DLLDebug_ConsolePrintf(__VA_ARGS__) #else @@ -266,6 +269,23 @@ void IdleGameTracker() { } } +static void SendClientHolePunch(SOCKADDR_IN *addr) { + game_packet_header HolePunchAck; + network_address send_address; + + memset(&send_address, 0, sizeof(network_address)); + memcpy(send_address.address, &addr->sin_addr, 4); + send_address.port = htons(addr->sin_port); + send_address.connection_type = NP_TCP; + + HolePunchAck.game_type = GameType; + HolePunchAck.type = INTEL_INT(GNT_NAT_HOLE_PUNCH_ACK); + HolePunchAck.len = INTEL_INT(GAME_HEADER_ONLY_SIZE); + HolePunchAck.sig = 0; // to make sure tracker ignores this packet when it's ACK'd there + + DLLnw_SendWithID(PXO_NETID_GAME_TRACKER, (uint8_t *)&HolePunchAck, INTEL_INT(HolePunchAck.len), &send_address); +} + void HandleGamePacket(uint8_t *data, int len, network_address *from) { memcpy(&inpacket, data, sizeof(inpacket)); @@ -294,6 +314,20 @@ void HandleGamePacket(uint8_t *data, int len, network_address *from) { } } break; + case GNT_NAT_HOLE_PUNCH_REQ: + if (len == (GAME_HEADER_ONLY_SIZE+sizeof(hole_punch_addr_ip6))) { + // we don't support IPv6 yet so skip this one + } else { + SOCKADDR_IN nataddr; + + auto ipv4 = reinterpret_cast(&inpacket.data); + nataddr.sin_addr.s_addr = ipv4->addr; + nataddr.sin_port = ipv4->port; + nataddr.sin_family = AF_INET; + + SendClientHolePunch(&nataddr); + } + break; } // mprintf(0,"Sending ACK.\n"); AckPacket(inpacket.sig); diff --git a/netcon/mtclient/mtgametrack.h b/netcon/mtclient/mtgametrack.h index 6f3171a3e..3d7665788 100644 --- a/netcon/mtclient/mtgametrack.h +++ b/netcon/mtclient/mtgametrack.h @@ -133,6 +133,9 @@ #define GNT_GAMEUPDATE_TINY 9 #define GNT_GAMELIST_LITE_DATA 10 #define GNT_GAMELIST_LITE_FILTER_REQ 11 +// NOTE: IDs 12-16 are special for Descent3 and shouldn't be used here!! +#define GNT_NAT_HOLE_PUNCH_REQ 17 +#define GNT_NAT_HOLE_PUNCH_ACK 18 #define GT_FREESPACE 1 #define GT_DESCENT3 2 @@ -211,6 +214,17 @@ struct game_list { uint16_t game_port[MAX_GAME_LISTS_PER_PACKET * 4]; }; +struct hole_punch_addr { + uint32_t addr; + uint16_t port; +}; + +struct hole_punch_addr_ip6 { + // in6_addr addr; + uint8_t addr[16]; // NOTE: replace with above line that uses in6_addr once IPv6 is supported + uint16_t port; +}; + // Function prototypes int InitGameTrackerClient(int gametype);