foxygit / doom Log in
commit 6043f76a8a44d6900b42dcdcfe78f20a0be91431
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sun Jan 22 22:29:42 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sun Jan 22 22:29:42 2006 +0000

    Periodically request the time from clients to estimate their offset to
    the server time.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 323
---
 src/d_net.h      |   7 +++-
 src/net_client.c |  32 ++++++++++++++++-
 src/net_defs.h   |   8 ++++-
 src/net_server.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 146 insertions(+), 4 deletions(-)

diff --git a/src/d_net.h b/src/d_net.h
index 2b293dac..07f4e59a 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: d_net.h 18 2005-07-23 18:56:07Z fraggle $
+// $Id: d_net.h 323 2006-01-22 22:29:42Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -131,6 +131,7 @@ typedef struct
 } doomcom_t;


+extern int extratics;

 // Create any new ticcmds and broadcast to other players.
 void NetUpdate (void);
@@ -148,6 +149,10 @@ void TryRunTics (void);
 //-----------------------------------------------------------------------------
 //
 // $Log$
+// Revision 1.4  2006/01/22 22:29:42  fraggle
+// Periodically request the time from clients to estimate their offset to
+// the server time.
+//
 // Revision 1.3  2005/07/23 18:56:07  fraggle
 // Remove unneccessary pragmas
 //
diff --git a/src/net_client.c b/src/net_client.c
index ed24c239..b1f14c20 100644
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.c 312 2006-01-21 14:16:49Z fraggle $
+// $Id: net_client.c 323 2006-01-22 22:29:42Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,10 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.23  2006/01/22 22:29:42  fraggle
+// Periodically request the time from clients to estimate their offset to
+// the server time.
+//
 // Revision 1.22  2006/01/21 14:16:49  fraggle
 // Add first game data sending code. Check the client version when connecting.
 //
@@ -373,6 +377,28 @@ static void NET_CL_ParseGameStart(net_packet_t *packet)
     autostart = true;
 }

+static void NET_CL_ParseTimeRequest(net_packet_t *packet)
+{
+    net_packet_t *reply;
+    unsigned int seq;
+
+    // Received a request from the server for our current time.
+
+    if (!NET_ReadInt32(packet, &seq))
+    {
+	return;
+    }
+
+    // Send a response with our current time.
+
+    reply = NET_NewPacket(10);
+    NET_WriteInt16(reply, NET_PACKET_TYPE_TIME_RESP);
+    NET_WriteInt32(reply, seq);
+    NET_WriteInt32(reply, I_GetTimeMS());
+    NET_Conn_SendPacket(&client_connection, reply);
+    NET_FreePacket(reply);
+}
+
 // parse a received packet

 static void NET_CL_ParsePacket(net_packet_t *packet)
@@ -403,6 +429,10 @@ static void NET_CL_ParsePacket(net_packet_t *packet)
             case NET_PACKET_TYPE_GAMEDATA:
                 break;

+	    case NET_PACKET_TYPE_TIME_REQ:
+		NET_CL_ParseTimeRequest(packet);
+		break;
+
             default:
                 break;
         }
diff --git a/src/net_defs.h b/src/net_defs.h
index 310bb4ec..906ad91a 100644
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_defs.h 312 2006-01-21 14:16:49Z fraggle $
+// $Id: net_defs.h 323 2006-01-22 22:29:42Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,10 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.11  2006/01/22 22:29:42  fraggle
+// Periodically request the time from clients to estimate their offset to
+// the server time.
+//
 // Revision 1.10  2006/01/21 14:16:49  fraggle
 // Add first game data sending code. Check the client version when connecting.
 //
@@ -148,6 +152,8 @@ typedef enum
     NET_PACKET_TYPE_DISCONNECT,
     NET_PACKET_TYPE_DISCONNECT_ACK,
     NET_PACKET_TYPE_RELIABLE_ACK,
+    NET_PACKET_TYPE_TIME_REQ,
+    NET_PACKET_TYPE_TIME_RESP,
 } net_packet_type_t;

 typedef struct
