foxygit / doom Log in
commit 76178ee71572e399ede72eac8d448595e6daac63
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Sat Feb 9 19:25:33 2019 -0500
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Sat Feb 9 19:25:33 2019 -0500

    net: Add initial server code for NAT hole punching.

    This allows the master server to send a hole punch request to servers
    that will assist clients in connecting to them if they are behind
    firewalls / NAT gateways. However, this is just the first piece in
    implementation of #469 and more work is needed.
---
 src/net_defs.h   |  2 ++
 src/net_query.c  | 35 ++++++++++++++-------------------
 src/net_query.h  |  2 +-
 src/net_server.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/net_defs.h b/src/net_defs.h
index bf6a264e..10fda972 100644
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -149,6 +149,7 @@ typedef enum
     NET_PACKET_TYPE_QUERY,
     NET_PACKET_TYPE_QUERY_RESPONSE,
     NET_PACKET_TYPE_LAUNCH,
+    NET_PACKET_TYPE_NAT_HOLE_PUNCH,
 } net_packet_type_t;

 typedef enum
@@ -163,6 +164,7 @@ typedef enum
     NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE,
     NET_MASTER_PACKET_TYPE_SIGN_END,
     NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE,
+    NET_MASTER_PACKET_TYPE_NAT_HOLE_PUNCH,
 } net_master_packet_type_t;

 // Settings specified when the client connects to the server.
diff --git a/src/net_query.c b/src/net_query.c
index da292b50..97c42ca0 100644
--- a/src/net_query.c
+++ b/src/net_query.c
@@ -120,40 +120,35 @@ void NET_Query_AddToMaster(net_addr_t *master_addr)

 // Process a packet received from the master server.

-void NET_Query_MasterResponse(net_packet_t *packet)
+void NET_Query_AddResponse(net_packet_t *packet)
 {
-    unsigned int packet_type;
     unsigned int result;

-    if (!NET_ReadInt16(packet, &packet_type)
-     || !NET_ReadInt16(packet, &result))
+    if (!NET_ReadInt16(packet, &result))
     {
         return;
     }

-    if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE)
+    if (result != 0)
     {
-        if (result != 0)
-        {
-            // Only show the message once.
+        // Only show the message once.

-            if (!registered_with_master)
-            {
-                printf("Registered with master server at %s\n",
-                       MASTER_SERVER_ADDRESS);
-                registered_with_master = true;
-            }
-        }
-        else
+        if (!registered_with_master)
         {
-            // Always show rejections.
-
-            printf("Failed to register with master server at %s\n",
+            printf("Registered with master server at %s\n",
                    MASTER_SERVER_ADDRESS);
+            registered_with_master = true;
         }
+    }
+    else
+    {
+        // Always show rejections.

-        got_master_response = true;
+        printf("Failed to register with master server at %s\n",
+               MASTER_SERVER_ADDRESS);
     }
+
+    got_master_response = true;
 }

 boolean NET_Query_CheckAddedToMaster(boolean *result)
diff --git a/src/net_query.h b/src/net_query.h
index 563a055b..2fea8357 100644
--- a/src/net_query.h
+++ b/src/net_query.h
@@ -38,7 +38,7 @@ extern int NET_Query_Poll(net_query_callback_t callback, void *user_data);
 extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context);
 extern void NET_Query_AddToMaster(net_addr_t *master_addr);
 extern boolean NET_Query_CheckAddedToMaster(boolean *result);
-extern void NET_Query_MasterResponse(net_packet_t *packet);
+extern void NET_Query_AddResponse(net_packet_t *packet);

 #endif /* #ifndef NET_QUERY_H */

diff --git a/src/net_server.c b/src/net_server.c
index c9dd3d9b..5c374b4a 100644
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1423,6 +1423,63 @@ void NET_SV_SendQueryResponse(net_addr_t *addr)
     NET_FreePacket(reply);
 }

+static void NET_SV_ParseHolePunch(net_packet_t *packet)
+{
+    const char *addr_string;
+    net_packet_t *sendpacket;
+    net_addr_t *addr;
+
+    addr_string = NET_ReadString(packet);
+    if (addr_string == NULL)
+    {
+        NET_Log("server: error: hole punch request but no address provided");
+        return;
+    }
+
+    addr = NET_ResolveAddress(server_context, addr_string);
+    if (addr == NULL)
+    {
+        NET_Log("server: error: failed to resolve address: %s", addr_string);
+        return;
+    }
+
+    sendpacket = NET_NewPacket(16);
+    NET_WriteInt16(sendpacket, NET_PACKET_TYPE_NAT_HOLE_PUNCH);
+    NET_SendPacket(addr, sendpacket);
+    NET_FreePacket(sendpacket);
+
+    // TODO: We should NET_FreeAddress(addr) here, but this could cause a
+    // problem if the client has already connected. The address system needs
+    // to be changed to use a reference-counting system to prevent this.
+}
+
+static void NET_SV_MasterPacket(net_packet_t *packet)
+{
+    unsigned int packet_type;
+
+    // Read the packet type
+
+    if (!NET_ReadInt16(packet, &packet_type))
+    {
+        NET_Log("server: error: no packet type in master server message");
+        return;
+    }
+
+    NET_Log("server: packet from master server; type %d", packet_type);
+    NET_LogPacket(packet);
+
+    switch (packet_type)
+    {
+        case NET_MASTER_PACKET_TYPE_ADD_RESPONSE:
+            NET_Query_AddResponse(packet);
+            break;
+
+        case NET_MASTER_PACKET_TYPE_NAT_HOLE_PUNCH:
+            NET_SV_ParseHolePunch(packet);
+            break;
+    }
+}
+
 // Process a packet received by the server

 static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
@@ -1434,7 +1491,7 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)

     if (addr != NULL && addr == master_server)
     {
-        NET_Query_MasterResponse(packet);
+        NET_SV_MasterPacket(packet);
         return;
     }