foxygit / doom Log in
commit d1f2b422e6cbcf2b50b0e02b989cb3fbb314eb9e
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Sat Feb 9 23:00:33 2019 -0500
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Sat Feb 9 23:00:33 2019 -0500

    net: Send hole punch requests on connect.

    To avoid spurious requests, only send requests if no response is received
    after 2 seconds - most connect requests should complete before that if the
    server port is publicly accessible.
---
 src/net_client.c | 26 ++++++++++++--------------
 src/net_query.c  | 22 ++++++++++++++++++++++
 src/net_query.h  |  1 +
 3 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/src/net_client.c b/src/net_client.c
index d0bada14..cf83450c 100644
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -35,6 +35,7 @@
 #include "net_gui.h"
 #include "net_io.h"
 #include "net_packet.h"
+#include "net_query.h"
 #include "net_server.h"
 #include "net_structrw.h"
 #include "w_checksum.h"
@@ -1024,6 +1025,7 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
 {
     int start_time;
     int last_send_time;
+    boolean sent_hole_punch;

     server_addr = addr;
     NET_ReferenceAddress(addr);
@@ -1032,13 +1034,10 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
     memcpy(net_local_deh_sha1sum, data->deh_sha1sum, sizeof(sha1_digest_t));
     net_local_is_freedoom = data->is_freedoom;

-    // create a new network I/O context and add just the
-    // necessary module
-
+    // create a new network I/O context and add just the necessary module
     client_context = NET_NewContext();

     // initialize module for client mode
-
     if (!addr->module->InitClient())
     {
         return false;
@@ -1048,13 +1047,11 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)

     net_client_connected = true;
     net_client_received_wait_data = false;
-
-    // Initialize connection
+    sent_hole_punch = false;

     NET_Conn_InitClient(&client_connection, addr, NET_PROTOCOL_UNKNOWN);

     // try to connect
-
     start_time = I_GetTimeMS();
     last_send_time = -1;

@@ -1063,7 +1060,6 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
         int nowtime = I_GetTimeMS();

         // Send a SYN packet every second.
-
         if (nowtime - last_send_time > 1000 || last_send_time < 0)
         {
             NET_CL_SendSYN(data);
@@ -1071,23 +1067,25 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
         }

         // time out after 5 seconds
-
         if (nowtime - start_time > 5000)
         {
             break;
         }

-        // run client code
+        if (!sent_hole_punch && nowtime - start_time > 2000)
+        {
+            NET_Log("client: no response to SYN, requesting hole punch");
+            NET_RequestHolePunch(client_context, addr);
+            sent_hole_punch = true;
+        }

+        // run client code
         NET_CL_Run();

-        // run the server, just incase we are doing a loopback
-        // connect
-
+        // run the server, just in case we are doing a loopback connect
         NET_SV_Run();

         // Don't hog the CPU
-
         I_Sleep(1);
     }

diff --git a/src/net_query.c b/src/net_query.c
index e6e1cd6a..ed71db27 100644
--- a/src/net_query.c
+++ b/src/net_query.c
@@ -176,6 +176,28 @@ static void NET_Query_SendMasterQuery(net_addr_t *addr)
     NET_FreePacket(packet);
 }

+// Send a hole punch request to the master server for the server at the
+// given address.
+void NET_RequestHolePunch(net_context_t *context, net_addr_t *addr)
+{
+    net_addr_t *master_addr;
+    net_packet_t *packet;
+
+    master_addr = NET_Query_ResolveMaster(context);
+    if (master_addr == NULL)
+    {
+        return;
+    }
+
+    packet = NET_NewPacket(32);
+    NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_NAT_HOLE_PUNCH);
+    NET_WriteString(packet, NET_AddrToString(addr));
+    NET_SendPacket(master_addr, packet);
+
+    NET_FreePacket(packet);
+    NET_ReleaseAddress(master_addr);
+}
+
 // Given the specified address, find the target associated.  If no
 // target is found, and 'create' is true, a new target is created.

diff --git a/src/net_query.h b/src/net_query.h
index 2fea8357..6a92eae8 100644
--- a/src/net_query.h
+++ b/src/net_query.h
@@ -39,6 +39,7 @@ 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_AddResponse(net_packet_t *packet);
+extern void NET_RequestHolePunch(net_context_t *context, net_addr_t *addr);

 #endif /* #ifndef NET_QUERY_H */