Promote DataPacketSerializer from SDR code to shared code

Use this in the plain UDP code, so now all serializers are the same.

P4:9135021
This commit is contained in:
Fletcher Dunn
2024-08-29 17:32:06 -07:00
parent 9ebccd7646
commit 3286a85755
2 changed files with 67 additions and 19 deletions
@@ -539,45 +539,37 @@ int CConnectionTransportUDPBase::SendEncryptedDataChunk( const void *pChunk, int
UDPSendPacketContext_t &ctx = static_cast<UDPSendPacketContext_t &>( ctxBase );
uint8 pkt[ k_cbSteamNetworkingSocketsMaxUDPMsgLen ];
UDPDataMsgHdr *hdr = (UDPDataMsgHdr *)pkt;
hdr->m_unMsgFlags = 0x80;
iovec gather[2];
gather[0].iov_base = pkt;
DataPacketSerializer<UDPDataMsgHdr> out( gather, pChunk, cbChunk );
out.hdr.m_unMsgFlags = 0x80;
Assert( m_connection.m_unConnectionIDRemote != 0 );
hdr->m_unToConnectionID = LittleDWord( m_connection.m_unConnectionIDRemote );
hdr->m_unSeqNum = LittleWord( m_connection.m_statsEndToEnd.ConsumeSendPacketNumberAndGetWireFmt( ctx.m_usecNow ) );
byte *p = (byte*)( hdr + 1 );
out.hdr.m_unToConnectionID = LittleDWord( m_connection.m_unConnectionIDRemote );
out.hdr.m_unSeqNum = LittleWord( m_connection.m_statsEndToEnd.ConsumeSendPacketNumberAndGetWireFmt( ctx.m_usecNow ) );
// Check how much bigger we could grow the header
// and still fit in a packet
int cbHdrOutSpaceRemaining = pkt + sizeof(pkt) - p - cbChunk;
if ( cbHdrOutSpaceRemaining < 0 )
if ( out.HdrBytesRemaining() < 0 )
{
AssertMsg( false, "MTU / header size problem!" );
return 0;
}
// Try to trim stuff from blob, if it won't fit
ctx.Trim( cbHdrOutSpaceRemaining );
ctx.Trim( out.HdrBytesRemaining() );
if ( ctx.Serialize( p ) )
if ( ctx.Serialize( out.m_pOut ) )
{
// Update bookkeeping with the stuff we are actually sending
TrackSentStats( ctx );
// Mark header with the flag
hdr->m_unMsgFlags |= hdr->kFlag_ProtobufBlob;
out.hdr.m_unMsgFlags |= out.hdr.kFlag_ProtobufBlob;
}
// !FIXME! Time since previous, for jitter measurement?
// Use gather-based send. This saves one memcpy of every payload
iovec gather[2];
gather[0].iov_base = pkt;
gather[0].iov_len = p - pkt;
gather[1].iov_base = const_cast<void*>( pChunk );
gather[1].iov_len = cbChunk;
int cbSend = gather[0].iov_len + gather[1].iov_len;
int cbSend = out.Finish();
Assert( cbSend <= sizeof(pkt) ); // Bug in the code above. We should never "overflow" the packet. (Ignoring the fact that we using a gather-based send. The data could be tiny with a large header for piggy-backed stats.)
// !FIXME! Should we track data payload separately? Maybe we ought to track
@@ -1036,6 +1036,62 @@ protected:
virtual ~CPossibleOutOfOrderPacket();
};
// Helper used to serialize data packets with a header and optional inline stats blob
struct DataPacketSerializerBase
{
int HdrBytesRemaining() const { return int( m_pMaxOut - m_pOut ); }
inline void PutUint16( uint16 x )
{
*(uint16*)m_pOut = x;
m_pOut += sizeof(uint16);
Assert( m_pOut <= m_pMaxOut );
}
uint8 *m_pOut;
uint8 *m_pMaxOut;
};
// Data packet serializer used in client code, where we use iovec
// so that we let th OS gather the header and the payload in
// a single system call
template <typename THdr >
struct DataPacketSerializer : DataPacketSerializerBase
{
DataPacketSerializer( iovec *pOvecOut, const void *pPayloadIn, int cbPayload )
: m_iov_out( pOvecOut )
, hdr( *(THdr *)( pOvecOut[0].iov_base ) )
{
// Make sure we have room for our header, and some occasional inline stats, and the max payload
COMPILE_TIME_ASSERT( sizeof(THdr) + k_cbSteamNetworkingSocketsMaxEncryptedPayloadSend + 32 <= k_cbSteamNetworkingSocketsMaxUDPMsgLen );
// Set payload
m_iov_out[1].iov_base = (void*)pPayloadIn;
m_iov_out[1].iov_len = cbPayload;
// Write pointer for data after header
m_pOut = (uint8*)( &hdr + 1 );
// Max place we could advance this cursor, and still fit in the payload
m_pMaxOut = m_pOut + ( k_cbSteamNetworkingSocketsMaxUDPMsgLen - sizeof(THdr) - cbPayload );
Assert( m_pMaxOut >= m_pOut );
}
int Finish()
{
Assert( m_pOut <= m_pMaxOut );
// Set header size
m_iov_out[0].iov_len = m_pOut - (uint8*)m_iov_out[0].iov_base;
return int( m_iov_out[0].iov_len + m_iov_out[1].iov_len );
}
THdr &hdr;
iovec *m_iov_out;
};
} // namespace SteamNetworkingSocketsLib
#include <tier0/memdbgon.h>