diff --git a/src/net_server.c b/src/net_server.c
index a84c53a2..b9a15594 100644
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_server.c 312 2006-01-21 14:16:49Z fraggle $
+// $Id: net_server.c 323 2006-01-22 22:29:42Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,10 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.23  2006/01/22 22:29:42  fraggle
+// Periodically request the time from clients to estimate their offset to
+// the server time.
+//
 // Revision 1.22  2006/01/21 14:16:49  fraggle
 // Add first game data sending code. Check the client version when connecting.
 //
@@ -141,6 +145,12 @@ typedef struct
     net_connection_t connection;
     int last_send_time;
     char *name;
+
+    // time query variables
+
+    int last_time_req_time;
+    int time_req_seq;
+    signed int time_offset;
 } net_client_t;

 static net_server_state_t server_state;
@@ -401,6 +411,9 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
         client->addr = addr;
         client->last_send_time = -1;
         client->name = strdup(player_name);
+	client->last_time_req_time = -1;
+	client->time_req_seq = 0;
+	client->time_offset = 0;
     }

     if (client->connection.state == NET_CONN_STATE_WAITING_ACK)
@@ -460,6 +473,60 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)
     }
 }

+static void NET_SV_ParseTimeResponse(net_packet_t *packet, net_client_t *client)
+{
+    unsigned int seq;
+    unsigned int remote_time;
+    unsigned int rtt;
+    unsigned int nowtime;
+    signed int time_offset;
+
+    if (!NET_ReadInt32(packet, &seq)
+     || !NET_ReadInt32(packet, &remote_time))
+    {
+	return;
+    }
+
+    if (seq != client->time_req_seq)
+    {
+	// Not the time response we are expecting
+
+	return;
+    }
+
+    // Calculate the round trip time
+
+    nowtime = I_GetTimeMS();
+    rtt = nowtime - client->last_time_req_time;
+
+    // Adjust the remote time based on the round trip time
+
+    remote_time += rtt / 2;
+
+    // Calculate the offset to our own time
+
+    time_offset = remote_time - nowtime;
+
+    // Update the time offset
+
+    if (client->time_req_seq == 1)
+    {
+	// This is the first reply, so this is the only sample we have
+	// so far
+
+	client->time_offset = time_offset;
+    }
+    else
+    {
+	// Apply a low level filter to the time offset adjustments
+
+	client->time_offset = ((client->time_offset * 3) / 4)
+	                    + (time_offset / 4);
+    }
+
+    printf("client %p time offset: %i(%i)->%i\n", client, time_offset, rtt, client->time_offset);
+}
+
 // Process a packet received by the server

 static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
@@ -501,6 +568,9 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
             case NET_PACKET_TYPE_GAMESTART:
                 NET_SV_ParseGameStart(packet, client);
                 break;
+	    case NET_PACKET_TYPE_TIME_RESP:
+		NET_SV_ParseTimeResponse(packet, client);
+		break;
             default:
                 // unknown packet type

@@ -566,6 +636,25 @@ static void NET_SV_SendWaitingData(net_client_t *client)
     NET_FreePacket(packet);
 }

+static void NET_SV_SendTimeRequest(net_client_t *client)
+{
+    net_packet_t *packet;
+
+    ++client->time_req_seq;
+
+    // Transmit the request packet
+
+    packet = NET_NewPacket(10);
+    NET_WriteInt16(packet, NET_PACKET_TYPE_TIME_REQ);
+    NET_WriteInt32(packet, client->time_req_seq);
+    NET_Conn_SendPacket(&client->connection, packet);
+    NET_FreePacket(packet);
+
+    // Save the time we send the request
+
+    client->last_time_req_time = I_GetTimeMS();
+}
+
 // Perform any needed action on a client

 static void NET_SV_RunClient(net_client_t *client)
@@ -605,6 +694,18 @@ static void NET_SV_RunClient(net_client_t *client)
             client->last_send_time = I_GetTimeMS();
         }
     }
+
+    if (client->last_time_req_time < 0)
+    {
+	client->last_time_req_time = I_GetTimeMS() - 5000;
+    }
+
+    if (I_GetTimeMS() - client->last_time_req_time > 10000)
+    {
+	// Query the clients' times once every ten seconds.
+
+	NET_SV_SendTimeRequest(client);
+    }
 }

 // Initialise server and wait for connections