diff --git a/codemp/server/server.h b/codemp/server/server.h index 8077bde54d..9f4839afb8 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -236,6 +236,7 @@ extern refexport_t *re; // interface to refresh .dll extern cvar_t *sv_snapsMin; extern cvar_t *sv_snapsMax; +extern cvar_t *sv_snapsPolicy; extern cvar_t *sv_fps; extern cvar_t *sv_timeout; extern cvar_t *sv_zombietime; @@ -254,6 +255,9 @@ extern cvar_t *sv_killserver; extern cvar_t *sv_mapname; extern cvar_t *sv_mapChecksum; extern cvar_t *sv_serverid; +extern cvar_t *sv_ratePolicy; +extern cvar_t *sv_clientRate; +extern cvar_t *sv_minRate; extern cvar_t *sv_maxRate; extern cvar_t *sv_minPing; extern cvar_t *sv_maxPing; diff --git a/codemp/server/sv_client.cpp b/codemp/server/sv_client.cpp index ef1c010f86..f6f9635f64 100644 --- a/codemp/server/sv_client.cpp +++ b/codemp/server/sv_client.cpp @@ -1130,35 +1130,54 @@ void SV_UserinfoChanged( client_t *cl ) { // if the client is on the same subnet as the server and we aren't running an // internet public server, assume they don't need a rate choke if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1 ) { - cl->rate = 99999; // lans should not rate limit + cl->rate = 100000; // lans should not rate limit } else { val = Info_ValueForKey (cl->userinfo, "rate"); - if (strlen(val)) { + if (sv_ratePolicy->integer == 1) + { + // NOTE: what if server sets some dumb sv_clientRate value? + cl->rate = sv_clientRate->integer; + } + else if( sv_ratePolicy->integer == 2) + { i = atoi(val); - cl->rate = i; - if (cl->rate < 1000) { - cl->rate = 1000; - } else if (cl->rate > 90000) { - cl->rate = 90000; + if (!i) { + i = sv_maxRate->integer; //FIXME old code was 3000 here, should increase to 5000 instead or maxRate? + } + i = Com_Clampi(1000, 100000, i); + i = Com_Clampi( sv_minRate->integer, sv_maxRate->integer, i ); + if (i != cl->rate) { + cl->rate = i; } - } else { - cl->rate = 3000; } } // snaps command //Note: cl->snapshotMsec is also validated in sv_main.cpp -> SV_CheckCvars if sv_fps, sv_snapsMin or sv_snapsMax is changed - int minSnaps = Com_Clampi( 1, sv_snapsMax->integer, sv_snapsMin->integer ); // between 1 and sv_snapsMax ( 1 <-> 40 ) - int maxSnaps = Q_min( sv_fps->integer, sv_snapsMax->integer ); // can't produce more than sv_fps snapshots/sec, but can send less than sv_fps snapshots/sec - val = Info_ValueForKey( cl->userinfo, "snaps" ); - cl->wishSnaps = atoi( val ); - if ( !cl->wishSnaps ) + int minSnaps = Com_Clampi(1, sv_snapsMax->integer, sv_snapsMin->integer); // between 1 and sv_snapsMax ( 1 <-> 40 ) + int maxSnaps = Q_min(sv_fps->integer, sv_snapsMax->integer); // can't produce more than sv_fps snapshots/sec, but can send less than sv_fps snapshots/sec + val = Info_ValueForKey(cl->userinfo, "snaps"); + cl->wishSnaps = atoi(val); + if (!cl->wishSnaps) cl->wishSnaps = maxSnaps; - i = 1000/Com_Clampi( minSnaps, maxSnaps, cl->wishSnaps ); - if( i != cl->snapshotMsec ) { - // Reset next snapshot so we avoid desync between server frame time and snapshot send time - cl->nextSnapshotTime = -1; - cl->snapshotMsec = i; + if (sv_snapsPolicy->integer == 1) + { + cl->wishSnaps = sv_fps->integer; + i = 1000 / sv_fps->integer; + if (i != cl->snapshotMsec) { + // Reset next snapshot so we avoid desync between server frame time and snapshot send time + cl->nextSnapshotTime = -1; + cl->snapshotMsec = i; + } + } + else if (sv_snapsPolicy->integer == 2) + { + i = 1000 / Com_Clampi(minSnaps, maxSnaps, cl->wishSnaps); + if (i != cl->snapshotMsec) { + // Reset next snapshot so we avoid desync between server frame time and snapshot send time + cl->nextSnapshotTime = -1; + cl->snapshotMsec = i; + } } // TTimo diff --git a/codemp/server/sv_init.cpp b/codemp/server/sv_init.cpp index d7df152eac..6a3cd6e95f 100644 --- a/codemp/server/sv_init.cpp +++ b/codemp/server/sv_init.cpp @@ -951,6 +951,14 @@ void SV_Init (void) { Cvar_CheckRange( sv_privateClients, 0, MAX_CLIENTS, qtrue ); sv_hostname = Cvar_Get ("sv_hostname", "*Jedi*", CVAR_SERVERINFO | CVAR_ARCHIVE, "The name of the server that is displayed in the serverlist" ); sv_maxclients = Cvar_Get ("sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH, "Max. connected clients" ); + + + //cvar_t *sv_ratePolicy; // 1-2 + //cvar_t *sv_clientRate; + sv_ratePolicy = Cvar_Get( "sv_ratePolicy", "1", CVAR_ARCHIVE, "Determines which policy of enforcement is used for client's \"rate\" cvar" ); + Cvar_CheckRange(sv_ratePolicy, 1, 2, qtrue); + sv_clientRate = Cvar_Get( "sv_clientRate", "50000", CVAR_ARCHIVE); + sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, "Min bandwidth rate allowed on server. Use 0 for unlimited." ); sv_maxRate = Cvar_Get ("sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, "Max bandwidth rate allowed on server. Use 0 for unlimited." ); sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); @@ -969,6 +977,8 @@ void SV_Init (void) { sv_privatePassword = Cvar_Get ("sv_privatePassword", "", CVAR_TEMP ); sv_snapsMin = Cvar_Get ("sv_snapsMin", "10", CVAR_ARCHIVE ); // 1 <=> sv_snapsMax sv_snapsMax = Cvar_Get ("sv_snapsMax", "40", CVAR_ARCHIVE ); // sv_snapsMin <=> sv_fps + sv_snapsPolicy = Cvar_Get ("sv_snapsPolicy", "1", CVAR_ARCHIVE, "Determines which policy of enforcement is used for client's \"snaps\" cvar"); + Cvar_CheckRange(sv_snapsPolicy, 0, 2, qtrue); sv_fps = Cvar_Get ("sv_fps", "40", CVAR_SERVERINFO, "Server frames per second" ); sv_timeout = Cvar_Get ("sv_timeout", "200", CVAR_TEMP ); sv_zombietime = Cvar_Get ("sv_zombietime", "2", CVAR_TEMP ); diff --git a/codemp/server/sv_main.cpp b/codemp/server/sv_main.cpp index bc67f228d2..6c61869bff 100644 --- a/codemp/server/sv_main.cpp +++ b/codemp/server/sv_main.cpp @@ -32,6 +32,7 @@ server_t sv; // local server cvar_t *sv_snapsMin; // minimum snapshots/sec a client can request, also limited by sv_snapsMax cvar_t *sv_snapsMax; // maximum snapshots/sec a client can request, also limited by sv_fps +cvar_t *sv_snapsPolicy; // 0-2 cvar_t *sv_fps = NULL; // time rate for running non-clients cvar_t *sv_timeout; // seconds without any message cvar_t *sv_zombietime; // seconds to sink messages after disconnect @@ -50,6 +51,9 @@ cvar_t *sv_killserver; // menu system can set to 1 to shut server down cvar_t *sv_mapname; cvar_t *sv_mapChecksum; cvar_t *sv_serverid; +cvar_t *sv_ratePolicy; // 1-2 +cvar_t *sv_clientRate; +cvar_t *sv_minRate; cvar_t *sv_maxRate; cvar_t *sv_minPing; cvar_t *sv_maxPing; @@ -981,6 +985,8 @@ SV_CheckCvars */ void SV_CheckCvars( void ) { static int lastModHostname = -1, lastModFramerate = -1, lastModSnapsMin = -1, lastModSnapsMax = -1; + static int lastModSnapsPolicy = -1, lastModRatePolicy = -1, lastModClientRate = -1; + static int lastModMaxRate = -1, lastModMinRate = -1; qboolean changed = qfalse; if ( sv_hostname->modificationCount != lastModHostname ) { @@ -1004,26 +1010,103 @@ void SV_CheckCvars( void ) { } } + // check limits on client "rate" values based on server settings + if ( sv_clientRate->modificationCount != lastModClientRate || + sv_minRate->modificationCount != lastModMinRate || + sv_maxRate->modificationCount != lastModMaxRate || + sv_ratePolicy->modificationCount != lastModRatePolicy ) + { + sv_clientRate->modificationCount = lastModClientRate; + sv_maxRate->modificationCount = lastModMaxRate; + sv_minRate->modificationCount = lastModMinRate; + sv_ratePolicy->modificationCount = lastModRatePolicy; + + if (sv_ratePolicy->integer == 1) + { + // NOTE: what if server sets some dumb sv_clientRate value? + client_t *cl = NULL; + int i = 0; + + for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { + // if the client is on the same subnet as the server and we aren't running an + // internet public server, assume they don't need a rate choke + if (Sys_IsLANAddress(cl->netchan.remoteAddress) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) { + cl->rate = 100000; // lans should not rate limit + } + else { + int val = sv_clientRate->integer; + if (val != cl->rate) { + cl->rate = val; + } + } + } + } + else if (sv_ratePolicy->integer == 2) + { + // NOTE: what if server sets some dumb sv_clientRate value? + client_t *cl = NULL; + int i = 0; + + for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { + // if the client is on the same subnet as the server and we aren't running an + // internet public server, assume they don't need a rate choke + if (Sys_IsLANAddress(cl->netchan.remoteAddress) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) { + cl->rate = 100000; // lans should not rate limit + } + else { + int val = cl->rate; + if (!val) { + val = sv_maxRate->integer; + } + val = Com_Clampi( 1000, 90000, val ); + val = Com_Clampi( sv_minRate->integer, sv_maxRate->integer, val ); + if (val != cl->rate) { + cl->rate = val; + } + } + } + } + } + // check limits on client "snaps" value based on server framerate and snapshot rate if ( sv_fps->modificationCount != lastModFramerate || sv_snapsMin->modificationCount != lastModSnapsMin || - sv_snapsMax->modificationCount != lastModSnapsMax ) + sv_snapsMax->modificationCount != lastModSnapsMax || + sv_snapsPolicy->modificationCount != lastModSnapsPolicy ) { - client_t *cl = NULL; - int i=0; - int minSnaps = Com_Clampi( 1, sv_snapsMax->integer, sv_snapsMin->integer ); // between 1 and sv_snapsMax ( 1 <-> 40 ) - int maxSnaps = Q_min( sv_fps->integer, sv_snapsMax->integer ); // can't produce more than sv_fps snapshots/sec, but can send less than sv_fps snapshots/sec - lastModFramerate = sv_fps->modificationCount; lastModSnapsMin = sv_snapsMin->modificationCount; lastModSnapsMax = sv_snapsMax->modificationCount; + lastModSnapsPolicy = sv_snapsPolicy->modificationCount; - for ( i=0, cl=svs.clients; iinteger; i++, cl++ ) { - int val = 1000/Com_Clampi( minSnaps, maxSnaps, cl->wishSnaps ); - if ( val != cl->snapshotMsec ) { - // Reset last sent snapshot so we avoid desync between server frame time and snapshot send time - cl->nextSnapshotTime = -1; - cl->snapshotMsec = val; + if (sv_snapsPolicy->integer == 1) + { + client_t *cl = NULL; + int i = 0; + + for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { + int val = 1000 / sv_fps->integer; + if (val != cl->snapshotMsec) { + // Reset last sent snapshot so we avoid desync between server frame time and snapshot send time + cl->nextSnapshotTime = -1; + cl->snapshotMsec = val; + } + } + } + else if (sv_snapsPolicy->integer == 2) + { + client_t *cl = NULL; + int i = 0; + int minSnaps = Com_Clampi(1, sv_snapsMax->integer, sv_snapsMin->integer); // between 1 and sv_snapsMax ( 1 <-> 40 ) + int maxSnaps = Q_min(sv_fps->integer, sv_snapsMax->integer); // can't produce more than sv_fps snapshots/sec, but can send less than sv_fps snapshots/sec + + for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { + int val = 1000 / Com_Clampi(minSnaps, maxSnaps, cl->wishSnaps); + if (val != cl->snapshotMsec) { + // Reset last sent snapshot so we avoid desync between server frame time and snapshot send time + cl->nextSnapshotTime = -1; + cl->snapshotMsec = val; + } } } } diff --git a/codemp/server/sv_snapshot.cpp b/codemp/server/sv_snapshot.cpp index 286d7f41b8..b8515bf376 100644 --- a/codemp/server/sv_snapshot.cpp +++ b/codemp/server/sv_snapshot.cpp @@ -667,6 +667,15 @@ static int SV_RateMsec( client_t *client, int messageSize ) { 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; + } + } + rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / ((int) (rate * com_timescale->value)); return rateMsec;