EscalateQuotaTimePeriod

EscalateQuotaTimePeriod

#Overview

name: EscalateQuotaTimePeriod

The value of this variable can be defined or overridden in .ini config files. 5 .ini config files referencing this setting variable.

It is referenced in 14 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of EscalateQuotaTimePeriod is to define the time period used for determining RPC (Remote Procedure Call) count and time escalation quotas in Unreal Engine’s networking system, specifically for DoS (Denial of Service) detection and prevention.

This setting variable is primarily used by the networking subsystem of Unreal Engine, particularly in the RPC DoS detection module. It’s referenced in the Engine and Net Core modules.

The value of this variable is typically set in configuration files or through code initialization. It’s often applied in the ApplyImpliedValues() and ApplyState() functions of the RPC DoS detection system.

EscalateQuotaTimePeriod interacts with several other variables, including EscalateQuotaRPCsPerPeriod, EscalateTimeQuotaMSPerPeriod, and various counters used for tracking RPC calls over time.

Developers must be aware that:

  1. The value is capped at a maximum of 16 (as indicated by comments in the code).
  2. A value of -1 indicates that the quota system is disabled for this particular time period.
  3. It’s used in conjunction with other quota-related variables to determine when to escalate DoS prevention measures.

Best practices when using this variable include:

  1. Carefully tuning it along with other quota variables to balance between security and performance.
  2. Ensuring it’s set to a positive value when using related quota systems (EscalateQuotaRPCsPerPeriod or EscalateTimeQuotaMSPerPeriod).
  3. Validating its value in conjunction with other time period settings to maintain consistency in the DoS prevention system.
  4. Consider the implications on network performance and security when adjusting this value.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:1737, section: [RPCDoSDetection.Hitch]

Location: <Workspace>/Engine/Config/BaseEngine.ini:1745, section: [RPCDoSDetection.Burst]

Location: <Workspace>/Engine/Config/BaseEngine.ini:1756, section: [RPCDoSDetection.PersistentBurst]

Location: <Workspace>/Engine/Config/BaseEngine.ini:1769, section: [RPCDoSDetection.DoS]

Location: <Workspace>/Engine/Config/BaseEngine.ini:1785, section: [RPCDoSDetection.ExpensiveDoS]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:124

Scope (from outer to inner):

file
function     void FRPCDoSState::ApplyImpliedValues

Source code excerpt:

