From 2bf2118d79994cfd805c3ffb5b421c6a65658b84 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Wed, 13 Jul 2011 17:11:30 +0000 Subject: - Improve snapshot rate and data rate control - Make server send packet fragments and queued packets when server is idle - Voip protocol detection is tied to com_protocol making past-end-of-message reading unncessary - Use Hunk_AllocateTempMemory() for buffering VOIP packets and fix buffering scheme that ryan hates so much - Disable packet scrambling for new protocol as it is useless now - Get rid of the old packet scrambling functions predating latest point release - Use Hunk_AllocateTempMemory() for netchan packet queue to fix memory leak when client gets disconnected with packets in the queue - Use Hunk_AllocateTempMemory() for download blocks to fix memory leak when client gets disconnected with download blocks in the queue - Fix SV_RateMsec to account for udp/udp6 packet lengths --- src/server/sv_client.c | 183 +++++++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 76 deletions(-) (limited to 'src/server/sv_client.c') diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 99dca704..b05aba56 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -348,7 +348,7 @@ gotnewcl: Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name ); newcl->state = CS_CONNECTED; - newcl->nextSnapshotTime = svs.time; + newcl->lastSnapshotTime = 0; newcl->lastPacketTime = svs.time; newcl->lastConnectTime = svs.time; @@ -535,7 +535,7 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { client->gentity = ent; client->deltaMessage = -1; - client->nextSnapshotTime = svs.time; // generate a snapshot immediately + client->lastSnapshotTime = 0; // generate a snapshot immediately if(cmd) memcpy(&client->lastUsercmd, cmd, sizeof(client->lastUsercmd)); @@ -574,7 +574,7 @@ static void SV_CloseDownload( client_t *cl ) { // Free the temporary buffer space for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) { if (cl->downloadBlocks[i]) { - Z_Free( cl->downloadBlocks[i] ); + Hunk_FreeTempMemory(cl->downloadBlocks[i]); cl->downloadBlocks[i] = NULL; } } @@ -766,7 +766,7 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) - cl->downloadBlocks[curindex] = Z_Malloc( MAX_DOWNLOAD_BLKSIZE ); + cl->downloadBlocks[curindex] = Hunk_AllocateTempMemory(MAX_DOWNLOAD_BLKSIZE); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); @@ -833,11 +833,42 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) return 1; } +/* +================== +SV_SendQueuedMessages + +Send one round of fragments, or queued messages to all clients that have data pending. +Return the shortest time interval for sending next packet to client +================== +*/ + +int SV_SendQueuedMessages(void) +{ + int i, retval = -1, nextFragT; + client_t *cl; + + for(i=0; i < sv_maxclients->integer; i++) + { + cl = &svs.clients[i]; + + if(cl->state) + { + nextFragT = SV_Netchan_TransmitNextFragment(cl); + + if(nextFragT >= 0 && (retval == -1 || retval > nextFragT)) + retval = nextFragT; + } + } + + return retval; +} + + /* ================== SV_SendDownloadMessages -Send download messages to all clients +Send one round of download messages to all clients ================== */ @@ -848,25 +879,22 @@ int SV_SendDownloadMessages(void) msg_t msg; byte msgBuffer[MAX_MSGLEN]; - for(i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) + for(i=0; i < sv_maxclients->integer; i++) { + cl = &svs.clients[i]; + if(cl->state && *cl->downloadName) { - if(cl->netchan.unsentFragments) - SV_Netchan_TransmitNextFragment(cl); - else - { - MSG_Init(&msg, msgBuffer, sizeof(msgBuffer)); - MSG_WriteLong(&msg, cl->lastClientCommand); + MSG_Init(&msg, msgBuffer, sizeof(msgBuffer)); + MSG_WriteLong(&msg, cl->lastClientCommand); - retval = SV_WriteDownloadToClient(cl, &msg); + retval = SV_WriteDownloadToClient(cl, &msg); - if(retval) - { - MSG_WriteByte(&msg, svc_EOF); - SV_Netchan_Transmit(cl, &msg); - numDLs += retval; - } + if(retval) + { + MSG_WriteByte(&msg, svc_EOF); + SV_Netchan_Transmit(cl, &msg); + numDLs += retval; } } } @@ -884,43 +912,41 @@ Check to see if there is any VoIP queued for a client, and send if there is. */ void SV_WriteVoipToClient( client_t *cl, msg_t *msg ) { - voipServerPacket_t *packet = &cl->voipPacket[0]; - int totalbytes = 0; - int i; - - if (*cl->downloadName) { + if(*cl->downloadName) + { cl->queuedVoipPackets = 0; return; // no VoIP allowed if download is going, to save bandwidth. } - // Write as many VoIP packets as we reasonably can... - for (i = 0; i < cl->queuedVoipPackets; i++, packet++) { - totalbytes += packet->len; - if (totalbytes > MAX_DOWNLOAD_BLKSIZE) - break; + if(cl->queuedVoipPackets) + { + int totalbytes = 0; + int i; + voipServerPacket_t *packet; - // You have to start with a svc_EOF, so legacy clients drop the - // rest of this packet. Otherwise, those without VoIP support will - // see the svc_voip command, then panic and disconnect. - // Generally we don't send VoIP packets to legacy clients, but this - // serves as both a safety measure and a means to keep demo files - // compatible. - MSG_WriteByte( msg, svc_EOF ); - MSG_WriteByte( msg, svc_extension ); - MSG_WriteByte( msg, svc_voip ); - MSG_WriteShort( msg, packet->sender ); - MSG_WriteByte( msg, (byte) packet->generation ); - MSG_WriteLong( msg, packet->sequence ); - MSG_WriteByte( msg, packet->frames ); - MSG_WriteShort( msg, packet->len ); - MSG_WriteData( msg, packet->data, packet->len ); - } + // Write as many VoIP packets as we reasonably can... + for(i = cl->queuedVoipIndex; i < cl->queuedVoipPackets; i++) + { + packet = cl->voipPacket[i % ARRAY_LEN(cl->voipPacket)]; + + totalbytes += packet->len; + if (totalbytes > (msg->maxsize - msg->cursize) / 2) + break; + + MSG_WriteByte(msg, svc_voip); + MSG_WriteShort(msg, packet->sender); + MSG_WriteByte(msg, (byte) packet->generation); + MSG_WriteLong(msg, packet->sequence); + MSG_WriteByte(msg, packet->frames); + MSG_WriteShort(msg, packet->len); + MSG_WriteData(msg, packet->data, packet->len); + + Hunk_FreeTempMemory(packet); + } - // !!! FIXME: I hate this queue system. - cl->queuedVoipPackets -= i; - if (cl->queuedVoipPackets > 0) { - memmove( &cl->voipPacket[0], &cl->voipPacket[i], - sizeof (voipServerPacket_t) * i); + cl->queuedVoipPackets -= i; + cl->queuedVoipIndex += i; + cl->queuedVoipIndex %= ARRAY_LEN(cl->voipPacket); } } #endif @@ -1092,7 +1118,7 @@ static void SV_VerifyPaks_f( client_t *cl ) { } else { cl->pureAuthentic = 0; - cl->nextSnapshotTime = -1; + cl->lastSnapshotTime = 0; cl->state = CS_ACTIVE; SV_SendClientSnapshot( cl ); SV_SendServerCommand( cl, "disconnect \"Unpure Client. " @@ -1161,23 +1187,38 @@ void SV_UserinfoChanged( client_t *cl ) { // snaps command val = Info_ValueForKey (cl->userinfo, "snaps"); - if (strlen(val)) { + + if(strlen(val)) + { i = atoi(val); - if ( i < 1 ) { + + if(i < 1) i = 1; - } else if ( i > sv_fps->integer ) { + else if(i > sv_fps->integer) i = sv_fps->integer; - } - cl->snapshotMsec = 1000/i; - } else { - cl->snapshotMsec = 50; + + i = 1000 / i; + } + else + i = 50; + + if(i != cl->snapshotMsec) + { + // Reset last sent snapshot so we avoid desync between server frame time and snapshot send time + cl->lastSnapshotTime = 0; + cl->snapshotMsec = i; } #ifdef USE_VOIP - // in the future, (val) will be a protocol version string, so only - // accept explicitly 1, not generally non-zero. - val = Info_ValueForKey (cl->userinfo, "cl_voip"); - cl->hasVoip = (atoi(val) == 1) ? qtrue : qfalse; +#ifdef LEGACY_PROTOCOL + if(cl->compat) + cl->hasVoip = qfalse; + else +#endif + { + val = Info_ValueForKey(cl->userinfo, "cl_voip"); + cl->hasVoip = atoi(val); + } #endif // TTimo @@ -1514,7 +1555,7 @@ void SV_UserVoip( client_t *cl, msg_t *msg ) { const int recip2 = MSG_ReadLong(msg); const int recip3 = MSG_ReadLong(msg); const int packetsize = MSG_ReadShort(msg); - byte encoded[sizeof (cl->voipPacket[0].data)]; + byte encoded[sizeof(cl->voipPacket[0]->data)]; client_t *client = NULL; voipServerPacket_t *packet = NULL; int i; @@ -1588,13 +1629,15 @@ void SV_UserVoip( client_t *cl, msg_t *msg ) { continue; // no room for another packet right now. } - packet = &client->voipPacket[client->queuedVoipPackets]; + packet = Hunk_AllocateTempMemory(sizeof(*packet)); packet->sender = sender; packet->frames = frames; packet->len = packetsize; packet->generation = generation; packet->sequence = sequence; memcpy(packet->data, encoded, packetsize); + + client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet; client->queuedVoipPackets++; } } @@ -1687,18 +1730,6 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { do { c = MSG_ReadByte( msg ); - // See if this is an extension command after the EOF, which means we - // got data that a legacy server should ignore. - if ((c == clc_EOF) && (MSG_LookaheadByte( msg ) == clc_extension)) { - MSG_ReadByte( msg ); // throw the clc_extension byte away. - c = MSG_ReadByte( msg ); // something legacy servers can't do! - // sometimes you get a clc_extension at end of stream...dangling - // bits in the huffman decoder giving a bogus value? - if (c == -1) { - c = clc_EOF; - } - } - if ( c == clc_EOF ) { break; } -- cgit