2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-12-13 23:52:31 +00:00
# include "PacketProcessor.h"
// DG: workaround for GCC bug
const int idPacketProcessor : : RETURN_TYPE_NONE = 0 ;
const int idPacketProcessor : : RETURN_TYPE_OOB = 1 ;
const int idPacketProcessor : : RETURN_TYPE_INBAND = 2 ;
const int idPacketProcessor : : FRAGMENT_START = 0 ;
const int idPacketProcessor : : FRAGMENT_MIDDLE = 1 ;
const int idPacketProcessor : : FRAGMENT_END = 2 ;
// DG end
2012-11-26 18:58:24 +00:00
idCVar net_maxRate ( " net_maxRate " , " 50 " , CVAR_INTEGER , " max send rate in kilobytes per second " ) ;
idCVar net_showReliableCompression ( " net_showReliableCompression " , " 0 " , CVAR_BOOL , " Show reliable compression ratio. " ) ;
// we use an assert(0); return idiom in some places, which lint complains about
//lint -e527 unreachable code at token 'return'
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : QueueReliableAck
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idPacketProcessor : : QueueReliableAck ( int lastReliable )
{
2012-11-26 18:58:24 +00:00
// NOTE - Even if it was the last known sequence, go ahead and ack it, in case our last ack for this sequence got dropped
2012-11-28 15:47:07 +00:00
if ( lastReliable > = reliableSequenceRecv )
{
2012-11-26 18:58:24 +00:00
queuedReliableAck = lastReliable ;
reliableSequenceRecv = lastReliable ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : FinalizeRead
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idPacketProcessor : : FinalizeRead ( idBitMsg & inMsg , idBitMsg & outMsg , int & userValue )
{
2012-11-26 18:58:24 +00:00
userValue = 0 ;
2012-11-28 15:47:07 +00:00
idInnerPacketHeader header ;
2012-11-26 18:58:24 +00:00
header . ReadFromMsg ( inMsg ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( header . Type ( ) ! = PACKET_TYPE_FRAGMENTED ) ) // We shouldn't be fragmented at this point
{
idLib : : Printf ( " Received invalid fragmented packet. \n " ) ;
2012-11-26 18:58:24 +00:00
return RETURN_TYPE_NONE ;
}
2012-11-28 15:47:07 +00:00
if ( header . Type ( ) = = PACKET_TYPE_RELIABLE_ACK )
{
2012-11-26 18:58:24 +00:00
// Handle reliable ack
int reliableSequence = inMsg . ReadLong ( ) ;
reliable . RemoveOlderThan ( reliableSequence + 1 ) ;
header . ReadFromMsg ( inMsg ) ; // Read the new header, since the reliable ack sits on top the actual header of the message
}
2012-11-28 15:47:07 +00:00
if ( header . Type ( ) = = PACKET_TYPE_OOB )
{
2012-11-26 18:58:24 +00:00
// out-of-band packet
userValue = header . Value ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// At this point, this MUST be an in-band packet
2012-11-28 15:47:07 +00:00
if ( ! verify ( header . Type ( ) = = PACKET_TYPE_INBAND ) )
{
idLib : : Printf ( " In-band packet expected, received type %i instead. \n " , header . Type ( ) ) ;
2012-11-26 18:58:24 +00:00
return RETURN_TYPE_NONE ;
}
// Reset number of reliables received (NOTE - This means you MUST unload all reliables as they are received)
numReliable = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Handle reliable portion of in-band packets
int numReliableRecv = header . Value ( ) ;
int bufferPos = 0 ;
2012-11-28 15:47:07 +00:00
if ( numReliableRecv > 0 )
{
2012-11-26 18:58:24 +00:00
// Byte align msg
inMsg . ReadByteAlign ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int compressedSize = inMsg . ReadShort ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lzwCompressionData_t lzwData ;
idLZWCompressor lzwCompressor ( & lzwData ) ;
2012-11-28 15:47:07 +00:00
lzwCompressor . Start ( ( uint8 * ) inMsg . GetReadData ( ) + inMsg . GetReadCount ( ) , compressedSize ) ; // Read from msg
2012-11-26 18:58:24 +00:00
int reliableSequence = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lzwCompressor . ReadAgnostic < int > ( reliableSequence ) ;
2012-11-28 15:47:07 +00:00
for ( int r = 0 ; r < numReliableRecv ; r + + )
{
2012-11-26 18:58:24 +00:00
uint8 uncompMem [ MAX_MSG_SIZE ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint16 reliableDataLength = 0 ;
lzwCompressor . ReadAgnostic < uint16 > ( reliableDataLength ) ;
lzwCompressor . Read ( uncompMem , reliableDataLength ) ;
2012-11-28 15:47:07 +00:00
if ( reliableSequence + r > reliableSequenceRecv ) // Only accept newer reliable msg's than we've currently already received
{
if ( ! verify ( bufferPos + reliableDataLength < = sizeof ( reliableBuffer ) ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Reliable msg size overflow. \n " ) ;
return RETURN_TYPE_NONE ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( numReliable < MAX_RELIABLE_QUEUE ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Reliable msg count overflow. \n " ) ;
return RETURN_TYPE_NONE ;
}
memcpy ( reliableBuffer + bufferPos , uncompMem , reliableDataLength ) ;
reliableMsgSize [ numReliable ] = reliableDataLength ;
reliableMsgPtrs [ numReliable + + ] = & reliableBuffer [ bufferPos ] ;
2012-11-28 15:47:07 +00:00
bufferPos + = reliableDataLength ;
}
else
{
2012-11-26 18:58:24 +00:00
extern idCVar net_verboseReliable ;
2012-11-28 15:47:07 +00:00
if ( net_verboseReliable . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Ignoring reliable msg %i because %i was already acked \n " , ( reliableSequence + r ) , reliableSequenceRecv ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( lzwCompressor . IsOverflowed ( ) = = false ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " lzwCompressor.IsOverflowed() == true. \n " ) ;
return RETURN_TYPE_NONE ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
inMsg . SetReadCount ( inMsg . GetReadCount ( ) + compressedSize ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
QueueReliableAck ( reliableSequence + numReliableRecv - 1 ) ;
}
}
// Load actual msg
outMsg . BeginWriting ( ) ;
outMsg . WriteData ( inMsg . GetReadData ( ) + inMsg . GetReadCount ( ) , inMsg . GetRemainingData ( ) ) ;
outMsg . SetSize ( inMsg . GetRemainingData ( ) ) ;
return ( header . Type ( ) = = PACKET_TYPE_OOB ) ? RETURN_TYPE_OOB : RETURN_TYPE_INBAND ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : QueueReliableMessage
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : QueueReliableMessage ( byte type , const byte * data , int dataLen )
{
2012-11-26 18:58:24 +00:00
return reliable . Append ( reliableSequenceSend + + , & type , 1 , data , dataLen ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : CanSendMoreData
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : CanSendMoreData ( ) const
{
if ( net_maxRate . GetInteger ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return ( outgoingRateBytes < = net_maxRate . GetInteger ( ) * 1024 ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : UpdateOutgoingRate
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idPacketProcessor : : UpdateOutgoingRate ( const int time , const int size )
{
2012-11-26 18:58:24 +00:00
outgoingBytes + = size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// update outgoing rate variables
2012-11-28 15:47:07 +00:00
if ( time > outgoingRateTime )
{
outgoingRateBytes - = outgoingRateBytes * ( float ) ( time - outgoingRateTime ) / 1000.0f ;
if ( outgoingRateBytes < 0.0f )
{
2012-11-26 18:58:24 +00:00
outgoingRateBytes = 0.0f ;
}
}
outgoingRateTime = time ;
outgoingRateBytes + = size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// compute an average bandwidth at intervals
2012-11-28 15:47:07 +00:00
if ( time - lastOutgoingRateTime > BANDWIDTH_AVERAGE_PERIOD )
{
2012-11-26 18:58:24 +00:00
currentOutgoingRate = 1000 * ( outgoingBytes - lastOutgoingBytes ) / ( time - lastOutgoingRateTime ) ;
lastOutgoingBytes = outgoingBytes ;
lastOutgoingRateTime = time ;
}
}
/*
= = = = = = = = = = = = = = = = =
idPacketProcessor : : UpdateIncomingRate
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idPacketProcessor : : UpdateIncomingRate ( const int time , const int size )
{
2012-11-26 18:58:24 +00:00
incomingBytes + = size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// update incoming rate variables
2012-11-28 15:47:07 +00:00
if ( time > incomingRateTime )
{
incomingRateBytes - = incomingRateBytes * ( float ) ( time - incomingRateTime ) / 1000.0f ;
if ( incomingRateBytes < 0.0f )
{
2012-11-26 18:58:24 +00:00
incomingRateBytes = 0.0f ;
}
}
incomingRateTime = time ;
incomingRateBytes + = size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// compute an average bandwidth at intervals
2012-11-28 15:47:07 +00:00
if ( time - lastIncomingRateTime > BANDWIDTH_AVERAGE_PERIOD )
{
2012-11-26 18:58:24 +00:00
currentIncomingRate = 1000 * ( incomingBytes - lastIncomingBytes ) / ( time - lastIncomingRateTime ) ;
lastIncomingBytes = incomingBytes ;
lastIncomingRateTime = time ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : ProcessOutgoing
NOTE - We only compress reliables because we assume everything else has already been compressed .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : ProcessOutgoing ( const int time , const idBitMsg & msg , bool isOOB , int userData )
{
2012-11-26 18:58:24 +00:00
// We can only do ONE ProcessOutgoing call, then we need to do GetSendFragment to
// COMPLETELY empty unsentMsg before calling ProcessOutgoing again.
2012-11-28 15:47:07 +00:00
if ( ! verify ( fragmentedSend = = false ) )
{
idLib : : Warning ( " ProcessOutgoing: fragmentedSend == true! " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( unsentMsg . GetRemainingData ( ) = = 0 ) )
{
idLib : : Warning ( " ProcessOutgoing: unsentMsg.GetRemainingData() > 0! " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
// Build the full msg to send, which could include reliable data
unsentMsg . InitWrite ( unsentBuffer , sizeof ( unsentBuffer ) ) ;
unsentMsg . BeginWriting ( ) ;
// Ack reliables if we need to (NOTE - We will send this ack on both the in-band and out-of-band channels)
2012-11-28 15:47:07 +00:00
if ( queuedReliableAck > = 0 )
{
2012-11-26 18:58:24 +00:00
idInnerPacketHeader header ( PACKET_TYPE_RELIABLE_ACK , 0 ) ;
header . WriteToMsg ( unsentMsg ) ;
unsentMsg . WriteLong ( queuedReliableAck ) ;
queuedReliableAck = - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( isOOB )
{
if ( msg . GetSize ( ) + unsentMsg . GetSize ( ) > MAX_OOB_MSG_SIZE ) // Fragmentation not allowed for out-of-band msg's
{
idLib : : Printf ( " Out-of-band packet too large %i \n " , unsentMsg . GetSize ( ) ) ;
2012-11-26 18:58:24 +00:00
assert ( 0 ) ;
return false ;
}
// We don't need to worry about reliable for out of band packets
idInnerPacketHeader header ( PACKET_TYPE_OOB , userData ) ;
header . WriteToMsg ( unsentMsg ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Add reliable msg's here if this is an in-band packet
idInnerPacketHeader header ( PACKET_TYPE_INBAND , reliable . Num ( ) ) ;
header . WriteToMsg ( unsentMsg ) ;
2012-11-28 15:47:07 +00:00
if ( reliable . Num ( ) > 0 )
{
// Byte align unsentMsg
2012-11-26 18:58:24 +00:00
unsentMsg . WriteByteAlign ( ) ;
lzwCompressionData_t lzwData ;
idLZWCompressor lzwCompressor ( & lzwData ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lzwCompressor . Start ( unsentMsg . GetWriteData ( ) + unsentMsg . GetSize ( ) + 2 , unsentMsg . GetRemainingSpace ( ) - 2 ) ; // Write to compressed mem, not exceeding MAX_MSG_SIZE (+2 to reserve space for compressed size)
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int uncompressedSize = 4 ;
lzwCompressor . WriteAgnostic < int > ( reliable . ItemSequence ( 0 ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < reliable . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
lzwCompressor . WriteAgnostic < uint16 > ( reliable . ItemLength ( i ) ) ;
lzwCompressor . Write ( reliable . ItemData ( i ) , reliable . ItemLength ( i ) ) ;
uncompressedSize + = 2 + reliable . ItemLength ( i ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lzwCompressor . End ( ) ;
2012-11-28 15:47:07 +00:00
if ( lzwCompressor . IsOverflowed ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " reliable msg compressor overflow. " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
unsentMsg . WriteShort ( lzwCompressor . Length ( ) ) ;
unsentMsg . SetSize ( unsentMsg . GetSize ( ) + lzwCompressor . Length ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( net_showReliableCompression . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
static int totalUncompressed = 0 ;
static int totalCompressed = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
totalUncompressed + = uncompressedSize ;
totalCompressed + = lzwCompressor . Length ( ) ;
2012-11-28 15:47:07 +00:00
float ratio1 = ( float ) lzwCompressor . Length ( ) / ( float ) uncompressedSize ;
float ratio2 = ( float ) totalCompressed / ( float ) totalUncompressed ;
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Uncompressed: %i, Compressed: %i, TotalUncompressed: %i, TotalCompressed: %i, (%2.2f / %2.2f ) \n " , uncompressedSize , lzwCompressor . Length ( ) , totalUncompressed , totalCompressed , ratio1 , ratio2 ) ;
}
}
}
// Fill up with actual msg
unsentMsg . WriteData ( msg . GetReadData ( ) , msg . GetSize ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( unsentMsg . GetSize ( ) > MAX_PACKET_SIZE )
{
if ( isOOB )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " oob msg's cannot fragment " ) ;
}
fragmentedSend = true ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : GetSendFragment
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : GetSendFragment ( const int time , sessionId_t sessionID , idBitMsg & outMsg )
{
2012-11-26 18:58:24 +00:00
lastSendTime = time ;
2012-11-28 15:47:07 +00:00
if ( unsentMsg . GetRemainingData ( ) < = 0 )
{
2012-11-26 18:58:24 +00:00
return false ; // Nothing to send
}
outMsg . BeginWriting ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idOuterPacketHeader outerHeader ( sessionID ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write outer packet header to the msg
outerHeader . WriteToMsg ( outMsg ) ;
2012-11-28 15:47:07 +00:00
if ( ! fragmentedSend )
{
2012-11-26 18:58:24 +00:00
// Simple case, no fragments to sent
outMsg . WriteData ( unsentMsg . GetReadData ( ) , unsentMsg . GetSize ( ) ) ;
unsentMsg . SetSize ( 0 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
int currentSize = idMath : : ClampInt ( 0 , MAX_PACKET_SIZE , unsentMsg . GetRemainingData ( ) ) ;
assert ( currentSize > 0 ) ;
assert ( unsentMsg . GetRemainingData ( ) - currentSize > = 0 ) ;
// See if we'll have more fragments once we subtract off how much we're about to write
bool moreFragments = ( unsentMsg . GetRemainingData ( ) - currentSize > 0 ) ? true : false ;
2012-11-28 15:47:07 +00:00
if ( ! unsentMsg . GetReadCount ( ) ) // If this is the first read, then we know it's the first fragment
{
2012-11-26 18:58:24 +00:00
assert ( moreFragments ) ; // If we have a first, we must have more or something went wrong
idInnerPacketHeader header ( PACKET_TYPE_FRAGMENTED , FRAGMENT_START ) ;
header . WriteToMsg ( outMsg ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idInnerPacketHeader header ( PACKET_TYPE_FRAGMENTED , moreFragments ? FRAGMENT_MIDDLE : FRAGMENT_END ) ;
header . WriteToMsg ( outMsg ) ;
}
outMsg . WriteLong ( fragmentSequence ) ;
outMsg . WriteData ( unsentMsg . GetReadData ( ) + unsentMsg . GetReadCount ( ) , currentSize ) ;
unsentMsg . ReadData ( NULL , currentSize ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( moreFragments = = unsentMsg . GetRemainingData ( ) > 0 ) ;
fragmentedSend = moreFragments ;
fragmentSequence + + ; // Advance sequence
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
fragmentAccumulator + + ; // update the counter for the net debug hud
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// The caller needs to send this packet, so assume he did, and update rates
UpdateOutgoingRate ( time , outMsg . GetSize ( ) ) ;
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : ProcessIncoming
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idPacketProcessor : : ProcessIncoming ( int time , sessionId_t expectedSessionID , idBitMsg & msg , idBitMsg & out , int & userData , const int peerNum )
{
2012-11-26 18:58:24 +00:00
assert ( msg . GetSize ( ) < = MAX_FINAL_PACKET_SIZE ) ;
UpdateIncomingRate ( time , msg . GetSize ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idOuterPacketHeader outerHeader ;
outerHeader . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionId_t sessionID = outerHeader . GetSessionID ( ) ;
assert ( sessionID = = expectedSessionID ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( sessionID ! = SESSION_ID_CONNECTIONLESS_PARTY & & sessionID ! = SESSION_ID_CONNECTIONLESS_GAME & & sessionID ! = SESSION_ID_CONNECTIONLESS_GAME_STATE ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Expected non connectionless ID, but got a connectionless one \n " ) ;
return RETURN_TYPE_NONE ;
}
2012-11-28 15:47:07 +00:00
if ( sessionID ! = expectedSessionID )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Expected session id: %8x but got %8x instead \n " , expectedSessionID , sessionID ) ;
return RETURN_TYPE_NONE ;
}
2012-11-28 15:47:07 +00:00
int c , b ;
2012-11-26 18:58:24 +00:00
msg . SaveReadState ( c , b ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idInnerPacketHeader header ;
header . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
if ( header . Type ( ) ! = PACKET_TYPE_FRAGMENTED )
{
2012-11-26 18:58:24 +00:00
// Non fragmented
msg . RestoreReadState ( c , b ) ; // Reset since we took a byte to check the type
return FinalizeRead ( msg , out , userData ) ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
// Decode fragmented packet
int readSequence = msg . ReadLong ( ) ; // Read sequence of fragment
2012-11-28 15:47:07 +00:00
if ( header . Value ( ) = = FRAGMENT_START )
{
2012-11-26 18:58:24 +00:00
msgWritePos = 0 ; // Reset msg reconstruction write pos
2012-11-28 15:47:07 +00:00
}
else if ( fragmentSequence = = - 1 | | readSequence ! = fragmentSequence + 1 )
{
2012-11-26 18:58:24 +00:00
droppedFrags + + ;
idLib : : Printf ( " Dropped Fragments - PeerNum: %i FragmentSeq: %i, ReadSeq: %i, Total: %i \n " , peerNum , fragmentSequence , readSequence , droppedFrags ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If this is the middle or end, make sure we are reading in fragmentSequence
fragmentSequence = - 1 ;
return RETURN_TYPE_NONE ; // Out of sequence
}
fragmentSequence = readSequence ;
assert ( msg . GetRemainingData ( ) > 0 ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( msgWritePos + msg . GetRemainingData ( ) < sizeof ( msgBuffer ) ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " ProcessIncoming: Fragmented msg buffer overflow. " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memcpy ( msgBuffer + msgWritePos , msg . GetReadData ( ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
msgWritePos + = msg . GetRemainingData ( ) ;
2012-11-28 15:47:07 +00:00
if ( header . Value ( ) = = FRAGMENT_END )
{
2012-11-26 18:58:24 +00:00
// Done reconstructing the msg
idBitMsg msg ( msgBuffer , sizeof ( msgBuffer ) ) ;
msg . SetSize ( msgWritePos ) ;
return FinalizeRead ( msg , out , userData ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( header . Value ( ) = = FRAGMENT_START | | header . Value ( ) = = FRAGMENT_MIDDLE ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " ProcessIncoming: Invalid packet. \n " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we get here, this is part (either beginning or end) of a fragmented packet.
// We return RETURN_TYPE_NONE to let the caller know they don't need to do anything yet.
return RETURN_TYPE_NONE ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : ProcessConnectionlessOutgoing
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : ProcessConnectionlessOutgoing ( idBitMsg & msg , idBitMsg & out , int lobbyType , int userData )
{
2012-11-26 18:58:24 +00:00
sessionId_t sessionID = lobbyType + 1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write outer header
idOuterPacketHeader outerHeader ( sessionID ) ;
outerHeader . WriteToMsg ( out ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write inner header
idInnerPacketHeader header ( PACKET_TYPE_OOB , userData ) ;
header . WriteToMsg ( out ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write msg
out . WriteData ( msg . GetReadData ( ) , msg . GetSize ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : ProcessConnectionlessIncoming
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idPacketProcessor : : ProcessConnectionlessIncoming ( idBitMsg & msg , idBitMsg & out , int & userData )
{
2012-11-26 18:58:24 +00:00
idOuterPacketHeader outerHeader ;
outerHeader . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionId_t sessionID = outerHeader . GetSessionID ( ) ;
2012-11-28 15:47:07 +00:00
if ( sessionID ! = SESSION_ID_CONNECTIONLESS_PARTY & & sessionID ! = SESSION_ID_CONNECTIONLESS_GAME & & sessionID ! = SESSION_ID_CONNECTIONLESS_GAME_STATE )
{
2012-11-26 18:58:24 +00:00
// Not a connectionless msg (this can happen if a previously connected peer keeps sending data for whatever reason)
idLib : : Printf ( " ProcessConnectionlessIncoming: Invalid session ID - %d \n " , sessionID ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idInnerPacketHeader header ;
header . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
if ( header . Type ( ) ! = PACKET_TYPE_OOB )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " ProcessConnectionlessIncoming: header.Type() != PACKET_TYPE_OOB \n " ) ;
return false ; // Only out-of-band packets supported for connectionless
}
userData = header . Value ( ) ;
out . BeginWriting ( ) ;
out . WriteData ( msg . GetReadData ( ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
out . SetSize ( msg . GetRemainingData ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : GetSessionID
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idPacketProcessor : : sessionId_t idPacketProcessor : : GetSessionID ( idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
sessionId_t sessionID ;
2012-11-28 15:47:07 +00:00
int c , b ;
2012-11-26 18:58:24 +00:00
msg . SaveReadState ( c , b ) ;
// Read outer header
idOuterPacketHeader outerHeader ;
outerHeader . ReadFromMsg ( msg ) ;
// Get session ID
sessionID = outerHeader . GetSessionID ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . RestoreReadState ( c , b ) ;
return sessionID ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idPacketProcessor : : VerifyEmptyReliableQueue
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
idCVar net_verifyReliableQueue ( " net_verifyReliableQueue " , " 2 " , CVAR_INTEGER , " 0: warn only, 1: error, 2: fixup, 3: fixup and verbose, 4: force test " ) ;
# define RELIABLE_VERBOSE if ( net_verifyReliableQueue.GetInteger() >= 3 ) idLib::Printf
2012-11-28 15:47:07 +00:00
void idPacketProcessor : : VerifyEmptyReliableQueue ( byte keepMsgBelowThis , byte replaceWithThisMsg )
{
if ( net_verifyReliableQueue . GetInteger ( ) = = 4 )
{
2012-11-26 18:58:24 +00:00
RELIABLE_VERBOSE ( " pushing a fake game reliable \n " ) ;
2012-11-28 15:47:07 +00:00
const char * garbage = " garbage " ;
QueueReliableMessage ( keepMsgBelowThis + 4 , ( const byte * ) garbage , 8 ) ;
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( replaceWithThisMsg , NULL , 0 ) ;
}
2012-11-28 15:47:07 +00:00
if ( reliable . Num ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( net_verifyReliableQueue . GetInteger ( ) = = 1 )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " reliable queue is not empty: %d messages " , reliable . Num ( ) ) ;
return ;
}
idLib : : Warning ( " reliable queue is not empty: %d messages " , reliable . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( net_verifyReliableQueue . GetInteger ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
// drop some stuff that is potentially dangerous and should not transmit
idDataQueue < MAX_RELIABLE_QUEUE , MAX_MSG_SIZE > clean ;
RELIABLE_VERBOSE ( " rollback send sequence from %d to %d \n " , reliableSequenceSend , reliable . ItemSequence ( 0 ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < reliable . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
byte peek = reliable . ItemData ( i ) [ 0 ] ;
2012-11-28 15:47:07 +00:00
if ( peek < keepMsgBelowThis )
{
2012-11-26 18:58:24 +00:00
RELIABLE_VERBOSE ( " keeping %d \n " , peek ) ;
clean . Append ( reliable . ItemSequence ( i ) , reliable . ItemData ( i ) , reliable . ItemLength ( i ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Replace with fake msg, so we retain itemsequence ordering.
2012-11-28 15:47:07 +00:00
// If we don't do this, it's possible we remove the last msg, then append a single msg before the next send,
2012-11-26 18:58:24 +00:00
// and the client may think he already received the msg, since his last reliableSequenceRecv could be greater than our
// reliableSequenceSend if he already received the group of reliables we are mucking with
clean . Append ( reliable . ItemSequence ( i ) , & replaceWithThisMsg , 1 ) ;
RELIABLE_VERBOSE ( " dropping %d \n " , peek ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( reliable . Num ( ) = = clean . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
reliable = clean ;
}