r5sdk/r5dev/engine/net_chan.cpp
Kawe Mazidjatari fdd74aa622 Implement net message processing budget
Implement net message process budget (channel gets removed if value is exceeded).
Use 'net_processLimit' to enable the implementation on the server. It will get enabled by default after testing and some cleanup. This helps against people trying to slow the server down by spamming net messages with a higher rate, e.g. using 'bind "mousewheel_up" "status"'.
2022-09-18 23:19:50 +02:00

260 lines
8.1 KiB
C++

//=============================================================================//
//
// Purpose: Netchannel system utilities
//
//=============================================================================//
#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "engine/net.h"
#include "engine/net_chan.h"
#ifndef CLIENT_DLL
#include "engine/server/server.h"
#include "engine/client/client.h"
#include "server/vengineserver_impl.h"
#endif // !CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel name
// Output : const char*
//-----------------------------------------------------------------------------
const char* CNetChan::GetName(void) const
{
return this->m_Name;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel address
// Output : const char*
//-----------------------------------------------------------------------------
const char* CNetChan::GetAddress(void) const
{
// Select a static buffer
static char s[4][INET6_ADDRSTRLEN];
static int slot = 0;
int useSlot = (slot++) % 4;
// Render into it
if (!inet_ntop(AF_INET6, &this->remote_address.adr, s[useSlot], sizeof(s[0])))
{
Warning(eDLL_T::ENGINE, "%s - Address conversion failed: %s", __FUNCTION__, NET_ErrorString(WSAGetLastError()));
}
// Pray the caller uses it before it gets clobbered
return s[useSlot];
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel data rate
// Output : int
//-----------------------------------------------------------------------------
int CNetChan::GetDataRate(void) const
{
return this->m_Rate;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel buffer size (NET_FRAMES_BACKUP)
// Output : int
//-----------------------------------------------------------------------------
int CNetChan::GetBufferSize(void) const
{
return NET_FRAMES_BACKUP;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel latency
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetLatency(int flow) const
{
return this->m_DataFlow[flow].latency;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel average choke
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetAvgChoke(int flow) const
{
return this->m_DataFlow[flow].avgchoke;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel average latency
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetAvgLatency(int flow) const
{
return this->m_DataFlow[flow].avglatency;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel average loss
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetAvgLoss(int flow) const
{
return this->m_DataFlow[flow].avgloss;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel average packets
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetAvgPackets(int flow) const
{
return this->m_DataFlow[flow].avgpacketspersec;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel average data
// Input : flow -
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetAvgData(int flow) const
{
return this->m_DataFlow[flow].avgbytespersec;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel total data
// Input : flow -
// Output : int64_t
//-----------------------------------------------------------------------------
int64_t CNetChan::GetTotalData(int flow) const
{
return this->m_DataFlow[flow].totalbytes;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel total packets
// Input : flow -
// Output : int64_t
//-----------------------------------------------------------------------------
int64_t CNetChan::GetTotalPackets(int flow) const
{
return this->m_DataFlow[flow].totalpackets;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel sequence number
// Input : flow -
// Output : int
//-----------------------------------------------------------------------------
int CNetChan::GetSequenceNr(int flow) const
{
if (flow == FLOW_OUTGOING)
{
return this->m_nOutSequenceNr;
}
else if (flow == FLOW_INCOMING)
{
return this->m_nInSequenceNr;
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel connect time
// Output : double
//-----------------------------------------------------------------------------
double CNetChan::GetConnectTime(void) const
{
return this->connect_time;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel timeout
// Output : float
//-----------------------------------------------------------------------------
float CNetChan::GetTimeoutSeconds(void) const
{
return this->m_Timeout;
}
//-----------------------------------------------------------------------------
// Purpose: gets the netchannel socket
// Output : int
//-----------------------------------------------------------------------------
int CNetChan::GetSocket(void) const
{
return this->m_Socket;
}
//-----------------------------------------------------------------------------
// Purpose: checks if the reliable stream is overflowed
// Output : true if overflowed, false otherwise
//-----------------------------------------------------------------------------
bool CNetChan::IsOverflowed(void) const
{
return this->m_StreamReliable.IsOverflowed();
}
//-----------------------------------------------------------------------------
// Purpose: clears the netchannel
//-----------------------------------------------------------------------------
void CNetChan::Clear(bool bStopProcessing)
{
v_NetChan_Clear(this, bStopProcessing);
}
//-----------------------------------------------------------------------------
// Purpose: process message
// Input : *pChan -
// *pMsg -
// Output : true on success, false on failure
//-----------------------------------------------------------------------------
bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg)
{
#ifndef CLIENT_DLL
if (!ThreadInServerFrameThread() || !net_processLimit->GetInt())
return v_NetChan_ProcessMessages(pChan, pMsg);
const double flStartTime = Plat_FloatTime();
const bool bResult = v_NetChan_ProcessMessages(pChan, pMsg);
CClient* pClient = reinterpret_cast<CClient*>(pChan->m_MessageHandler);
uint16_t nSlot = pClient->GetUserID();
ServerPlayer_t* pSlot = &g_ServerPlayer[nSlot];
if (flStartTime - pSlot->m_flLastNetProcessTime >= 1.0 ||
pSlot->m_flLastNetProcessTime == -1.0)
{
pSlot->m_flLastNetProcessTime = flStartTime;
pSlot->m_flCurrentNetProcessTime = 0.0;
}
pSlot->m_flCurrentNetProcessTime +=
(Plat_FloatTime() * 1000) - (flStartTime * 1000);
if (pSlot->m_flCurrentNetProcessTime >=
net_processLimit->GetDouble())
{
pClient->Disconnect(2, "#DISCONNECT_NETCHAN_OVERFLOW");
return false;
}
return bResult;
#else // !CLIENT_DLL
return v_NetChan_ProcessMessages(pChan, pMsg);
#endif
}
///////////////////////////////////////////////////////////////////////////////
void NetChan_Attach()
{
DetourAttach((LPVOID*)&v_NetChan_ProcessMessages, &CNetChan::ProcessMessages);
}
void NetChan_Detach()
{
DetourDetach((LPVOID*)&v_NetChan_ProcessMessages, &CNetChan::ProcessMessages);
}