mirror of
https://github.com/dashr9230/SA-MP.git
synced 2024-12-22 22:47:29 +08:00
2522 lines
86 KiB
C++
2522 lines
86 KiB
C++
/// \file
|
|
///
|
|
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
|
|
///
|
|
/// Usage of RakNet is subject to the appropriate license agreement.
|
|
/// Creative Commons Licensees are subject to the
|
|
/// license found at
|
|
/// http://creativecommons.org/licenses/by-nc/2.5/
|
|
/// Single application licensees are subject to the license found at
|
|
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
|
|
/// Custom license users are subject to the terms therein.
|
|
/// GPL license users are subject to the GNU General Public
|
|
/// License as published by the Free
|
|
/// Software Foundation; either version 2 of the License, or (at your
|
|
/// option) any later version.
|
|
|
|
#include "ReliabilityLayer.h"
|
|
#include "GetTime.h"
|
|
#include "SocketLayer.h"
|
|
#include "PluginInterface.h"
|
|
#include "RakAssert.h"
|
|
#include "Rand.h"
|
|
#include "PacketEnumerations.h"
|
|
|
|
// alloca
|
|
#ifdef _COMPATIBILITY_1
|
|
#elif defined(_WIN32)
|
|
#include <malloc.h>
|
|
#elif defined(_COMPATIBILITY_2)
|
|
#include "Compatibility2Includes.h"
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
static const int DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE=512;
|
|
static const float PACKETLOSS_TOLERANCE=.02f; // What percentile packetloss we are willing to accept as background noise.
|
|
static const double MINIMUM_SEND_BPS=14400.0; // Won't go below this send rate
|
|
static const double STARTING_SEND_BPS=28800.0; // What send rate to start at.
|
|
static const float PING_MULTIPLIER_TO_RESEND=3.0; // So internet ping variation doesn't cause needless resends
|
|
static const RakNetTime MIN_PING_TO_RESEND=30; // So system timer changes and CPU lag don't send needless resends
|
|
static const RakNetTimeNS TIME_TO_NEW_SAMPLE=500000; // How many ns to wait before starting a new sample. This way buffers have time to overflow or relax at the new send rate, if they are indeed going to overflow.
|
|
static const RakNetTimeNS MAX_TIME_TO_SAMPLE=250000; // How many ns to sample the connection before deciding on a course of action(increase or decrease throughput). You must be at full send rate the whole time
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( push )
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
//#define _DEBUG_LOGGER
|
|
#ifdef _DEBUG_LOGGER
|
|
#include <windows.h>
|
|
#endif
|
|
#endif
|
|
|
|
int SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data )
|
|
{
|
|
if (key < data->splitPacketList[0]->splitPacketId)
|
|
return -1;
|
|
if (key == data->splitPacketList[0]->splitPacketId)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data )
|
|
{
|
|
if (key < data->splitPacketIndex)
|
|
return -1;
|
|
if (key == data->splitPacketIndex)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Constructor
|
|
//-------------------------------------------------------------------------------------------------------
|
|
ReliabilityLayer::ReliabilityLayer() : updateBitStream( DEFAULT_MTU_SIZE ) // preallocate the update bitstream so we can avoid a lot of reallocs at runtime
|
|
{
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
readWriteSocket = INVALID_SOCKET;
|
|
#endif
|
|
|
|
freeThreadedMemoryOnNextUpdate = false;
|
|
#ifdef _DEBUG
|
|
// Wait longer to disconnect in debug so I don't get disconnected while tracing
|
|
timeoutTime=30000;
|
|
#else
|
|
timeoutTime=10000;
|
|
#endif
|
|
|
|
#ifndef _RELEASE
|
|
maxSendBPS=minExtraPing=extraPingVariance=0;
|
|
#endif
|
|
|
|
InitializeVariables();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Destructor
|
|
//-------------------------------------------------------------------------------------------------------
|
|
ReliabilityLayer::~ReliabilityLayer()
|
|
{
|
|
FreeMemory( true ); // Free all memory immediately
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
if ( readWriteSocket != INVALID_SOCKET )
|
|
closesocket( readWriteSocket );
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Resets the layer for reuse
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::Reset( bool resetVariables )
|
|
{
|
|
FreeMemory( true ); // true because making a memory reset pending in the update cycle causes resets after reconnects. Instead, just call Reset from a single thread
|
|
if (resetVariables)
|
|
InitializeVariables();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Sets up encryption
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SetEncryptionKey( const unsigned char* key )
|
|
{
|
|
if ( key )
|
|
encryptor.SetKey( key );
|
|
else
|
|
encryptor.UnsetKey();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Assign a socket for the reliability layer to use for writing
|
|
//-------------------------------------------------------------------------------------------------------
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
|
|
#endif
|
|
void ReliabilityLayer::SetSocket( SOCKET s )
|
|
{
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
// If this hits I am probably using sequential ports while doing IO completion ports
|
|
assert( s != INVALID_SOCKET );
|
|
readWriteSocket = s;
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Get the socket held by the reliability layer
|
|
//-------------------------------------------------------------------------------------------------------
|
|
SOCKET ReliabilityLayer::GetSocket( void )
|
|
{
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
return readWriteSocket;
|
|
#else
|
|
|
|
return INVALID_SOCKET;
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable packet
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SetTimeoutTime( RakNetTime time )
|
|
{
|
|
timeoutTime=time;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Returns the value passed to SetTimeoutTime. or the default if it was never called
|
|
//-------------------------------------------------------------------------------------------------------
|
|
RakNetTime ReliabilityLayer::GetTimeoutTime(void)
|
|
{
|
|
return timeoutTime;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Initialize the variables
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::InitializeVariables( void )
|
|
{
|
|
memset( waitingForOrderedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType));
|
|
memset( waitingForSequencedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) );
|
|
memset( waitingForOrderedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) );
|
|
memset( waitingForSequencedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) );
|
|
memset( &statistics, 0, sizeof( statistics ) );
|
|
statistics.connectionStartTime = RakNet::GetTime();
|
|
splitPacketId = 0;
|
|
messageNumber = 0;
|
|
availableBandwidth=0;
|
|
lastUpdateTime= RakNet::GetTimeNS();
|
|
currentBandwidth=STARTING_SEND_BPS;
|
|
// lastPacketSendTime=retransmittedFrames=sentPackets=sentFrames=receivedPacketsCount=bytesSent=bytesReceived=0;
|
|
|
|
deadConnection = cheater = false;
|
|
lastAckTime = 0;
|
|
|
|
lowBandwidth=STARTING_SEND_BPS;
|
|
histogramStartTime=lastUpdateTime+TIME_TO_NEW_SAMPLE+ping*2*1000;
|
|
histogramEndTime=histogramStartTime+MAX_TIME_TO_SAMPLE;
|
|
|
|
highBandwidth=0;
|
|
histogramPlossCount=0;
|
|
histogramAckCount=0;
|
|
continuousSend=false;
|
|
histogramReceiveMarker=0;
|
|
noPacketlossIncreaseCount=0;
|
|
nextAckTime=statistics.connectionStartTime;
|
|
|
|
receivedPacketsBaseIndex=0;
|
|
resetReceivedPackets=true;
|
|
sendPacketCount=receivePacketCount=0;
|
|
SetPing( 1000 );
|
|
resendList.Preallocate(RESEND_TREE_ORDER*2);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Frees all allocated memory
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::FreeMemory( bool freeAllImmediately )
|
|
{
|
|
if ( freeAllImmediately )
|
|
{
|
|
FreeThreadedMemory();
|
|
FreeThreadSafeMemory();
|
|
}
|
|
else
|
|
{
|
|
FreeThreadSafeMemory();
|
|
freeThreadedMemoryOnNextUpdate = true;
|
|
}
|
|
}
|
|
|
|
void ReliabilityLayer::FreeThreadedMemory( void )
|
|
{
|
|
}
|
|
|
|
void ReliabilityLayer::FreeThreadSafeMemory( void )
|
|
{
|
|
unsigned i,j;
|
|
InternalPacket *internalPacket;
|
|
|
|
for (i=0; i < splitPacketChannelList.Size(); i++)
|
|
{
|
|
for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++)
|
|
{
|
|
delete [] splitPacketChannelList[i]->splitPacketList[j]->data;
|
|
internalPacketPool.ReleasePointer( splitPacketChannelList[i]->splitPacketList[j] );
|
|
}
|
|
delete splitPacketChannelList[i];
|
|
}
|
|
splitPacketChannelList.Clear();
|
|
|
|
while ( outputQueue.Size() > 0 )
|
|
{
|
|
internalPacket = outputQueue.Pop();
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
|
|
outputQueue.ClearAndForceAllocation( 32 );
|
|
|
|
for ( i = 0; i < orderingList.Size(); i++ )
|
|
{
|
|
if ( orderingList[ i ] )
|
|
{
|
|
DataStructures::LinkedList<InternalPacket*>* theList = orderingList[ i ];
|
|
|
|
if ( theList )
|
|
{
|
|
while ( theList->Size() )
|
|
{
|
|
internalPacket = orderingList[ i ]->Pop();
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
|
|
delete theList;
|
|
}
|
|
}
|
|
}
|
|
|
|
orderingList.Clear();
|
|
|
|
//resendList.ForEachData(DeleteInternalPacket);
|
|
resendList.Clear();
|
|
while ( resendQueue.Size() )
|
|
{
|
|
// The resend Queue can have NULL pointer holes. This is so we can deallocate blocks without having to compress the array
|
|
internalPacket = resendQueue.Pop();
|
|
|
|
if ( internalPacket )
|
|
{
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
}
|
|
resendQueue.ClearAndForceAllocation( DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE );
|
|
|
|
|
|
for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ )
|
|
{
|
|
j = 0;
|
|
for ( ; j < sendPacketSet[ i ].Size(); j++ )
|
|
{
|
|
delete [] ( sendPacketSet[ i ] ) [ j ]->data;
|
|
internalPacketPool.ReleasePointer( ( sendPacketSet[ i ] ) [ j ] );
|
|
}
|
|
|
|
sendPacketSet[ i ].ClearAndForceAllocation( 32 ); // Preallocate the send lists so we don't do a bunch of reallocations unnecessarily
|
|
}
|
|
|
|
#ifndef _RELEASE
|
|
for (unsigned i = 0; i < delayList.Size(); i++ )
|
|
delete delayList[ i ];
|
|
delayList.Clear();
|
|
#endif
|
|
|
|
internalPacketPool.ClearPool();
|
|
|
|
//messageHistogram.Clear();
|
|
|
|
acknowlegements.Clear();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Packets are read directly from the socket layer and skip the reliability
|
|
//layer because unconnected players do not use the reliability layer
|
|
// This function takes packet data after a player has been confirmed as
|
|
//connected. The game should not use that data directly
|
|
// because some data is used internally, such as packet acknowledgement and
|
|
//split packets
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffer, int length, PlayerID playerId, DataStructures::List<PluginInterface*> &messageHandlerList, int MTUSize )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( !( length <= 0 || buffer == 0 ) );
|
|
#endif
|
|
|
|
if ( length <= 1 || buffer == 0 ) // Length of 1 is a connection request resend that we just ignore
|
|
return true;
|
|
|
|
//int numberOfAcksInFrame = 0;
|
|
RakNetTimeNS time;
|
|
bool indexFound;
|
|
int count, size;
|
|
MessageNumberType holeCount;
|
|
unsigned i;
|
|
unsigned ackedHistogramCounter;
|
|
bool hasAcks=false;
|
|
|
|
// bool duplicatePacket;
|
|
|
|
// bytesReceived+=length + UDP_HEADER_SIZE;
|
|
|
|
UpdateThreadedMemory();
|
|
|
|
// decode this whole chunk if the decoder is defined.
|
|
if ( encryptor.IsKeySet() )
|
|
{
|
|
if ( encryptor.Decrypt( ( unsigned char* ) buffer, length, ( unsigned char* ) buffer, &length ) == false )
|
|
{
|
|
statistics.bitsWithBadCRCReceived += length * 8;
|
|
statistics.packetsWithBadCRCReceived++;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
statistics.bitsReceived += length * 8;
|
|
statistics.packetsReceived++;
|
|
|
|
RakNet::BitStream socketData( (unsigned char*) buffer, length, false ); // Convert the incoming data to a bitstream for easy parsing
|
|
time = RakNet::GetTimeNS();
|
|
|
|
DataStructures::RangeList<MessageNumberType> incomingAcks;
|
|
socketData.Read(hasAcks);
|
|
if (hasAcks)
|
|
{
|
|
MessageNumberType messageNumber;
|
|
if (incomingAcks.Deserialize(&socketData)==false)
|
|
return false;
|
|
for (i=0; i<incomingAcks.ranges.Size();i++)
|
|
{
|
|
if (incomingAcks.ranges[i].minIndex>incomingAcks.ranges[i].maxIndex)
|
|
{
|
|
RakAssert(incomingAcks.ranges[i].minIndex<=incomingAcks.ranges[i].maxIndex);
|
|
return false;
|
|
}
|
|
|
|
for (messageNumber=incomingAcks.ranges[i].minIndex; messageNumber >= incomingAcks.ranges[i].minIndex && messageNumber <= incomingAcks.ranges[i].maxIndex; messageNumber++)
|
|
{
|
|
hasAcks=true;
|
|
|
|
// SHOW - ack received
|
|
//printf("Got Ack for %i. resendList.Size()=%i sendQueue[0].Size() = %i\n",internalPacket->messageNumber, resendList.Size(), sendQueue[0].Size());
|
|
ackedHistogramCounter=RemovePacketFromResendListAndDeleteOlderReliableSequenced( messageNumber, time );
|
|
|
|
#ifdef _DEBUG_LOGGER
|
|
{
|
|
char temp[256];
|
|
sprintf(temp, "%p: Got ack for %i. Resend queue size=%i\n", this, messageNumber, resendQueue.Size());
|
|
OutputDebugStr(temp);
|
|
}
|
|
#endif
|
|
|
|
if (time >= histogramStartTime && ackedHistogramCounter!=(unsigned)-1 && ackedHistogramCounter==histogramReceiveMarker)
|
|
++histogramAckCount;
|
|
|
|
// internalPacketPool.ReleasePointer( internalPacket );
|
|
|
|
|
|
if ( resendList.IsEmpty() )
|
|
{
|
|
lastAckTime = 0; // Not resending anything so clear this var so we don't drop the connection on not getting any more acks
|
|
}
|
|
else
|
|
{
|
|
lastAckTime = time; // Just got an ack. Record when we got it so we know the connection is alive
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Parse the bitstream to create an internal packet
|
|
InternalPacket* internalPacket = CreateInternalPacketFromBitStream( &socketData, time );
|
|
|
|
if (internalPacket==0)
|
|
return hasAcks;
|
|
|
|
while ( internalPacket )
|
|
{
|
|
for (i=0; i < messageHandlerList.Size(); i++)
|
|
messageHandlerList[i]->OnInternalPacket(internalPacket, receivePacketCount, playerId, (RakNetTime)(time/(RakNetTimeNS)1000), false);
|
|
|
|
{
|
|
#ifdef _DEBUG_LOGGER
|
|
{
|
|
char temp[256];
|
|
sprintf(temp, "%p: Got packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength);
|
|
OutputDebugStr(temp);
|
|
}
|
|
#endif
|
|
|
|
// receivedPacketsCount++;
|
|
if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE )
|
|
{
|
|
SendAcknowledgementPacket( internalPacket->messageNumber, time );
|
|
}
|
|
|
|
// resetReceivedPackets is set from a non-threadsafe function.
|
|
// We do the actual reset in this function so the data is not modified by multiple threads
|
|
if (resetReceivedPackets)
|
|
{
|
|
hasReceivedPacketQueue.ClearAndForceAllocation(DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE);
|
|
receivedPacketsBaseIndex=0;
|
|
resetReceivedPackets=false;
|
|
}
|
|
|
|
// If the following conditional is true then this either a duplicate packet
|
|
// or an older out of order packet
|
|
// The subtraction unsigned overflow is intentional
|
|
holeCount = (MessageNumberType)(internalPacket->messageNumber-receivedPacketsBaseIndex);
|
|
const int typeRange = (MessageNumberType)-1;
|
|
|
|
if (holeCount==0)
|
|
{
|
|
// Got what we were expecting
|
|
if (hasReceivedPacketQueue.Size())
|
|
hasReceivedPacketQueue.Pop();
|
|
++receivedPacketsBaseIndex;
|
|
}
|
|
else if (holeCount > typeRange-typeRange/2)
|
|
{
|
|
// Underflow - got a packet we have already counted past
|
|
statistics.duplicateMessagesReceived++;
|
|
|
|
// Duplicate packet
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
else if (holeCount<hasReceivedPacketQueue.Size())
|
|
{
|
|
// Got a higher count out of order packet that was missing in the sequence or we already got
|
|
if (hasReceivedPacketQueue[holeCount]!=0) // non-zero means this is a hole
|
|
{
|
|
// Fill in the hole
|
|
hasReceivedPacketQueue[holeCount]=0; // We got the packet at holeCount
|
|
}
|
|
else
|
|
{
|
|
// Not a hole - just a duplicate packet
|
|
statistics.duplicateMessagesReceived++;
|
|
|
|
// Duplicate packet
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
}
|
|
else // holeCount>=receivedPackets.Size()
|
|
{
|
|
// Got a higher count out of order packet whose messageNumber is higher than we have ever got
|
|
|
|
// Add 0 times to the queue until (messageNumber - baseIndex) < queue size.
|
|
while ((MessageNumberType)(holeCount) > hasReceivedPacketQueue.Size())
|
|
hasReceivedPacketQueue.Push(time+(RakNetTimeNS)timeoutTime*1000); // Didn't get this packet - set the time to give up waiting
|
|
hasReceivedPacketQueue.Push(0); // Got the packet
|
|
#ifdef _DEBUG
|
|
// If this assert hits then MessageNumberType has overflowed
|
|
assert(hasReceivedPacketQueue.Size() < (unsigned int)((MessageNumberType)(-1)));
|
|
#endif
|
|
}
|
|
|
|
// Pop all expired times. 0 means we got the packet, in which case we don't track this index either.
|
|
while ( hasReceivedPacketQueue.Size()>0 && hasReceivedPacketQueue.Peek() < time )
|
|
{
|
|
hasReceivedPacketQueue.Pop();
|
|
++receivedPacketsBaseIndex;
|
|
}
|
|
|
|
statistics.messagesReceived++;
|
|
|
|
// If the allocated buffer is > DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE and it is 3x greater than the number of elements actually being used
|
|
if (hasReceivedPacketQueue.AllocationSize() > (unsigned int) DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE && hasReceivedPacketQueue.AllocationSize() > hasReceivedPacketQueue.Size() * 3)
|
|
hasReceivedPacketQueue.Compress();
|
|
|
|
// Keep on top of deleting old unreliable split packets so they don't clog the list.
|
|
if ( internalPacket->splitPacketCount > 0 )
|
|
DeleteOldUnreliableSplitPackets( time );
|
|
|
|
if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS );
|
|
#endif
|
|
|
|
if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS )
|
|
{
|
|
// Invalid packet
|
|
#ifdef _DEBUG
|
|
printf( "Got invalid packet\n" );
|
|
#endif
|
|
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
|
|
if ( IsOlderOrderedPacket( internalPacket->orderingIndex, waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] ) == false )
|
|
{
|
|
statistics.sequencedMessagesInOrder++;
|
|
|
|
|
|
// Is this a split packet?
|
|
if ( internalPacket->splitPacketCount > 0 )
|
|
{
|
|
// Generate the split
|
|
// Verify some parameters to make sure we don't get junk data
|
|
|
|
|
|
// Check for a rebuilt packet
|
|
InsertIntoSplitPacketList( internalPacket, time );
|
|
|
|
// Sequenced
|
|
internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time );
|
|
|
|
if ( internalPacket )
|
|
{
|
|
// Update our index to the newest packet
|
|
waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1;
|
|
|
|
// If there is a rebuilt packet, add it to the output queue
|
|
outputQueue.Push( internalPacket );
|
|
internalPacket = 0;
|
|
}
|
|
|
|
// else don't have all the parts yet
|
|
}
|
|
|
|
else
|
|
{
|
|
// Update our index to the newest packet
|
|
waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1;
|
|
|
|
// Not a split packet. Add the packet to the output queue
|
|
outputQueue.Push( internalPacket );
|
|
internalPacket = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
statistics.sequencedMessagesOutOfOrder++;
|
|
|
|
// Older sequenced packet. Discard it
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
|
|
// Is this an unsequenced split packet?
|
|
if ( internalPacket->splitPacketCount > 0 )
|
|
{
|
|
// An unsequenced split packet. May be ordered though.
|
|
|
|
// Check for a rebuilt packet
|
|
if ( internalPacket->reliability != RELIABLE_ORDERED )
|
|
internalPacket->orderingChannel = 255; // Use 255 to designate not sequenced and not ordered
|
|
|
|
InsertIntoSplitPacketList( internalPacket, time );
|
|
|
|
internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time );
|
|
|
|
if ( internalPacket == 0 )
|
|
{
|
|
|
|
// Don't have all the parts yet
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
|
|
// else continue down to handle RELIABLE_ORDERED
|
|
}
|
|
|
|
if ( internalPacket->reliability == RELIABLE_ORDERED )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS );
|
|
#endif
|
|
|
|
if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS )
|
|
{
|
|
#ifdef _DEBUG
|
|
printf("Got invalid ordering channel %i from packet %i\n", internalPacket->orderingChannel, internalPacket->messageNumber);
|
|
#endif
|
|
// Invalid packet
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
|
|
if ( waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] == internalPacket->orderingIndex )
|
|
{
|
|
// Get the list to hold ordered packets for this stream
|
|
DataStructures::LinkedList<InternalPacket*> *orderingListAtOrderingStream;
|
|
unsigned char orderingChannelCopy = internalPacket->orderingChannel;
|
|
|
|
statistics.orderedMessagesInOrder++;
|
|
|
|
// Show ordering index increment
|
|
//printf("Pushing immediate packet %i with ordering index %i\n", internalPacket->messageNumber, internalPacket->orderingIndex );
|
|
|
|
// Push the packet for the user to read
|
|
outputQueue.Push( internalPacket );
|
|
internalPacket = 0; // Don't reference this any longer since other threads access it
|
|
|
|
// Wait for the next ordered packet in sequence
|
|
waitingForOrderedPacketReadIndex[ orderingChannelCopy ] ++; // This wraps
|
|
|
|
orderingListAtOrderingStream = GetOrderingListAtOrderingStream( orderingChannelCopy );
|
|
|
|
if ( orderingListAtOrderingStream != 0)
|
|
{
|
|
while ( orderingListAtOrderingStream->Size() > 0 )
|
|
{
|
|
// Cycle through the list until nothing is found
|
|
orderingListAtOrderingStream->Beginning();
|
|
indexFound=false;
|
|
size=orderingListAtOrderingStream->Size();
|
|
count=0;
|
|
|
|
while (count++ < size)
|
|
{
|
|
if ( orderingListAtOrderingStream->Peek()->orderingIndex == waitingForOrderedPacketReadIndex[ orderingChannelCopy ] )
|
|
{
|
|
/*
|
|
RakNet::BitStream temp(orderingListAtOrderingStream->Peek()->data, BITS_TO_BYTES(orderingListAtOrderingStream->Peek()->dataBitLength), false);
|
|
temp.IgnoreBits(8);
|
|
unsigned int receivedPacketNumber=0;
|
|
temp.Read(receivedPacketNumber);
|
|
printf("Receive: receivedPacketNumber=%i orderingIndex=%i waitingFor=%i\n", receivedPacketNumber, orderingListAtOrderingStream->Peek()->orderingIndex, waitingForOrderedPacketReadIndex[ orderingChannelCopy ]);
|
|
*/
|
|
|
|
//printf("Pushing delayed packet %i with ordering index %i. outputQueue.Size()==%i\n", orderingListAtOrderingStream->Peek()->messageNumber, orderingListAtOrderingStream->Peek()->orderingIndex, outputQueue.Size() );
|
|
outputQueue.Push( orderingListAtOrderingStream->Pop() );
|
|
waitingForOrderedPacketReadIndex[ orderingChannelCopy ]++; // This wraps at 255
|
|
indexFound=true;
|
|
}
|
|
else
|
|
(*orderingListAtOrderingStream)++;
|
|
}
|
|
|
|
if (indexFound==false)
|
|
break;
|
|
}
|
|
}
|
|
|
|
internalPacket = 0;
|
|
}
|
|
else
|
|
{
|
|
// assert(waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] < internalPacket->orderingIndex);
|
|
statistics.orderedMessagesOutOfOrder++;
|
|
|
|
// This is a newer ordered packet than we are waiting for. Store it for future use
|
|
AddToOrderingList( internalPacket );
|
|
}
|
|
|
|
goto CONTINUE_SOCKET_DATA_PARSE_LOOP;
|
|
}
|
|
|
|
// Nothing special about this packet. Add it to the output queue
|
|
outputQueue.Push( internalPacket );
|
|
|
|
internalPacket = 0;
|
|
}
|
|
|
|
// Used for a goto to jump to the next packet immediately
|
|
|
|
CONTINUE_SOCKET_DATA_PARSE_LOOP:
|
|
// Parse the bitstream to create an internal packet
|
|
internalPacket = CreateInternalPacketFromBitStream( &socketData, time );
|
|
}
|
|
|
|
/*
|
|
if (numberOfAcksInFrame > 0)
|
|
// if (time > lastWindowAdjustTime+ping)
|
|
{
|
|
// printf("Window size up\n");
|
|
windowSize+=1 + numberOfAcksInFrame/windowSize;
|
|
if ( windowSize > MAXIMUM_WINDOW_SIZE )
|
|
windowSize = MAXIMUM_WINDOW_SIZE;
|
|
//lastWindowAdjustTime=time;
|
|
}
|
|
//else
|
|
// printf("No acks in frame\n");
|
|
*/
|
|
/*
|
|
// numberOfAcksInFrame>=windowSize means that all the packets we last sent from the resendList are cleared out
|
|
// 11/17/05 - the problem with numberOfAcksInFrame >= windowSize is that if the entire frame is filled with resends but not all resends filled the frame
|
|
// then the sender is limited by how many resends can fit in one frame
|
|
if ( numberOfAcksInFrame >= windowSize && ( sendPacketSet[ SYSTEM_PRIORITY ].Size() > 0 || sendPacketSet[ HIGH_PRIORITY ].Size() > 0 || sendPacketSet[ MEDIUM_PRIORITY ].Size() > 0 ) )
|
|
{
|
|
// reliabilityLayerMutexes[windowSize_MUTEX].Lock();
|
|
//printf("windowSize=%i lossyWindowSize=%i\n", windowSize, lossyWindowSize);
|
|
|
|
if ( windowSize < lossyWindowSize || (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // Increases the window size slowly, testing for packetloss
|
|
{
|
|
// If we get a frame which clears out the resend queue after handling one or more acks, and we have packets waiting to go out,
|
|
// and we didn't recently lose a packet then increase the window size by 1
|
|
windowSize++;
|
|
|
|
if ( (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // The increase is to test for packetloss
|
|
lastWindowIncreaseSizeTime = time;
|
|
|
|
// If the window is so large that we couldn't possibly fit any more packets into the frame, then just leave it alone
|
|
if ( windowSize > MAXIMUM_WINDOW_SIZE )
|
|
windowSize = MAXIMUM_WINDOW_SIZE;
|
|
|
|
// SHOW - WINDOWING
|
|
//else
|
|
// printf("Increasing windowSize to %i. Lossy window size = %i\n", windowSize, lossyWindowSize);
|
|
|
|
// If we are more than 5 over the lossy window size, increase the lossy window size by 1
|
|
if ( windowSize == MAXIMUM_WINDOW_SIZE || windowSize - lossyWindowSize > 5 )
|
|
lossyWindowSize++;
|
|
}
|
|
// reliabilityLayerMutexes[windowSize_MUTEX].Unlock();
|
|
}
|
|
*/
|
|
|
|
if (hasAcks)
|
|
{
|
|
UpdateWindowFromAck(time);
|
|
}
|
|
|
|
receivePacketCount++;
|
|
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// This gets an end-user packet already parsed out. Returns number of BITS put into the buffer
|
|
//-------------------------------------------------------------------------------------------------------
|
|
int ReliabilityLayer::Receive( unsigned char **data )
|
|
{
|
|
// Wait until the clear occurs
|
|
if (freeThreadedMemoryOnNextUpdate)
|
|
return 0;
|
|
|
|
InternalPacket * internalPacket;
|
|
|
|
if ( outputQueue.Size() > 0 )
|
|
{
|
|
// #ifdef _DEBUG
|
|
// assert(bitStream->GetNumberOfBitsUsed()==0);
|
|
// #endif
|
|
internalPacket = outputQueue.Pop();
|
|
|
|
int bitLength;
|
|
*data = internalPacket->data;
|
|
bitLength = internalPacket->dataBitLength;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return bitLength;
|
|
}
|
|
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Puts data on the send queue
|
|
// bitStream contains the data to send
|
|
// priority is what priority to send the data at
|
|
// reliability is what reliability to use
|
|
// ordering channel is from 0 to 255 and specifies what stream to use
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::Send( char *data, int numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, RakNetTimeNS currentTime )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( !( reliability > RELIABLE_SEQUENCED || reliability < 0 ) );
|
|
assert( !( priority > NUMBER_OF_PRIORITIES || priority < 0 ) );
|
|
assert( !( orderingChannel < 0 || orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) );
|
|
assert( numberOfBitsToSend > 0 );
|
|
#endif
|
|
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
|
|
if ( readWriteSocket == INVALID_SOCKET )
|
|
return false;
|
|
|
|
#endif
|
|
|
|
// Fix any bad parameters
|
|
if ( reliability > RELIABLE_SEQUENCED || reliability < 0 )
|
|
reliability = RELIABLE;
|
|
|
|
if ( priority > NUMBER_OF_PRIORITIES || priority < 0 )
|
|
priority = HIGH_PRIORITY;
|
|
|
|
if ( orderingChannel >= NUMBER_OF_ORDERED_STREAMS )
|
|
orderingChannel = 0;
|
|
|
|
int numberOfBytesToSend=BITS_TO_BYTES(numberOfBitsToSend);
|
|
if ( numberOfBitsToSend == 0 )
|
|
{
|
|
#ifdef _DEBUG
|
|
printf( "Error!! ReliabilityLayer::Send bitStream->GetNumberOfBytesUsed()==0\n" );
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
InternalPacket * internalPacket = internalPacketPool.GetPointer();
|
|
//InternalPacket * internalPacket = sendPacketSet[priority].WriteLock();
|
|
#ifdef _DEBUG
|
|
// Remove accessing undefined memory warning
|
|
memset( internalPacket, 255, sizeof( InternalPacket ) );
|
|
#endif
|
|
|
|
internalPacket->creationTime = currentTime;
|
|
|
|
if ( makeDataCopy )
|
|
{
|
|
internalPacket->data = new unsigned char [ numberOfBytesToSend ];
|
|
memcpy( internalPacket->data, data, numberOfBytesToSend );
|
|
// printf("Allocated %i\n", internalPacket->data);
|
|
}
|
|
else
|
|
{
|
|
// Allocated the data elsewhere, delete it in here
|
|
internalPacket->data = ( unsigned char* ) data;
|
|
// printf("Using Pre-Allocated %i\n", internalPacket->data);
|
|
}
|
|
|
|
internalPacket->dataBitLength = numberOfBitsToSend;
|
|
internalPacket->nextActionTime = 0;
|
|
|
|
internalPacket->messageNumber = messageNumber;
|
|
|
|
internalPacket->priority = priority;
|
|
internalPacket->reliability = reliability;
|
|
internalPacket->splitPacketCount = 0;
|
|
|
|
// Calculate if I need to split the packet
|
|
int headerLength = BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) );
|
|
|
|
int maxDataSize = MTUSize - UDP_HEADER_SIZE - headerLength;
|
|
|
|
if ( encryptor.IsKeySet() )
|
|
maxDataSize -= 8; // Extra data for the encryptor
|
|
|
|
bool splitPacket = numberOfBytesToSend > maxDataSize;
|
|
|
|
// If a split packet, we might have to upgrade the reliability
|
|
if ( splitPacket )
|
|
statistics.numberOfSplitMessages++;
|
|
else
|
|
statistics.numberOfUnsplitMessages++;
|
|
|
|
++messageNumber;
|
|
|
|
|
|
if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED )
|
|
{
|
|
// Assign the sequence stream and index
|
|
internalPacket->orderingChannel = orderingChannel;
|
|
internalPacket->orderingIndex = waitingForSequencedPacketWriteIndex[ orderingChannel ] ++;
|
|
|
|
// This packet supersedes all other sequenced packets on the same ordering channel
|
|
// Delete all packets in all send lists that are sequenced and on the same ordering channel
|
|
// UPDATE:
|
|
// Disabled. We don't have enough info to consistently do this. Sometimes newer data does supercede
|
|
// older data such as with constantly declining health, but not in all cases.
|
|
// For example, with sequenced unreliable sound packets just because you send a newer one doesn't mean you
|
|
// don't need the older ones because the odds are they will still arrive in order
|
|
/*
|
|
for (int i=0; i < NUMBER_OF_PRIORITIES; i++)
|
|
{
|
|
DeleteSequencedPacketsInList(orderingChannel, sendQueue[i]);
|
|
}
|
|
*/
|
|
}
|
|
|
|
else
|
|
if ( internalPacket->reliability == RELIABLE_ORDERED )
|
|
{
|
|
// Assign the ordering channel and index
|
|
internalPacket->orderingChannel = orderingChannel;
|
|
internalPacket->orderingIndex = waitingForOrderedPacketWriteIndex[ orderingChannel ] ++;
|
|
}
|
|
|
|
if ( splitPacket ) // If it uses a secure header it will be generated here
|
|
{
|
|
// Must split the packet. This will also generate the SHA1 if it is required. It also adds it to the send list.
|
|
//InternalPacket packetCopy;
|
|
//memcpy(&packetCopy, internalPacket, sizeof(InternalPacket));
|
|
//sendPacketSet[priority].CancelWriteLock(internalPacket);
|
|
//SplitPacket( &packetCopy, MTUSize );
|
|
SplitPacket( internalPacket, MTUSize );
|
|
//delete [] packetCopy.data;
|
|
return true;
|
|
}
|
|
|
|
sendPacketSet[ internalPacket->priority ].Push( internalPacket );
|
|
|
|
// sendPacketSet[priority].WriteUnlock();
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Run this once per game cycle. Handles internal lists and actually does the send
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::Update( SOCKET s, PlayerID playerId, int MTUSize, RakNetTimeNS time, DataStructures::List<PluginInterface*> &messageHandlerList )
|
|
{
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
|
|
if ( readWriteSocket == INVALID_SOCKET )
|
|
return;
|
|
|
|
if (deadConnection)
|
|
return;
|
|
#endif
|
|
|
|
// This line is necessary because the timer isn't accurate
|
|
if (time <= lastUpdateTime)
|
|
{
|
|
// Always set the last time in case of overflow
|
|
lastUpdateTime=time;
|
|
return;
|
|
}
|
|
|
|
RakNetTimeNS elapsedTime = time - lastUpdateTime;
|
|
availableBandwidth+=currentBandwidth * ((double)elapsedTime/1000000.0f);
|
|
if (availableBandwidth > currentBandwidth)
|
|
availableBandwidth = currentBandwidth;
|
|
lastUpdateTime=time;
|
|
|
|
// unsigned resendListSize;
|
|
bool reliableDataSent;
|
|
UpdateThreadedMemory();
|
|
|
|
// Due to thread vagarities and the way I store the time to avoid slow calls to RakNet::GetTime
|
|
// time may be less than lastAck
|
|
if ( resendList.IsEmpty()==false && time > lastAckTime && lastAckTime && time - lastAckTime > (RakNetTimeNS)timeoutTime*1000 )
|
|
{
|
|
// SHOW - dead connection
|
|
// printf("The connection has been lost.\n");
|
|
// We've waited a very long time for a reliable packet to get an ack and it never has
|
|
deadConnection = true;
|
|
return;
|
|
}
|
|
|
|
// Water canister has to have enough room to put more water in :)
|
|
double requiredBuffer=(float)((MTUSize+UDP_HEADER_SIZE)*8);
|
|
if (requiredBuffer > currentBandwidth)
|
|
requiredBuffer=currentBandwidth;
|
|
|
|
while ( availableBandwidth > requiredBuffer )
|
|
{
|
|
updateBitStream.Reset();
|
|
GenerateDatagram( &updateBitStream, MTUSize, &reliableDataSent, time, playerId, messageHandlerList );
|
|
if ( updateBitStream.GetNumberOfBitsUsed() > 0 )
|
|
{
|
|
#ifndef _RELEASE
|
|
if (minExtraPing > 0 || extraPingVariance > 0)
|
|
{
|
|
// Delay the send to simulate lag
|
|
DataAndTime *dt;
|
|
dt = new DataAndTime;
|
|
memcpy( dt->data, updateBitStream.GetData(), updateBitStream.GetNumberOfBytesUsed() );
|
|
dt->length = updateBitStream.GetNumberOfBytesUsed();
|
|
dt->sendTime = time + (RakNetTimeNS)minExtraPing*1000;
|
|
if (extraPingVariance > 0)
|
|
dt->sendTime += ( randomMT() % (int)extraPingVariance );
|
|
delayList.Insert( dt );
|
|
}
|
|
else
|
|
#endif
|
|
SendBitStream( s, playerId, &updateBitStream );
|
|
|
|
availableBandwidth-=updateBitStream.GetNumberOfBitsUsed()+UDP_HEADER_SIZE*8;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
bool lastContinuousSend=continuousSend;
|
|
continuousSend=availableBandwidth < requiredBuffer;
|
|
|
|
if (continuousSend==true && lastContinuousSend==false)
|
|
{
|
|
histogramAckCount=0;
|
|
histogramPlossCount=0;
|
|
histogramStartTime=time+ping*2*1000;
|
|
histogramEndTime=histogramStartTime+MAX_TIME_TO_SAMPLE;
|
|
if (++histogramReceiveMarker==(unsigned)-1)
|
|
histogramReceiveMarker=0;
|
|
}
|
|
|
|
if (time >= histogramEndTime )
|
|
{
|
|
float packetloss;
|
|
|
|
double delta;
|
|
if (histogramAckCount+histogramPlossCount)
|
|
packetloss=(float)histogramPlossCount / ((float)histogramAckCount+(float)histogramPlossCount);
|
|
else
|
|
packetloss=0.0f; // This line can be true if we are sending only acks
|
|
|
|
if (continuousSend==false)
|
|
{
|
|
if (packetloss > PACKETLOSS_TOLERANCE)
|
|
{
|
|
highBandwidth=currentBandwidth;
|
|
if (packetloss > .2)
|
|
{
|
|
lowBandwidth/=2;
|
|
}
|
|
else
|
|
{
|
|
lowBandwidth*=.9;
|
|
}
|
|
|
|
if (lowBandwidth < MINIMUM_SEND_BPS)
|
|
lowBandwidth=MINIMUM_SEND_BPS;
|
|
|
|
delta = (highBandwidth-lowBandwidth)/2;
|
|
currentBandwidth=delta+lowBandwidth;
|
|
noPacketlossIncreaseCount=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (packetloss <= PACKETLOSS_TOLERANCE)
|
|
lowBandwidth=currentBandwidth;
|
|
else
|
|
highBandwidth=currentBandwidth;
|
|
|
|
if (packetloss==0.0)
|
|
{
|
|
// If no packetloss for many increases in a row, drop the high range and go into search mode.
|
|
if (++noPacketlossIncreaseCount==10)
|
|
{
|
|
noPacketlossIncreaseCount=0;
|
|
highBandwidth=0;
|
|
}
|
|
}
|
|
else
|
|
noPacketlossIncreaseCount=0;
|
|
if (highBandwidth!=0.0)
|
|
{
|
|
// If a lot of packetloss at any time, decrease the low range by half
|
|
if (packetloss > .2)
|
|
{
|
|
lowBandwidth/=2;
|
|
if (lowBandwidth < MINIMUM_SEND_BPS)
|
|
lowBandwidth=MINIMUM_SEND_BPS;
|
|
}
|
|
|
|
delta = (highBandwidth-lowBandwidth)/2;
|
|
if (delta < MINIMUM_SEND_BPS/4)
|
|
{
|
|
// If no packetloss and done searching, increase the high range by 50%
|
|
if (packetloss==0.0)
|
|
{
|
|
highBandwidth*=1.5;
|
|
}
|
|
else if (packetloss < PACKETLOSS_TOLERANCE)
|
|
{
|
|
// If some packetloss and done searching, increase the high range by 5%
|
|
highBandwidth*=1.05;
|
|
}
|
|
else if (packetloss < PACKETLOSS_TOLERANCE*2)
|
|
{
|
|
// If some packetloss, but not a huge amount and done searching, decrease the low range by 10%
|
|
lowBandwidth*=.9;
|
|
if (lowBandwidth < MINIMUM_SEND_BPS)
|
|
lowBandwidth=MINIMUM_SEND_BPS;
|
|
}
|
|
delta = (highBandwidth-lowBandwidth)/2;
|
|
}
|
|
currentBandwidth=delta+lowBandwidth;
|
|
}
|
|
else
|
|
{
|
|
// Don't know the maximum bandwidth, so keep doubling to find out
|
|
currentBandwidth*=2.0;
|
|
}
|
|
}
|
|
|
|
histogramPlossCount=0;
|
|
histogramAckCount=0;
|
|
histogramStartTime=time+TIME_TO_NEW_SAMPLE+ping*2*1000;
|
|
histogramEndTime=histogramStartTime+MAX_TIME_TO_SAMPLE;
|
|
if (++histogramReceiveMarker==(unsigned)-1)
|
|
histogramReceiveMarker=0;
|
|
}
|
|
|
|
#ifndef _RELEASE
|
|
// Do any lagged sends
|
|
unsigned i = 0;
|
|
while ( i < delayList.Size() )
|
|
{
|
|
if ( delayList[ i ]->sendTime < time )
|
|
{
|
|
updateBitStream.Reset();
|
|
updateBitStream.Write( delayList[ i ]->data, delayList[ i ]->length );
|
|
// Send it now
|
|
SendBitStream( s, playerId, &updateBitStream );
|
|
|
|
delete delayList[ i ];
|
|
if (i != delayList.Size() - 1)
|
|
delayList[ i ] = delayList[ delayList.Size() - 1 ];
|
|
delayList.Del();
|
|
}
|
|
|
|
else
|
|
i++;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Writes a bitstream to the socket
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SendBitStream( SOCKET s, PlayerID playerId, RakNet::BitStream *bitStream )
|
|
{
|
|
// SHOW - showing reliable flow
|
|
// if (bitStream->GetNumberOfBytesUsed()>50)
|
|
// printf("Sending %i bytes. sendQueue[0].Size()=%i, resendList.Size()=%i\n", bitStream->GetNumberOfBytesUsed(), sendQueue[0].Size(),resendList.Size());
|
|
|
|
int oldLength, length;
|
|
|
|
// sentFrames++;
|
|
|
|
#ifndef _RELEASE
|
|
if (maxSendBPS>0)
|
|
{
|
|
double chanceToLosePacket = (double)currentBandwidth / (double)maxSendBPS;
|
|
if (frandomMT() < (float)chanceToLosePacket)
|
|
return;
|
|
|
|
}
|
|
#endif
|
|
|
|
// Encode the whole bitstream if the encoder is defined.
|
|
|
|
if ( encryptor.IsKeySet() )
|
|
{
|
|
length = bitStream->GetNumberOfBytesUsed();
|
|
oldLength = length;
|
|
|
|
encryptor.Encrypt( ( unsigned char* ) bitStream->GetData(), length, ( unsigned char* ) bitStream->GetData(), &length );
|
|
statistics.encryptionBitsSent += ( length - oldLength ) * 8;
|
|
|
|
assert( ( length % 16 ) == 0 );
|
|
}
|
|
else
|
|
{
|
|
length = bitStream->GetNumberOfBytesUsed();
|
|
}
|
|
|
|
#ifdef __USE_IO_COMPLETION_PORTS
|
|
if ( readWriteSocket == INVALID_SOCKET )
|
|
{
|
|
assert( 0 );
|
|
return ;
|
|
}
|
|
|
|
statistics.packetsSent++;
|
|
statistics.totalBitsSent += length * 8;
|
|
SocketLayer::Instance()->Write( readWriteSocket, ( const char* ) bitStream->GetData(), length );
|
|
#else
|
|
|
|
statistics.packetsSent++;
|
|
statistics.totalBitsSent += length * 8;
|
|
//printf("total bits=%i length=%i\n", BITS_TO_BYTES(statistics.totalBitsSent), length);
|
|
|
|
SocketLayer::Instance()->SendTo( s, ( char* ) bitStream->GetData(), length, playerId.binaryAddress, playerId.port );
|
|
#endif // __USE_IO_COMPLETION_PORTS
|
|
|
|
// lastPacketSendTime=time;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Generates a datagram (coalesced packets)
|
|
//-------------------------------------------------------------------------------------------------------
|
|
unsigned ReliabilityLayer::GenerateDatagram( RakNet::BitStream *output, int MTUSize, bool *reliableDataSent, RakNetTimeNS time, PlayerID playerId, DataStructures::List<PluginInterface*> &messageHandlerList )
|
|
{
|
|
InternalPacket * internalPacket;
|
|
// InternalPacket *temp;
|
|
int maxDataBitSize;
|
|
int reliableBits = 0;
|
|
int nextPacketBitLength;
|
|
unsigned i, messageHandlerIndex;
|
|
bool isReliable, onlySendUnreliable;
|
|
bool writeFalseToHeader;
|
|
unsigned messagesSent=0;
|
|
|
|
maxDataBitSize = MTUSize - UDP_HEADER_SIZE;
|
|
|
|
if ( encryptor.IsKeySet() )
|
|
maxDataBitSize -= 16; // Extra data for the encryptor
|
|
|
|
maxDataBitSize <<= 3;
|
|
|
|
*reliableDataSent = false;
|
|
|
|
if (time > nextAckTime)
|
|
{
|
|
if (acknowlegements.Size()>0)
|
|
{
|
|
output->Write(true);
|
|
messagesSent++;
|
|
statistics.acknowlegementBitsSent +=acknowlegements.Serialize(output, (MTUSize-UDP_HEADER_SIZE)*8-1, true);
|
|
if (acknowlegements.Size()==0)
|
|
nextAckTime=time+(RakNetTimeNS)(ping*(RakNetTime)(PING_MULTIPLIER_TO_RESEND/4.0f));
|
|
else
|
|
{
|
|
// printf("Ack full\n");
|
|
}
|
|
|
|
writeFalseToHeader=false;
|
|
}
|
|
else
|
|
{
|
|
writeFalseToHeader=true;
|
|
nextAckTime=time+(RakNetTimeNS)(ping*(RakNetTime)(PING_MULTIPLIER_TO_RESEND/4.0f));
|
|
}
|
|
}
|
|
else
|
|
writeFalseToHeader=true;
|
|
|
|
while ( resendQueue.Size() > 0 )
|
|
{
|
|
internalPacket = resendQueue.Peek();
|
|
// The resend Queue can have holes. This is so we can deallocate blocks without having to compress the array
|
|
if ( internalPacket->nextActionTime == 0 )
|
|
{
|
|
resendQueue.Pop();
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
continue; // This was a hole
|
|
}
|
|
|
|
if ( resendQueue.Peek()->nextActionTime < time )
|
|
{
|
|
internalPacket = resendQueue.Pop();
|
|
|
|
nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength;
|
|
|
|
if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize )
|
|
{
|
|
resendQueue.PushAtHead( internalPacket ); // Not enough room to use this packet after all!
|
|
|
|
goto END_OF_GENERATE_FRAME;
|
|
}
|
|
|
|
RakAssert(internalPacket->priority >= 0);
|
|
|
|
#ifdef _DEBUG_LOGGER
|
|
{
|
|
char temp[256];
|
|
sprintf(temp, "%p: Resending packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength);
|
|
OutputDebugStr(temp);
|
|
}
|
|
#endif
|
|
|
|
for (messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++)
|
|
messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, sendPacketCount, playerId, (RakNetTime)(time/(RakNetTimeNS)1000), true);
|
|
|
|
// Write to the output bitstream
|
|
statistics.messageResends++;
|
|
statistics.messageDataBitsResent += internalPacket->dataBitLength;
|
|
|
|
if (writeFalseToHeader)
|
|
{
|
|
output->Write(false);
|
|
writeFalseToHeader=false;
|
|
}
|
|
statistics.messagesTotalBitsResent += WriteToBitStreamFromInternalPacket( output, internalPacket );
|
|
internalPacket->packetNumber=sendPacketCount;
|
|
messagesSent++;
|
|
|
|
*reliableDataSent = true;
|
|
|
|
statistics.packetsContainingOnlyAcknowlegementsAndResends++;
|
|
|
|
internalPacket->nextActionTime = time + ackTimeIncrement;
|
|
if (time >= histogramStartTime && internalPacket->histogramMarker==histogramReceiveMarker)
|
|
histogramPlossCount++;
|
|
|
|
internalPacket->histogramMarker=histogramReceiveMarker;
|
|
|
|
//printf("PACKETLOSS\n ");
|
|
|
|
// Put the packet back into the resend list at the correct spot
|
|
// Don't make a copy since I'm reinserting an allocated struct
|
|
InsertPacketIntoResendList( internalPacket, time, false, false );
|
|
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
onlySendUnreliable = false;
|
|
|
|
|
|
// From highest to lowest priority, fill up the output bitstream from the send lists
|
|
for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ )
|
|
{
|
|
while ( sendPacketSet[ i ].Size() )
|
|
{
|
|
internalPacket = sendPacketSet[ i ].Pop();
|
|
|
|
nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength;
|
|
|
|
if (unreliableTimeout!=0 &&
|
|
(internalPacket->reliability==UNRELIABLE || internalPacket->reliability==UNRELIABLE_SEQUENCED) &&
|
|
time > internalPacket->creationTime+(RakNetTimeNS)unreliableTimeout)
|
|
{
|
|
// Unreliable packets are deleted
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
continue;
|
|
}
|
|
|
|
|
|
if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize )
|
|
{
|
|
// This output won't fit.
|
|
sendPacketSet[ i ].PushAtHead( internalPacket ); // Push this back at the head so it is the next thing to go out
|
|
break;
|
|
}
|
|
|
|
if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED )
|
|
isReliable = true;
|
|
else
|
|
isReliable = false;
|
|
|
|
// Write to the output bitstream
|
|
statistics.messagesSent[ i ] ++;
|
|
statistics.messageDataBitsSent[ i ] += internalPacket->dataBitLength;
|
|
|
|
#ifdef _DEBUG_LOGGER
|
|
{
|
|
char temp[256];
|
|
sprintf(temp, "%p: Sending packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength);
|
|
OutputDebugStr(temp);
|
|
}
|
|
#endif
|
|
|
|
for (messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++)
|
|
messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, sendPacketCount, playerId, (RakNetTime)(time/(RakNetTimeNS)1000), true);
|
|
|
|
if (writeFalseToHeader)
|
|
{
|
|
output->Write(false);
|
|
writeFalseToHeader=false;
|
|
}
|
|
statistics.messageTotalBitsSent[ i ] += WriteToBitStreamFromInternalPacket( output, internalPacket );
|
|
//output->PrintBits();
|
|
internalPacket->packetNumber=sendPacketCount;
|
|
messagesSent++;
|
|
|
|
if ( isReliable )
|
|
{
|
|
// Reliable packets are saved to resend later
|
|
reliableBits += internalPacket->dataBitLength;
|
|
internalPacket->nextActionTime = time + ackTimeIncrement;
|
|
internalPacket->histogramMarker=histogramReceiveMarker;
|
|
resendList.Insert( internalPacket->messageNumber, internalPacket);
|
|
//printf("ackTimeIncrement=%i\n", ackTimeIncrement/1000);
|
|
InsertPacketIntoResendList( internalPacket, time, false, true);
|
|
*reliableDataSent = true;
|
|
}
|
|
else
|
|
{
|
|
// Unreliable packets are deleted
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
}
|
|
}
|
|
|
|
END_OF_GENERATE_FRAME:
|
|
;
|
|
|
|
// if (output->GetNumberOfBitsUsed()>0)
|
|
// {
|
|
// Update the throttle with the header
|
|
// bytesSent+=output->GetNumberOfBytesUsed() + UDP_HEADER_SIZE;
|
|
//}
|
|
|
|
if (output->GetNumberOfBitsUsed()>0)
|
|
sendPacketCount++;
|
|
|
|
return messagesSent;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Are we waiting for any data to be sent out or be processed by the player?
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::IsDataWaiting(void)
|
|
{
|
|
unsigned i;
|
|
for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ )
|
|
{
|
|
if (sendPacketSet[ i ].Size() > 0)
|
|
return true;
|
|
}
|
|
|
|
return acknowlegements.Size() > 0 || resendList.IsEmpty()==false || outputQueue.Size() > 0 || orderingList.Size() > 0 || splitPacketChannelList.Size() > 0;
|
|
}
|
|
|
|
bool ReliabilityLayer::AreAcksWaiting(void)
|
|
{
|
|
return acknowlegements.Size() > 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::ApplyNetworkSimulator( double _maxSendBPS, RakNetTime _minExtraPing, RakNetTime _extraPingVariance )
|
|
{
|
|
#ifndef _RELEASE
|
|
maxSendBPS=_maxSendBPS;
|
|
minExtraPing=_minExtraPing;
|
|
extraPingVariance=_extraPingVariance;
|
|
if (ping < (unsigned int)(minExtraPing+extraPingVariance)*2)
|
|
ping=(minExtraPing+extraPingVariance)*2;
|
|
#endif
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SetSplitMessageProgressInterval(int interval)
|
|
{
|
|
splitMessageProgressInterval=interval;
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SetUnreliableTimeout(RakNetTime timeoutMS)
|
|
{
|
|
unreliableTimeout=(RakNetTimeNS)timeoutMS*(RakNetTimeNS)1000;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// This will return true if we should not send at this time
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::IsSendThrottled( int MTUSize )
|
|
{
|
|
return false;
|
|
// return resendList.Size() > windowSize;
|
|
|
|
// Disabling this, because it can get stuck here forever
|
|
/*
|
|
unsigned packetsWaiting;
|
|
unsigned resendListDataSize=0;
|
|
unsigned i;
|
|
for (i=0; i < resendList.Size(); i++)
|
|
{
|
|
if (resendList[i])
|
|
resendListDataSize+=resendList[i]->dataBitLength;
|
|
}
|
|
packetsWaiting = 1 + ((BITS_TO_BYTES(resendListDataSize)) / (MTUSize - UDP_HEADER_SIZE - 10)); // 10 to roughly estimate the raknet header
|
|
|
|
return packetsWaiting >= windowSize;
|
|
*/
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// We lost a packet
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::UpdateWindowFromPacketloss( RakNetTimeNS time )
|
|
{
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Increase the window size
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::UpdateWindowFromAck( RakNetTimeNS time )
|
|
{
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Does what the function name says
|
|
//-------------------------------------------------------------------------------------------------------
|
|
unsigned ReliabilityLayer::RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, RakNetTimeNS time )
|
|
{
|
|
InternalPacket * internalPacket;
|
|
//InternalPacket *temp;
|
|
PacketReliability reliability; // What type of reliability algorithm to use with this packet
|
|
unsigned char orderingChannel; // What ordering channel this packet is on, if the reliability type uses ordering channels
|
|
OrderingIndexType orderingIndex; // The ID used as identification for ordering channels
|
|
// unsigned j;
|
|
|
|
bool deleted;
|
|
deleted=resendList.Delete(messageNumber, internalPacket);
|
|
if (deleted)
|
|
{
|
|
reliability = internalPacket->reliability;
|
|
orderingChannel = internalPacket->orderingChannel;
|
|
orderingIndex = internalPacket->orderingIndex;
|
|
// delete [] internalPacket->data;
|
|
// internalPacketPool.ReleasePointer( internalPacket );
|
|
internalPacket->nextActionTime=0; // Will be freed in the update function
|
|
return internalPacket->histogramMarker;
|
|
|
|
// Rarely used and thus disabled for speed
|
|
/*
|
|
// If the deleted packet was reliable sequenced, also delete all older reliable sequenced resends on the same ordering channel.
|
|
// This is because we no longer need to send these.
|
|
if ( reliability == RELIABLE_SEQUENCED )
|
|
{
|
|
unsigned j = 0;
|
|
while ( j < resendList.Size() )
|
|
{
|
|
internalPacket = resendList[ j ];
|
|
|
|
if ( internalPacket && internalPacket->reliability == RELIABLE_SEQUENCED && internalPacket->orderingChannel == orderingChannel && IsOlderOrderedPacket( internalPacket->orderingIndex, orderingIndex ) )
|
|
{
|
|
// Delete the packet
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
resendList[ j ] = 0; // Generate a hole
|
|
}
|
|
|
|
j++;
|
|
}
|
|
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
|
|
statistics.duplicateAcknowlegementsReceived++;
|
|
}
|
|
|
|
return (unsigned)-1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Acknowledge receipt of the packet with the specified messageNumber
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SendAcknowledgementPacket( const MessageNumberType messageNumber, RakNetTimeNS time )
|
|
{
|
|
statistics.acknowlegementsSent++;
|
|
acknowlegements.Insert(messageNumber);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Parse an internalPacket and figure out how many header bits would be
|
|
// written. Returns that number
|
|
//-------------------------------------------------------------------------------------------------------
|
|
int ReliabilityLayer::GetBitStreamHeaderLength( const InternalPacket *const internalPacket )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( internalPacket );
|
|
#endif
|
|
|
|
int bitLength;
|
|
|
|
bitLength=sizeof(MessageNumberType)*2*8;
|
|
|
|
// Write the PacketReliability. This is encoded in 3 bits
|
|
//bitStream->WriteBits((unsigned char*)&(internalPacket->reliability), 3, true);
|
|
bitLength += 3;
|
|
|
|
// If the reliability requires an ordering channel and ordering index, we Write those.
|
|
if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED )
|
|
{
|
|
// ordering channel encoded in 5 bits (from 0 to 31)
|
|
//bitStream->WriteBits((unsigned char*)&(internalPacket->orderingChannel), 5, true);
|
|
bitLength+=5;
|
|
|
|
// ordering index is one byte
|
|
//bitStream->WriteCompressed(internalPacket->orderingIndex);
|
|
bitLength+=sizeof(OrderingIndexType)*8;
|
|
}
|
|
|
|
// Write if this is a split packet (1 bit)
|
|
bool isSplitPacket = internalPacket->splitPacketCount > 0;
|
|
|
|
//bitStream->Write(isSplitPacket);
|
|
bitLength += 1;
|
|
|
|
if ( isSplitPacket )
|
|
{
|
|
// split packet indices are two bytes (so one packet can be split up to 65535
|
|
// times - maximum packet size would be about 500 * 65535)
|
|
//bitStream->Write(internalPacket->splitPacketId);
|
|
//bitStream->WriteCompressed(internalPacket->splitPacketIndex);
|
|
//bitStream->WriteCompressed(internalPacket->splitPacketCount);
|
|
bitLength += (sizeof(SplitPacketIdType) + sizeof(SplitPacketIndexType) * 2) * 8;
|
|
}
|
|
|
|
// Write how many bits the packet data is. Stored in an unsigned short and
|
|
// read from 16 bits
|
|
//bitStream->WriteBits((unsigned char*)&(internalPacket->dataBitLength), 16, true);
|
|
|
|
// Read how many bits the packet data is. Stored in 16 bits
|
|
bitLength += 16;
|
|
|
|
// Byte alignment
|
|
//bitLength += 8 - ((bitLength -1) %8 + 1);
|
|
|
|
return bitLength;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Parse an internalPacket and create a bitstream to represent this data
|
|
//-------------------------------------------------------------------------------------------------------
|
|
int ReliabilityLayer::WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( bitStream && internalPacket );
|
|
#endif
|
|
|
|
int start = bitStream->GetNumberOfBitsUsed();
|
|
const unsigned char c = (unsigned char) internalPacket->reliability;
|
|
|
|
// testing
|
|
//if (internalPacket->reliability==UNRELIABLE)
|
|
// printf("Sending unreliable packet %i\n", internalPacket->messageNumber);
|
|
//else if (internalPacket->reliability==RELIABLE_SEQUENCED || internalPacket->reliability==RELIABLE_ORDERED || internalPacket->reliability==RELIABLE)
|
|
// printf("Sending reliable packet number %i\n", internalPacket->messageNumber);
|
|
|
|
//bitStream->AlignWriteToByteBoundary();
|
|
|
|
// Write the message number (2 bytes)
|
|
bitStream->Write( internalPacket->messageNumber );
|
|
|
|
// Acknowledgment packets have no more data than the messageNumber and whether it is anacknowledgment
|
|
|
|
|
|
#ifdef _DEBUG
|
|
assert( internalPacket->dataBitLength > 0 );
|
|
#endif
|
|
|
|
// Write the PacketReliability. This is encoded in 3 bits
|
|
bitStream->WriteBits( (const unsigned char *)&c, 3, true );
|
|
|
|
// If the reliability requires an ordering channel and ordering index, we Write those.
|
|
if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED )
|
|
{
|
|
// ordering channel encoded in 5 bits (from 0 to 31)
|
|
bitStream->WriteBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5, true );
|
|
|
|
// One or two bytes
|
|
bitStream->Write( internalPacket->orderingIndex );
|
|
}
|
|
|
|
// Write if this is a split packet (1 bit)
|
|
bool isSplitPacket = internalPacket->splitPacketCount > 0;
|
|
|
|
bitStream->Write( isSplitPacket );
|
|
|
|
if ( isSplitPacket )
|
|
{
|
|
bitStream->Write( internalPacket->splitPacketId );
|
|
bitStream->WriteCompressed( internalPacket->splitPacketIndex );
|
|
bitStream->WriteCompressed( internalPacket->splitPacketCount );
|
|
}
|
|
|
|
// Write how many bits the packet data is. Stored in 13 bits
|
|
#ifdef _DEBUG
|
|
assert( BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ); // I never send more than MTU_SIZE bytes
|
|
|
|
#endif
|
|
|
|
unsigned short length = ( unsigned short ) internalPacket->dataBitLength; // Ignore the 2 high bytes for WriteBits
|
|
|
|
bitStream->WriteCompressed( length );
|
|
|
|
// Write the actual data.
|
|
bitStream->WriteAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) );
|
|
|
|
//bitStream->WriteBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength);
|
|
|
|
return bitStream->GetNumberOfBitsUsed() - start;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Parse a bitstream and create an internal packet to represent this data
|
|
//-------------------------------------------------------------------------------------------------------
|
|
InternalPacket* ReliabilityLayer::CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, RakNetTimeNS time )
|
|
{
|
|
bool bitStreamSucceeded;
|
|
InternalPacket* internalPacket;
|
|
|
|
if ( bitStream->GetNumberOfUnreadBits() < (int) sizeof( internalPacket->messageNumber ) * 8 )
|
|
return 0; // leftover bits
|
|
|
|
internalPacket = internalPacketPool.GetPointer();
|
|
|
|
#ifdef _DEBUG
|
|
// Remove accessing undefined memory error
|
|
memset( internalPacket, 255, sizeof( InternalPacket ) );
|
|
#endif
|
|
|
|
internalPacket->creationTime = time;
|
|
|
|
//bitStream->AlignReadToByteBoundary();
|
|
|
|
// Read the packet number (2 bytes)
|
|
bitStreamSucceeded = bitStream->Read( internalPacket->messageNumber );
|
|
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
// Read the PacketReliability. This is encoded in 3 bits
|
|
unsigned char reliability;
|
|
|
|
bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) ( &( reliability ) ), 3 );
|
|
|
|
internalPacket->reliability = ( const PacketReliability ) reliability;
|
|
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
// assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
// If the reliability requires an ordering channel and ordering index, we read those.
|
|
if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED )
|
|
{
|
|
// ordering channel encoded in 5 bits (from 0 to 31)
|
|
bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5 );
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
bitStreamSucceeded = bitStream->Read( internalPacket->orderingIndex );
|
|
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Read if this is a split packet (1 bit)
|
|
bool isSplitPacket;
|
|
|
|
bitStreamSucceeded = bitStream->Read( isSplitPacket );
|
|
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
if ( isSplitPacket )
|
|
{
|
|
bitStreamSucceeded = bitStream->Read( internalPacket->splitPacketId );
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
// assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketIndex );
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketCount );
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
else
|
|
internalPacket->splitPacketIndex = internalPacket->splitPacketCount = 0;
|
|
|
|
// Optimization - do byte alignment here
|
|
//unsigned char zero;
|
|
//bitStream->ReadBits(&zero, 8 - (bitStream->GetNumberOfBitsUsed() %8));
|
|
//assert(zero==0);
|
|
|
|
|
|
unsigned short length;
|
|
|
|
bitStreamSucceeded = bitStream->ReadCompressed( length );
|
|
|
|
// Read into an unsigned short. Otherwise the data would be offset too high by two bytes
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
internalPacket->dataBitLength = length;
|
|
#ifdef _DEBUG
|
|
// 10/08/05 - Disabled assert since this hits from offline packets arriving when the sender does not know we just connected, which is an unavoidable condition sometimes
|
|
// assert( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE );
|
|
#endif
|
|
if ( ! ( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ) )
|
|
{
|
|
// 10/08/05 - internalPacket->data wasn't allocated yet
|
|
// delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
// Allocate memory to hold our data
|
|
internalPacket->data = new unsigned char [ BITS_TO_BYTES( internalPacket->dataBitLength ) ];
|
|
//printf("Allocating %i\n", internalPacket->data);
|
|
|
|
// Set the last byte to 0 so if ReadBits does not read a multiple of 8 the last bits are 0'ed out
|
|
internalPacket->data[ BITS_TO_BYTES( internalPacket->dataBitLength ) - 1 ] = 0;
|
|
|
|
// Read the data the packet holds
|
|
bitStreamSucceeded = bitStream->ReadAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) );
|
|
|
|
//bitStreamSucceeded = bitStream->ReadBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength);
|
|
#ifdef _DEBUG
|
|
|
|
// 10/08/05 - Disabled assert since this hits from offline packets
|
|
//assert( bitStreamSucceeded );
|
|
#endif
|
|
|
|
if ( bitStreamSucceeded == false )
|
|
{
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
return 0;
|
|
}
|
|
|
|
// PRINTING UNRELIABLE STRINGS
|
|
// if (internalPacket->data && internalPacket->dataBitLength>5*8)
|
|
// printf("Received %s\n",internalPacket->data);
|
|
|
|
return internalPacket;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Get the SHA1 code
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::GetSHA1( unsigned char * const buffer, unsigned int
|
|
nbytes, char code[ SHA1_LENGTH ] )
|
|
{
|
|
CSHA1 sha1;
|
|
|
|
sha1.Reset();
|
|
sha1.Update( ( unsigned char* ) buffer, nbytes );
|
|
sha1.Final();
|
|
memcpy( code, sha1.GetHash(), SHA1_LENGTH );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Check the SHA1 code
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::CheckSHA1( char code[ SHA1_LENGTH ], unsigned char *
|
|
const buffer, unsigned int nbytes )
|
|
{
|
|
char code2[ SHA1_LENGTH ];
|
|
GetSHA1( buffer, nbytes, code2 );
|
|
|
|
for ( int i = 0; i < SHA1_LENGTH; i++ )
|
|
if ( code[ i ] != code2[ i ] )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Search the specified list for sequenced packets on the specified ordering
|
|
// stream, optionally skipping those with splitPacketId, and delete them
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::List<InternalPacket*>&theList, int splitPacketId )
|
|
{
|
|
unsigned i = 0;
|
|
|
|
while ( i < theList.Size() )
|
|
{
|
|
if ( ( theList[ i ]->reliability == RELIABLE_SEQUENCED || theList[ i ]->reliability == UNRELIABLE_SEQUENCED ) &&
|
|
theList[ i ]->orderingChannel == orderingChannel && ( splitPacketId == -1 || theList[ i ]->splitPacketId != (unsigned int) splitPacketId ) )
|
|
{
|
|
InternalPacket * internalPacket = theList[ i ];
|
|
theList.RemoveAtIndex( i );
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
}
|
|
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Search the specified list for sequenced packets with a value less than orderingIndex and delete them
|
|
// Note - I added functionality so you can use the Queue as a list (in this case for searching) but it is less efficient to do so than a regular list
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::Queue<InternalPacket*>&theList )
|
|
{
|
|
InternalPacket * internalPacket;
|
|
int listSize = theList.Size();
|
|
int i = 0;
|
|
|
|
while ( i < listSize )
|
|
{
|
|
if ( ( theList[ i ]->reliability == RELIABLE_SEQUENCED || theList[ i ]->reliability == UNRELIABLE_SEQUENCED ) && theList[ i ]->orderingChannel == orderingChannel )
|
|
{
|
|
internalPacket = theList[ i ];
|
|
theList.Del( i );
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
listSize--;
|
|
}
|
|
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex )
|
|
{
|
|
// This should give me 255 or 65535
|
|
OrderingIndexType maxRange = (OrderingIndexType) -1;
|
|
|
|
if ( waitingForPacketOrderingIndex > maxRange/2 )
|
|
{
|
|
if ( newPacketOrderingIndex >= waitingForPacketOrderingIndex - maxRange/2+1 && newPacketOrderingIndex < waitingForPacketOrderingIndex )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
else
|
|
if ( newPacketOrderingIndex >= ( OrderingIndexType ) ( waitingForPacketOrderingIndex - (( OrderingIndexType ) maxRange/2+1) ) ||
|
|
newPacketOrderingIndex < waitingForPacketOrderingIndex )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Old packet
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Split the passed packet into chunks under MTU_SIZEbytes (including headers) and save those new chunks
|
|
// Optimized version
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SplitPacket( InternalPacket *internalPacket, int MTUSize )
|
|
{
|
|
// Doing all sizes in bytes in this function so I don't write partial bytes with split packets
|
|
internalPacket->splitPacketCount = 1; // This causes GetBitStreamHeaderLength to account for the split packet header
|
|
int headerLength = BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) );
|
|
int dataByteLength = BITS_TO_BYTES( internalPacket->dataBitLength );
|
|
int maxDataSize;
|
|
int maximumSendBlock, byteOffset, bytesToSend;
|
|
SplitPacketIndexType splitPacketIndex;
|
|
int i;
|
|
InternalPacket **internalPacketArray;
|
|
|
|
maxDataSize = MTUSize - UDP_HEADER_SIZE;
|
|
|
|
if ( encryptor.IsKeySet() )
|
|
maxDataSize -= 8; // Extra data for the encryptor
|
|
|
|
#ifdef _DEBUG
|
|
// Make sure we need to split the packet to begin with
|
|
assert( dataByteLength > maxDataSize - headerLength );
|
|
#endif
|
|
|
|
// How much to send in the largest block
|
|
maximumSendBlock = maxDataSize - headerLength;
|
|
|
|
// Calculate how many packets we need to create
|
|
internalPacket->splitPacketCount = ( ( dataByteLength - 1 ) / ( maximumSendBlock ) + 1 );
|
|
|
|
statistics.totalSplits += internalPacket->splitPacketCount;
|
|
|
|
// Optimization
|
|
// internalPacketArray = new InternalPacket*[internalPacket->splitPacketCount];
|
|
bool usedAlloca=false;
|
|
#if !defined(_COMPATIBILITY_1)
|
|
if (sizeof( InternalPacket* ) * internalPacket->splitPacketCount < MAX_ALLOCA_STACK_ALLOCATION)
|
|
{
|
|
internalPacketArray = ( InternalPacket** ) alloca( sizeof( InternalPacket* ) * internalPacket->splitPacketCount );
|
|
usedAlloca=true;
|
|
}
|
|
else
|
|
#endif
|
|
internalPacketArray = new InternalPacket*[internalPacket->splitPacketCount];
|
|
|
|
for ( i = 0; i < ( int ) internalPacket->splitPacketCount; i++ )
|
|
{
|
|
internalPacketArray[ i ] = internalPacketPool.GetPointer();
|
|
//internalPacketArray[ i ] = (InternalPacket*) alloca( sizeof( InternalPacket ) );
|
|
// internalPacketArray[ i ] = sendPacketSet[internalPacket->priority].WriteLock();
|
|
memcpy( internalPacketArray[ i ], internalPacket, sizeof( InternalPacket ) );
|
|
}
|
|
|
|
// This identifies which packet this is in the set
|
|
splitPacketIndex = 0;
|
|
|
|
// Do a loop to send out all the packets
|
|
do
|
|
{
|
|
byteOffset = splitPacketIndex * maximumSendBlock;
|
|
bytesToSend = dataByteLength - byteOffset;
|
|
|
|
if ( bytesToSend > maximumSendBlock )
|
|
bytesToSend = maximumSendBlock;
|
|
|
|
// Copy over our chunk of data
|
|
internalPacketArray[ splitPacketIndex ]->data = new unsigned char[ bytesToSend ];
|
|
|
|
memcpy( internalPacketArray[ splitPacketIndex ]->data, internalPacket->data + byteOffset, bytesToSend );
|
|
|
|
if ( bytesToSend != maximumSendBlock )
|
|
internalPacketArray[ splitPacketIndex ]->dataBitLength = internalPacket->dataBitLength - splitPacketIndex * ( maximumSendBlock << 3 );
|
|
else
|
|
internalPacketArray[ splitPacketIndex ]->dataBitLength = bytesToSend << 3;
|
|
|
|
internalPacketArray[ splitPacketIndex ]->splitPacketIndex = splitPacketIndex;
|
|
internalPacketArray[ splitPacketIndex ]->splitPacketId = splitPacketId;
|
|
internalPacketArray[ splitPacketIndex ]->splitPacketCount = internalPacket->splitPacketCount;
|
|
|
|
if ( splitPacketIndex > 0 ) // For the first split packet index we keep the messageNumber already assigned
|
|
{
|
|
// For every further packet we use a new messageNumber.
|
|
// Note that all split packets are reliable
|
|
internalPacketArray[ splitPacketIndex ]->messageNumber = messageNumber;
|
|
|
|
//if ( ++messageNumber == RECEIVED_PACKET_LOG_LENGTH )
|
|
// messageNumber = 0;
|
|
++messageNumber;
|
|
|
|
}
|
|
|
|
// Add the new packet to send list at the correct priority
|
|
// sendQueue[internalPacket->priority].Insert(newInternalPacket);
|
|
// SHOW SPLIT PACKET GENERATION
|
|
// if (splitPacketIndex % 100 == 0)
|
|
// printf("splitPacketIndex=%i\n",splitPacketIndex);
|
|
//} while(++splitPacketIndex < internalPacket->splitPacketCount);
|
|
}
|
|
|
|
while ( ++splitPacketIndex < internalPacket->splitPacketCount );
|
|
|
|
splitPacketId++; // It's ok if this wraps to 0
|
|
|
|
// InternalPacket *workingPacket;
|
|
|
|
// Copy all the new packets into the split packet list
|
|
for ( i = 0; i < ( int ) internalPacket->splitPacketCount; i++ )
|
|
{
|
|
sendPacketSet[ internalPacket->priority ].Push( internalPacketArray[ i ] );
|
|
// workingPacket=sendPacketSet[internalPacket->priority].WriteLock();
|
|
// memcpy(workingPacket, internalPacketArray[ i ], sizeof(InternalPacket));
|
|
// sendPacketSet[internalPacket->priority].WriteUnlock();
|
|
}
|
|
|
|
// Delete the original
|
|
delete [] internalPacket->data;
|
|
internalPacketPool.ReleasePointer( internalPacket );
|
|
|
|
if (usedAlloca==false)
|
|
delete [] internalPacketArray;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Insert a packet into the split packet list
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::InsertIntoSplitPacketList( InternalPacket * internalPacket, RakNetTimeNS time )
|
|
{
|
|
bool objectExists;
|
|
unsigned index;
|
|
index=splitPacketChannelList.GetIndexFromKey(internalPacket->splitPacketId, &objectExists);
|
|
if (objectExists==false)
|
|
{
|
|
SplitPacketChannel *newChannel = new SplitPacketChannel;
|
|
index=splitPacketChannelList.Insert(internalPacket->splitPacketId, newChannel);
|
|
}
|
|
splitPacketChannelList[index]->splitPacketList.Insert(internalPacket->splitPacketIndex, internalPacket);
|
|
splitPacketChannelList[index]->lastUpdateTime=time;
|
|
|
|
if (splitMessageProgressInterval &&
|
|
splitPacketChannelList[index]->splitPacketList[0]->splitPacketIndex==0 &&
|
|
splitPacketChannelList[index]->splitPacketList.Size()!=splitPacketChannelList[index]->splitPacketList[0]->splitPacketCount &&
|
|
(splitPacketChannelList[index]->splitPacketList.Size()%splitMessageProgressInterval)==0)
|
|
{
|
|
// printf("msgID=%i Progress %i/%i Partsize=%i\n",
|
|
// splitPacketChannelList[index]->splitPacketList[0]->data[0],
|
|
// splitPacketChannelList[index]->splitPacketList.Size(),
|
|
// internalPacket->splitPacketCount,
|
|
// BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength));
|
|
|
|
// Return ID_DOWNLOAD_PROGRESS
|
|
// Write splitPacketIndex (SplitPacketIndexType)
|
|
// Write splitPacketCount (SplitPacketIndexType)
|
|
// Write byteLength (4)
|
|
// Write data, splitPacketChannelList[index]->splitPacketList[0]->data
|
|
InternalPacket *progressIndicator = internalPacketPool.GetPointer();
|
|
unsigned int length = sizeof(MessageID) + sizeof(unsigned int)*2 + sizeof(unsigned int) + BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength);
|
|
progressIndicator->data = new unsigned char [length];
|
|
progressIndicator->dataBitLength=BYTES_TO_BITS(length);
|
|
progressIndicator->data[0]=(MessageID)ID_DOWNLOAD_PROGRESS;
|
|
unsigned int temp;
|
|
temp=splitPacketChannelList[index]->splitPacketList.Size();
|
|
memcpy(progressIndicator->data+sizeof(MessageID), &temp, sizeof(unsigned int));
|
|
temp=(unsigned int)internalPacket->splitPacketCount;
|
|
memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*1, &temp, sizeof(unsigned int));
|
|
temp=BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength);
|
|
memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*2, &temp, sizeof(unsigned int));
|
|
memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*3, splitPacketChannelList[index]->splitPacketList[0]->data, BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength));
|
|
outputQueue.Push(progressIndicator);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Take all split chunks with the specified splitPacketId and try to
|
|
//reconstruct a packet. If we can, allocate and return it. Otherwise return 0
|
|
// Optimized version
|
|
//-------------------------------------------------------------------------------------------------------
|
|
InternalPacket * ReliabilityLayer::BuildPacketFromSplitPacketList( SplitPacketIdType splitPacketId, RakNetTimeNS time )
|
|
{
|
|
unsigned i, j;
|
|
unsigned byteProgress;
|
|
InternalPacket * internalPacket;
|
|
bool objectExists;
|
|
|
|
i=splitPacketChannelList.GetIndexFromKey(splitPacketId, &objectExists);
|
|
#ifdef _DEBUG
|
|
assert(objectExists);
|
|
#endif
|
|
|
|
if (splitPacketChannelList[i]->splitPacketList.Size()==splitPacketChannelList[i]->splitPacketList[0]->splitPacketCount)
|
|
{
|
|
// Reconstruct
|
|
internalPacket = CreateInternalPacketCopy( splitPacketChannelList[i]->splitPacketList[0], 0, 0, time );
|
|
internalPacket->dataBitLength=0;
|
|
for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++)
|
|
internalPacket->dataBitLength+=splitPacketChannelList[i]->splitPacketList[j]->dataBitLength;
|
|
|
|
internalPacket->data = new unsigned char[ BITS_TO_BYTES( internalPacket->dataBitLength ) ];
|
|
|
|
byteProgress=0;
|
|
for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++)
|
|
{
|
|
memcpy(internalPacket->data+byteProgress, splitPacketChannelList[i]->splitPacketList[j]->data, BITS_TO_BYTES(splitPacketChannelList[i]->splitPacketList[j]->dataBitLength));
|
|
byteProgress+=BITS_TO_BYTES(splitPacketChannelList[i]->splitPacketList[j]->dataBitLength);
|
|
}
|
|
|
|
for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++)
|
|
{
|
|
delete [] splitPacketChannelList[i]->splitPacketList[j]->data;
|
|
internalPacketPool.ReleasePointer(splitPacketChannelList[i]->splitPacketList[j]);
|
|
}
|
|
delete splitPacketChannelList[i];
|
|
splitPacketChannelList.RemoveAtIndex(i);
|
|
|
|
return internalPacket;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Delete any unreliable split packets that have long since expired
|
|
void ReliabilityLayer::DeleteOldUnreliableSplitPackets( RakNetTimeNS time )
|
|
{
|
|
unsigned i,j;
|
|
i=0;
|
|
while (i < splitPacketChannelList.Size())
|
|
{
|
|
if (time > splitPacketChannelList[i]->lastUpdateTime + 10000000 &&
|
|
(splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE || splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE_SEQUENCED))
|
|
{
|
|
for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++)
|
|
{
|
|
delete [] splitPacketChannelList[i]->splitPacketList[j]->data;
|
|
internalPacketPool.ReleasePointer(splitPacketChannelList[i]->splitPacketList[j]);
|
|
}
|
|
delete splitPacketChannelList[i];
|
|
splitPacketChannelList.RemoveAtIndex(i);
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Creates a copy of the specified internal packet with data copied from the original starting at dataByteOffset for dataByteLength bytes.
|
|
// Does not copy any split data parameters as that information is always generated does not have any reason to be copied
|
|
//-------------------------------------------------------------------------------------------------------
|
|
InternalPacket * ReliabilityLayer::CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, RakNetTimeNS time )
|
|
{
|
|
InternalPacket * copy = internalPacketPool.GetPointer();
|
|
#ifdef _DEBUG
|
|
// Remove accessing undefined memory error
|
|
memset( copy, 255, sizeof( InternalPacket ) );
|
|
#endif
|
|
// Copy over our chunk of data
|
|
|
|
if ( dataByteLength > 0 )
|
|
{
|
|
copy->data = new unsigned char[ dataByteLength ];
|
|
memcpy( copy->data, original->data + dataByteOffset, dataByteLength );
|
|
}
|
|
else
|
|
copy->data = 0;
|
|
|
|
copy->dataBitLength = dataByteLength << 3;
|
|
copy->creationTime = time;
|
|
copy->nextActionTime = 0;
|
|
copy->orderingIndex = original->orderingIndex;
|
|
copy->orderingChannel = original->orderingChannel;
|
|
copy->messageNumber = original->messageNumber;
|
|
copy->priority = original->priority;
|
|
copy->reliability = original->reliability;
|
|
|
|
return copy;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Get the specified ordering list
|
|
//-------------------------------------------------------------------------------------------------------
|
|
DataStructures::LinkedList<InternalPacket*> *ReliabilityLayer::GetOrderingListAtOrderingStream( unsigned char orderingChannel )
|
|
{
|
|
if ( orderingChannel >= orderingList.Size() )
|
|
return 0;
|
|
|
|
return orderingList[ orderingChannel ];
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Add the internal packet to the ordering list in order based on order index
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::AddToOrderingList( InternalPacket * internalPacket )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS );
|
|
#endif
|
|
|
|
if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS )
|
|
{
|
|
return;
|
|
}
|
|
|
|
DataStructures::LinkedList<InternalPacket*> *theList;
|
|
|
|
if ( internalPacket->orderingChannel >= orderingList.Size() || orderingList[ internalPacket->orderingChannel ] == 0 )
|
|
{
|
|
// Need a linked list in this index
|
|
orderingList.Replace( new DataStructures::LinkedList<InternalPacket*>, 0, internalPacket->orderingChannel );
|
|
theList=orderingList[ internalPacket->orderingChannel ];
|
|
}
|
|
else
|
|
{
|
|
// Have a linked list in this index
|
|
if ( orderingList[ internalPacket->orderingChannel ]->Size() == 0 )
|
|
{
|
|
theList=orderingList[ internalPacket->orderingChannel ];
|
|
}
|
|
else
|
|
{
|
|
theList = GetOrderingListAtOrderingStream( internalPacket->orderingChannel );
|
|
}
|
|
}
|
|
|
|
theList->End();
|
|
theList->Add(internalPacket);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Inserts a packet into the resend list in order
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::InsertPacketIntoResendList( InternalPacket *internalPacket, RakNetTimeNS time, bool makeCopyOfInternalPacket, bool firstResend )
|
|
{
|
|
// lastAckTime is the time we last got an acknowledgment - however we also initialize the value if this is the first resend and
|
|
// either we never got an ack before or we are inserting into an empty resend queue
|
|
if ( firstResend && (lastAckTime == 0 || resendList.IsEmpty()))
|
|
{
|
|
lastAckTime = time; // Start the timer for the ack of this packet if we aren't already waiting for an ack
|
|
}
|
|
|
|
if (makeCopyOfInternalPacket)
|
|
{
|
|
InternalPacket *pool=internalPacketPool.GetPointer();
|
|
//printf("Adding %i\n", internalPacket->data);
|
|
memcpy(pool, internalPacket, sizeof(InternalPacket));
|
|
resendQueue.Push( pool );
|
|
}
|
|
else
|
|
{
|
|
RakAssert(internalPacket->nextActionTime!=0);
|
|
|
|
resendQueue.Push( internalPacket );
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// If Read returns -1 and this returns true then a modified packet was detected
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::IsCheater( void ) const
|
|
{
|
|
return cheater;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Were you ever unable to deliver a packet despite retries?
|
|
//-------------------------------------------------------------------------------------------------------
|
|
bool ReliabilityLayer::IsDeadConnection( void ) const
|
|
{
|
|
return deadConnection;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Causes IsDeadConnection to return true
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::KillConnection( void )
|
|
{
|
|
deadConnection=true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// How long to wait between packet resends
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::SetPing( RakNetTime i )
|
|
{
|
|
//assert(i < (RakNetTimeNS)timeoutTime*1000);
|
|
if (i > timeoutTime)
|
|
ping=500;
|
|
else
|
|
ping = i;
|
|
if (ping < 30)
|
|
ping=30; // Leave a buffer for variations in ping
|
|
#ifndef _RELEASE
|
|
if (ping < (RakNetTime)(minExtraPing+extraPingVariance)*2)
|
|
ping=(minExtraPing+extraPingVariance)*2;
|
|
#endif
|
|
|
|
UpdateNextActionTime();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::UpdateNextActionTime(void)
|
|
{
|
|
//double multiple = log10(currentBandwidth/MINIMUM_SEND_BPS) / 0.30102999566398119521373889472449;
|
|
if (ping*(RakNetTime)PING_MULTIPLIER_TO_RESEND < MIN_PING_TO_RESEND)
|
|
ackTimeIncrement=(RakNetTimeNS)MIN_PING_TO_RESEND*1000;
|
|
else
|
|
ackTimeIncrement=(RakNetTimeNS)(ping*(RakNetTime)PING_MULTIPLIER_TO_RESEND)*1000;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Statistics
|
|
//-------------------------------------------------------------------------------------------------------
|
|
RakNetStatisticsStruct * const ReliabilityLayer::GetStatistics( void )
|
|
{
|
|
unsigned i;
|
|
|
|
for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ )
|
|
{
|
|
statistics.messageSendBuffer[i] = sendPacketSet[i].Size();
|
|
// statistics.messageSendBuffer[i] = sendPacketSet[i].Size();
|
|
}
|
|
|
|
statistics.acknowlegementsPending = acknowlegements.Size();
|
|
statistics.messagesWaitingForReassembly = 0;
|
|
for (i=0; i < splitPacketChannelList.Size(); i++)
|
|
statistics.messagesWaitingForReassembly+=splitPacketChannelList[i]->splitPacketList.Size();
|
|
statistics.internalOutputQueueSize = outputQueue.Size();
|
|
statistics.bitsPerSecond = currentBandwidth;
|
|
//statistics.lossySize = lossyWindowSize == MAXIMUM_WINDOW_SIZE + 1 ? 0 : lossyWindowSize;
|
|
// statistics.lossySize=0;
|
|
statistics.messagesOnResendQueue = GetResendListDataSize();
|
|
|
|
return &statistics;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Returns the number of packets in the resend queue, not counting holes
|
|
//-------------------------------------------------------------------------------------------------------
|
|
unsigned int ReliabilityLayer::GetResendListDataSize(void) const
|
|
{
|
|
/*
|
|
unsigned int i, count;
|
|
for (count=0, i=0; i < resendList.Size(); i++)
|
|
if (resendList[i]!=0)
|
|
count++;
|
|
return count;
|
|
*/
|
|
|
|
// Not accurate but thread-safe. The commented version might crash if the queue is cleared while we loop through it
|
|
return resendList.Size();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
// Process threaded commands
|
|
//-------------------------------------------------------------------------------------------------------
|
|
void ReliabilityLayer::UpdateThreadedMemory(void)
|
|
{
|
|
if ( freeThreadedMemoryOnNextUpdate )
|
|
{
|
|
freeThreadedMemoryOnNextUpdate = false;
|
|
FreeThreadedMemory();
|
|
}
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( pop )
|
|
#endif
|