diff options
author | Simon Howard | 2006-10-05 17:19:43 +0000 |
---|---|---|
committer | Simon Howard | 2006-10-05 17:19:43 +0000 |
commit | 3dfc0893fae028cdcb21ffa7a18ccf3796c68e6a (patch) | |
tree | 2dfdd02673f42a1cdcd666c1441c35befeaab772 | |
parent | 14a26c3d0825a67eedffa37af5fb463776c4a7bb (diff) | |
download | chocolate-doom-3dfc0893fae028cdcb21ffa7a18ccf3796c68e6a.tar.gz chocolate-doom-3dfc0893fae028cdcb21ffa7a18ccf3796c68e6a.tar.bz2 chocolate-doom-3dfc0893fae028cdcb21ffa7a18ccf3796c68e6a.zip |
Prevent against deadlock where client and server are both stuck waiting
for each other to send data.
Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 685
-rw-r--r-- | src/net_client.c | 47 | ||||
-rw-r--r-- | src/net_server.c | 76 |
2 files changed, 116 insertions, 7 deletions
diff --git a/src/net_client.c b/src/net_client.c index e13b8ea3..a3281ac8 100644 --- a/src/net_client.c +++ b/src/net_client.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_client.c 680 2006-09-29 21:25:13Z fraggle $ +// $Id: net_client.c 685 2006-10-05 17:19:43Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -542,7 +542,6 @@ static void NET_CL_SendTics(int start, int end) return; } - if (start < 0) start = 0; @@ -748,10 +747,16 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) printf("Syncing netgames like Vanilla Doom.\n"); } + // Clear the receive window + memset(recvwindow, 0, sizeof(recvwindow)); recvwindow_start = 0; memset(&recvwindow_cmd_base, 0, sizeof(recvwindow_cmd_base)); + // Clear the send queue + + memset(&send_queue, 0x00, sizeof(send_queue)); + netgame = true; autostart = true; } @@ -973,19 +978,53 @@ static void NET_CL_ParseGameData(net_packet_t *packet) static void NET_CL_ParseResendRequest(net_packet_t *packet) { static unsigned int start; + static unsigned int end; static unsigned int num_tics; + if (drone) + { + // Drones don't send gamedata. + + return; + } + if (!NET_ReadInt32(packet, &start) || !NET_ReadInt8(packet, &num_tics)) { return; } + end = start + num_tics - 1; + + //printf("requested resend %i-%i .. ", start, end); + + // Check we have the tics being requested. If not, reduce the + // window of tics to only what we have. + + while (start <= end + && (!send_queue[start % BACKUPTICS].active + || send_queue[start % BACKUPTICS].seq != start)) + { + ++start; + } + + while (start <= end + && (!send_queue[end % BACKUPTICS].active + || send_queue[end % BACKUPTICS].seq != end)) + { + --end; + } + + //printf("%i-%i\n", start, end); + // Resend those tics - //printf("CL: resend %i-%i\n", start, start+num_tics-1); + if (start <= end) + { + //printf("CL: resend %i-%i\n", start, start+num_tics-1); - NET_CL_SendTics(start, start + num_tics - 1); + NET_CL_SendTics(start, end); + } } // Console message that the server wants the client to print diff --git a/src/net_server.c b/src/net_server.c index fb676843..87180793 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_server.c 682 2006-09-30 10:22:48Z fraggle $ +// $Id: net_server.c 685 2006-10-05 17:19:43Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -199,6 +199,10 @@ typedef struct int last_send_time; char *name; + // Last time new gamedata was received from this client + + int last_gamedata_time; + // recording a demo without -longtics boolean recording_lowres; @@ -535,6 +539,9 @@ static void NET_SV_InitNewClient(net_client_t *client, client->sendseq = 0; client->acknowledged = 0; client->drone = false; + + client->last_gamedata_time = 0; + memset(client->sendqueue, 0xff, sizeof(client->sendqueue)); } @@ -707,6 +714,7 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) { net_gamesettings_t settings; net_packet_t *startpacket; + int nowtime; int i; if (client != NET_SV_Controller()) @@ -757,6 +765,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) } } + nowtime = I_GetTimeMS(); + // Send start packets to each connected node for (i=0; i<MAXNETNODES; ++i) @@ -764,6 +774,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) if (!ClientConnected(&clients[i])) continue; + clients[i].last_gamedata_time = nowtime; + startpacket = NET_Conn_NewReliable(&clients[i].connection, NET_PACKET_TYPE_GAMESTART); @@ -923,6 +935,10 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) return; } + // Get the current time + + nowtime = I_GetTimeMS(); + // Expand 8-bit values to the full sequence number ackseq = NET_SV_ExpandTicNum(ackseq); @@ -954,6 +970,8 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) recvobj->active = true; recvobj->diff = diff; recvobj->latency = latency; + + client->last_gamedata_time = nowtime; } // Higher acknowledgement point? @@ -977,8 +995,6 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; - nowtime = I_GetTimeMS(); - index = resend_end - 1; resend_start = resend_end; @@ -1008,6 +1024,12 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) if (resend_start < resend_end) { + /* + printf("missed %i-%i before %i, send resend\n", + recvwindow_start + resend_start, + recvwindow_start + resend_end - 1, + seq); + */ NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end - 1); @@ -1391,6 +1413,53 @@ static void NET_SV_PumpSendQueue(net_client_t *client) ++client->sendseq; } +// Prevent against deadlock: resend requests are usually only +// triggered if we miss a packet and receive the next one. +// If we miss a whole load of packets, we can end up in a +// deadlock situation where the client will not send any more. +// If we don't receive any game data in a while, trigger a resend +// request for the next tic we're expecting. + +void NET_SV_CheckDeadlock(net_client_t *client) +{ + int nowtime; + int i; + + // Don't expect game data from clients. + + if (client->drone) + { + return; + } + + nowtime = I_GetTimeMS(); + + // If we haven't received anything for a long time, it may be a deadlock. + + if (nowtime - client->last_gamedata_time > 1000) + { + // Search the receive window for the first tic we are expecting + // from this player. + + for (i=0; i<BACKUPTICS; ++i) + { + if (!recvwindow[client->player_number][i].active) + { + //printf("Possible deadlock: Sending resend request\n"); + + // Found a tic we haven't received. Send a resend request. + + NET_SV_SendResendRequest(client, + recvwindow_start + i, + recvwindow_start + i + 5); + + client->last_gamedata_time = nowtime; + break; + } + } + } +} + // Perform any needed action on a client static void NET_SV_RunClient(net_client_t *client) @@ -1450,6 +1519,7 @@ static void NET_SV_RunClient(net_client_t *client) if (server_state == SERVER_IN_GAME) { NET_SV_PumpSendQueue(client); + NET_SV_CheckDeadlock(client); } } |