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) { NET_Log("server: no gamedata from %s since %d - deadlock?", NET_AddrToString(client->addr), client->last_gamedata_time); // 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) { NET_Log("server: deadlock: sending resend request for %d-%d", recvwindow_start + i, recvwindow_start + i + 5); // 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; } } // If we sent a resend request to break the deadlock, also trigger a // resend of any tics we have sitting in the send queue, in case the // client is blocked waiting on tics from us that have been lost. // This fixes deadlock with some older clients which do not send // resends to break deadlock. if (i < BACKUPTICS && client->sendseq > client->acknowledged) { NET_Log("server: also resending tics %d-%d to break deadlock", client->acknowledged, client->sendseq - 1); NET_SV_SendTics(client, client->acknowledged, client->sendseq - 1); } } }
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; } } } }
static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) { net_client_recv_t *recvobj; unsigned int seq; unsigned int ackseq; unsigned int num_tics; unsigned int nowtime; size_t i; int player; int resend_start, resend_end; int index; if (server_state != SERVER_IN_GAME) { return; } if (client->drone) { // Drones do not contribute any game data. return; } player = client->player_number; // Read header if (!NET_ReadInt8(packet, &ackseq) || !NET_ReadInt8(packet, &seq) || !NET_ReadInt8(packet, &num_tics)) { return; } // Get the current time nowtime = I_GetTimeMS(); // Expand 8-bit values to the full sequence number ackseq = NET_SV_ExpandTicNum(ackseq); seq = NET_SV_ExpandTicNum(seq); // Sanity checks for (i=0; i<num_tics; ++i) { net_ticdiff_t diff; signed int latency; if (!NET_ReadSInt16(packet, &latency) || !NET_ReadTiccmdDiff(packet, &diff, sv_settings.lowres_turn)) { return; } index = seq + i - recvwindow_start; if (index < 0 || index >= BACKUPTICS) { // Not in range of the recv window continue; } recvobj = &recvwindow[index][player]; recvobj->active = true; recvobj->diff = diff; recvobj->latency = latency; client->last_gamedata_time = nowtime; } // Higher acknowledgement point? if (ackseq > client->acknowledged) { client->acknowledged = ackseq; } // Has this been received out of sequence, ie. have we not received // all tics before the first tic in this packet? If so, send a // resend request. //printf("SV: %p: %i\n", client, seq); resend_end = seq - recvwindow_start; if (resend_end <= 0) return; if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; index = resend_end - 1; resend_start = resend_end; while (index >= 0) { recvobj = &recvwindow[index][player]; if (recvobj->active) { // ended our run of unreceived tics break; } if (recvobj->resend_time != 0) { // Already sent a resend request for this tic break; } resend_start = index; --index; } // Possibly send a resend request 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); } }
static void NET_SV_CheckResends(net_client_t *client) { int i; int player; int resend_start, resend_end; unsigned int nowtime; nowtime = I_GetTimeMS(); player = client->player_number; resend_start = -1; resend_end = -1; for (i=0; i<BACKUPTICS; ++i) { net_client_recv_t *recvobj; boolean need_resend; recvobj = &recvwindow[i][player]; // if need_resend is true, this tic needs another retransmit // request (300ms timeout) need_resend = !recvobj->active && recvobj->resend_time != 0 && nowtime > recvobj->resend_time + 300; if (need_resend) { // Start a new run of resend tics? if (resend_start < 0) { resend_start = i; } resend_end = i; } else { if (resend_start >= 0) { // End of a run of resend tics //printf("SV: resend request timed out: %i-%i\n", resend_start, resend_end); NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); resend_start = -1; } } } if (resend_start >= 0) { NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); } }