ref: 6043f76a8a44d6900b42dcdcfe78f20a0be91431
parent: e66fffd3202fe22a2eefbb4a3cb6a73048890de5
author: Simon Howard <fraggle@gmail.com>
date: Sun Jan 22 17:29:42 EST 2006
Periodically request the time from clients to estimate their offset to the server time. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 323
--- 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 @@
} doomcom_t;
+extern int extratics;
// Create any new ticcmds and broadcast to other players.
void NetUpdate (void);
@@ -148,6 +149,10 @@
//-----------------------------------------------------------------------------
//
// $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
//
--- 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 @@
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)
@@ -402,6 +428,10 @@
case NET_PACKET_TYPE_GAMEDATA:
break;
+
+ case NET_PACKET_TYPE_TIME_REQ:
+ NET_CL_ParseTimeRequest(packet);
+ break;
default:
break;
--- 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 @@
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
--- 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 @@
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 @@
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_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 @@
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 @@
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)
@@ -604,6 +693,18 @@
NET_SV_SendWaitingData(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);
}
}