Skip to content

Commit 3286a85

Browse files
committed
Promote DataPacketSerializer from SDR code to shared code
Use this in the plain UDP code, so now all serializers are the same. P4:9135021
1 parent 9ebccd7 commit 3286a85

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

src/steamnetworkingsockets/clientlib/steamnetworkingsockets_udp.cpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -539,45 +539,37 @@ int CConnectionTransportUDPBase::SendEncryptedDataChunk( const void *pChunk, int
539539
UDPSendPacketContext_t &ctx = static_cast<UDPSendPacketContext_t &>( ctxBase );
540540

541541
uint8 pkt[ k_cbSteamNetworkingSocketsMaxUDPMsgLen ];
542-
UDPDataMsgHdr *hdr = (UDPDataMsgHdr *)pkt;
543-
hdr->m_unMsgFlags = 0x80;
542+
iovec gather[2];
543+
gather[0].iov_base = pkt;
544+
DataPacketSerializer<UDPDataMsgHdr> out( gather, pChunk, cbChunk );
545+
out.hdr.m_unMsgFlags = 0x80;
544546
Assert( m_connection.m_unConnectionIDRemote != 0 );
545-
hdr->m_unToConnectionID = LittleDWord( m_connection.m_unConnectionIDRemote );
546-
hdr->m_unSeqNum = LittleWord( m_connection.m_statsEndToEnd.ConsumeSendPacketNumberAndGetWireFmt( ctx.m_usecNow ) );
547-
548-
byte *p = (byte*)( hdr + 1 );
547+
out.hdr.m_unToConnectionID = LittleDWord( m_connection.m_unConnectionIDRemote );
548+
out.hdr.m_unSeqNum = LittleWord( m_connection.m_statsEndToEnd.ConsumeSendPacketNumberAndGetWireFmt( ctx.m_usecNow ) );
549549

550550
// Check how much bigger we could grow the header
551551
// and still fit in a packet
552-
int cbHdrOutSpaceRemaining = pkt + sizeof(pkt) - p - cbChunk;
553-
if ( cbHdrOutSpaceRemaining < 0 )
552+
if ( out.HdrBytesRemaining() < 0 )
554553
{
555554
AssertMsg( false, "MTU / header size problem!" );
556555
return 0;
557556
}
558557

559558
// Try to trim stuff from blob, if it won't fit
560-
ctx.Trim( cbHdrOutSpaceRemaining );
559+
ctx.Trim( out.HdrBytesRemaining() );
561560

562-
if ( ctx.Serialize( p ) )
561+
if ( ctx.Serialize( out.m_pOut ) )
563562
{
564563
// Update bookkeeping with the stuff we are actually sending
565564
TrackSentStats( ctx );
566565

567566
// Mark header with the flag
568-
hdr->m_unMsgFlags |= hdr->kFlag_ProtobufBlob;
567+
out.hdr.m_unMsgFlags |= out.hdr.kFlag_ProtobufBlob;
569568
}
570569

571570
// !FIXME! Time since previous, for jitter measurement?
572571

573-
// Use gather-based send. This saves one memcpy of every payload
574-
iovec gather[2];
575-
gather[0].iov_base = pkt;
576-
gather[0].iov_len = p - pkt;
577-
gather[1].iov_base = const_cast<void*>( pChunk );
578-
gather[1].iov_len = cbChunk;
579-
580-
int cbSend = gather[0].iov_len + gather[1].iov_len;
572+
int cbSend = out.Finish();
581573
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.)
582574

583575
// !FIXME! Should we track data payload separately? Maybe we ought to track

src/steamnetworkingsockets/steamnetworkingsockets_internal.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,62 @@ class CPossibleOutOfOrderPacket
10361036
virtual ~CPossibleOutOfOrderPacket();
10371037
};
10381038

1039+
// Helper used to serialize data packets with a header and optional inline stats blob
1040+
struct DataPacketSerializerBase
1041+
{
1042+
int HdrBytesRemaining() const { return int( m_pMaxOut - m_pOut ); }
1043+
1044+
inline void PutUint16( uint16 x )
1045+
{
1046+
*(uint16*)m_pOut = x;
1047+
m_pOut += sizeof(uint16);
1048+
Assert( m_pOut <= m_pMaxOut );
1049+
}
1050+
1051+
uint8 *m_pOut;
1052+
uint8 *m_pMaxOut;
1053+
};
1054+
1055+
// Data packet serializer used in client code, where we use iovec
1056+
// so that we let th OS gather the header and the payload in
1057+
// a single system call
1058+
template <typename THdr >
1059+
struct DataPacketSerializer : DataPacketSerializerBase
1060+
{
1061+
DataPacketSerializer( iovec *pOvecOut, const void *pPayloadIn, int cbPayload )
1062+
: m_iov_out( pOvecOut )
1063+
, hdr( *(THdr *)( pOvecOut[0].iov_base ) )
1064+
{
1065+
1066+
// Make sure we have room for our header, and some occasional inline stats, and the max payload
1067+
COMPILE_TIME_ASSERT( sizeof(THdr) + k_cbSteamNetworkingSocketsMaxEncryptedPayloadSend + 32 <= k_cbSteamNetworkingSocketsMaxUDPMsgLen );
1068+
1069+
// Set payload
1070+
m_iov_out[1].iov_base = (void*)pPayloadIn;
1071+
m_iov_out[1].iov_len = cbPayload;
1072+
1073+
// Write pointer for data after header
1074+
m_pOut = (uint8*)( &hdr + 1 );
1075+
1076+
// Max place we could advance this cursor, and still fit in the payload
1077+
m_pMaxOut = m_pOut + ( k_cbSteamNetworkingSocketsMaxUDPMsgLen - sizeof(THdr) - cbPayload );
1078+
Assert( m_pMaxOut >= m_pOut );
1079+
}
1080+
1081+
int Finish()
1082+
{
1083+
Assert( m_pOut <= m_pMaxOut );
1084+
1085+
// Set header size
1086+
m_iov_out[0].iov_len = m_pOut - (uint8*)m_iov_out[0].iov_base;
1087+
1088+
return int( m_iov_out[0].iov_len + m_iov_out[1].iov_len );
1089+
}
1090+
1091+
THdr &hdr;
1092+
iovec *m_iov_out;
1093+
};
1094+
10391095
} // namespace SteamNetworkingSocketsLib
10401096

10411097
#include <tier0/memdbgon.h>

0 commit comments

Comments
 (0)