Add plumbing for internal code to send specific ECN values

Added a macro to detect if the platform supports sending ECN.
This is currently incorrect, in that it claims that only Win32 can do it,
when obviously POSIX can, too.  I left a note to come back and fix this,
and when the macro is correct, I will promote it to platform_sockets.h

P4:9147212
This commit is contained in:
Fletcher Dunn
2024-08-29 17:55:43 -07:00
parent 57600854bb
commit ec82c98767
3 changed files with 44 additions and 25 deletions
@@ -26,7 +26,6 @@
#endif
#endif
#include <tier0/memdbgoff.h>
// Ugggggggggg MSVC VS2013 STL bug: try_lock_for doesn't actually respect the timeout, it always ends up using an infinite timeout.
@@ -985,11 +984,11 @@ public:
#endif
// Implements IRawUDPSocket
virtual bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo ) const override;
virtual bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo, int ecn = -1 ) const override;
virtual void Close() override;
//// Send a packet, for really realz right now. (No checking for fake loss or lag.)
inline bool BReallySendRawPacket( int nChunks, const iovec *pChunks, const netadr_t &adrTo ) const
inline bool BReallySendRawPacket( int nChunks, const iovec *pChunks, const netadr_t &adrTo, int ecn ) const
{
Assert( m_socket != INVALID_SOCKET );
Assert( nChunks > 0 );
@@ -1081,8 +1080,11 @@ public:
CHAR control[WSA_CMSG_SPACE(sizeof(INT))];
COMPILE_TIME_ASSERT( PlatformCanSendECN() );
// Check if we need to send ECN
int ecn = GlobalConfig::ECN.Get();
if ( ecn < 0 )
ecn = GlobalConfig::ECN.Get();
if ( ecn >= 0 )
{
wsaMsg.Control.len = sizeof(control);
@@ -1126,6 +1128,8 @@ public:
}
#endif
#else
COMPILE_TIME_ASSERT( !PlatformCanSendECN() );
bool bResult;
if ( nChunks == 1 )
{
@@ -1568,7 +1572,8 @@ public:
iovec temp;
temp.iov_len = pkt.m_info.m_cbPkt;
temp.iov_base = (void *)pkt.m_pkt;
pkt.SockOwner()->BReallySendRawPacket( 1, &temp, pkt.m_info.m_adrFrom );
int ecn = pkt.m_info.m_tos == 0xff ? -1 : pkt.m_info.m_tos;
pkt.SockOwner()->BReallySendRawPacket( 1, &temp, pkt.m_info.m_adrFrom, ecn );
}
};
@@ -1776,7 +1781,7 @@ inline SteamNetworkingMicroseconds RandomJitter( const GlobalConfigValue<float>
return (SteamNetworkingMicroseconds)( flJitterMS * 1000.0f );
}
bool CRawUDPSocketImpl::BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo ) const
bool CRawUDPSocketImpl::BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo, int ecn ) const
{
SteamNetworkingGlobalLock::AssertHeldByCurrentThread();
@@ -1842,28 +1847,23 @@ bool CRawUDPSocketImpl::BSendRawPacketGather( int nChunks, const iovec *pChunks,
}
usecWhenProcess += usecReorderLag;
// No special TOS.
// Note that in the future we might want to be able to allow the caller
// to specify an ECN value.
constexpr uint8 tos = 0xff;
// Check for simulating random packet duplication
if ( bDup )
{
SteamNetworkingMicroseconds usecDupLag = 1 + (SteamNetworkingMicroseconds)WeakRandomFloat( 0.0f, GlobalConfig::FakePacketDup_TimeMax.Get()*1000.0f );
s_packetLagQueueSend.LagPacket( const_cast<CRawUDPSocketImpl *>( this ), adrTo, usecWhenProcess + usecDupLag, nChunks, pChunks, tos );
s_packetLagQueueSend.LagPacket( const_cast<CRawUDPSocketImpl *>( this ), adrTo, usecWhenProcess + usecDupLag, nChunks, pChunks, (uint8)ecn );
}
// Lag the original packet?
if ( usecWhenProcess > usecNow )
{
s_packetLagQueueSend.LagPacket( const_cast<CRawUDPSocketImpl *>( this ), adrTo, usecWhenProcess, nChunks, pChunks, tos );
s_packetLagQueueSend.LagPacket( const_cast<CRawUDPSocketImpl *>( this ), adrTo, usecWhenProcess, nChunks, pChunks, (uint8)ecn );
return true;
}
}
// Now really send it
return BReallySendRawPacket( nChunks, pChunks, adrTo );
return BReallySendRawPacket( nChunks, pChunks, adrTo, ecn );
}
void CRawUDPSocketImpl::InternalAddToCleanupQueue()
@@ -100,27 +100,27 @@ public:
/// Packets sent through this method are subject to fake loss (steamdatagram_fakepacketloss_send),
/// lag (steamdatagram_fakepacketlag_send and steamdatagram_fakepacketreorder_send), and
/// duplication (steamdatagram_fakepacketdup_send)
inline bool BSendRawPacket( const void *pPkt, int cbPkt, const netadr_t &adrTo ) const
inline bool BSendRawPacket( const void *pPkt, int cbPkt, const netadr_t &adrTo, int ecn = -1 ) const
{
iovec temp;
temp.iov_len = cbPkt;
temp.iov_base = (void *)pPkt;
return BSendRawPacketGather( 1, &temp, adrTo );
return BSendRawPacketGather( 1, &temp, adrTo, ecn );
}
inline bool BSendRawPacket( const void *pPkt, int cbPkt, const SteamNetworkingIPAddr &adrTo ) const
inline bool BSendRawPacket( const void *pPkt, int cbPkt, const SteamNetworkingIPAddr &adrTo, int ecn = -1 ) const
{
netadr_t netadrTo;
SteamNetworkingIPAddrToNetAdr( netadrTo, adrTo );
return BSendRawPacket( pPkt, cbPkt, netadrTo );
return BSendRawPacket( pPkt, cbPkt, netadrTo, ecn );
}
/// Gather-based send. Simulated lag, loss, etc are applied
virtual bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo ) const = 0;
inline bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const SteamNetworkingIPAddr &adrTo ) const
virtual bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const netadr_t &adrTo, int ecn = -1 ) const = 0;
inline bool BSendRawPacketGather( int nChunks, const iovec *pChunks, const SteamNetworkingIPAddr &adrTo, int ecn = -1 ) const
{
netadr_t netadrTo;
SteamNetworkingIPAddrToNetAdr( netadrTo, adrTo );
return BSendRawPacketGather( nChunks, pChunks, netadrTo );
return BSendRawPacketGather( nChunks, pChunks, netadrTo, ecn );
}
/// Logically close the socket. This might not actually close the socket IMMEDIATELY,
@@ -198,15 +198,15 @@ class IBoundUDPSocket
public:
/// Send a packet on this socket to the bound remote host
inline bool BSendRawPacket( const void *pPkt, int cbPkt ) const
inline bool BSendRawPacket( const void *pPkt, int cbPkt, int ecn = -1 ) const
{
return m_pRawSock->BSendRawPacket( pPkt, cbPkt, m_adr );
return m_pRawSock->BSendRawPacket( pPkt, cbPkt, m_adr, ecn );
}
/// Gather-based send to the bound remote host
inline bool BSendRawPacketGather( int nChunks, const iovec *pChunks ) const
inline bool BSendRawPacketGather( int nChunks, const iovec *pChunks, int ecn = -1 ) const
{
return m_pRawSock->BSendRawPacketGather( nChunks, pChunks, m_adr );
return m_pRawSock->BSendRawPacketGather( nChunks, pChunks, m_adr, ecn );
}
/// Close this socket and stop talking to the specified remote host
@@ -1094,6 +1094,25 @@ struct DataPacketSerializer : DataPacketSerializerBase
iovec *m_iov_out;
};
// Helpers for manipulating the Type-of-Service (TOS) field in the IPv4 header.
// https://en.wikipedia.org/wiki/Type_of_service
constexpr uint8 IPv4_TOS_DSCP_bits = 0xfc;
constexpr uint8 IPv4_TOS_ECN_bits = 0x3;
inline uint8 IPv4_TOS_make( uint8 dscp, uint8 ecn )
{
Assert( dscp < 0x40 );
Assert( ecn < 0x4 );
return ( (dscp<<2) | ecn );
}
// FIXME POSIX supports this! Need to check console support and implement all supported platforms,
// and then move this to platform_sockets
#ifdef _WIN32
#define PlatformCanSendECN() true
#else
#define PlatformCanSendECN() false
#endif
} // namespace SteamNetworkingSocketsLib
#include <tier0/memdbgon.h>