Skip to content

Commit

Permalink
MP: Implement new policies for snaps and rate for servers
Browse files Browse the repository at this point in the history
This patch adds 4 new cvars:
sv_snapsPolicy 0-2
sv_ratePolicy 1 or 2
sv_clientRate <value>
sv_minRate <value>

sv_snapsPolicy 1 - New Default will enforce all connected clients' snaps to be equal to sv_fps, their local cvar setting in the userinfo is ignored.

sv_snapsPolicy 2 - Old OpenJK behavior of sv_snapsMin<>sv_snapsMax but not more than sv_fps.

sv_snapsPolicy 0 - disable entirely (do not recommend)

sv_ratePolicy - 1 New Default - Enforces all client's rate cvars to be ignored and instead uses the value within the sv_clientRate cvar instead.  See below for its default values.

sv_ratePolicy 2 - Mostly old JKA/OpenJK behaivor - sv_maxRate controlled the maximum value. No rate cvar from client means maxRate now used instead of 3000 in such cases. Hardcap of client rate is 1000 from 100000. (Previously was 1000 to 90000)

sv_clientRate - Default 50000 - This is the value which all clients are enforced to use for `rate` with sv_ratePolicy 1.

sv_minRate - Default 0 (unlimited - no lower bound) - New lower bound setting for sv_ratePolicy 2. Setting between 1 and 1000 will essentially do nothing because the minimum rate is always 1000 but not recommended. Advised keep to something sane like no lower than 4000 or 5000.
  • Loading branch information
ensiform committed May 16, 2017
1 parent 948b55b commit 6aba690
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 31 deletions.
4 changes: 4 additions & 0 deletions codemp/server/server.h
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
57 changes: 38 additions & 19 deletions codemp/server/sv_client.cpp
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions codemp/server/sv_init.cpp
Expand Up @@ -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 );
Expand All @@ -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 );
Expand Down
107 changes: 95 additions & 12 deletions codemp/server/sv_main.cpp
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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 ) {
Expand All @@ -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; 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;
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;
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions codemp/server/sv_snapshot.cpp
Expand Up @@ -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;
Expand Down

1 comment on commit 6aba690

@AlexCS1337
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

Please sign in to comment.