void FRPCDoSState::ApplyImpliedValues()
{
	EscalateQuotaTimePeriod = (EscalateQuotaRPCsPerPeriod != -1 || EscalateTimeQuotaMSPerPeriod != -1) ? EscalateQuotaTimePeriod : -1;
	RPCRepeatLimitTimePeriod = (RPCRepeatLimitPerPeriod != -1 || RPCRepeatLimitMSPerPeriod != -1) ? RPCRepeatLimitTimePeriod : -1;

	bTrackRecentRPCs = bTrackRecentRPCs || (RPCRepeatLimitPerPeriod != -1 && RPCRepeatLimitTimePeriod != -1);
	EscalateTimeQuotaSecsPerFrame = (EscalateTimeQuotaMSPerFrame != -1 ? (EscalateTimeQuotaMSPerFrame / 1000.0) : 0.0);
	EscalateTimeQuotaSecsPerPeriod = (EscalateTimeQuotaMSPerPeriod != -1 ? (EscalateTimeQuotaMSPerPeriod / 1000.0) : 0.0);
	RPCRepeatLimitSecsPerPeriod = (RPCRepeatLimitMSPerPeriod != -1 ? (RPCRepeatLimitMSPerPeriod / 1000.0) : 0.0);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:145

Scope (from outer to inner):

file
function     bool FRPCDoSState::HasHitQuota_Count

Source code excerpt:

	if (EscalateQuotaRPCsPerPeriod > 0 && !bReturnVal)
	{
		const FRPCDoSCounters& PeriodCounter = PerPeriodHistory[EscalateQuotaTimePeriod - 1];

		bReturnVal = PeriodCounter.RPCCounter + InFrameCounter.RPCCounter >= EscalateQuotaRPCsPerPeriod;

#if RPC_QUOTA_DEBUG
		UE_CLOG(bReturnVal, LogNet, Log, TEXT("HasHitQuota_Count: Hit Period Quota: RPCsPerPeriodCounter: %i, Limit: %i"),
				(PeriodCounter.RPCCounter + InFrameCounter.RPCCounter), EscalateQuotaRPCsPerPeriod);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:178

Scope (from outer to inner):

file
function     bool FRPCDoSState::HasHitQuota_Time

Source code excerpt:

	if (EscalateTimeQuotaMSPerPeriod > 0 && !bReturnVal)
	{
		const FRPCDoSCounters& PeriodCounter = PerPeriodHistory[EscalateQuotaTimePeriod - 1];

		bReturnVal = (PeriodCounter.AccumRPCTime + InFrameCounter.AccumRPCTime) >= EscalateTimeQuotaSecsPerPeriod;

#if RPC_QUOTA_DEBUG
		bDebugReturnVal = (PeriodCounter.DebugAccumRPCTime + InFrameCounter.DebugAccumRPCTime) >=
							EscalateTimeQuotaSecsPerPeriod;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:213

Scope (from outer to inner):

file
function     void FRPCDoSStateConfig::ApplyImpliedValues

Source code excerpt:

	FRPCDoSState::ApplyImpliedValues();

	if (EscalateQuotaTimePeriod > 0)
	{
		AllTimePeriods.AddUnique(EscalateQuotaTimePeriod);
	}

	if (RPCRepeatLimitTimePeriod > 0)
	{
		AllTimePeriods.AddUnique(RPCRepeatLimitTimePeriod);
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:285

Scope (from outer to inner):

file
function     void FRPCDoSStateConfig::ValidateConfig

Source code excerpt:

		};

	ValidateTimePeriod(EscalateQuotaTimePeriod, TEXT("EscalateQuotaTimePeriod"),
						(EscalateQuotaRPCsPerPeriod > 0 || EscalateTimeQuotaMSPerPeriod > 0));

	ValidateTimePeriod(RPCRepeatLimitTimePeriod, TEXT("RPCRepeatLimitTimePeriod"),
						(RPCRepeatLimitPerPeriod > 0 || RPCRepeatLimitMSPerPeriod > 0));

	if (AutoEscalateTime > 0 && AutoEscalateTime < CooloffTime)
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:317

Scope (from outer to inner):

file
function     void FRPCDoSStateConfig::ApplyState

Source code excerpt:

	Target.EscalateQuotaRPCsPerPeriod		= EscalateQuotaRPCsPerPeriod;
	Target.EscalateTimeQuotaMSPerPeriod		= EscalateTimeQuotaMSPerPeriod;
	Target.EscalateQuotaTimePeriod			= EscalateQuotaTimePeriod;
	Target.RPCRepeatLimitPerPeriod			= RPCRepeatLimitPerPeriod;
	Target.RPCRepeatLimitMSPerPeriod		= RPCRepeatLimitMSPerPeriod;
	Target.RPCRepeatLimitTimePeriod			= RPCRepeatLimitTimePeriod;
	Target.CooloffTime						= CooloffTime;
	Target.AutoEscalateTime					= AutoEscalateTime;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Net/RPCDoSDetection.cpp:663

Scope (from outer to inner):

file
function     void FRPCDoSDetection::UpdateSeverity_Private

Source code excerpt:

						double WorstTimePerSec = 0.0;

						for (int32 SecIdx=0; SecIdx<OldState.EscalateQuotaTimePeriod; SecIdx++)
						{
							int32 PerSecHistoryIdx = LastCounterPerSecHistoryIdx - SecIdx;

							PerSecHistoryIdx = (PerSecHistoryIdx < 0 ? CounterPerSecHistory.Num() + PerSecHistoryIdx : PerSecHistoryIdx);

							WorstCountPerSec = FMath::Max(CounterPerSecHistory[PerSecHistoryIdx].RPCCounter, WorstCountPerSec);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/Net/RPCDoSDetection.h:208

Scope: file

Source code excerpt:

	/** The time period to use for determining RPC count and time escalation quotas (Max: 16) */
	UPROPERTY(config)
	int8 EscalateQuotaTimePeriod		= -1;


	/** Escalation monitoring - for setting thresholds for triggering analytics (does not affect escalation quota's and RPC limiting) */

	/** The number of times this stage must be escalated to, before it is 'confirmed' as having been escalated to (for analytics) */
	UPROPERTY(config)

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Private/Net/Core/Connection/NetConnectionFaultRecoveryBase.cpp:44

Scope (from outer to inner):

file
function     EInitStateDefaultsResult FNetFaultState::InitConfigDefaultsInternal

Source code excerpt:

		bDormant = true;
		EscalateQuotaFaultsPerPeriod = 1;
		EscalateQuotaTimePeriod = 1;
	}
	else if (SeverityCategory == TEXT("Fault"))
	{
		EscalateQuotaFaultsPerPeriod = 8;
		DescalateQuotaFaultsPerPeriod = 6;
		EscalateQuotaTimePeriod = 8;
		CooloffTime = 10;
		AutoEscalateTime = 11;
	}
	else if (SeverityCategory == TEXT("PersistentFault"))
	{
		EscalateQuotaFaultsPerPeriod = 64;

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Private/Net/Core/Connection/NetConnectionFaultRecoveryBase.cpp:60

Scope (from outer to inner):

file
function     EInitStateDefaultsResult FNetFaultState::InitConfigDefaultsInternal

Source code excerpt:

		DescalateQuotaFaultsPerPeriod = 48;
		DescalateQuotaFaultPercentPerPeriod = 40;
		EscalateQuotaTimePeriod = 8;
		CooloffTime = 10;
		AutoEscalateTime = 20;
		bLogEscalate = true;
	}
	else if (SeverityCategory == TEXT("DisconnectCountdown"))
	{
		EscalateQuotaFaultPercentPerPeriod = 70;
		DescalateQuotaFaultPercentPerPeriod = 56;
		EscalateQuotaTimePeriod = 16;
		CooloffTime = 10;
		AutoEscalateTime = 60;
		bLogEscalate = true;
	}
	else if (SeverityCategory == TEXT("Disconnect"))
	{
		bCloseConnection = true;
		bLogEscalate = true;
		EscalateQuotaTimePeriod = 0;
	}
	else
	{
		ReturnVal = EInitStateDefaultsResult::NotInitialized;
	}

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Private/Net/Core/Connection/NetConnectionFaultRecoveryBase.cpp:111

Scope (from outer to inner):

file
function     void FNetFaultState::ApplyImpliedValuesInternal

Source code excerpt:



	if (EscalateQuotaTimePeriod > 0)
	{
		AllTimePeriods.AddUnique(EscalateQuotaTimePeriod);
	}

	HighestTimePeriod = FMath::Max(AllTimePeriods);
}

void FNetFaultState::ValidateConfigInternal()

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Private/Net/Core/Connection/NetConnectionFaultRecoveryBase.cpp:125

Scope (from outer to inner):

file
function     void FNetFaultState::ValidateConfigInternal

Source code excerpt:

	Super::ValidateConfigInternal();

	ValidateTimePeriod(EscalateQuotaTimePeriod, TEXT("EscalateQuotaTimePeriod"),
		((EscalateQuotaFaultsPerPeriod > 0 || EscalateQuotaFaultPercentPerPeriod > 0) ? EValidateTime::MustBeSet : EValidateTime::Optional));
}


bool FNetFaultState::HasHitAnyQuota(FHasHitAnyQuotaParms Parms) const
{
	using namespace UE::Net;

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Private/Net/Core/Connection/NetConnectionFaultRecoveryBase.cpp:145

Scope (from outer to inner):

file
function     bool FNetFaultState::HasHitAnyQuota

Source code excerpt:

			const TArrayView<FEscalationCounter>& SecondCounters = Parms.SecondCounters;
			const TArrayView<FEscalationCounter>& FrameCounters = Parms.FrameCounters;
			const TArrayView<FEscalationCounter>& CurHistory = Parms.PerPeriodHistory[EscalateQuotaTimePeriod - 1];
			int32 HighestFaultCount = 0;
			const uint8 PacketCountIdx = ToInt(ENetFaultCounters::PacketCount);
			const int32 FullPacketCount = CurHistory[PacketCountIdx].Counter + SecondCounters[PacketCountIdx].Counter +
											FrameCounters[PacketCountIdx].Counter;

			for (const int32 CounterIdx : NetCorruptionCounters)

#Loc: <Workspace>/Engine/Source/Runtime/Net/Core/Public/Net/Core/Connection/NetConnectionFaultRecoveryBase.h:68

Scope: file

Source code excerpt:

	/** The time period to use for determining escalation/de-escalation quotas (Max: 16) */
	UPROPERTY(config)
	int8 EscalateQuotaTimePeriod				= -1;


public:
	static NETCORE_API const TCHAR* GetConfigSection();
	static NETCORE_API UClass* GetBaseConfigClass();