From de55d8479592399f79423ed15d9e4528945e62d6 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 21 Aug 2023 16:29:28 +0200 Subject: [PATCH] Rebuild CNetChan::ProcessMessages() Full rebuild for future 'proper' rate limit implementation. --- r5dev/engine/net_chan.cpp | 174 +++++++++++++++++++++++++++++++++++++- r5dev/engine/net_chan.h | 32 ++++--- 2 files changed, 191 insertions(+), 15 deletions(-) diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index 2d2afce0..000093b3 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -333,14 +333,14 @@ void CNetChan::_Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, // *pMsg - // Output : true on success, false on failure //----------------------------------------------------------------------------- -bool CNetChan::_ProcessMessages(CNetChan* pChan, bf_read* pMsg) +bool CNetChan::_ProcessMessages(CNetChan* pChan, bf_read* pBuf) { #ifndef CLIENT_DLL if (!ThreadInServerFrameThread() || !net_processTimeBudget->GetInt()) - return v_NetChan_ProcessMessages(pChan, pMsg); + return pChan->ProcessMessages(pBuf); const double flStartTime = Plat_FloatTime(); - const bool bResult = v_NetChan_ProcessMessages(pChan, pMsg); + const bool bResult = pChan->ProcessMessages(pBuf); if (!pChan->m_MessageHandler) // NetChannel removed? return bResult; @@ -369,10 +369,123 @@ bool CNetChan::_ProcessMessages(CNetChan* pChan, bf_read* pMsg) return bResult; #else // !CLIENT_DLL - return v_NetChan_ProcessMessages(pChan, pMsg); + return pChan->ProcessMessages(buf); #endif } +//----------------------------------------------------------------------------- +// Purpose: process message +// Input : *buf - +// Output : true on success, false on failure +//----------------------------------------------------------------------------- +bool CNetChan::ProcessMessages(bf_read* buf) +{ + m_bStopProcessing = false; + + while (true) + { + int cmd = net_NOP; + + while (true) + { + if (buf->GetNumBitsLeft() < NETMSG_TYPE_BITS) + return true; // Reached the end. + + if (!NET_ReadMessageType(&cmd, buf) && buf->m_bOverflow) + { + Warning(eDLL_T::ENGINE, "%s(%s): Incoming buffer overflow!\n", __FUNCTION__, GetAddress()); + m_MessageHandler->ConnectionCrashed("Buffer overflow in net message"); + return false; + } + + if (cmd <= net_Disconnect) + break; // Either a Disconnect or NOP packet; process it below. + + INetMessage* netMsg = FindMessage(cmd); + + if (!netMsg) + { + if (IsDebug()) + { + Warning(eDLL_T::ENGINE, "%s(%s): Received unknown net message (%i)!\n", + __FUNCTION__, GetAddress(), cmd); + } + + Assert(0); + return false; + } + + if (!netMsg->ReadFromBuffer(buf)) + { + if (IsDebug()) + { + Warning(eDLL_T::ENGINE, "%s(%s): Failed reading message '%s'!\n", + __FUNCTION__, GetAddress(), netMsg->GetName()); + } + + Assert(0); + return false; + } + + // Netmessage calls the Process function that was registered by + // it's MessageHandler. + m_bProcessingMessages = true; + const bool bRet = netMsg->Process(); + m_bProcessingMessages = false; + + // This means we were deleted during the processing of that message. + if (m_bShouldDelete) + { + delete this; + return false; + } + + // This means our message buffer was freed or invalidated during + // the processing of that message. + if (m_bStopProcessing) + return false; + + if (!bRet) + { + if (IsDebug()) + { + Warning(eDLL_T::ENGINE, "%s(%s): Failed processing message '%s'!\n", + __FUNCTION__, GetAddress(), netMsg->GetName()); + } + + Assert(0); + return false; + } + + if (IsOverflowed()) + return false; + } + + m_bProcessingMessages = true; + + if (cmd == net_NOP) // NOP; continue to next packet. + { + m_bProcessingMessages = false; + continue; + } + else if (cmd == net_Disconnect) // Disconnect request. + { + char reason[1024]; + buf->ReadString(reason, sizeof(reason), false); + + m_MessageHandler->ConnectionClosing(reason, 1); + m_bProcessingMessages = false; + } + + m_bProcessingMessages = false; + + if (m_bShouldDelete) + delete this; + + return false; + } +} + //----------------------------------------------------------------------------- // Purpose: send message // Input : &msg - @@ -408,6 +521,59 @@ bool CNetChan::SendNetMsg(INetMessage& msg, bool bForceReliable, bool bVoice) return true; } +//----------------------------------------------------------------------------- +// Purpose: finds a registered net message by type +// Input : type - +// Output : net message pointer on success, NULL otherwise +//----------------------------------------------------------------------------- +INetMessage* CNetChan::FindMessage(int type) +{ + int numtypes = m_NetMessages.Count(); + + for (int i = 0; i < numtypes; i++) + { + if (m_NetMessages[i]->GetType() == type) + return m_NetMessages[i]; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: registers a net message +// Input : *msg +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CNetChan::RegisterMessage(INetMessage* msg) +{ + Assert(msg); + + if (FindMessage(msg->GetType())) + { + Assert(0); // Duplicate registration! + return false; + } + + m_NetMessages.AddToTail(msg); + msg->SetNetChannel(this); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: free's the receive data fragment list +//----------------------------------------------------------------------------- +void CNetChan::FreeReceiveList() +{ + m_ReceiveList.blockSize = NULL; + m_ReceiveList.transferSize = NULL; + if (m_ReceiveList.buffer) + { + delete m_ReceiveList.buffer; + m_ReceiveList.buffer = nullptr; + } +} + //----------------------------------------------------------------------------- // Purpose: check if there is still data in the reliable waiting buffers //----------------------------------------------------------------------------- diff --git a/r5dev/engine/net_chan.h b/r5dev/engine/net_chan.h index f9a7d4a8..ba3a483b 100644 --- a/r5dev/engine/net_chan.h +++ b/r5dev/engine/net_chan.h @@ -66,17 +66,17 @@ typedef struct netflow_s //----------------------------------------------------------------------------- struct dataFragments_t { - char* data; - int64_t block_size; - bool m_bIsCompressed; + char* buffer; + int64_t blockSize; + bool isCompressed; uint8_t gap11[7]; - int64_t m_nRawSize; - bool m_bFirstFragment; - bool m_bLastFragment; - bool m_bIsOutbound; + int64_t uncompressedSize; + bool firstFragment; + bool lastFragment; + bool isOutbound; int transferID; - int m_nTransferSize; - int m_nCurrentOffset; + int transferSize; + int currentOffset; }; //----------------------------------------------------------------------------- @@ -109,6 +109,12 @@ inline bool(*v_NetChan_ProcessMessages)(CNetChan* pChan, bf_read* pMsg); class CNetChan { public: + ~CNetChan() + { + Shutdown("NetChannel removed.", 1, false); + FreeReceiveList(); + } + inline const char* GetName(void) const { return m_Name; } inline const char* GetAddress(bool onlyBase = false) const { return remote_address.ToString(onlyBase); } inline int GetPort(void) const { return int(ntohs(remote_address.GetPort())); } @@ -141,9 +147,13 @@ public: inline int SendDatagram(bf_write* pDatagram) { return v_NetChan_SendDatagram(this, pDatagram); } bool SendNetMsg(INetMessage& msg, bool bForceReliable, bool bVoice); + INetMessage* FindMessage(int type); + bool RegisterMessage(INetMessage* msg); + inline void Clear(bool bStopProcessing) { v_NetChan_Clear(this, bStopProcessing); } - inline void Shutdown(const char* szReason, uint8_t bBadRep, bool bRemoveNow) - { v_NetChan_Shutdown(this, szReason, bBadRep, bRemoveNow); } + inline void Shutdown(const char* szReason, uint8_t bBadRep, bool bRemoveNow) { v_NetChan_Shutdown(this, szReason, bBadRep, bRemoveNow); } + void FreeReceiveList(); + bool ProcessMessages(bf_read* pMsg); static void _Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, bool bRemoveNow); static bool _ProcessMessages(CNetChan* pChan, bf_read* pMsg);