From 976f1ab5ae46c08e225bec96618a5cd00c9e42d3 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:13:47 +0100 Subject: [PATCH] Engine: fix netchan bugs and add SendData() Fixed bug in CNetChan::SendNetMsg() where the return value of INetMessage::WriteToBuffer() was not checked, nor did we return if the stream we added the message in was overflowed. If the function gets to the stage of writing the msg in the buffer, we need to return true only if we didn't overflow AND if the msg was successfully written. Also added a method for sending bitbuf data into stream of choice. --- src/engine/net_chan.cpp | 111 ++++++++++++++++++++++++++++++++++------ src/engine/net_chan.h | 10 +++- 2 files changed, 103 insertions(+), 18 deletions(-) diff --git a/src/engine/net_chan.cpp b/src/engine/net_chan.cpp index 50b9299d..1aa23ed5 100644 --- a/src/engine/net_chan.cpp +++ b/src/engine/net_chan.cpp @@ -19,16 +19,18 @@ //----------------------------------------------------------------------------- -// Purpose: gets the netchannel network loss +// Purpose: gets the netchannel resend rate // Output : float //----------------------------------------------------------------------------- -float CNetChan::GetNetworkLoss() const +float CNetChan::GetResendRate() const { - int64_t totalupdates = this->m_DataFlow[FLOW_INCOMING].totalupdates; + const int64_t totalupdates = this->m_DataFlow[FLOW_INCOMING].totalupdates; + if (!totalupdates && !this->m_nSequencesSkipped_MAYBE) return 0.0f; float lossRate = (float)(totalupdates + m_nSequencesSkipped_MAYBE); + if (totalupdates + m_nSequencesSkipped_MAYBE < 0.0f) lossRate += float(2 ^ 64); @@ -64,6 +66,36 @@ double CNetChan::GetTimeConnected(void) const return (t > 0.0) ? t : 0.0; } +//----------------------------------------------------------------------------- +// Purpose: gets the number of bits written in selected stream +//----------------------------------------------------------------------------- +int CNetChan::GetNumBitsWritten(const bool bReliable) +{ + bf_write* pStream = &m_StreamUnreliable; + + if (bReliable) + { + pStream = &m_StreamReliable; + } + + return pStream->GetNumBitsWritten(); +} + +//----------------------------------------------------------------------------- +// Purpose: gets the number of bits written in selected stream +//----------------------------------------------------------------------------- +int CNetChan::GetNumBitsLeft(const bool bReliable) +{ + bf_write* pStream = &m_StreamUnreliable; + + if (bReliable) + { + pStream = &m_StreamReliable; + } + + return pStream->GetNumBitsLeft(); +} + //----------------------------------------------------------------------------- // Purpose: flows a new packet // Input : *pChan - @@ -394,8 +426,9 @@ bool CNetChan::ProcessMessages(bf_read* buf) if (!NET_ReadMessageType(&cmd, buf) && buf->m_bOverflow) { - Warning(eDLL_T::ENGINE, "%s(%s): Incoming buffer overflow!\n", __FUNCTION__, GetAddress()); + Error(eDLL_T::ENGINE, 0, "%s(%s): Incoming buffer overflow!\n", __FUNCTION__, GetAddress()); m_MessageHandler->ConnectionCrashed("Buffer overflow in net message"); + return false; } @@ -475,6 +508,12 @@ bool CNetChan::ProcessMessages(bf_read* buf) } } +bool CNetChan::ReadSubChannelData(bf_read& buf) +{ + // TODO: rebuild this and hook + return false; +} + //----------------------------------------------------------------------------- // Purpose: send message // Input : &msg - @@ -482,10 +521,10 @@ bool CNetChan::ProcessMessages(bf_read* buf) // bVoice - // Output : true on success, false on failure //----------------------------------------------------------------------------- -bool CNetChan::SendNetMsg(INetMessage& msg, bool bForceReliable, bool bVoice) +bool CNetChan::SendNetMsg(INetMessage& msg, const bool bForceReliable, const bool bVoice) { if (remote_address.GetType() == netadrtype_t::NA_NULL) - return false; + return true; bf_write* pStream = &m_StreamUnreliable; @@ -495,19 +534,59 @@ bool CNetChan::SendNetMsg(INetMessage& msg, bool bForceReliable, bool bVoice) if (bVoice) pStream = &m_StreamVoice; - if (pStream != &m_StreamUnreliable || - pStream->GetNumBytesLeft() >= NET_UNRELIABLE_STREAM_MINSIZE) - { - AcquireSRWLockExclusive(&m_Lock); + if (pStream == &m_StreamUnreliable && pStream->GetNumBytesLeft() < NET_UNRELIABLE_STREAM_MINSIZE) + return true; - pStream->WriteUBitLong(msg.GetType(), NETMSG_TYPE_BITS); - if (!pStream->IsOverflowed()) - msg.WriteToBuffer(pStream); + AcquireSRWLockExclusive(&m_Lock); - ReleaseSRWLockExclusive(&m_Lock); - } + pStream->WriteUBitLong(msg.GetType(), NETMSG_TYPE_BITS); + const bool ret = msg.WriteToBuffer(pStream); - return true; + ReleaseSRWLockExclusive(&m_Lock); + + return !pStream->IsOverflowed() && ret; +} + +//----------------------------------------------------------------------------- +// Purpose: send data +// Input : &msg - +// bReliable - +// Output : true on success, false on failure +//----------------------------------------------------------------------------- +bool CNetChan::SendData(bf_write& msg, const bool bReliable) +{ + // Always queue any pending reliable data ahead of the fragmentation buffer + + if (remote_address.GetType() == netadrtype_t::NA_NULL) + return true; + + if (msg.GetNumBitsWritten() <= 0) + return true; + + if (msg.IsOverflowed() && !bReliable) + return true; + + bf_write& buf = bReliable + ? m_StreamReliable + : m_StreamUnreliable; + + const int dataBits = msg.GetNumBitsWritten(); + const int bitsLeft = buf.GetNumBitsLeft(); + + if (dataBits > bitsLeft) + { + if (bReliable) + { + Error(eDLL_T::ENGINE, 0, "%s(%s): Data too large for reliable buffer (%i > %i)!\n", + __FUNCTION__, GetAddress(), msg.GetNumBytesWritten(), buf.GetNumBytesLeft()); + + m_MessageHandler->ChannelDisconnect("reliable buffer is full"); + } + + return false; + } + + return buf.WriteBits(msg.GetData(), dataBits); } //----------------------------------------------------------------------------- diff --git a/src/engine/net_chan.h b/src/engine/net_chan.h index 3cd8dec5..1a032bbe 100644 --- a/src/engine/net_chan.h +++ b/src/engine/net_chan.h @@ -110,7 +110,7 @@ public: inline int GetDataRate(void) const { return m_Rate; } inline int GetBufferSize(void) const { return NET_FRAMES_BACKUP; } - float GetNetworkLoss() const; + float GetResendRate() const; inline float GetLatency(int flow) const { Assert(flow >= 0 && flow < SDK_ARRAYSIZE(m_DataFlow)); return m_DataFlow[flow].latency; } inline float GetAvgChoke(int flow) const { Assert(flow >= 0 && flow < SDK_ARRAYSIZE(m_DataFlow)); return m_DataFlow[flow].avgchoke; } @@ -128,13 +128,17 @@ public: inline int GetSocket(void) const { return m_Socket; } inline const bf_write& GetStreamVoice(void) const { return m_StreamVoice; } inline const netadr_t& GetRemoteAddress(void) const { return remote_address; } + + int GetNumBitsWritten(const bool bReliable); + int GetNumBitsLeft(const bool bReliable); inline bool IsOverflowed(void) const { return m_StreamReliable.IsOverflowed(); } bool HasPendingReliableData(void); inline bool CanPacket(void) const { return CNetChan__CanPacket(this); } inline int SendDatagram(bf_write* pDatagram) { return CNetChan__SendDatagram(this, pDatagram); } - bool SendNetMsg(INetMessage& msg, bool bForceReliable, bool bVoice); + bool SendNetMsg(INetMessage& msg, const bool bForceReliable, const bool bVoice); + bool SendData(bf_write& msg, const bool bReliable); INetMessage* FindMessage(int type); bool RegisterMessage(INetMessage* msg); @@ -144,6 +148,8 @@ public: void FreeReceiveList(); bool ProcessMessages(bf_read* pMsg); + bool ReadSubChannelData(bf_read& buf); + static void _Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, bool bRemoveNow); static bool _ProcessMessages(CNetChan* pChan, bf_read* pMsg);