From e6ba500164dd4f9e75d8fe3958797807e2c0027e Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Fri, 15 Jul 2011 16:51:54 +0000 Subject: [PATCH] Move rate limiting / queued packet sending logic from Com_Frame() to sv_main.c --- code/qcommon/common.c | 117 +++++++++++------------------------------ code/qcommon/net_ip.c | 3 ++ code/qcommon/qcommon.h | 3 +- code/server/server.h | 3 ++ code/server/sv_init.c | 1 + code/server/sv_main.c | 81 ++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 87 deletions(-) diff --git a/code/qcommon/common.c b/code/qcommon/common.c index ce1e8765..b490ae96 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -77,7 +77,6 @@ cvar_t *cl_paused; cvar_t *sv_paused; cvar_t *cl_packetdelay; cvar_t *sv_packetdelay; -cvar_t *sv_dlRate; cvar_t *com_cameraMode; cvar_t *com_ansiColor; cvar_t *com_unfocused; @@ -2781,7 +2780,6 @@ void Com_Init( char *commandLine ) { sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM); cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT); sv_packetdelay = Cvar_Get ("sv_packetdelay", "0", CVAR_CHEAT); - sv_dlRate = Cvar_Get ("sv_dlRate", "100", CVAR_ARCHIVE); com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM); com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM); com_buildScript = Cvar_Get( "com_buildScript", "0", 0 ); @@ -3029,6 +3027,26 @@ int Com_ModifyMsec( int msec ) { return msec; } +/* +================= +Com_TimeVal +================= +*/ + +int Com_TimeVal(int minMsec) +{ + int timeVal; + + timeVal = Sys_Milliseconds() - com_frameTime; + + if(timeVal >= minMsec) + timeVal = 0; + else + timeVal = minMsec - timeVal; + + return timeVal; +} + /* ================= Com_Frame @@ -3037,10 +3055,7 @@ Com_Frame void Com_Frame( void ) { int msec, minMsec; - int timeVal; - int numBlocks = 1; - int dlStart, deltaT, delayT; - static int dlNextRound = 0; + int timeVal, timeValSV; static int lastTime = 0, bias = 0; int timeBeforeFirstEvents; @@ -3100,94 +3115,26 @@ void Com_Frame( void ) { else minMsec = 1; - msec = Sys_Milliseconds() - com_frameTime; - - if(msec >= minMsec) - timeVal = 0; - else - timeVal = minMsec - msec; - + timeVal = 0; do { if(com_sv_running->integer) { - // Send out fragmented packets now that we're idle - delayT = SV_SendQueuedMessages(); - if(delayT >= 0 && delayT < timeVal) - timeVal = delayT; + timeValSV = SV_SendQueuedPackets(); + + timeVal = Com_TimeVal(minMsec); - if(sv_dlRate->integer) - { - // Rate limiting. This is very imprecise for high - // download rates due to millisecond timedelta resolution - dlStart = Sys_Milliseconds(); - deltaT = dlNextRound - dlStart; - - if(deltaT > 0) - { - if(deltaT < timeVal) - timeVal = deltaT + 1; - } - else - { - numBlocks = SV_SendDownloadMessages(); - - if(numBlocks) - { - // There are active downloads - deltaT = Sys_Milliseconds() - dlStart; - - delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE; - delayT /= sv_dlRate->integer * 1024; - - if(delayT <= deltaT + 1) - { - // Sending the last round of download messages - // took too long for given rate, don't wait for - // next round, but always enforce a 1ms delay - // between DL message rounds so we don't hog - // all of the bandwidth. This will result in an - // effective maximum rate of 1MB/s per user, but the - // low download window size limits this anyways. - if(timeVal > 2) - timeVal = 2; - - dlNextRound = dlStart + deltaT + 1; - } - else - { - dlNextRound = dlStart + delayT; - delayT -= deltaT; - - if(delayT < timeVal) - timeVal = delayT; - } - } - } - } - else - { - if(SV_SendDownloadMessages()) - timeVal = 1; - } + if(timeValSV < timeVal) + timeVal = timeValSV; } - - if(timeVal == 0) - timeVal = 1; - - if(com_busyWait->integer) + else + timeVal = Com_TimeVal(minMsec); + + if(com_busyWait->integer || timeVal < 1) NET_Sleep(0); else NET_Sleep(timeVal - 1); - - msec = Sys_Milliseconds() - com_frameTime; - - if(msec >= minMsec) - timeVal = 0; - else - timeVal = minMsec - msec; - - } while(timeVal > 0); + } while(Com_TimeVal(minMsec)); lastTime = com_frameTime; com_frameTime = Com_EventLoop(); diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index f6f45a25..fb336cfb 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -1675,6 +1675,9 @@ void NET_Sleep(int msec) fd_set fdr; int highestfd = -1, retval; + if(msec < 0) + msec = 0; + FD_ZERO(&fdr); if(ip_socket != INVALID_SOCKET) diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 99063b99..26548888 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -1039,8 +1039,7 @@ void SV_Frame( int msec ); void SV_PacketEvent( netadr_t from, msg_t *msg ); int SV_FrameMsec(void); qboolean SV_GameCommand( void ); -int SV_SendDownloadMessages(void); -int SV_SendQueuedMessages(void); +int SV_SendQueuedPackets(void); // // UI interface diff --git a/code/server/server.h b/code/server/server.h index aaaa1b6a..b8f1ac3d 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -279,6 +279,7 @@ extern cvar_t *sv_mapChecksum; extern cvar_t *sv_serverid; extern cvar_t *sv_minRate; extern cvar_t *sv_maxRate; +extern cvar_t *sv_dlRate; extern cvar_t *sv_minPing; extern cvar_t *sv_maxPing; extern cvar_t *sv_gametype; @@ -355,6 +356,8 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ); void SV_ClientThink (client_t *cl, usercmd_t *cmd); int SV_WriteDownloadToClient(client_t *cl , msg_t *msg); +int SV_SendDownloadMessages(void); +int SV_SendQueuedMessages(void); #ifdef USE_VOIP void SV_WriteVoipToClient( client_t *cl, msg_t *msg ); diff --git a/code/server/sv_init.c b/code/server/sv_init.c index cdedc376..92e519c2 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -643,6 +643,7 @@ void SV_Init (void) sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_maxRate = Cvar_Get ("sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); + sv_dlRate = Cvar_Get("sv_dlRate", "100", CVAR_ARCHIVE | CVAR_SERVERINFO); sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_floodProtect = Cvar_Get ("sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO ); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index a4ce5081..614270c7 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -50,6 +50,7 @@ cvar_t *sv_mapChecksum; cvar_t *sv_serverid; cvar_t *sv_minRate; cvar_t *sv_maxRate; +cvar_t *sv_dlRate; cvar_t *sv_minPing; cvar_t *sv_maxPing; cvar_t *sv_gametype; @@ -1205,3 +1206,83 @@ int SV_RateMsec(client_t *client) else return rateMsec - rate; } + +/* +==================== +SV_SendQueuedPackets + +Send download messages and queued packets in the time that we're idle, i.e. +not computing a server frame or sending client snapshots. +Return the time in msec until we expect to be called next +==================== +*/ + +int SV_SendQueuedPackets() +{ + int numBlocks; + int dlStart, deltaT, delayT; + static int dlNextRound = 0; + int timeVal = INT_MAX; + + // Send out fragmented packets now that we're idle + delayT = SV_SendQueuedMessages(); + if(delayT >= 0) + timeVal = delayT; + + if(sv_dlRate->integer) + { + // Rate limiting. This is very imprecise for high + // download rates due to millisecond timedelta resolution + dlStart = Sys_Milliseconds(); + deltaT = dlNextRound - dlStart; + + if(deltaT > 0) + { + if(deltaT < timeVal) + timeVal = deltaT + 1; + } + else + { + numBlocks = SV_SendDownloadMessages(); + + if(numBlocks) + { + // There are active downloads + deltaT = Sys_Milliseconds() - dlStart; + + delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE; + delayT /= sv_dlRate->integer * 1024; + + if(delayT <= deltaT + 1) + { + // Sending the last round of download messages + // took too long for given rate, don't wait for + // next round, but always enforce a 1ms delay + // between DL message rounds so we don't hog + // all of the bandwidth. This will result in an + // effective maximum rate of 1MB/s per user, but the + // low download window size limits this anyways. + if(timeVal > 2) + timeVal = 2; + + dlNextRound = dlStart + deltaT + 1; + } + else + { + dlNextRound = dlStart + delayT; + delayT -= deltaT; + + if(delayT < timeVal) + timeVal = delayT; + } + } + } + } + else + { + if(SV_SendDownloadMessages()) + timeVal = 0; + } + + return timeVal; +}