diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/qcommon/common.c | 66 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 6 | ||||
-rw-r--r-- | src/server/server.h | 2 | ||||
-rw-r--r-- | src/server/sv_client.c | 134 | ||||
-rw-r--r-- | src/server/sv_snapshot.c | 7 |
5 files changed, 140 insertions, 75 deletions
diff --git a/src/qcommon/common.c b/src/qcommon/common.c index 4a0e48ad..c9f9816d 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -77,6 +77,7 @@ 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; @@ -2649,6 +2650,7 @@ 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", "1000", 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 ); @@ -2873,6 +2875,9 @@ void Com_Frame( void ) { int msec, minMsec; int timeVal; + int numBlocks = 1; + int dlStart, deltaT, delayT; + static int dlNextRound = 0; static int lastTime = 0, bias = 0; int timeBeforeFirstEvents; @@ -2933,13 +2938,70 @@ void Com_Frame( void ) { minMsec = 1; timeVal = 0; + do { // Busy sleep the last millisecond for better timeout precision - if(com_busyWait->integer || timeVal < 2) + if(timeVal < 2) NET_Sleep(0); else - NET_Sleep(timeVal - 1); + { + if(com_sv_running->integer) + { + // Send out download messages now that we're idle + 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. + timeVal = 2; + dlNextRound = dlStart + deltaT + 1; + } + else + { + dlNextRound = dlStart + delayT; + timeVal = delayT - deltaT; + } + } + } + } + else + SV_SendDownloadMessages(); + } + + if(com_busyWait->integer) + NET_Sleep(0); + else + NET_Sleep(timeVal - 1); + } msec = Sys_Milliseconds() - com_frameTime; diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 8a7dbe7f..165dccae 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -190,8 +190,9 @@ void NET_Sleep(int msec); #define MAX_MSGLEN 16384 // max length of a message, which may // be fragmented into multiple packets -#define MAX_DOWNLOAD_WINDOW 8 // max of eight download frames -#define MAX_DOWNLOAD_BLKSIZE 2048 // 2048 byte block chunks +#define MAX_DOWNLOAD_WINDOW 48 // ACK window of 48 download chunks. Cannot set this higher, or clients + // will overflow the reliable commands buffer +#define MAX_DOWNLOAD_BLKSIZE 1024 // 896 byte block chunks /* @@ -1008,6 +1009,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); // diff --git a/src/server/server.h b/src/server/server.h index 697d8a30..1434a87f 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -332,7 +332,7 @@ void SV_DropClient( client_t *drop, const char *reason ); void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ); void SV_ClientThink (client_t *cl, usercmd_t *cmd); -void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ); +int SV_WriteDownloadToClient(client_t *cl , msg_t *msg); #ifdef USE_VOIP void SV_WriteVoipToClient( client_t *cl, msg_t *msg ); diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 082c0417..8ff3f0a1 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -646,21 +646,19 @@ static void SV_BeginDownload_f( client_t *cl ) { SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client -Fill up msg with data +Fill up msg with data, return number of download blocks added ================== */ -void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) +int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) { int curindex; - int rate; - int blockspersnap; int unreferenced = 1; char errorMessage[1024]; char pakbuf[MAX_QPATH], *pakptr; int numRefPaks; if (!*cl->downloadName) - return; // Nothing being downloaded + return 0; // Nothing being downloaded if(!cl->download) { @@ -736,7 +734,7 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) if(cl->download) FS_FCloseFile(cl->download); - return; + return 0; } Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName ); @@ -781,81 +779,85 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) cl->downloadEOF = qtrue; // We have added the EOF block } - // Loop up to window size times based on how many blocks we can fit in the - // client snapMsec and rate + if (cl->downloadClientBlock == cl->downloadCurrentBlock) + return 0; // Nothing to transmit - // based on the rate, how many bytes can we fit in the snapMsec time of the client - // normal rate / snapshotMsec calculation - rate = cl->rate; - if ( sv_maxRate->integer ) { - if ( sv_maxRate->integer < 1000 ) { - Cvar_Set( "sv_MaxRate", "1000" ); - } - if ( sv_maxRate->integer < rate ) { - rate = sv_maxRate->integer; - } - } - if ( sv_minRate->integer ) { - if ( sv_minRate->integer < 1000 ) - Cvar_Set( "sv_minRate", "1000" ); - if ( sv_minRate->integer > rate ) - rate = sv_minRate->integer; + // Write out the next section of the file, if we have already reached our window, + // automatically start retransmitting + if (cl->downloadXmitBlock == cl->downloadCurrentBlock) + { + // We have transmitted the complete window, should we start resending? + if (svs.time - cl->downloadSendTime > 1000) + cl->downloadXmitBlock = cl->downloadClientBlock; + else + return 0; } - if (!rate) { - blockspersnap = 1; - } else { - blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / - MAX_DOWNLOAD_BLKSIZE; - } + // Send current block + curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); - if (blockspersnap < 0) - blockspersnap = 1; + MSG_WriteByte( msg, svc_download ); + MSG_WriteShort( msg, cl->downloadXmitBlock ); - while (blockspersnap--) { + // block zero is special, contains file size + if ( cl->downloadXmitBlock == 0 ) + MSG_WriteLong( msg, cl->downloadSize ); - // Write out the next section of the file, if we have already reached our window, - // automatically start retransmitting + MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); - if (cl->downloadClientBlock == cl->downloadCurrentBlock) - return; // Nothing to transmit + // Write the block + if(cl->downloadBlockSize[curindex]) + MSG_WriteData(msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex]); - if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { - // We have transmitted the complete window, should we start resending? + Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); - //FIXME: This uses a hardcoded one second timeout for lost blocks - //the timeout should be based on client rate somehow - if (svs.time - cl->downloadSendTime > 1000) - cl->downloadXmitBlock = cl->downloadClientBlock; - else - return; - } + // Move on to the next block + // It will get sent with next snap shot. The rate will keep us in line. + cl->downloadXmitBlock++; + cl->downloadSendTime = svs.time; - // Send current block - curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); + return 1; +} - MSG_WriteByte( msg, svc_download ); - MSG_WriteShort( msg, cl->downloadXmitBlock ); +/* +================== +SV_SendDownloadMessages - // block zero is special, contains file size - if ( cl->downloadXmitBlock == 0 ) - MSG_WriteLong( msg, cl->downloadSize ); - - MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); +Send download messages to all clients +================== +*/ - // Write the block - if ( cl->downloadBlockSize[curindex] ) { - MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); +int SV_SendDownloadMessages(void) +{ + int i, numDLs = 0, retval; + client_t *cl; + msg_t msg; + byte msgBuffer[MAX_MSGLEN]; + + for(i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) + { + 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); + + retval = SV_WriteDownloadToClient(cl, &msg); + + if(retval) + { + MSG_WriteByte(&msg, svc_EOF); + SV_Netchan_Transmit(cl, &msg); + numDLs += retval; + } + } } - - Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); - - // Move on to the next block - // It will get sent with next snap shot. The rate will keep us in line. - cl->downloadXmitBlock++; - - cl->downloadSendTime = svs.time; } + + return numDLs; } #ifdef USE_VOIP diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c index 10820d07..590cfd7e 100644 --- a/src/server/sv_snapshot.c +++ b/src/server/sv_snapshot.c @@ -642,9 +642,6 @@ void SV_SendClientSnapshot( client_t *client ) { // and the playerState_t SV_WriteSnapshotToClient( client, &msg ); - // Add any download data if the client is downloading - SV_WriteDownloadToClient( client, &msg ); - #ifdef USE_VOIP SV_WriteVoipToClient( client, &msg ); #endif @@ -678,6 +675,9 @@ void SV_SendClientMessages( void ) { continue; // not time yet } + if(*c->downloadName) + continue; // Client is downloading, don't send snapshots + // send additional message fragments if the last message // was too large to send at once if ( c->netchan.unsentFragments ) { @@ -691,4 +691,3 @@ void SV_SendClientMessages( void ) { SV_SendClientSnapshot( c ); } } - |