/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ /// \file /// #include "ReliabilityLayer.h" #include "GetTime.h" #include "SocketLayer.h" #include "PluginInterface2.h" #include "RakAssert.h" #include "Rand.h" #include "MessageIdentifiers.h" #ifdef USE_THREADED_SEND #include "SendToThread.h" #endif #include using namespace RakNet; // Can't figure out which library has this function on the PS3 double Ceil(double d) {if (((double)((int)d))==d) return d; return (int) (d+1.0);} // #if defined(new) // #pragma push_macro("new") // #undef new // #define RELIABILITY_LAYER_NEW_UNDEF_ALLOCATING_QUEUE // #endif //#define _DEBUG_LOGGER #if CC_TIME_TYPE_BYTES==4 static const CCTimeType MAX_TIME_BETWEEN_PACKETS= 350; // 350 milliseconds static const CCTimeType HISTOGRAM_RESTART_CYCLE=10000; // Every 10 seconds reset the histogram #else static const CCTimeType MAX_TIME_BETWEEN_PACKETS= 350000; // 350 milliseconds //static const CCTimeType HISTOGRAM_RESTART_CYCLE=10000000; // Every 10 seconds reset the histogram #endif static const int DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE=512; static const CCTimeType STARTING_TIME_BETWEEN_PACKETS=MAX_TIME_BETWEEN_PACKETS; //static const long double TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_DEFAULT=.02; //static const long double TIME_BETWEEN_PACKETS_DECREASE_MULTIPLIER_DEFAULT=1.0 / 9.0; typedef uint32_t BitstreamLengthEncoding; #ifdef _MSC_VER #pragma warning( push ) #endif //#define PRINT_TO_FILE_RELIABLE_ORDERED_TEST #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST static unsigned int packetNumber=0; static FILE *fp=0; #endif //#define FLIP_SEND_ORDER_TEST //#define LOG_TRIVIAL_NOTIFICATIONS BPSTracker::TimeAndValue2::TimeAndValue2() {} BPSTracker::TimeAndValue2::~TimeAndValue2() {} BPSTracker::TimeAndValue2::TimeAndValue2(RakNet::TimeUS t, uint64_t v1) : value1(v1), time(t) {} //BPSTracker::TimeAndValue2::TimeAndValue2(RakNet::TimeUS t, uint64_t v1, uint64_t v2) : time(t), value1(v1), value2(v2) {} BPSTracker::BPSTracker() {Reset(_FILE_AND_LINE_);} BPSTracker::~BPSTracker() {} //void BPSTracker::Reset(const char *file, unsigned int line) {total1=total2=lastSec1=lastSec2=0; dataQueue.Clear(file,line);} void BPSTracker::Reset(const char *file, unsigned int line) {total1=lastSec1=0; dataQueue.Clear(file,line);} //void BPSTracker::Push2(RakNetTimeUS time, uint64_t value1, uint64_t value2) {dataQueue.Push(TimeAndValue2(time,value1,value2),_FILE_AND_LINE_); total1+=value1; lastSec1+=value1; total2+=value2; lastSec2+=value2;} //uint64_t BPSTracker::GetBPS2(RakNetTimeUS time) {ClearExpired2(time); return lastSec2;} //void BPSTracker::GetBPS1And2(RakNetTimeUS time, uint64_t &out1, uint64_t &out2) {ClearExpired2(time); out1=lastSec1; out2=lastSec2;} uint64_t BPSTracker::GetTotal1(void) const {return total1;} //uint64_t BPSTracker::GetTotal2(void) const {return total2;} // void BPSTracker::ClearExpired2(RakNet::TimeUS time) { // RakNet::TimeUS threshold=time; // if (threshold < 1000000) // return; // threshold-=1000000; // while (dataQueue.IsEmpty()==false && dataQueue.Peek().time < threshold) // { // lastSec1-=dataQueue.Peek().value1; // lastSec2-=dataQueue.Peek().value2; // dataQueue.Pop(); // } // } void BPSTracker::ClearExpired1(RakNet::TimeUS time) { while (dataQueue.IsEmpty()==false && #if CC_TIME_TYPE_BYTES==8 dataQueue.Peek().time+1000000 < time #else dataQueue.Peek().time+1000 < time #endif ) { lastSec1-=dataQueue.Peek().value1; dataQueue.Pop(); } } struct DatagramHeaderFormat { #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 CCTimeType sourceSystemTime; #endif DatagramSequenceNumberType datagramNumber; // Use floats to save bandwidth // float B; // Link capacity float AS; // Data arrival rate bool isACK; bool isNAK; bool isPacketPair; bool hasBAndAS; bool isContinuousSend; bool needsBAndAs; bool isValid; // To differentiate between what I serialized, and offline data static BitSize_t GetDataHeaderBitLength() { return BYTES_TO_BITS(GetDataHeaderByteLength()); } static unsigned int GetDataHeaderByteLength() { //return 2 + 3 + sizeof(RakNet::TimeMS) + sizeof(float)*2; return 2 + 3 + #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 sizeof(RakNetTimeMS) + #endif sizeof(float)*1; } void Serialize(RakNet::BitStream *b) { // Not endian safe // RakAssert(GetDataHeaderByteLength()==sizeof(DatagramHeaderFormat)); // b->WriteAlignedBytes((const unsigned char*) this, sizeof(DatagramHeaderFormat)); // return; b->Write(true); // IsValid if (isACK) { b->Write(true); b->Write(hasBAndAS); b->AlignWriteToByteBoundary(); #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 RakNet::TimeMS timeMSLow=(RakNet::TimeMS) sourceSystemTime&0xFFFFFFFF; b->Write(timeMSLow); #endif if (hasBAndAS) { // b->Write(B); b->Write(AS); } } else if (isNAK) { b->Write(false); b->Write(true); } else { b->Write(false); b->Write(false); b->Write(isPacketPair); b->Write(isContinuousSend); b->Write(needsBAndAs); b->AlignWriteToByteBoundary(); #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 RakNet::TimeMS timeMSLow=(RakNet::TimeMS) sourceSystemTime&0xFFFFFFFF; b->Write(timeMSLow); #endif b->Write(datagramNumber); } } void Deserialize(RakNet::BitStream *b) { // Not endian safe // b->ReadAlignedBytes((unsigned char*) this, sizeof(DatagramHeaderFormat)); // return; b->Read(isValid); b->Read(isACK); if (isACK) { isNAK=false; isPacketPair=false; b->Read(hasBAndAS); b->AlignReadToByteBoundary(); #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 RakNet::TimeMS timeMS; b->Read(timeMS); sourceSystemTime=(CCTimeType) timeMS; #endif if (hasBAndAS) { // b->Read(B); b->Read(AS); } } else { b->Read(isNAK); if (isNAK) { isPacketPair=false; } else { b->Read(isPacketPair); b->Read(isContinuousSend); b->Read(needsBAndAs); b->AlignReadToByteBoundary(); #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 RakNet::TimeMS timeMS; b->Read(timeMS); sourceSystemTime=(CCTimeType) timeMS; #endif b->Read(datagramNumber); } } } }; #if !defined(__GNUC__) && !defined(__ARMCC) #pragma warning(disable:4702) // unreachable code #endif #ifdef _WIN32 //#define _DEBUG_LOGGER #ifdef _DEBUG_LOGGER #include "WindowsIncludes.h" #endif #endif //#define DEBUG_SPLIT_PACKET_PROBLEMS #if defined (DEBUG_SPLIT_PACKET_PROBLEMS) static int waitFlag=-1; #endif using namespace RakNet; int RakNet::SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data ) { #if PREALLOCATE_LARGE_MESSAGES==1 if (key < data->returnedPacket->splitPacketId) return -1; if (key == data->returnedPacket->splitPacketId) return 0; #else if (key < data->splitPacketList[0]->splitPacketId) return -1; if (key == data->splitPacketList[0]->splitPacketId) return 0; #endif return 1; } // DEFINE_MULTILIST_PTR_TO_MEMBER_COMPARISONS( InternalPacket, SplitPacketIndexType, splitPacketIndex ) /* bool operator<( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get() < cls->splitPacketIndex; } bool operator>( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get() > cls->splitPacketIndex; } bool operator==( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get() == cls->splitPacketIndex; } /// Semi-hack: This is necessary to call Sort() bool operator<( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get()->splitPacketIndex < cls->splitPacketIndex; } bool operator>( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get()->splitPacketIndex > cls->splitPacketIndex; } bool operator==( const DataStructures::MLKeyRef &inputKey, const InternalPacket *cls ) { return inputKey.Get()->splitPacketIndex == cls->splitPacketIndex; } */ int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data ) { if (key < data->splitPacketIndex) return -1; if (key == data->splitPacketIndex) return 0; return 1; } //------------------------------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------------------------------- // Add 21 to the default MTU so if we encrypt it can hold potentially 21 more bytes of extra data + padding. ReliabilityLayer::ReliabilityLayer() { #ifdef _DEBUG // Wait longer to disconnect in debug so I don't get disconnected while tracing timeoutTime=30000; #else timeoutTime=10000; #endif #ifdef _DEBUG minExtraPing=extraPingVariance=0; packetloss=(double) minExtraPing; #endif #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST if (fp==0 && 0) { fp = fopen("reliableorderedoutput.txt", "wt"); } #endif InitializeVariables(); //int i = sizeof(InternalPacket); datagramHistoryMessagePool.SetPageSize(sizeof(MessageNumberNode)*128); internalPacketPool.SetPageSize(sizeof(InternalPacket)*INTERNAL_PACKET_PAGE_SIZE); refCountedDataPool.SetPageSize(sizeof(InternalPacketRefCountedData)*32); } //------------------------------------------------------------------------------------------------------- // Destructor //------------------------------------------------------------------------------------------------------- ReliabilityLayer::~ReliabilityLayer() { FreeMemory( true ); // Free all memory immediately } //------------------------------------------------------------------------------------------------------- // Resets the layer for reuse //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Reset( bool resetVariables, int MTUSize, bool _useSecurity ) { 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(); #if LIBCAT_SECURITY==1 useSecurity = _useSecurity; if (_useSecurity) MTUSize -= cat::AuthenticatedEncryption::OVERHEAD_BYTES; #else (void) _useSecurity; #endif // LIBCAT_SECURITY congestionManager.Init(RakNet::GetTimeUS(), MTUSize - UDP_HEADER_SIZE); } } //------------------------------------------------------------------------------------------------------- // Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable packet //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetTimeoutTime( RakNet::TimeMS time ) { timeoutTime=time; } //------------------------------------------------------------------------------------------------------- // Returns the value passed to SetTimeoutTime. or the default if it was never called //------------------------------------------------------------------------------------------------------- RakNet::TimeMS ReliabilityLayer::GetTimeoutTime(void) { return timeoutTime; } //------------------------------------------------------------------------------------------------------- // Initialize the variables //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InitializeVariables( void ) { memset( orderedWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType)); memset( sequencedWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( orderedReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( highestSequencedReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( &statistics, 0, sizeof( statistics ) ); memset( &heapIndexOffsets, 0, sizeof( heapIndexOffsets ) ); statistics.connectionStartTime = RakNet::GetTimeUS(); splitPacketId = 0; elapsedTimeSinceLastUpdate=0; throughputCapCountdown=0; sendReliableMessageNumberIndex = 0; internalOrderIndex=0; timeToNextUnreliableCull=0; unreliableLinkedListHead=0; lastUpdateTime= RakNet::GetTimeUS(); bandwidthExceededStatistic=false; remoteSystemTime=0; unreliableTimeout=0; lastBpsClear=0; // Disable packet pairs countdownToNextPacketPair=15; nextAllowedThroughputSample=0; deadConnection = cheater = false; timeOfLastContinualSend=0; // timeResendQueueNonEmpty = 0; timeLastDatagramArrived=RakNet::GetTimeMS(); // packetlossThisSample=false; // backoffThisSample=0; // packetlossThisSampleResendCount=0; // lastPacketlossTime=0; statistics.messagesInResendBuffer=0; statistics.bytesInResendBuffer=0; receivedPacketsBaseIndex=0; resetReceivedPackets=true; receivePacketCount=0; // SetPing( 1000 ); timeBetweenPackets=STARTING_TIME_BETWEEN_PACKETS; ackPingIndex=0; ackPingSum=(CCTimeType)0; nextSendTime=lastUpdateTime; //nextLowestPingReset=(CCTimeType)0; // continuousSend=false; // histogramStart=(CCTimeType)0; // histogramBitsSent=0; unacknowledgedBytes=0; resendLinkedListHead=0; totalUserDataBytesAcked=0; datagramHistoryPopCount=0; InitHeapWeights(); for (int i=0; i < NUMBER_OF_PRIORITIES; i++) { statistics.messageInSendBuffer[i]=0; statistics.bytesInSendBuffer[i]=0.0; } for (int i=0; i < RNS_PER_SECOND_METRICS_COUNT; i++) { bpsMetrics[i].Reset(_FILE_AND_LINE_); } } //------------------------------------------------------------------------------------------------------- // Frees all allocated memory //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::FreeMemory( bool freeAllImmediately ) { (void) freeAllImmediately; FreeThreadSafeMemory(); } void ReliabilityLayer::FreeThreadSafeMemory( void ) { unsigned i,j; InternalPacket *internalPacket; ClearPacketsAndDatagrams(); for (i=0; i < splitPacketChannelList.Size(); i++) { for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { FreeInternalPacketData(splitPacketChannelList[i]->splitPacketList[j], _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( splitPacketChannelList[i]->splitPacketList[j] ); } #if PREALLOCATE_LARGE_MESSAGES==1 if (splitPacketChannelList[i]->returnedPacket) { FreeInternalPacketData(splitPacketChannelList[i]->returnedPacket, __FILE__, __LINE__ ); ReleaseToInternalPacketPool( splitPacketChannelList[i]->returnedPacket ); } #endif RakNet::OP_DELETE(splitPacketChannelList[i], __FILE__, __LINE__); } splitPacketChannelList.Clear(false, _FILE_AND_LINE_); while ( outputQueue.Size() > 0 ) { internalPacket = outputQueue.Pop(); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); } outputQueue.ClearAndForceAllocation( 32, _FILE_AND_LINE_ ); /* for ( i = 0; i < orderingList.Size(); i++ ) { if ( orderingList[ i ] ) { DataStructures::LinkedList* theList = orderingList[ i ]; if ( theList ) { while ( theList->Size() ) { internalPacket = orderingList[ i ]->Pop(); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); } RakNet::OP_DELETE(theList, _FILE_AND_LINE_); } } } orderingList.Clear(false, _FILE_AND_LINE_); */ for (i=0; i < NUMBER_OF_ORDERED_STREAMS; i++) { for (j=0; j < orderingHeaps[i].Size(); j++) { FreeInternalPacketData(orderingHeaps[i][j], _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( orderingHeaps[i][j] ); } orderingHeaps[i].Clear(true, _FILE_AND_LINE_); } //resendList.ForEachData(DeleteInternalPacket); // resendTree.Clear(_FILE_AND_LINE_); memset(resendBuffer, 0, sizeof(resendBuffer)); statistics.messagesInResendBuffer=0; statistics.bytesInResendBuffer=0; if (resendLinkedListHead) { InternalPacket *prev; InternalPacket *iter = resendLinkedListHead; #ifdef _MSC_VER #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #endif while (1) { if (iter->data) FreeInternalPacketData(iter, _FILE_AND_LINE_ ); prev=iter; iter=iter->resendNext; if (iter==resendLinkedListHead) { ReleaseToInternalPacketPool(prev); break; } ReleaseToInternalPacketPool(prev); } resendLinkedListHead=0; } unacknowledgedBytes=0; // acknowlegements.Clear(_FILE_AND_LINE_); for ( j=0 ; j < outgoingPacketBuffer.Size(); j++ ) { if ( outgoingPacketBuffer[ j ]->data) FreeInternalPacketData( outgoingPacketBuffer[ j ], _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( outgoingPacketBuffer[ j ] ); } outgoingPacketBuffer.Clear(true, _FILE_AND_LINE_); #ifdef _DEBUG for (unsigned i = 0; i < delayList.Size(); i++ ) RakNet::OP_DELETE(delayList[ i ], __FILE__, __LINE__); delayList.Clear(__FILE__, __LINE__); #endif unreliableWithAckReceiptHistory.Clear(false, _FILE_AND_LINE_); packetsToSendThisUpdate.Clear(false, _FILE_AND_LINE_); packetsToSendThisUpdate.Preallocate(512, _FILE_AND_LINE_); packetsToDeallocThisUpdate.Clear(false, _FILE_AND_LINE_); packetsToDeallocThisUpdate.Preallocate(512, _FILE_AND_LINE_); packetsToSendThisUpdateDatagramBoundaries.Clear(false, _FILE_AND_LINE_); packetsToSendThisUpdateDatagramBoundaries.Preallocate(128, _FILE_AND_LINE_); datagramSizesInBytes.Clear(false, _FILE_AND_LINE_); datagramSizesInBytes.Preallocate(128, _FILE_AND_LINE_); internalPacketPool.Clear(_FILE_AND_LINE_); refCountedDataPool.Clear(_FILE_AND_LINE_); /* DataStructures::Page *cur = datagramMessageIDTree.GetListHead(); while (cur) { int treeIndex; for (treeIndex=0; treeIndex < cur->size; treeIndex++) ReleaseToDatagramMessageIDPool(cur->data[treeIndex]); cur=cur->resendNext; } datagramMessageIDTree.Clear(_FILE_AND_LINE_); datagramMessageIDPool.Clear(_FILE_AND_LINE_); */ while (datagramHistory.Size()) { RemoveFromDatagramHistory(datagramHistoryPopCount); datagramHistory.Pop(); datagramHistoryPopCount++; } datagramHistoryMessagePool.Clear(_FILE_AND_LINE_); datagramHistoryPopCount=0; acknowlegements.Clear(); NAKs.Clear(); unreliableLinkedListHead=0; } //------------------------------------------------------------------------------------------------------- // 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 acknowledgment and //split packets //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffer, unsigned int length, SystemAddress &systemAddress, DataStructures::List &messageHandlerList, int MTUSize, RakNetSocket2 *s, RakNetRandom *rnr, CCTimeType timeRead, BitStream &updateBitStream) { #ifdef _DEBUG RakAssert( !( buffer == 0 ) ); #endif #if CC_TIME_TYPE_BYTES==4 timeRead/=1000; #endif bpsMetrics[(int) ACTUAL_BYTES_RECEIVED].Push1(timeRead,length); (void) MTUSize; if ( length <= 2 || buffer == 0 ) // Length of 1 is a connection request resend that we just ignore { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("length <= 2 || buffer == 0", BYTES_TO_BITS(length), systemAddress, true); return true; } timeLastDatagramArrived=RakNet::GetTimeMS(); // CCTimeType time; // bool indexFound; // int count, size; DatagramSequenceNumberType holeCount; unsigned i; #if LIBCAT_SECURITY==1 if (useSecurity) { unsigned int received = length; if (!auth_enc.Decrypt((cat::u8*)buffer, received)) return false; length = received; } #endif RakNet::BitStream socketData( (unsigned char*) buffer, length, false ); // Convert the incoming data to a bitstream for easy parsing // time = RakNet::GetTimeUS(); // Set to the current time if it is not zero, and we get incoming data // if (timeResendQueueNonEmpty!=0) // timeResendQueueNonEmpty=timeRead; DatagramHeaderFormat dhf; dhf.Deserialize(&socketData); if (dhf.isValid==false) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("dhf.isValid==false", BYTES_TO_BITS(length), systemAddress, true); return true; } if (dhf.isACK) { DatagramSequenceNumberType datagramNumber; // datagramNumber=dhf.datagramNumber; #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 RakNet::TimeMS timeMSLow=(RakNet::TimeMS) timeRead&0xFFFFFFFF; CCTimeType rtt = timeMSLow-dhf.sourceSystemTime; #if CC_TIME_TYPE_BYTES==4 if (rtt > 10000) #else if (rtt > 10000000) #endif { // Sanity check. This could happen due to type overflow, especially since I only send the low 4 bytes to reduce bandwidth rtt=(CCTimeType) congestionManager.GetRTT(); } // RakAssert(rtt < 500000); // printf("%i ", (RakNet::TimeMS)(rtt/1000)); ackPing=rtt; #endif #ifdef _DEBUG if (dhf.hasBAndAS==false) { // dhf.B=0; dhf.AS=0; } #endif // congestionManager.OnAck(timeRead, rtt, dhf.hasBAndAS, dhf.B, dhf.AS, totalUserDataBytesAcked ); incomingAcks.Clear(); if (incomingAcks.Deserialize(&socketData)==false) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("incomingAcks.Deserialize failed", BYTES_TO_BITS(length), systemAddress, true); return false; } for (i=0; iincomingAcks.ranges[i].maxIndex || (incomingAcks.ranges[i].maxIndex == (uint24_t)(0xFFFFFFFF))) { RakAssert(incomingAcks.ranges[i].minIndex<=incomingAcks.ranges[i].maxIndex); for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("incomingAcks minIndex > maxIndex or maxIndex is max value", BYTES_TO_BITS(length), systemAddress, true); return false; } for (datagramNumber=incomingAcks.ranges[i].minIndex; datagramNumber >= incomingAcks.ranges[i].minIndex && datagramNumber <= incomingAcks.ranges[i].maxIndex; datagramNumber++) { CCTimeType whenSent; if (unreliableWithAckReceiptHistory.Size()>0) { unsigned int k=0; while (k < unreliableWithAckReceiptHistory.Size()) { if (unreliableWithAckReceiptHistory[k].datagramNumber == datagramNumber) { InternalPacket *ackReceipt = AllocateFromInternalPacketPool(); AllocInternalPacketData(ackReceipt, 5, false, _FILE_AND_LINE_ ); ackReceipt->dataBitLength=BYTES_TO_BITS(5); ackReceipt->data[0]=(MessageID)ID_SND_RECEIPT_ACKED; memcpy(ackReceipt->data+sizeof(MessageID), &unreliableWithAckReceiptHistory[k].sendReceiptSerial, sizeof(uint32_t)); outputQueue.Push(ackReceipt, _FILE_AND_LINE_ ); // Remove, swap with last unreliableWithAckReceiptHistory.RemoveAtIndex(k); } else k++; } } MessageNumberNode *messageNumberNode = GetMessageNumberNodeByDatagramIndex(datagramNumber, &whenSent); if (messageNumberNode) { // printf("%p Got ack for %i\n", this, datagramNumber.val); #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 congestionManager.OnAck(timeRead, rtt, dhf.hasBAndAS, 0, dhf.AS, totalUserDataBytesAcked, bandwidthExceededStatistic, datagramNumber ); #else CCTimeType ping; if (timeRead>whenSent) ping=timeRead-whenSent; else ping=0; congestionManager.OnAck(timeRead, ping, dhf.hasBAndAS, 0, dhf.AS, totalUserDataBytesAcked, bandwidthExceededStatistic, datagramNumber ); #endif while (messageNumberNode) { // TESTING1 // printf("Remove %i on ack for datagramNumber=%i.\n", messageNumberNode->messageNumber.val, datagramNumber.val); RemovePacketFromResendListAndDeleteOlderReliableSequenced( messageNumberNode->messageNumber, timeRead, messageHandlerList, systemAddress ); messageNumberNode=messageNumberNode->next; } RemoveFromDatagramHistory(datagramNumber); } // else if (isReliable) // { // // Previously used slot, rather than empty unreliable slot // printf("%p Ack %i is duplicate\n", this, datagramNumber.val); // // congestionManager.OnDuplicateAck(timeRead, datagramNumber); // } } } } else if (dhf.isNAK) { DatagramSequenceNumberType messageNumber; DataStructures::RangeList incomingNAKs; if (incomingNAKs.Deserialize(&socketData)==false) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("incomingNAKs.Deserialize failed", BYTES_TO_BITS(length), systemAddress, true); return false; } for (i=0; iincomingNAKs.ranges[i].maxIndex) { RakAssert(incomingNAKs.ranges[i].minIndex<=incomingNAKs.ranges[i].maxIndex); for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("incomingNAKs minIndex>maxIndex", BYTES_TO_BITS(length), systemAddress, true); return false; } // Sanity check //RakAssert(incomingNAKs.ranges[i].maxIndex.val-incomingNAKs.ranges[i].minIndex.val<1000); for (messageNumber=incomingNAKs.ranges[i].minIndex; messageNumber >= incomingNAKs.ranges[i].minIndex && messageNumber <= incomingNAKs.ranges[i].maxIndex; messageNumber++) { congestionManager.OnNAK(timeRead, messageNumber); // REMOVEME // printf("%p NAK %i\n", this, dhf.datagramNumber.val); CCTimeType timeSent; MessageNumberNode *messageNumberNode = GetMessageNumberNodeByDatagramIndex(messageNumber, &timeSent); while (messageNumberNode) { // Update timers so resends occur immediately InternalPacket *internalPacket = resendBuffer[messageNumberNode->messageNumber & (uint32_t) RESEND_BUFFER_ARRAY_MASK]; if (internalPacket) { if (internalPacket->nextActionTime!=0) { internalPacket->nextActionTime=timeRead; } } messageNumberNode=messageNumberNode->next; } } } } else { uint32_t skippedMessageCount; if (!congestionManager.OnGotPacket(dhf.datagramNumber, dhf.isContinuousSend, timeRead, length, &skippedMessageCount)) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("congestionManager.OnGotPacket failed", BYTES_TO_BITS(length), systemAddress, true); return true; } if (dhf.isPacketPair) congestionManager.OnGotPacketPair(dhf.datagramNumber, length, timeRead); DatagramHeaderFormat dhfNAK; dhfNAK.isNAK=true; uint32_t skippedMessageOffset; for (skippedMessageOffset=skippedMessageCount; skippedMessageOffset > 0; skippedMessageOffset--) { NAKs.Insert(dhf.datagramNumber-skippedMessageOffset); } remoteSystemNeedsBAndAS=dhf.needsBAndAs; // Ack dhf.datagramNumber // Ack even unreliable messages for congestion control, just don't resend them on no ack #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 SendAcknowledgementPacket( dhf.datagramNumber, dhf.sourceSystemTime); #else SendAcknowledgementPacket( dhf.datagramNumber, 0); #endif InternalPacket* internalPacket = CreateInternalPacketFromBitStream( &socketData, timeRead ); if (internalPacket==0) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("CreateInternalPacketFromBitStream failed", BYTES_TO_BITS(length), systemAddress, true); return true; } while ( internalPacket ) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) { #if CC_TIME_TYPE_BYTES==4 messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, receivePacketCount, systemAddress, timeRead, false); #else messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, receivePacketCount, systemAddress, (RakNet::TimeMS)(timeRead/(CCTimeType)1000), false); #endif } { // 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, _FILE_AND_LINE_); receivedPacketsBaseIndex=0; resetReceivedPackets=false; } // Check for corrupt orderingChannel if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS", BYTES_TO_BITS(length), systemAddress, true); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } // 8/12/09 was previously not checking if the message was reliable. However, on packetloss this would mean you'd eventually exceed the // hole count because unreliable messages were never resent, and you'd stop getting messages if (internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // 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 = (DatagramSequenceNumberType)(internalPacket->reliableMessageNumber-receivedPacketsBaseIndex); const DatagramSequenceNumberType typeRange = (DatagramSequenceNumberType)(const uint32_t)-1; // TESTING1 // printf("waiting on reliableMessageNumber=%i holeCount=%i datagramNumber=%i\n", receivedPacketsBaseIndex.val, holeCount.val, dhf.datagramNumber.val); if (holeCount==(DatagramSequenceNumberType) 0) { // Got what we were expecting if (hasReceivedPacketQueue.Size()) hasReceivedPacketQueue.Pop(); ++receivedPacketsBaseIndex; } else if (holeCount > typeRange/(DatagramSequenceNumberType) 2) { bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("holeCount > typeRange/(DatagramSequenceNumberType) 2", BYTES_TO_BITS(length), systemAddress, false); // Duplicate packet FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } else if ((unsigned int) holeCountOnReliabilityLayerNotification("Higher count pushed to hasReceivedPacketQueue", BYTES_TO_BITS(length), systemAddress, false); #endif // Fill in the hole hasReceivedPacketQueue[holeCount]=false; // We got the packet at holeCount } else { bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("Duplicate packet ignored", BYTES_TO_BITS(length), systemAddress, false); #endif // Duplicate packet FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } else // holeCount>=receivedPackets.Size() { if (holeCount > (DatagramSequenceNumberType) 1000000) { RakAssert("Hole count too high. See ReliabilityLayer.h" && 0); for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("holeCount > 1000000", BYTES_TO_BITS(length), systemAddress, true); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); // Would crash due to out of memory! FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("Adding to hasReceivedPacketQueue later ordered message", BYTES_TO_BITS(length), systemAddress, false); #endif // Fix - sending on a higher priority gives us a very very high received packets base index if we formerly had pre-split a lot of messages and // used that as the message number. Because of this, a lot of time is spent in this linear loop and the timeout time expires because not // all of the message is sent in time. // Fixed by late assigning message IDs on the sender // Add 0 times to the queue until (reliableMessageNumber - baseIndex) < queue size. while ((unsigned int)(holeCount) > hasReceivedPacketQueue.Size()) hasReceivedPacketQueue.Push(true, _FILE_AND_LINE_ ); // time+(CCTimeType)60 * (CCTimeType)1000 * (CCTimeType)1000); // Didn't get this packet - set the time to give up waiting hasReceivedPacketQueue.Push(false, _FILE_AND_LINE_ ); // Got the packet #ifdef _DEBUG // If this assert hits then DatagramSequenceNumberType has overflowed RakAssert(hasReceivedPacketQueue.Size() < (unsigned int)((DatagramSequenceNumberType)(const uint32_t)(-1))); #endif } while ( hasReceivedPacketQueue.Size()>0 && hasReceivedPacketQueue.Peek()==false ) { hasReceivedPacketQueue.Pop(); ++receivedPacketsBaseIndex; } } // 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(_FILE_AND_LINE_); /* if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED ) { #ifdef _DEBUG RakAssert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS", BYTES_TO_BITS(length), systemAddress); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } if ( IsOlderOrderedPacket( internalPacket->orderingIndex, waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] ) == false ) { // 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, timeRead ); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_PROCESSED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); // Sequenced internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, timeRead, s, systemAddress, rnr, remotePortRakNetWasStartedOn_PS3, extraSocketOptions); if ( internalPacket ) { // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + (OrderingIndexType)1; // If there is a rebuilt packet, add it to the output queue outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); internalPacket = 0; } // else don't have all the parts yet } else { // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + (OrderingIndexType)1; // Not a split packet. Add the packet to the output queue bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_PROCESSED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); internalPacket = 0; } } else { // Older sequenced packet. Discard it FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Is this an unsequenced split packet? if ( internalPacket->splitPacketCount > 0 ) { // Check for a rebuilt packet if ( internalPacket->reliability != RELIABLE_ORDERED ) internalPacket->orderingChannel = 255; // Use 255 to designate not sequenced and not ordered InsertIntoSplitPacketList( internalPacket, timeRead ); internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, timeRead, s, systemAddress, rnr, remotePortRakNetWasStartedOn_PS3, extraSocketOptions); if ( internalPacket == 0 ) { // Don't have all the parts yet goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } */ /* if ( internalPacket->reliability == RELIABLE_ORDERED ) { #ifdef _DEBUG RakAssert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { // Invalid packet FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_IGNORED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_PROCESSED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); if ( waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] == internalPacket->orderingIndex ) { // Get the list to hold ordered packets for this stream DataStructures::LinkedList *orderingListAtOrderingStream; unsigned char orderingChannelCopy = internalPacket->orderingChannel; // Push the packet for the user to read outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); internalPacket = 0; // Don't reference this any longer since other threads access it // Wait for the resendNext 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 ] ) { outputQueue.Push( orderingListAtOrderingStream->Pop(), _FILE_AND_LINE_ ); waitingForOrderedPacketReadIndex[ orderingChannelCopy ]++; indexFound=true; } else (*orderingListAtOrderingStream)++; } if (indexFound==false) break; } } internalPacket = 0; } else { // This is a newer ordered packet than we are waiting for. Store it for future use AddToOrderingList( internalPacket ); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } */ // Is this a split packet? If so then reassemble if ( internalPacket->splitPacketCount > 0 ) { // Check for a rebuilt packet if ( internalPacket->reliability != RELIABLE_ORDERED && internalPacket->reliability!=RELIABLE_SEQUENCED && internalPacket->reliability!=UNRELIABLE_SEQUENCED) internalPacket->orderingChannel = 255; // Use 255 to designate not sequenced and not ordered InsertIntoSplitPacketList( internalPacket, timeRead ); internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, timeRead, s, systemAddress, rnr, updateBitStream); if ( internalPacket == 0 ) { #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("BuildPacketFromSplitPacketList did not return anything.", BYTES_TO_BITS(length), systemAddress, false); #endif // Don't have all the parts yet goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST unsigned char packetId; char *type="UNDEFINED"; #endif if (internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED) { #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST // ___________________ BitStream bitStream(internalPacket->data, BITS_TO_BYTES(internalPacket->dataBitLength), false); unsigned int receivedPacketNumber; RakNet::Time receivedTime; unsigned char streamNumber; PacketReliability reliability; // ___________________ bitStream.IgnoreBits(8); // Ignore ID_TIMESTAMP bitStream.Read(receivedTime); bitStream.Read(packetId); bitStream.Read(receivedPacketNumber); bitStream.Read(streamNumber); bitStream.Read(reliability); if (packetId==ID_USER_PACKET_ENUM+1) { if (reliability==UNRELIABLE_SEQUENCED) type="UNRELIABLE_SEQUENCED"; else if (reliability==RELIABLE_ORDERED) type="RELIABLE_ORDERED"; else type="RELIABLE_SEQUENCED"; } // ___________________ #endif if (internalPacket->orderingIndex==orderedReadIndex[internalPacket->orderingChannel]) { // Has current ordering index if (internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED) { // Is sequenced if (IsOlderOrderedPacket(internalPacket->sequencingIndex,highestSequencedReadIndex[internalPacket->orderingChannel])==false) { // Expected or highest known value #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST if (packetId==ID_USER_PACKET_ENUM+1 && fp) { fprintf(fp, "Returning %i, %s by fallthrough. OI=%i. SI=%i.\n", receivedPacketNumber, type, internalPacket->orderingIndex.val, internalPacket->sequencingIndex); fflush(fp); } if (packetId==ID_USER_PACKET_ENUM+1) { if (receivedPacketNumberorderingChannel] = internalPacket->sequencingIndex+(OrderingIndexType)1; // Fallthrough, returned to user below } else { #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST if (packetId==ID_USER_PACKET_ENUM+1 && fp) { fprintf(fp, "Discarding %i, %s late sequenced. OI=%i. SI=%i.\n", receivedPacketNumber, type, internalPacket->orderingIndex.val, internalPacket->sequencingIndex); fflush(fp); } #endif #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("Sequenced rejected: lower than highest known value", BYTES_TO_BITS(length), systemAddress, false); #endif // Lower than highest known value FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } else { // Push to output buffer immediately bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_PROCESSED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST if (packetId==ID_USER_PACKET_ENUM+1 && fp) { fprintf(fp, "outputting immediate %i, %s. OI=%i. SI=%i.", receivedPacketNumber, type, internalPacket->orderingIndex.val, internalPacket->sequencingIndex); if (orderingHeaps[internalPacket->orderingChannel].Size()==0) fprintf(fp, "heap empty\n"); else fprintf(fp, "heap head=%i\n", orderingHeaps[internalPacket->orderingChannel].Peek()->orderingIndex.val); if (receivedPacketNumberorderingChannel]++; highestSequencedReadIndex[internalPacket->orderingChannel] = 0; // Return off heap until order lost while (orderingHeaps[internalPacket->orderingChannel].Size()>0 && orderingHeaps[internalPacket->orderingChannel].Peek()->orderingIndex==orderedReadIndex[internalPacket->orderingChannel]) { internalPacket = orderingHeaps[internalPacket->orderingChannel].Pop(0); #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST BitStream bitStream2(internalPacket->data, BITS_TO_BYTES(internalPacket->dataBitLength), false); bitStream2.IgnoreBits(8); // Ignore ID_TIMESTAMP bitStream2.Read(receivedTime); bitStream2.IgnoreBits(8); // Ignore ID_USER_ENUM+1 bitStream2.Read(receivedPacketNumber); bitStream2.Read(streamNumber); bitStream2.Read(reliability); char *type="UNDEFINED"; if (reliability==UNRELIABLE_SEQUENCED) type="UNRELIABLE_SEQUENCED"; else if (reliability==RELIABLE_ORDERED) type="RELIABLE_ORDERED"; if (packetId==ID_USER_PACKET_ENUM+1 && fp) { fprintf(fp, "Heap pop %i, %s. OI=%i. SI=%i.\n", receivedPacketNumber, type, internalPacket->orderingIndex.val, internalPacket->sequencingIndex); fflush(fp); if (receivedPacketNumberdataBitLength)); outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); if (internalPacket->reliability == RELIABLE_ORDERED) { orderedReadIndex[internalPacket->orderingChannel]++; } else { highestSequencedReadIndex[internalPacket->orderingChannel] = internalPacket->sequencingIndex; } } // Done goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } else if (IsOlderOrderedPacket(internalPacket->orderingIndex,orderedReadIndex[internalPacket->orderingChannel])==false) { // internalPacket->_orderingIndex is greater // If a message has a greater ordering index, and is sequenced or ordered, buffer it // Sequenced has a lower heap weight, ordered has max sequenced weight // Keep orderedHoleCount count small if (orderingHeaps[internalPacket->orderingChannel].Size()==0) heapIndexOffsets[internalPacket->orderingChannel]=orderedReadIndex[internalPacket->orderingChannel]; reliabilityHeapWeightType orderedHoleCount = internalPacket->orderingIndex-heapIndexOffsets[internalPacket->orderingChannel]; reliabilityHeapWeightType weight = orderedHoleCount*1048576; if (internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED) weight+=internalPacket->sequencingIndex; else weight+=(1048576-1); orderingHeaps[internalPacket->orderingChannel].Push(weight, internalPacket, _FILE_AND_LINE_); #ifdef PRINT_TO_FILE_RELIABLE_ORDERED_TEST if (packetId==ID_USER_PACKET_ENUM+1 && fp) { fprintf(fp, "Heap push %i, %s, weight=%" PRINTF_64_BIT_MODIFIER "u. OI=%i. waiting on %i. SI=%i.\n", receivedPacketNumber, type, weight, internalPacket->orderingIndex.val, orderedReadIndex[internalPacket->orderingChannel].val, internalPacket->sequencingIndex); fflush(fp); } #endif #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("Larger number ordered packet leaving holes", BYTES_TO_BITS(length), systemAddress, false); #endif // Buffered, nothing to do goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } else { // Out of order FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); #ifdef LOG_TRIVIAL_NOTIFICATIONS for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnReliabilityLayerNotification("Rejected older resend", BYTES_TO_BITS(length), systemAddress, false); #endif // Ignored, nothing to do goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } bpsMetrics[(int) USER_MESSAGE_BYTES_RECEIVED_PROCESSED].Push1(timeRead,BITS_TO_BYTES(internalPacket->dataBitLength)); // Nothing special about this packet. Add it to the output queue outputQueue.Push( internalPacket, _FILE_AND_LINE_ ); internalPacket = 0; } // Used for a goto to jump to the resendNext packet immediately CONTINUE_SOCKET_DATA_PARSE_LOOP: // Parse the bitstream to create an internal packet internalPacket = CreateInternalPacketFromBitStream( &socketData, timeRead ); } } receivePacketCount++; return true; } //------------------------------------------------------------------------------------------------------- // This gets an end-user packet already parsed out. Returns number of BITS put into the buffer //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::Receive( unsigned char **data ) { InternalPacket * internalPacket; if ( outputQueue.Size() > 0 ) { // #ifdef _DEBUG // RakAssert(bitStream->GetNumberOfBitsUsed()==0); // #endif internalPacket = outputQueue.Pop(); BitSize_t bitLength; *data = internalPacket->data; bitLength = internalPacket->dataBitLength; ReleaseToInternalPacketPool( 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, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, CCTimeType currentTime, uint32_t receipt ) { #ifdef _DEBUG RakAssert( !( reliability >= NUMBER_OF_RELIABILITIES || reliability < 0 ) ); RakAssert( !( priority > NUMBER_OF_PRIORITIES || priority < 0 ) ); RakAssert( !( orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) ); RakAssert( numberOfBitsToSend > 0 ); #endif #if CC_TIME_TYPE_BYTES==4 currentTime/=1000; #endif (void) MTUSize; // int a = BITS_TO_BYTES(numberOfBitsToSend); // Fix any bad parameters if ( reliability > RELIABLE_ORDERED_WITH_ACK_RECEIPT || reliability < 0 ) reliability = RELIABLE; if ( priority > NUMBER_OF_PRIORITIES || priority < 0 ) priority = HIGH_PRIORITY; if ( orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) orderingChannel = 0; unsigned int numberOfBytesToSend=(unsigned int) BITS_TO_BYTES(numberOfBitsToSend); if ( numberOfBitsToSend == 0 ) { return false; } InternalPacket * internalPacket = AllocateFromInternalPacketPool(); if (internalPacket==0) { notifyOutOfMemory(_FILE_AND_LINE_); return false; // Out of memory } bpsMetrics[(int) USER_MESSAGE_BYTES_PUSHED].Push1(currentTime,numberOfBytesToSend); internalPacket->creationTime = currentTime; if ( makeDataCopy ) { AllocInternalPacketData(internalPacket, numberOfBytesToSend, true, _FILE_AND_LINE_ ); //internalPacket->data = (unsigned char*) rakMalloc_Ex( numberOfBytesToSend, _FILE_AND_LINE_ ); memcpy( internalPacket->data, data, numberOfBytesToSend ); } else { // Allocated the data elsewhere, delete it in here //internalPacket->data = ( unsigned char* ) data; AllocInternalPacketData(internalPacket, (unsigned char*) data ); } internalPacket->dataBitLength = numberOfBitsToSend; internalPacket->messageInternalOrder = internalOrderIndex++; internalPacket->priority = priority; internalPacket->reliability = reliability; internalPacket->sendReceiptSerial=receipt; // Calculate if I need to split the packet // int headerLength = BITS_TO_BYTES( GetMessageHeaderLengthBits( internalPacket, true ) ); unsigned int maxDataSizeBytes = GetMaxDatagramSizeExcludingMessageHeaderBytes() - BITS_TO_BYTES(GetMaxMessageHeaderLengthBits()); bool splitPacket = numberOfBytesToSend > maxDataSizeBytes; // If a split packet, we might have to upgrade the reliability if ( splitPacket ) { // Split packets cannot be unreliable, in case that one part doesn't arrive and the whole cannot be reassembled. // One part could not arrive either due to packetloss or due to unreliable discard if (internalPacket->reliability==UNRELIABLE) internalPacket->reliability=RELIABLE; else if (internalPacket->reliability==UNRELIABLE_WITH_ACK_RECEIPT) internalPacket->reliability=RELIABLE_WITH_ACK_RECEIPT; else if (internalPacket->reliability==UNRELIABLE_SEQUENCED) internalPacket->reliability=RELIABLE_SEQUENCED; // else if (internalPacket->reliability==UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT) // internalPacket->reliability=RELIABLE_SEQUENCED_WITH_ACK_RECEIPT; } // ++sendMessageNumberIndex; if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED // || // internalPacket->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || // internalPacket->reliability == UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) { // Assign the sequence stream and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = orderedWriteIndex[ orderingChannel ]; internalPacket->sequencingIndex = sequencedWriteIndex[ 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 || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) { // Assign the ordering channel and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = orderedWriteIndex[ orderingChannel ] ++; sequencedWriteIndex[ orderingChannel ]=0; } 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 ); //RakNet::OP_DELETE_ARRAY(packetCopy.data, _FILE_AND_LINE_); return true; } RakAssert(internalPacket->dataBitLengthdataBitLengthmessageNumberAssigned==false); outgoingPacketBuffer.Push( GetNextWeight(internalPacket->priority), internalPacket, _FILE_AND_LINE_ ); RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthpriority]++; statistics.bytesInSendBuffer[(int)internalPacket->priority]+=(double) BITS_TO_BYTES(internalPacket->dataBitLength); // sendPacketSet[priority].WriteUnlock(); return true; } //------------------------------------------------------------------------------------------------------- // Run this once per game cycle. Handles internal lists and actually does the send //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Update( RakNetSocket2 *s, SystemAddress &systemAddress, int MTUSize, CCTimeType time, unsigned bitsPerSecondLimit, DataStructures::List &messageHandlerList, RakNetRandom *rnr, BitStream &updateBitStream) { (void) MTUSize; RakNet::TimeMS timeMs; #if CC_TIME_TYPE_BYTES==4 time/=1000; timeMs=time; #else timeMs=(RakNet::TimeMS) (time/(CCTimeType)1000); #endif #ifdef _DEBUG while (delayList.Size()) { if (delayList.Peek()->sendTime <= timeMs) { DataAndTime *dat = delayList.Pop(); // SocketLayer::SendTo( dat->s, dat->data, dat->length, systemAddress, __FILE__, __LINE__ ); RNS2_SendParameters bsp; bsp.data = (char*) dat->data; bsp.length = dat->length; bsp.systemAddress = systemAddress; dat->s->Send(&bsp, _FILE_AND_LINE_); RakNet::OP_DELETE(dat,__FILE__,__LINE__); } else { break; } } #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; } CCTimeType timeSinceLastTick = time - lastUpdateTime; lastUpdateTime=time; #if CC_TIME_TYPE_BYTES==4 if (timeSinceLastTick>100) timeSinceLastTick=100; #else if (timeSinceLastTick>100000) timeSinceLastTick=100000; #endif if (unreliableTimeout>0) { if (timeSinceLastTick>=timeToNextUnreliableCull) { if (unreliableLinkedListHead) { // Cull out all unreliable messages that have exceeded the timeout InternalPacket *cur = unreliableLinkedListHead; InternalPacket *end = unreliableLinkedListHead->unreliablePrev; #ifdef _MSC_VER #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #endif while (1) { if (time > cur->creationTime+(CCTimeType)unreliableTimeout) { // Flag invalid, and clear the memory. Still needs to be removed from the sendPacketSet later // This fixes a problem where a remote system disconnects, but we don't know it yet, and memory consumption increases to a huge value FreeInternalPacketData(cur, _FILE_AND_LINE_ ); cur->data=0; InternalPacket *next = cur->unreliableNext; RemoveFromUnreliableLinkedList(cur); if (cur==end) break; cur=next; } else { // if (cur==end) // break; // // cur=cur->unreliableNext; // They should be inserted in-order, so no need to iterate past the first failure break; } } } timeToNextUnreliableCull=unreliableTimeout/(CCTimeType)2; } else { timeToNextUnreliableCull-=timeSinceLastTick; } } // 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 CC_TIME_TYPE_BYTES==4 if ( statistics.messagesInResendBuffer!=0 && AckTimeout(time) ) #else if ( statistics.messagesInResendBuffer!=0 && AckTimeout(RakNet::TimeMS(time/(CCTimeType)1000)) ) #endif { // SHOW - dead connection // We've waited a very long time for a reliable packet to get an ack and it never has deadConnection = true; return; } if (congestionManager.ShouldSendACKs(time,timeSinceLastTick)) { SendACKs(s, systemAddress, time, rnr, updateBitStream); } if (NAKs.Size()>0) { updateBitStream.Reset(); DatagramHeaderFormat dhfNAK; dhfNAK.isNAK=true; dhfNAK.isACK=false; dhfNAK.isPacketPair=false; dhfNAK.Serialize(&updateBitStream); NAKs.Serialize(&updateBitStream, GetMaxDatagramSizeExcludingMessageHeaderBits(), true); SendBitStream( s, systemAddress, &updateBitStream, rnr, time ); } DatagramHeaderFormat dhf; dhf.needsBAndAs=congestionManager.GetIsInSlowStart(); dhf.isContinuousSend=bandwidthExceededStatistic; // bandwidthExceededStatistic=sendPacketSet[0].IsEmpty()==false || // sendPacketSet[1].IsEmpty()==false || // sendPacketSet[2].IsEmpty()==false || // sendPacketSet[3].IsEmpty()==false; bandwidthExceededStatistic=outgoingPacketBuffer.Size()>0; const bool hasDataToSendOrResend = IsResendQueueEmpty()==false || bandwidthExceededStatistic; RakAssert(NUMBER_OF_PRIORITIES==4); congestionManager.Update(time, hasDataToSendOrResend); statistics.BPSLimitByOutgoingBandwidthLimit = BITS_TO_BYTES(bitsPerSecondLimit); statistics.BPSLimitByCongestionControl = congestionManager.GetBytesPerSecondLimitByCongestionControl(); unsigned int i; if (time > lastBpsClear+ #if CC_TIME_TYPE_BYTES==4 100 #else 100000 #endif ) { for (i=0; i < RNS_PER_SECOND_METRICS_COUNT; i++) { bpsMetrics[i].ClearExpired1(time); } lastBpsClear=time; } if (unreliableWithAckReceiptHistory.Size()>0) { i=0; while (i < unreliableWithAckReceiptHistory.Size()) { //if (unreliableWithAckReceiptHistory[i].nextActionTime < time) if (time - unreliableWithAckReceiptHistory[i].nextActionTime < (((CCTimeType)-1)/2) ) { InternalPacket *ackReceipt = AllocateFromInternalPacketPool(); AllocInternalPacketData(ackReceipt, 5, false, _FILE_AND_LINE_ ); ackReceipt->dataBitLength=BYTES_TO_BITS(5); ackReceipt->data[0]=(MessageID)ID_SND_RECEIPT_LOSS; memcpy(ackReceipt->data+sizeof(MessageID), &unreliableWithAckReceiptHistory[i].sendReceiptSerial, sizeof(uint32_t)); outputQueue.Push(ackReceipt, _FILE_AND_LINE_ ); // Remove, swap with last unreliableWithAckReceiptHistory.RemoveAtIndex(i); } else i++; } } if (hasDataToSendOrResend==true) { InternalPacket *internalPacket; // bool forceSend=false; bool pushedAnything; BitSize_t nextPacketBitLength; dhf.isACK=false; dhf.isNAK=false; dhf.hasBAndAS=false; ResetPacketsAndDatagrams(); int transmissionBandwidth = congestionManager.GetTransmissionBandwidth(time, timeSinceLastTick, unacknowledgedBytes,dhf.isContinuousSend); int retransmissionBandwidth = congestionManager.GetRetransmissionBandwidth(time, timeSinceLastTick, unacknowledgedBytes,dhf.isContinuousSend); if (retransmissionBandwidth>0 || transmissionBandwidth>0) { statistics.isLimitedByCongestionControl=false; allDatagramSizesSoFar=0; // Keep filling datagrams until we exceed retransmission bandwidth while ((int)BITS_TO_BYTES(allDatagramSizesSoFar)messageNumberAssigned==true); //if ( internalPacket->nextActionTime < time ) if ( time - internalPacket->nextActionTime < (((CCTimeType)-1)/2) ) { nextPacketBitLength = internalPacket->headerLength + internalPacket->dataBitLength; if ( datagramSizeSoFar + nextPacketBitLength > GetMaxDatagramSizeExcludingMessageHeaderBits() ) { // Gathers all PushPackets() PushDatagram(); break; } PopListHead(false); CC_DEBUG_PRINTF_2("Rs %i ", internalPacket->reliableMessageNumber.val); bpsMetrics[(int) USER_MESSAGE_BYTES_RESENT].Push1(time,BITS_TO_BYTES(internalPacket->dataBitLength)); // Testing1 // if (internalPacket->reliability==RELIABLE_ORDERED || internalPacket->reliability==RELIABLE_ORDERED_WITH_ACK_RECEIPT) // printf("RESEND reliableMessageNumber %i with datagram %i\n", internalPacket->reliableMessageNumber.val, congestionManager.GetNextDatagramSequenceNumber().val); PushPacket(time,internalPacket,true); // Affects GetNewTransmissionBandwidth() internalPacket->timesSent++; congestionManager.OnResend(time, internalPacket->nextActionTime); internalPacket->retransmissionTime = congestionManager.GetRTOForRetransmission(internalPacket->timesSent); internalPacket->nextActionTime = internalPacket->retransmissionTime+time; pushedAnything=true; for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) { #if CC_TIME_TYPE_BYTES==4 messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, packetsToSendThisUpdateDatagramBoundaries.Size()+congestionManager.GetNextDatagramSequenceNumber(), systemAddress, (RakNet::TimeMS) time, true); #else messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, packetsToSendThisUpdateDatagramBoundaries.Size()+congestionManager.GetNextDatagramSequenceNumber(), systemAddress, (RakNet::TimeMS)(time/(CCTimeType)1000), true); #endif } // 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 ); // Removeme // printf("Resend:%i ", internalPacket->reliableMessageNumber); } else { // Filled one datagram. // If the 2nd and it's time to send a datagram pair, will be marked as a pair PushDatagram(); break; } } if (pushedAnything==false) break; } } else { statistics.isLimitedByCongestionControl=true; } if ((int)BITS_TO_BYTES(allDatagramSizesSoFar)messageNumberAssigned==false); RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthdata==0) { //sendPacketSet[ i ].Pop(); outgoingPacketBuffer.Pop(0); RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthpriority]--; statistics.bytesInSendBuffer[(int)internalPacket->priority]-=(double) BITS_TO_BYTES(internalPacket->dataBitLength); ReleaseToInternalPacketPool( internalPacket ); continue; } internalPacket->headerLength=GetMessageHeaderLengthBits(internalPacket); nextPacketBitLength = internalPacket->headerLength + internalPacket->dataBitLength; if ( datagramSizeSoFar + nextPacketBitLength > GetMaxDatagramSizeExcludingMessageHeaderBits() ) { // Hit MTU. May still push packets if smaller ones exist at a lower priority RakAssert(datagramSizeSoFar!=0); RakAssert(internalPacket->dataBitLengthreliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_WITH_ACK_RECEIPT || // internalPacket->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) isReliable = true; else isReliable = false; //sendPacketSet[ i ].Pop(); outgoingPacketBuffer.Pop(0); RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthmessageNumberAssigned==false); statistics.messageInSendBuffer[(int)internalPacket->priority]--; statistics.bytesInSendBuffer[(int)internalPacket->priority]-=(double) BITS_TO_BYTES(internalPacket->dataBitLength); if (isReliable /* I thought about this and agree that UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT and RELIABLE_SEQUENCED_WITH_ACK_RECEIPT is not useful unless you also know if the message was discarded. The problem is that internally, message numbers are only assigned to reliable messages, because message numbers are only used to discard duplicate message receipt and only reliable messages get sent more than once. However, without message numbers getting assigned and transmitted, there is no way to tell the sender about which messages were discarded. In fact, in looking this over I realized that UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT introduced a bug, because the remote system assumes all message numbers are used (no holes). With that send type, on packetloss, a permanent hole would have been created which eventually would cause the system to discard all further packets. So I have two options. Either do not support ack receipts when sending sequenced, or write complex and major new systems. UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT would need to send the message ID number on a special channel which allows for non-delivery. And both of them would need to have a special range list to indicate which message numbers were not delivered, so when acks are sent that can be indicated as well. A further problem is that the ack itself can be lost - it is possible that the message can arrive but be discarded, yet the ack is lost. On resend, the resent message would be ignored as duplicate, and you'd never get the discard message either (unless I made a special buffer for that case too). */ // || // If needs an ack receipt, keep the internal packet around in the list // internalPacket->reliability == UNRELIABLE_WITH_ACK_RECEIPT || // internalPacket->reliability == UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) { internalPacket->messageNumberAssigned=true; internalPacket->reliableMessageNumber=sendReliableMessageNumberIndex; internalPacket->retransmissionTime = congestionManager.GetRTOForRetransmission(internalPacket->timesSent+1); internalPacket->nextActionTime = internalPacket->retransmissionTime+time; #if CC_TIME_TYPE_BYTES==4 const CCTimeType threshhold = 10000; #else const CCTimeType threshhold = 10000000; #endif if (internalPacket->nextActionTime-time > threshhold) { // int a=5; RakAssert(time-internalPacket->nextActionTime < threshhold); } //resendTree.Insert( internalPacket->reliableMessageNumber, internalPacket); if (resendBuffer[internalPacket->reliableMessageNumber & (uint32_t) RESEND_BUFFER_ARRAY_MASK]!=0) { // bool overflow = ResendBufferOverflow(); RakAssert(0); } resendBuffer[internalPacket->reliableMessageNumber & (uint32_t) RESEND_BUFFER_ARRAY_MASK] = internalPacket; statistics.messagesInResendBuffer++; statistics.bytesInResendBuffer+=BITS_TO_BYTES(internalPacket->dataBitLength); // printf("pre:%i ", unacknowledgedBytes); InsertPacketIntoResendList( internalPacket, time, true, isReliable); // printf("post:%i ", unacknowledgedBytes); sendReliableMessageNumberIndex++; } else if (internalPacket->reliability == UNRELIABLE_WITH_ACK_RECEIPT) { unreliableWithAckReceiptHistory.Push(UnreliableWithAckReceiptNode( congestionManager.GetNextDatagramSequenceNumber() + packetsToSendThisUpdateDatagramBoundaries.Size(), internalPacket->sendReceiptSerial, congestionManager.GetRTOForRetransmission(internalPacket->timesSent+1)+time ), _FILE_AND_LINE_); } // If isReliable is false, the packet and its contents will be added to a list to be freed in ClearPacketsAndDatagrams // However, the internalPacket structure will remain allocated and be in the resendBuffer list if it requires a receipt bpsMetrics[(int) USER_MESSAGE_BYTES_SENT].Push1(time,BITS_TO_BYTES(internalPacket->dataBitLength)); // Testing1 // if (internalPacket->reliability==RELIABLE_ORDERED || internalPacket->reliability==RELIABLE_ORDERED_WITH_ACK_RECEIPT) // printf("SEND reliableMessageNumber %i in datagram %i\n", internalPacket->reliableMessageNumber.val, congestionManager.GetNextDatagramSequenceNumber().val); PushPacket(time,internalPacket, isReliable); internalPacket->timesSent++; for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) { #if CC_TIME_TYPE_BYTES==4 messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, packetsToSendThisUpdateDatagramBoundaries.Size()+congestionManager.GetNextDatagramSequenceNumber(), systemAddress, (RakNet::TimeMS)time, true); #else messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, packetsToSendThisUpdateDatagramBoundaries.Size()+congestionManager.GetNextDatagramSequenceNumber(), systemAddress, (RakNet::TimeMS)(time/(CCTimeType)1000), true); #endif } pushedAnything=true; if (ResendBufferOverflow()) break; } // if (ResendBufferOverflow()) // break; // }z // No datagrams pushed? if (datagramSizeSoFar==0) break; // Filled one datagram. // If the 2nd and it's time to send a datagram pair, will be marked as a pair PushDatagram(); } } for (unsigned int datagramIndex=0; datagramIndex < packetsToSendThisUpdateDatagramBoundaries.Size(); datagramIndex++) { if (datagramIndex>0) dhf.isContinuousSend=true; MessageNumberNode* messageNumberNode = 0; dhf.datagramNumber=congestionManager.GetAndIncrementNextDatagramSequenceNumber(); dhf.isPacketPair=datagramsToSendThisUpdateIsPair[datagramIndex]; //printf("%p pushing datagram %i\n", this, dhf.datagramNumber.val); bool isSecondOfPacketPair=dhf.isPacketPair && datagramIndex>0 && datagramsToSendThisUpdateIsPair[datagramIndex-1]; unsigned int msgIndex, msgTerm; if (datagramIndex==0) { msgIndex=0; msgTerm=packetsToSendThisUpdateDatagramBoundaries[0]; } else { msgIndex=packetsToSendThisUpdateDatagramBoundaries[datagramIndex-1]; msgTerm=packetsToSendThisUpdateDatagramBoundaries[datagramIndex]; } // More accurate time to reset here #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 dhf.sourceSystemTime=RakNet::GetTimeUS(); #endif updateBitStream.Reset(); dhf.Serialize(&updateBitStream); CC_DEBUG_PRINTF_2("S%i ",dhf.datagramNumber.val); while (msgIndex < msgTerm) { // If reliable or needs receipt if ( packetsToSendThisUpdate[msgIndex]->reliability != UNRELIABLE && packetsToSendThisUpdate[msgIndex]->reliability != UNRELIABLE_SEQUENCED ) { if (messageNumberNode==0) { messageNumberNode = AddFirstToDatagramHistory(dhf.datagramNumber, packetsToSendThisUpdate[msgIndex]->reliableMessageNumber, time); } else { messageNumberNode = AddSubsequentToDatagramHistory(messageNumberNode, packetsToSendThisUpdate[msgIndex]->reliableMessageNumber); } } RakAssert(updateBitStream.GetNumberOfBytesUsed()<=MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE); WriteToBitStreamFromInternalPacket( &updateBitStream, packetsToSendThisUpdate[msgIndex], time ); RakAssert(updateBitStream.GetNumberOfBytesUsed()<=MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE); msgIndex++; } if (isSecondOfPacketPair) { // Pad to size of first datagram RakAssert(updateBitStream.GetNumberOfBytesUsed()<=MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE); updateBitStream.PadWithZeroToByteLength(datagramSizesInBytes[datagramIndex-1]); RakAssert(updateBitStream.GetNumberOfBytesUsed()<=MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE); } if (messageNumberNode==0) { // Unreliable, add dummy node AddFirstToDatagramHistory(dhf.datagramNumber, time); } // Store what message ids were sent with this datagram // datagramMessageIDTree.Insert(dhf.datagramNumber,idList); congestionManager.OnSendBytes(time,UDP_HEADER_SIZE+DatagramHeaderFormat::GetDataHeaderByteLength()); SendBitStream( s, systemAddress, &updateBitStream, rnr, time ); bandwidthExceededStatistic=outgoingPacketBuffer.Size()>0; // bandwidthExceededStatistic=sendPacketSet[0].IsEmpty()==false || // sendPacketSet[1].IsEmpty()==false || // sendPacketSet[2].IsEmpty()==false || // sendPacketSet[3].IsEmpty()==false; if (bandwidthExceededStatistic==true) timeOfLastContinualSend=time; else timeOfLastContinualSend=0; } ClearPacketsAndDatagrams(); // Any data waiting to send after attempting to send, then bandwidth is exceeded bandwidthExceededStatistic=outgoingPacketBuffer.Size()>0; // bandwidthExceededStatistic=sendPacketSet[0].IsEmpty()==false || // sendPacketSet[1].IsEmpty()==false || // sendPacketSet[2].IsEmpty()==false || // sendPacketSet[3].IsEmpty()==false; } // Keep on top of deleting old unreliable split packets so they don't clog the list. //DeleteOldUnreliableSplitPackets( time ); } //------------------------------------------------------------------------------------------------------- // Writes a bitstream to the socket //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendBitStream( RakNetSocket2 *s, SystemAddress &systemAddress, RakNet::BitStream *bitStream, RakNetRandom *rnr, CCTimeType currentTime) { (void) systemAddress; (void) rnr; unsigned int length; length = (unsigned int) bitStream->GetNumberOfBytesUsed(); #ifdef _DEBUG if (packetloss > 0.0) { if (frandomMT() < packetloss) return; } if (minExtraPing > 0 || extraPingVariance > 0) { #ifdef FLIP_SEND_ORDER_TEST // Flip order of sends without delaying them for testing DataAndTime *dat = RakNet::OP_NEW(__FILE__,__LINE__); memcpy(dat->data, ( char* ) bitStream->GetData(), length ); dat->s=s; dat->length=length; dat->sendTime = 0; dat->remotePortRakNetWasStartedOn_PS3=remotePortRakNetWasStartedOn_PS3; dat->extraSocketOptions=extraSocketOptions; delayList.PushAtHead(dat, 0, _FILE_AND_LINE_); #else RakNet::TimeMS delay = minExtraPing; if (extraPingVariance>0) delay += (randomMT() % extraPingVariance); if (delay > 0) { DataAndTime *dat = RakNet::OP_NEW(__FILE__,__LINE__); memcpy(dat->data, ( char* ) bitStream->GetData(), length ); dat->s=s; dat->length=length; dat->sendTime = RakNet::GetTimeMS() + delay; for (unsigned int i=0; i < delayList.Size(); i++) { if (dat->sendTime < delayList[i]->sendTime) { delayList.PushAtHead(dat, i, __FILE__, __LINE__); dat=0; break; } } if (dat!=0) delayList.Push(dat,__FILE__,__LINE__); return; } #endif } #endif #if LIBCAT_SECURITY==1 if (useSecurity) { unsigned char *buffer = reinterpret_cast( bitStream->GetData() ); int buffer_size = bitStream->GetNumberOfBitsAllocated() / 8; // Verify there is enough room for encrypted output and encrypt // Encrypt() will increase length bool success = auth_enc.Encrypt(buffer, buffer_size, length); RakAssert(success); } #endif bpsMetrics[(int) ACTUAL_BYTES_SENT].Push1(currentTime,length); RakAssert(length <= congestionManager.GetMTU()); #ifdef USE_THREADED_SEND SendToThread::SendToThreadBlock *block = SendToThread::AllocateBlock(); memcpy(block->data, bitStream->GetData(), length); block->dataWriteOffset=length; block->extraSocketOptions=extraSocketOptions; block->remotePortRakNetWasStartedOn_PS3=remotePortRakNetWasStartedOn_PS3; block->s=s; block->systemAddress=systemAddress; SendToThread::ProcessBlock(block); #else // SocketLayer::SendTo( s, ( char* ) bitStream->GetData(), length, systemAddress, __FILE__, __LINE__ ); RNS2_SendParameters bsp; bsp.data = (char*) bitStream->GetData(); bsp.length = length; bsp.systemAddress = systemAddress; s->Send(&bsp, _FILE_AND_LINE_); #endif } //------------------------------------------------------------------------------------------------------- // Are we waiting for any data to be sent out or be processed by the player? //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsOutgoingDataWaiting(void) { if (outgoingPacketBuffer.Size()>0) return true; // unsigned i; // for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) // { // if (sendPacketSet[ i ].Size() > 0) // return true; // } return //acknowlegements.Size() > 0 || //resendTree.IsEmpty()==false;// || outputQueue.Size() > 0 || orderingList.Size() > 0 || splitPacketChannelList.Size() > 0; statistics.messagesInResendBuffer!=0; } bool ReliabilityLayer::AreAcksWaiting(void) { return acknowlegements.Size() > 0; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ApplyNetworkSimulator( double _packetloss, RakNet::TimeMS _minExtraPing, RakNet::TimeMS _extraPingVariance ) { #ifdef _DEBUG packetloss=_packetloss; 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(RakNet::TimeMS timeoutMS) { #if CC_TIME_TYPE_BYTES==4 unreliableTimeout=timeoutMS; #else unreliableTimeout=(CCTimeType)timeoutMS*(CCTimeType)1000; #endif } //------------------------------------------------------------------------------------------------------- // This will return true if we should not send at this time //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsSendThrottled( int MTUSize ) { (void) 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( CCTimeType time ) { (void) time; } //------------------------------------------------------------------------------------------------------- // Increase the window size //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::UpdateWindowFromAck( CCTimeType time ) { (void) time; } //------------------------------------------------------------------------------------------------------- // Does what the function name says //------------------------------------------------------------------------------------------------------- unsigned ReliabilityLayer::RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, CCTimeType time, DataStructures::List &messageHandlerList, const SystemAddress &systemAddress ) { (void) time; (void) messageNumber; 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; for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) { #if CC_TIME_TYPE_BYTES==4 messageHandlerList[messageHandlerIndex]->OnAck(messageNumber, systemAddress, time); #else messageHandlerList[messageHandlerIndex]->OnAck(messageNumber, systemAddress, (RakNet::TimeMS)(time/(CCTimeType)1000)); #endif } // Testing1 // if (resendLinkedListHead) // { // InternalPacket *internalPacket = resendLinkedListHead; // do // { // internalPacket=internalPacket->resendNext; // printf("%i ", internalPacket->reliableMessageNumber.val); // } while (internalPacket!=resendLinkedListHead); // printf("\n"); // } // bool deleted; // deleted=resendTree.Delete(messageNumber, internalPacket); internalPacket = resendBuffer[messageNumber & RESEND_BUFFER_ARRAY_MASK]; // May ask to remove twice, for example resend twice, then second ack if (internalPacket && internalPacket->reliableMessageNumber==messageNumber) { // ValidateResendList(); resendBuffer[messageNumber & RESEND_BUFFER_ARRAY_MASK]=0; CC_DEBUG_PRINTF_2("AckRcv %i ", messageNumber); statistics.messagesInResendBuffer--; statistics.bytesInResendBuffer-=BITS_TO_BYTES(internalPacket->dataBitLength); // orderingIndex = internalPacket->orderingIndex; totalUserDataBytesAcked+=(double) BITS_TO_BYTES(internalPacket->headerLength+internalPacket->dataBitLength); // Return receipt if asked for if (internalPacket->reliability>=RELIABLE_WITH_ACK_RECEIPT && (internalPacket->splitPacketCount==0 || internalPacket->splitPacketIndex+1==internalPacket->splitPacketCount) ) { InternalPacket *ackReceipt = AllocateFromInternalPacketPool(); AllocInternalPacketData(ackReceipt, 5, false, _FILE_AND_LINE_ ); ackReceipt->dataBitLength=BYTES_TO_BITS(5); ackReceipt->data[0]=(MessageID)ID_SND_RECEIPT_ACKED; memcpy(ackReceipt->data+sizeof(MessageID), &internalPacket->sendReceiptSerial, sizeof(internalPacket->sendReceiptSerial)); outputQueue.Push(ackReceipt, _FILE_AND_LINE_ ); } bool isReliable; if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_WITH_ACK_RECEIPT || // internalPacket->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) isReliable = true; else isReliable = false; RemoveFromList(internalPacket, isReliable); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); return 0; } else { } return (unsigned)-1; } //------------------------------------------------------------------------------------------------------- // Acknowledge receipt of the packet with the specified messageNumber //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendAcknowledgementPacket( const DatagramSequenceNumberType messageNumber, CCTimeType time ) { // REMOVEME // printf("%p Send ack %i\n", this, messageNumber.val); nextAckTimeToSend=time; acknowlegements.Insert(messageNumber); //printf("ACK_DG:%i ", messageNumber.val); CC_DEBUG_PRINTF_2("AckPush %i ", messageNumber); } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and figure out how many header bits would be // written. Returns that number //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::GetMaxMessageHeaderLengthBits( void ) { InternalPacket ip; ip.reliability=RELIABLE_SEQUENCED; ip.splitPacketCount=1; return GetMessageHeaderLengthBits(&ip); } //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::GetMessageHeaderLengthBits( const InternalPacket *const internalPacket ) { BitSize_t bitLength; // bitStream->AlignWriteToByteBoundary(); // Potentially unaligned // tempChar=(unsigned char)internalPacket->reliability; bitStream->WriteBits( (const unsigned char *)&tempChar, 3, true ); // 3 bits to write reliability. // bool hasSplitPacket = internalPacket->splitPacketCount>0; bitStream->Write(hasSplitPacket); // Write 1 bit to indicate if splitPacketCount>0 bitLength = 8*1; // bitStream->AlignWriteToByteBoundary(); // RakAssert(internalPacket->dataBitLength < 65535); // unsigned short s; s = (unsigned short) internalPacket->dataBitLength; bitStream->WriteAlignedVar16((const char*)& s); bitLength += 8*2; if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_WITH_ACK_RECEIPT || // internalPacket->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) bitLength += 8*3; // bitStream->Write(internalPacket->reliableMessageNumber); // Message sequence number // bitStream->AlignWriteToByteBoundary(); // Potentially nothing else to write if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED ) { bitLength += 8*3;; // bitStream->Write(internalPacket->_sequencingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. } if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) { bitLength += 8*3; // bitStream->Write(internalPacket->orderingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. bitLength += 8*1; // tempChar=internalPacket->orderingChannel; bitStream->WriteAlignedVar8((const char*)& tempChar); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. 5 bits needed, write one byte } if (internalPacket->splitPacketCount>0) { bitLength += 8*4; // bitStream->WriteAlignedVar32((const char*)& internalPacket->splitPacketCount); RakAssert(sizeof(SplitPacketIndexType)==4); // Only needed if splitPacketCount>0. 4 bytes bitLength += 8*sizeof(SplitPacketIdType); // bitStream->WriteAlignedVar16((const char*)& internalPacket->splitPacketId); RakAssert(sizeof(SplitPacketIdType)==2); // Only needed if splitPacketCount>0. bitLength += 8*4; // bitStream->WriteAlignedVar32((const char*)& internalPacket->splitPacketIndex); // Only needed if splitPacketCount>0. 4 bytes } return bitLength; } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and create a bitstream to represent this data //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket, CCTimeType curTime ) { (void) curTime; BitSize_t start = bitStream->GetNumberOfBitsUsed(); unsigned char tempChar; // (Incoming data may be all zeros due to padding) bitStream->AlignWriteToByteBoundary(); // Potentially unaligned if (internalPacket->reliability==UNRELIABLE_WITH_ACK_RECEIPT) tempChar=UNRELIABLE; else if (internalPacket->reliability==RELIABLE_WITH_ACK_RECEIPT) tempChar=RELIABLE; else if (internalPacket->reliability==RELIABLE_ORDERED_WITH_ACK_RECEIPT) tempChar=RELIABLE_ORDERED; else tempChar=(unsigned char)internalPacket->reliability; bitStream->WriteBits( (const unsigned char *)&tempChar, 3, true ); // 3 bits to write reliability. bool hasSplitPacket = internalPacket->splitPacketCount>0; bitStream->Write(hasSplitPacket); // Write 1 bit to indicate if splitPacketCount>0 bitStream->AlignWriteToByteBoundary(); RakAssert(internalPacket->dataBitLength < 65535); unsigned short s; s = (unsigned short) internalPacket->dataBitLength; bitStream->WriteAlignedVar16((const char*)& s); if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_WITH_ACK_RECEIPT || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) bitStream->Write(internalPacket->reliableMessageNumber); // Used for all reliable types bitStream->AlignWriteToByteBoundary(); // Potentially nothing else to write if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED ) { bitStream->Write(internalPacket->sequencingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. } if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) { bitStream->Write(internalPacket->orderingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. tempChar=internalPacket->orderingChannel; bitStream->WriteAlignedVar8((const char*)& tempChar); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. 5 bits needed, write one byte } if (internalPacket->splitPacketCount>0) { // printf("Write before\n"); // bitStream->PrintBits(); bitStream->WriteAlignedVar32((const char*)& internalPacket->splitPacketCount); RakAssert(sizeof(SplitPacketIndexType)==4); // Only needed if splitPacketCount>0. 4 bytes bitStream->WriteAlignedVar16((const char*)& internalPacket->splitPacketId); RakAssert(sizeof(SplitPacketIdType)==2); // Only needed if splitPacketCount>0. bitStream->WriteAlignedVar32((const char*)& internalPacket->splitPacketIndex); // Only needed if splitPacketCount>0. 4 bytes // printf("Write after\n"); // bitStream->PrintBits(); } // Write the actual data. bitStream->WriteAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) ); return bitStream->GetNumberOfBitsUsed() - start; } //------------------------------------------------------------------------------------------------------- // Parse a bitstream and create an internal packet to represent this data //------------------------------------------------------------------------------------------------------- InternalPacket* ReliabilityLayer::CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, CCTimeType time ) { bool bitStreamSucceeded; InternalPacket* internalPacket; unsigned char tempChar; bool hasSplitPacket=false; bool readSuccess; if ( bitStream->GetNumberOfUnreadBits() < (int) sizeof( internalPacket->reliableMessageNumber ) * 8 ) return 0; // leftover bits internalPacket = AllocateFromInternalPacketPool(); if (internalPacket==0) { // Out of memory RakAssert(0); return 0; } internalPacket->creationTime = time; // (Incoming data may be all zeros due to padding) bitStream->AlignReadToByteBoundary(); // Potentially unaligned bitStream->ReadBits( ( unsigned char* ) ( &( tempChar ) ), 3 ); internalPacket->reliability = ( const PacketReliability ) tempChar; readSuccess=bitStream->Read(hasSplitPacket); // Read 1 bit to indicate if splitPacketCount>0 bitStream->AlignReadToByteBoundary(); unsigned short s; bitStream->ReadAlignedVar16((char*)&s); internalPacket->dataBitLength=s; // Length of message (2 bytes) if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED // I don't write ACK_RECEIPT to the remote system // || // internalPacket->reliability == RELIABLE_WITH_ACK_RECEIPT || // internalPacket->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || // internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) bitStream->Read(internalPacket->reliableMessageNumber); // Message sequence number else internalPacket->reliableMessageNumber=(MessageNumberType)(const uint32_t)-1; bitStream->AlignReadToByteBoundary(); // Potentially nothing else to Read if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED ) { bitStream->Read(internalPacket->sequencingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. } if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE_ORDERED_WITH_ACK_RECEIPT ) { bitStream->Read(internalPacket->orderingIndex); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. 4 bytes. readSuccess=bitStream->ReadAlignedVar8((char*)& internalPacket->orderingChannel); // Used for UNRELIABLE_SEQUENCED, RELIABLE_SEQUENCED, RELIABLE_ORDERED. 5 bits needed, Read one byte } else internalPacket->orderingChannel=0; if (hasSplitPacket) { // printf("Read before\n"); // bitStream->PrintBits(); bitStream->ReadAlignedVar32((char*)& internalPacket->splitPacketCount); // Only needed if splitPacketCount>0. 4 bytes bitStream->ReadAlignedVar16((char*)& internalPacket->splitPacketId); // Only needed if splitPacketCount>0. readSuccess=bitStream->ReadAlignedVar32((char*)& internalPacket->splitPacketIndex); // Only needed if splitPacketCount>0. 4 bytes RakAssert(readSuccess); // printf("Read after\n"); // bitStream->PrintBits(); } else { internalPacket->splitPacketCount=0; } if (readSuccess==false || internalPacket->dataBitLength==0 || internalPacket->reliability>=NUMBER_OF_RELIABILITIES || internalPacket->orderingChannel>=32 || (hasSplitPacket && (internalPacket->splitPacketIndex >= internalPacket->splitPacketCount))) { // If this assert hits, encoding is garbage RakAssert("Encoding is garbage" && 0); ReleaseToInternalPacketPool( internalPacket ); return 0; } // Allocate memory to hold our data AllocInternalPacketData(internalPacket, BITS_TO_BYTES( internalPacket->dataBitLength ), false, _FILE_AND_LINE_ ); RakAssert(BITS_TO_BYTES( internalPacket->dataBitLength )data == 0) { RakAssert("Out of memory in ReliabilityLayer::CreateInternalPacketFromBitStream" && 0); notifyOutOfMemory(_FILE_AND_LINE_); ReleaseToInternalPacketPool( internalPacket ); return 0; } // 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 ) ); if ( bitStreamSucceeded == false ) { // If this hits, most likely the variable buff is too small in RunUpdateCycle in RakPeer.cpp RakAssert("Couldn't read all the data" && 0); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); return 0; } 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&theList, int splitPacketId ) { unsigned i = 0; while ( i < theList.Size() ) { if ( ( theList[ i ]->reliability == RELIABLE_SEQUENCED || theList[ i ]->reliability == UNRELIABLE_SEQUENCED // || // theList[ i ]->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || // theList[ i ]->reliability == UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) && theList[ i ]->orderingChannel == orderingChannel && ( splitPacketId == -1 || theList[ i ]->splitPacketId != (unsigned int) splitPacketId ) ) { InternalPacket * internalPacket = theList[ i ]; theList.RemoveAtIndex( i ); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( 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&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 ]->reliability == RELIABLE_SEQUENCED_WITH_ACK_RECEIPT || // theList[ i ]->reliability == UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) && theList[ i ]->orderingChannel == orderingChannel ) { internalPacket = theList[ i ]; theList.RemoveAtIndex( i ); FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); listSize--; } else i++; } } */ //------------------------------------------------------------------------------------------------------- // Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex ) { OrderingIndexType maxRange = (OrderingIndexType) (const uint32_t)-1; if ( waitingForPacketOrderingIndex > maxRange/(OrderingIndexType)2 ) { if ( newPacketOrderingIndex >= waitingForPacketOrderingIndex - maxRange/(OrderingIndexType)2+(OrderingIndexType)1 && newPacketOrderingIndex < waitingForPacketOrderingIndex ) { return true; } } else if ( newPacketOrderingIndex >= ( OrderingIndexType ) ( waitingForPacketOrderingIndex - (( OrderingIndexType ) maxRange/(OrderingIndexType)2+(OrderingIndexType)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 ) { // Doing all sizes in bytes in this function so I don't write partial bytes with split packets internalPacket->splitPacketCount = 1; // This causes GetMessageHeaderLengthBits to account for the split packet header unsigned int headerLength = (unsigned int) BITS_TO_BYTES( GetMessageHeaderLengthBits( internalPacket ) ); unsigned int dataByteLength = (unsigned int) BITS_TO_BYTES( internalPacket->dataBitLength ); int maximumSendBlockBytes, byteOffset, bytesToSend; SplitPacketIndexType splitPacketIndex; int i; InternalPacket **internalPacketArray; maximumSendBlockBytes = GetMaxDatagramSizeExcludingMessageHeaderBytes() - BITS_TO_BYTES(GetMaxMessageHeaderLengthBits()); // Calculate how many packets we need to create internalPacket->splitPacketCount = ( ( dataByteLength - 1 ) / ( maximumSendBlockBytes ) + 1 ); // Optimization // internalPacketArray = RakNet::OP_NEW(internalPacket->splitPacketCount, _FILE_AND_LINE_ ); bool usedAlloca=false; #if USE_ALLOCA==1 if (sizeof( InternalPacket* ) * internalPacket->splitPacketCount < MAX_ALLOCA_STACK_ALLOCATION) { internalPacketArray = ( InternalPacket** ) alloca( sizeof( InternalPacket* ) * internalPacket->splitPacketCount ); usedAlloca=true; } else #endif internalPacketArray = (InternalPacket**) rakMalloc_Ex( sizeof(InternalPacket*) * internalPacket->splitPacketCount, _FILE_AND_LINE_ ); for ( i = 0; i < ( int ) internalPacket->splitPacketCount; i++ ) { internalPacketArray[ i ] = AllocateFromInternalPacketPool(); //internalPacketArray[ i ] = (InternalPacket*) alloca( sizeof( InternalPacket ) ); // internalPacketArray[ i ] = sendPacketSet[internalPacket->priority].WriteLock(); *internalPacketArray[ i ]=*internalPacket; internalPacketArray[ i ]->messageNumberAssigned=false; if (i!=0) internalPacket->messageInternalOrder = internalOrderIndex++; } // This identifies which packet this is in the set splitPacketIndex = 0; InternalPacketRefCountedData *refCounter=0; // Do a loop to send out all the packets do { byteOffset = splitPacketIndex * maximumSendBlockBytes; bytesToSend = dataByteLength - byteOffset; if ( bytesToSend > maximumSendBlockBytes ) bytesToSend = maximumSendBlockBytes; // Copy over our chunk of data AllocInternalPacketData(internalPacketArray[ splitPacketIndex ], &refCounter, internalPacket->data, internalPacket->data + byteOffset); // internalPacketArray[ splitPacketIndex ]->data = (unsigned char*) rakMalloc_Ex( bytesToSend, _FILE_AND_LINE_ ); // memcpy( internalPacketArray[ splitPacketIndex ]->data, internalPacket->data + byteOffset, bytesToSend ); if ( bytesToSend != maximumSendBlockBytes ) internalPacketArray[ splitPacketIndex ]->dataBitLength = internalPacket->dataBitLength - splitPacketIndex * ( maximumSendBlockBytes << 3 ); else internalPacketArray[ splitPacketIndex ]->dataBitLength = bytesToSend << 3; internalPacketArray[ splitPacketIndex ]->splitPacketIndex = splitPacketIndex; internalPacketArray[ splitPacketIndex ]->splitPacketId = splitPacketId; internalPacketArray[ splitPacketIndex ]->splitPacketCount = internalPacket->splitPacketCount; RakAssert(internalPacketArray[ splitPacketIndex ]->dataBitLengthsplitPacketCount ); splitPacketId++; // It's ok if this wraps to 0 // InternalPacket *workingPacket; // Tell the heap we are going to push a list of elements where each element in the list follows the heap order RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthsplitPacketCount; i++ ) { internalPacketArray[ i ]->headerLength=headerLength; RakAssert(internalPacketArray[ i ]->dataBitLengthpriority ].Push( internalPacketArray[ i ], _FILE_AND_LINE_ ); RakAssert(internalPacketArray[ i ]->dataBitLengthmessageNumberAssigned==false); outgoingPacketBuffer.PushSeries(GetNextWeight(internalPacketArray[ i ]->priority), internalPacketArray[ i ], _FILE_AND_LINE_); RakAssert(outgoingPacketBuffer.Size()==0 || outgoingPacketBuffer.Peek()->dataBitLengthpriority]++; statistics.bytesInSendBuffer[(int)(int)internalPacketArray[ i ]->priority]+=(double) BITS_TO_BYTES(internalPacketArray[ i ]->dataBitLength); // workingPacket=sendPacketSet[internalPacket->priority].WriteLock(); // memcpy(workingPacket, internalPacketArray[ i ], sizeof(InternalPacket)); // sendPacketSet[internalPacket->priority].WriteUnlock(); } // Do not delete, original is referenced by all split packets to avoid numerous allocations. See AllocInternalPacketData above // FreeInternalPacketData(internalPacket, _FILE_AND_LINE_ ); ReleaseToInternalPacketPool( internalPacket ); if (usedAlloca==false) rakFree_Ex(internalPacketArray, _FILE_AND_LINE_ ); } //------------------------------------------------------------------------------------------------------- // Insert a packet into the split packet list //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertIntoSplitPacketList( InternalPacket * internalPacket, CCTimeType time ) { bool objectExists; unsigned index; // Find in splitPacketChannelList if a SplitPacketChannel with this splitPacketId was already allocated. If not, allocate and insert the channel into the list. index=splitPacketChannelList.GetIndexFromKey(internalPacket->splitPacketId, &objectExists); if (objectExists==false) { SplitPacketChannel *newChannel = RakNet::OP_NEW( __FILE__, __LINE__ ); #if PREALLOCATE_LARGE_MESSAGES==1 index=splitPacketChannelList.Insert(internalPacket->splitPacketId, newChannel, true, __FILE__,__LINE__); newChannel->returnedPacket=CreateInternalPacketCopy( internalPacket, 0, 0, time ); newChannel->gotFirstPacket=false; newChannel->splitPacketsArrived=0; AllocInternalPacketData(newChannel->returnedPacket, BITS_TO_BYTES( internalPacket->dataBitLength*internalPacket->splitPacketCount ), false, __FILE__, __LINE__ ); RakAssert(newChannel->returnedPacket->data); #else newChannel->firstPacket=0; index=splitPacketChannelList.Insert(internalPacket->splitPacketId, newChannel, true, __FILE__,__LINE__); // Preallocate to the final size, to avoid runtime copies newChannel->splitPacketList.Preallocate(internalPacket->splitPacketCount, __FILE__,__LINE__); #endif } #if PREALLOCATE_LARGE_MESSAGES==1 splitPacketChannelList[index]->lastUpdateTime=time; splitPacketChannelList[index]->splitPacketsArrived++; splitPacketChannelList[index]->returnedPacket->dataBitLength+=internalPacket->dataBitLength; bool dealloc; if (internalPacket->splitPacketIndex==0) { splitPacketChannelList[index]->gotFirstPacket=true; splitPacketChannelList[index]->stride=BITS_TO_BYTES(internalPacket->dataBitLength); for (unsigned int j=0; j < splitPacketChannelList[index]->splitPacketList.Size(); j++) { memcpy(splitPacketChannelList[index]->returnedPacket->data+internalPacket->splitPacketIndex*splitPacketChannelList[index]->stride, internalPacket->data, (size_t) BITS_TO_BYTES(internalPacket->dataBitLength)); FreeInternalPacketData(splitPacketChannelList[index]->splitPacketList[j], __FILE__, __LINE__ ); ReleaseToInternalPacketPool(splitPacketChannelList[index]->splitPacketList[j]); } memcpy(splitPacketChannelList[index]->returnedPacket->data, internalPacket->data, (size_t) BITS_TO_BYTES(internalPacket->dataBitLength)); splitPacketChannelList[index]->splitPacketList.Clear(true,__FILE__,__LINE__); dealloc=true; } else { if (splitPacketChannelList[index]->gotFirstPacket==true) { memcpy(splitPacketChannelList[index]->returnedPacket->data+internalPacket->splitPacketIndex*splitPacketChannelList[index]->stride, internalPacket->data, (size_t) BITS_TO_BYTES(internalPacket->dataBitLength)); dealloc=true; } else { splitPacketChannelList[index]->splitPacketList.Push(internalPacket,__FILE__,__LINE__); dealloc=false; } } if (splitPacketChannelList[index]->gotFirstPacket==true && splitMessageProgressInterval && // splitPacketChannelList[index]->firstPacket && // splitPacketChannelList[index]->splitPacketList.Size()!=splitPacketChannelList[index]->firstPacket->splitPacketCount && // (splitPacketChannelList[index]->splitPacketList.Size()%splitMessageProgressInterval)==0 splitPacketChannelList[index]->gotFirstPacket && splitPacketChannelList[index]->splitPacketsArrived!=splitPacketChannelList[index]->returnedPacket->splitPacketCount && (splitPacketChannelList[index]->splitPacketsArrived%splitMessageProgressInterval)==0 ) { // Return ID_DOWNLOAD_PROGRESS // Write splitPacketIndex (SplitPacketIndexType) // Write splitPacketCount (SplitPacketIndexType) // Write byteLength (4) // Write data, splitPacketChannelList[index]->splitPacketList[0]->data InternalPacket *progressIndicator = AllocateFromInternalPacketPool(); // unsigned int len = sizeof(MessageID) + sizeof(unsigned int)*2 + sizeof(unsigned int) + (unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->dataBitLength); unsigned int l = (unsigned int) splitPacketChannelList[index]->stride; const unsigned int len = sizeof(MessageID) + sizeof(unsigned int)*2 + sizeof(unsigned int) + l; AllocInternalPacketData(progressIndicator, len, false, __FILE__, __LINE__ ); progressIndicator->dataBitLength=BYTES_TO_BITS(len); progressIndicator->data[0]=(MessageID)ID_DOWNLOAD_PROGRESS; unsigned int temp; // temp=splitPacketChannelList[index]->splitPacketList.Size(); temp=splitPacketChannelList[index]->splitPacketsArrived; 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=(unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->dataBitLength); temp=(unsigned int) BITS_TO_BYTES(l); memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*2, &temp, sizeof(unsigned int)); //memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*3, splitPacketChannelList[index]->firstPacket->data, (size_t) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->dataBitLength)); memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*3, splitPacketChannelList[index]->returnedPacket->data, (size_t) BITS_TO_BYTES(l)); } if (dealloc) { FreeInternalPacketData(internalPacket, __FILE__, __LINE__ ); ReleaseToInternalPacketPool(internalPacket); } #else // Insert the packet into the SplitPacketChannel splitPacketChannelList[index]->splitPacketList.Insert(internalPacket, __FILE__, __LINE__ ); splitPacketChannelList[index]->lastUpdateTime=time; // If the index is 0, then this is the first packet. Record this so it can be returned to the user with download progress if (internalPacket->splitPacketIndex==0) splitPacketChannelList[index]->firstPacket=internalPacket; // Return download progress if we have the first packet, the list is not complete, and there are enough packets to justify it if (splitMessageProgressInterval && splitPacketChannelList[index]->firstPacket && splitPacketChannelList[index]->splitPacketList.Size()!=splitPacketChannelList[index]->firstPacket->splitPacketCount && (splitPacketChannelList[index]->splitPacketList.Size()%splitMessageProgressInterval)==0) { // Return ID_DOWNLOAD_PROGRESS // Write splitPacketIndex (SplitPacketIndexType) // Write splitPacketCount (SplitPacketIndexType) // Write byteLength (4) // Write data, splitPacketChannelList[index]->splitPacketList[0]->data InternalPacket *progressIndicator = AllocateFromInternalPacketPool(); unsigned int length = sizeof(MessageID) + sizeof(unsigned int)*2 + sizeof(unsigned int) + (unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->dataBitLength); AllocInternalPacketData(progressIndicator, length, false, __FILE__, __LINE__ ); 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=(unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->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]->firstPacket->data, (size_t) BITS_TO_BYTES(splitPacketChannelList[index]->firstPacket->dataBitLength)); outputQueue.Push(progressIndicator, __FILE__, __LINE__ ); } #endif } //------------------------------------------------------------------------------------------------------- // 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( SplitPacketChannel *splitPacketChannel, CCTimeType time ) { #if PREALLOCATE_LARGE_MESSAGES==1 InternalPacket *returnedPacket=splitPacketChannel->returnedPacket; RakNet::OP_DELETE(splitPacketChannel, __FILE__, __LINE__); (void) time; return returnedPacket; #else unsigned int j; InternalPacket * internalPacket, *splitPacket; // int splitPacketPartLength; // Reconstruct internalPacket = CreateInternalPacketCopy( splitPacketChannel->splitPacketList[0], 0, 0, time ); internalPacket->dataBitLength=0; for (j=0; j < splitPacketChannel->splitPacketList.Size(); j++) internalPacket->dataBitLength+=splitPacketChannel->splitPacketList[j]->dataBitLength; // splitPacketPartLength=BITS_TO_BYTES(splitPacketChannel->firstPacket->dataBitLength); internalPacket->data = (unsigned char*) rakMalloc_Ex( (size_t) BITS_TO_BYTES( internalPacket->dataBitLength ), _FILE_AND_LINE_ ); internalPacket->allocationScheme=InternalPacket::NORMAL; BitSize_t offset = 0; for (j=0; j < splitPacketChannel->splitPacketList.Size(); j++) { splitPacket=splitPacketChannel->splitPacketList[j]; memcpy(internalPacket->data + BITS_TO_BYTES(offset), splitPacket->data, (size_t)BITS_TO_BYTES(splitPacketChannel->splitPacketList[j]->dataBitLength)); offset += splitPacketChannel->splitPacketList[j]->dataBitLength; } for (j=0; j < splitPacketChannel->splitPacketList.Size(); j++) { FreeInternalPacketData(splitPacketChannel->splitPacketList[j], _FILE_AND_LINE_ ); ReleaseToInternalPacketPool(splitPacketChannel->splitPacketList[j]); } RakNet::OP_DELETE(splitPacketChannel, __FILE__, __LINE__); return internalPacket; #endif } //------------------------------------------------------------------------------------------------------- InternalPacket * ReliabilityLayer::BuildPacketFromSplitPacketList( SplitPacketIdType splitPacketId, CCTimeType time, RakNetSocket2 *s, SystemAddress &systemAddress, RakNetRandom *rnr, BitStream &updateBitStream) { unsigned int i; bool objectExists; SplitPacketChannel *splitPacketChannel; InternalPacket * internalPacket; // Find in splitPacketChannelList the SplitPacketChannel with this splitPacketId i=splitPacketChannelList.GetIndexFromKey(splitPacketId, &objectExists); splitPacketChannel=splitPacketChannelList[i]; #if PREALLOCATE_LARGE_MESSAGES==1 if (splitPacketChannel->splitPacketsArrived==splitPacketChannel->returnedPacket->splitPacketCount) #else if (splitPacketChannel->splitPacketList.Size()==splitPacketChannel->splitPacketList[0]->splitPacketCount) #endif { // Ack immediately, because for large files this can take a long time SendACKs(s, systemAddress, time, rnr, updateBitStream); internalPacket=BuildPacketFromSplitPacketList(splitPacketChannel,time); splitPacketChannelList.RemoveAtIndex(i); return internalPacket; } else { return 0; } } /* //------------------------------------------------------------------------------------------------------- // Delete any unreliable split packets that have long since expired void ReliabilityLayer::DeleteOldUnreliableSplitPackets( CCTimeType time ) { unsigned i,j; i=0; while (i < splitPacketChannelList.Size()) { #if CC_TIME_TYPE_BYTES==4 if (time > splitPacketChannelList[i]->lastUpdateTime + timeoutTime && #else if (time > splitPacketChannelList[i]->lastUpdateTime + (CCTimeType)timeoutTime*(CCTimeType)1000 && #endif (splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE || splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE_SEQUENCED)) { for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { RakNet::OP_DELETE_ARRAY(splitPacketChannelList[i]->splitPacketList[j]->data, _FILE_AND_LINE_); ReleaseToInternalPacketPool(splitPacketChannelList[i]->splitPacketList[j]); } RakNet::OP_DELETE(splitPacketChannelList[i], _FILE_AND_LINE_); 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, CCTimeType time ) { InternalPacket * copy = AllocateFromInternalPacketPool(); #ifdef _DEBUG // Remove accessing undefined memory error memset( copy, 255, sizeof( InternalPacket ) ); #endif // Copy over our chunk of data if ( dataByteLength > 0 ) { AllocInternalPacketData(copy, BITS_TO_BYTES(dataByteLength ), false, _FILE_AND_LINE_ ); 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->sequencingIndex = original->sequencingIndex; copy->orderingChannel = original->orderingChannel; copy->reliableMessageNumber = original->reliableMessageNumber; copy->priority = original->priority; copy->reliability = original->reliability; #if PREALLOCATE_LARGE_MESSAGES==1 copy->splitPacketCount = original->splitPacketCount; copy->splitPacketId = original->splitPacketId; copy->splitPacketIndex = original->splitPacketIndex; #endif return copy; } //------------------------------------------------------------------------------------------------------- // Get the specified ordering list //------------------------------------------------------------------------------------------------------- /* DataStructures::LinkedList *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 ) { } */ //------------------------------------------------------------------------------------------------------- // Inserts a packet into the resend list in order //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertPacketIntoResendList( InternalPacket *internalPacket, CCTimeType time, bool firstResend, bool modifyUnacknowledgedBytes ) { (void) firstResend; (void) time; (void) internalPacket; AddToListTail(internalPacket, modifyUnacknowledgedBytes); RakAssert(internalPacket->nextActionTime!=0); } //------------------------------------------------------------------------------------------------------- // 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; } //------------------------------------------------------------------------------------------------------- // Statistics //------------------------------------------------------------------------------------------------------- RakNetStatistics * ReliabilityLayer::GetStatistics( RakNetStatistics *rns ) { unsigned i; RakNet::TimeUS time = RakNet::GetTimeUS(); uint64_t uint64Denominator; double doubleDenominator; for (i=0; i < RNS_PER_SECOND_METRICS_COUNT; i++) { statistics.valueOverLastSecond[i]=bpsMetrics[i].GetBPS1Threadsafe(time); statistics.runningTotal[i]=bpsMetrics[i].GetTotal1(); } memcpy(rns, &statistics, sizeof(statistics)); if (rns->valueOverLastSecond[USER_MESSAGE_BYTES_SENT]+rns->valueOverLastSecond[USER_MESSAGE_BYTES_RESENT]>0) rns->packetlossLastSecond=(float)((double) rns->valueOverLastSecond[USER_MESSAGE_BYTES_RESENT]/((double) rns->valueOverLastSecond[USER_MESSAGE_BYTES_SENT]+(double) rns->valueOverLastSecond[USER_MESSAGE_BYTES_RESENT])); else rns->packetlossLastSecond=0.0f; rns->packetlossTotal=0.0f; uint64Denominator=(rns->runningTotal[USER_MESSAGE_BYTES_SENT]+rns->runningTotal[USER_MESSAGE_BYTES_RESENT]); if (uint64Denominator!=0&&rns->runningTotal[USER_MESSAGE_BYTES_SENT]/uint64Denominator>0) { doubleDenominator=((double) rns->runningTotal[USER_MESSAGE_BYTES_SENT]+(double) rns->runningTotal[USER_MESSAGE_BYTES_RESENT]); if(doubleDenominator!=0) { rns->packetlossTotal=(float)((double) rns->runningTotal[USER_MESSAGE_BYTES_RESENT]/doubleDenominator); } } rns->isLimitedByCongestionControl=statistics.isLimitedByCongestionControl; rns->BPSLimitByCongestionControl=statistics.BPSLimitByCongestionControl; rns->isLimitedByOutgoingBandwidthLimit=statistics.isLimitedByOutgoingBandwidthLimit; rns->BPSLimitByOutgoingBandwidthLimit=statistics.BPSLimitByOutgoingBandwidthLimit; return rns; } //------------------------------------------------------------------------------------------------------- // Returns the number of packets in the resend queue, not counting holes //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::GetResendListDataSize(void) const { // Not accurate but thread-safe. The commented version might crash if the queue is cleared while we loop through it // return resendTree.Size(); return statistics.messagesInResendBuffer; } //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::AckTimeout(RakNet::Time curTime) { // I check timeLastDatagramArrived-curTime because with threading it is possible that timeLastDatagramArrived is // slightly greater than curTime, in which case this is NOT an ack timeout return (timeLastDatagramArrived-curTime)>10000 && curTime-timeLastDatagramArrived>timeoutTime; } //------------------------------------------------------------------------------------------------------- CCTimeType ReliabilityLayer::GetNextSendTime(void) const { return nextSendTime; } //------------------------------------------------------------------------------------------------------- CCTimeType ReliabilityLayer::GetTimeBetweenPackets(void) const { return timeBetweenPackets; } //------------------------------------------------------------------------------------------------------- #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 CCTimeType ReliabilityLayer::GetAckPing(void) const { return ackPing; } #endif //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ResetPacketsAndDatagrams(void) { packetsToSendThisUpdate.Clear(true, _FILE_AND_LINE_); packetsToDeallocThisUpdate.Clear(true, _FILE_AND_LINE_); packetsToSendThisUpdateDatagramBoundaries.Clear(true, _FILE_AND_LINE_); datagramsToSendThisUpdateIsPair.Clear(true, _FILE_AND_LINE_); datagramSizesInBytes.Clear(true, _FILE_AND_LINE_); datagramSizeSoFar=0; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::PushPacket(CCTimeType time, InternalPacket *internalPacket, bool isReliable) { BitSize_t bitsForThisPacket=BYTES_TO_BITS(BITS_TO_BYTES(internalPacket->dataBitLength)+BITS_TO_BYTES(internalPacket->headerLength)); datagramSizeSoFar+=bitsForThisPacket; RakAssert(BITS_TO_BYTES(datagramSizeSoFar)headerLength==GetMessageHeaderLengthBits(internalPacket)); // This code tells me how much time elapses between when you send, and when the message actually goes out // if (internalPacket->data[0]==0) // { // RakNet::TimeMS t; // RakNet::BitStream bs(internalPacket->data+1,sizeof(t),false); // bs.Read(t); // RakNet::TimeMS curTime=RakNet::GetTimeMS(); // RakNet::TimeMS diff = curTime-t; // } congestionManager.OnSendBytes(time, BITS_TO_BYTES(internalPacket->dataBitLength)+BITS_TO_BYTES(internalPacket->headerLength)); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::PushDatagram(void) { if (datagramSizeSoFar>0) { packetsToSendThisUpdateDatagramBoundaries.Push(packetsToSendThisUpdate.Size(), _FILE_AND_LINE_ ); datagramsToSendThisUpdateIsPair.Push(false, _FILE_AND_LINE_ ); RakAssert(BITS_TO_BYTES(datagramSizeSoFar)=2) { datagramsToSendThisUpdateIsPair[datagramsToSendThisUpdateIsPair.Size()-2]=true; datagramsToSendThisUpdateIsPair[datagramsToSendThisUpdateIsPair.Size()-1]=true; return true; } return false; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ClearPacketsAndDatagrams(void) { unsigned int i; for (i=0; i < packetsToDeallocThisUpdate.Size(); i++) { // packetsToDeallocThisUpdate holds a boolean indicating if packetsToSendThisUpdate at this index should be freed if (packetsToDeallocThisUpdate[i]) { RemoveFromUnreliableLinkedList(packetsToSendThisUpdate[i]); FreeInternalPacketData(packetsToSendThisUpdate[i], _FILE_AND_LINE_ ); // if (keepInternalPacketIfNeedsAck==false || packetsToSendThisUpdate[i]->reliabilityresendNext=internalPacket; internalPacket->resendPrev=internalPacket; resendLinkedListHead=internalPacket; return; } internalPacket->resendPrev->resendNext = internalPacket->resendNext; internalPacket->resendNext->resendPrev = internalPacket->resendPrev; internalPacket->resendNext=resendLinkedListHead; internalPacket->resendPrev=resendLinkedListHead->resendPrev; internalPacket->resendPrev->resendNext=internalPacket; resendLinkedListHead->resendPrev=internalPacket; resendLinkedListHead=internalPacket; RakAssert(internalPacket->headerLength+internalPacket->dataBitLength>0); //ValidateResendList(); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::RemoveFromList(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes) { InternalPacket *newPosition; internalPacket->resendPrev->resendNext = internalPacket->resendNext; internalPacket->resendNext->resendPrev = internalPacket->resendPrev; newPosition = internalPacket->resendNext; if ( internalPacket == resendLinkedListHead ) resendLinkedListHead = newPosition; if (resendLinkedListHead==internalPacket) resendLinkedListHead=0; if (modifyUnacknowledgedBytes) { RakAssert(unacknowledgedBytes>=BITS_TO_BYTES(internalPacket->headerLength+internalPacket->dataBitLength)); unacknowledgedBytes-=BITS_TO_BYTES(internalPacket->headerLength+internalPacket->dataBitLength); // printf("-unacknowledgedBytes:%i ", unacknowledgedBytes); // ValidateResendList(); } } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AddToListTail(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes) { if (modifyUnacknowledgedBytes) { unacknowledgedBytes+=BITS_TO_BYTES(internalPacket->headerLength+internalPacket->dataBitLength); // printf("+unacknowledgedBytes:%i ", unacknowledgedBytes); } if (resendLinkedListHead==0) { internalPacket->resendNext=internalPacket; internalPacket->resendPrev=internalPacket; resendLinkedListHead=internalPacket; return; } internalPacket->resendNext=resendLinkedListHead; internalPacket->resendPrev=resendLinkedListHead->resendPrev; internalPacket->resendPrev->resendNext=internalPacket; resendLinkedListHead->resendPrev=internalPacket; // ValidateResendList(); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::PopListHead(bool modifyUnacknowledgedBytes) { RakAssert(resendLinkedListHead!=0); RemoveFromList(resendLinkedListHead, modifyUnacknowledgedBytes); } //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsResendQueueEmpty(void) const { return resendLinkedListHead==0; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendACKs(RakNetSocket2 *s, SystemAddress &systemAddress, CCTimeType time, RakNetRandom *rnr, BitStream &updateBitStream) { BitSize_t maxDatagramPayload = GetMaxDatagramSizeExcludingMessageHeaderBits(); while (acknowlegements.Size()>0) { // Send acks updateBitStream.Reset(); DatagramHeaderFormat dhf; dhf.isACK=true; dhf.isNAK=false; dhf.isPacketPair=false; #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 dhf.sourceSystemTime=time; #endif double B; double AS; bool hasBAndAS; if (remoteSystemNeedsBAndAS) { congestionManager.OnSendAckGetBAndAS(time, &hasBAndAS,&B,&AS); dhf.AS=(float)AS; dhf.hasBAndAS=hasBAndAS; } else dhf.hasBAndAS=false; #if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1 dhf.sourceSystemTime=nextAckTimeToSend; #endif // dhf.B=(float)B; updateBitStream.Reset(); dhf.Serialize(&updateBitStream); CC_DEBUG_PRINTF_1("AckSnd "); acknowlegements.Serialize(&updateBitStream, maxDatagramPayload, true); SendBitStream( s, systemAddress, &updateBitStream, rnr, time ); congestionManager.OnSendAck(time,updateBitStream.GetNumberOfBytesUsed()); // I think this is causing a bug where if the estimated bandwidth is very low for the recipient, only acks ever get sent // congestionManager.OnSendBytes(time,UDP_HEADER_SIZE+updateBitStream.GetNumberOfBytesUsed()); } } /* //------------------------------------------------------------------------------------------------------- ReliabilityLayer::DatagramMessageIDList* ReliabilityLayer::AllocateFromDatagramMessageIDPool(void) { DatagramMessageIDList*s; s=datagramMessageIDPool.Allocate( _FILE_AND_LINE_ ); // Call new operator, memoryPool doesn't do this s = new ((void*)s) DatagramMessageIDList; return s; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ReleaseToDatagramMessageIDPool(DatagramMessageIDList* d) { d->~DatagramMessageIDList(); datagramMessageIDPool.Release(d); } */ //------------------------------------------------------------------------------------------------------- InternalPacket* ReliabilityLayer::AllocateFromInternalPacketPool(void) { InternalPacket *ip = internalPacketPool.Allocate( _FILE_AND_LINE_ ); ip->reliableMessageNumber = (MessageNumberType) (const uint32_t)-1; ip->messageNumberAssigned=false; ip->nextActionTime = 0; ip->splitPacketCount = 0; ip->splitPacketIndex = 0; ip->splitPacketId = 0; ip->allocationScheme=InternalPacket::NORMAL; ip->data=0; ip->timesSent=0; return ip; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ReleaseToInternalPacketPool(InternalPacket *ip) { internalPacketPool.Release(ip, _FILE_AND_LINE_); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::RemoveFromUnreliableLinkedList(InternalPacket *internalPacket) { if (internalPacket->reliability==UNRELIABLE || internalPacket->reliability==UNRELIABLE_SEQUENCED || internalPacket->reliability==UNRELIABLE_WITH_ACK_RECEIPT // || // internalPacket->reliability==UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) { InternalPacket *newPosition; internalPacket->unreliablePrev->unreliableNext = internalPacket->unreliableNext; internalPacket->unreliableNext->unreliablePrev = internalPacket->unreliablePrev; newPosition = internalPacket->unreliableNext; if ( internalPacket == unreliableLinkedListHead ) unreliableLinkedListHead = newPosition; if (unreliableLinkedListHead==internalPacket) unreliableLinkedListHead=0; } } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AddToUnreliableLinkedList(InternalPacket *internalPacket) { if (internalPacket->reliability==UNRELIABLE || internalPacket->reliability==UNRELIABLE_SEQUENCED || internalPacket->reliability==UNRELIABLE_WITH_ACK_RECEIPT // || // internalPacket->reliability==UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT ) { if (unreliableLinkedListHead==0) { internalPacket->unreliableNext=internalPacket; internalPacket->unreliablePrev=internalPacket; unreliableLinkedListHead=internalPacket; return; } internalPacket->unreliableNext=unreliableLinkedListHead; internalPacket->unreliablePrev=unreliableLinkedListHead->unreliablePrev; internalPacket->unreliablePrev->unreliableNext=internalPacket; unreliableLinkedListHead->unreliablePrev=internalPacket; } } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ValidateResendList(void) const { // unsigned int count1=0, count2=0; // for (unsigned int i=0; i < RESEND_BUFFER_ARRAY_LENGTH; i++) // if (resendBuffer[i]) // count1++; // // if (resendLinkedListHead) // { // InternalPacket *internalPacket = resendLinkedListHead; // do // { // count2++; // internalPacket=internalPacket->resendNext; // } while (internalPacket!=resendLinkedListHead); // } // RakAssert(count1==count2); // RakAssert(count2<=RESEND_BUFFER_ARRAY_LENGTH); } //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::ResendBufferOverflow(void) const { int index1 = sendReliableMessageNumberIndex & (uint32_t) RESEND_BUFFER_ARRAY_MASK; // int index2 = (sendReliableMessageNumberIndex+(uint32_t)1) & (uint32_t) RESEND_BUFFER_ARRAY_MASK; RakAssert(index1= datagramHistory.Size()) return 0; *timeSent=datagramHistory[offsetIntoList].timeSent; return datagramHistory[offsetIntoList].head; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::RemoveFromDatagramHistory(DatagramSequenceNumberType index) { DatagramSequenceNumberType offsetIntoList = index - datagramHistoryPopCount; MessageNumberNode *mnm = datagramHistory[offsetIntoList].head; MessageNumberNode *next; while (mnm) { next=mnm->next; datagramHistoryMessagePool.Release(mnm, _FILE_AND_LINE_); mnm=next; } datagramHistory[offsetIntoList].head=0; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, CCTimeType timeSent) { (void) datagramNumber; if (datagramHistory.Size()>DATAGRAM_MESSAGE_ID_ARRAY_LENGTH) { RemoveFromDatagramHistory(datagramHistoryPopCount); datagramHistory.Pop(); datagramHistoryPopCount++; } datagramHistory.Push(DatagramHistoryNode(0, timeSent), _FILE_AND_LINE_); // printf("%p Pushed empty DatagramHistoryNode to datagram history at index %i\n", this, datagramHistory.Size()-1); } //------------------------------------------------------------------------------------------------------- ReliabilityLayer::MessageNumberNode* ReliabilityLayer::AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, DatagramSequenceNumberType messageNumber, CCTimeType timeSent) { (void) datagramNumber; // RakAssert(datagramHistoryPopCount+(unsigned int) datagramHistory.Size()==datagramNumber); if (datagramHistory.Size()>DATAGRAM_MESSAGE_ID_ARRAY_LENGTH) { RemoveFromDatagramHistory(datagramHistoryPopCount); datagramHistory.Pop(); datagramHistoryPopCount++; } MessageNumberNode *mnm = datagramHistoryMessagePool.Allocate(_FILE_AND_LINE_); mnm->next=0; mnm->messageNumber=messageNumber; datagramHistory.Push(DatagramHistoryNode(mnm, timeSent), _FILE_AND_LINE_); // printf("%p Pushed message %i to DatagramHistoryNode to datagram history at index %i\n", this, messageNumber.val, datagramHistory.Size()-1); return mnm; } //------------------------------------------------------------------------------------------------------- ReliabilityLayer::MessageNumberNode* ReliabilityLayer::AddSubsequentToDatagramHistory(MessageNumberNode *messageNumberNode, DatagramSequenceNumberType messageNumber) { messageNumberNode->next=datagramHistoryMessagePool.Allocate(_FILE_AND_LINE_); messageNumberNode->next->messageNumber=messageNumber; messageNumberNode->next->next=0; return messageNumberNode->next; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AllocInternalPacketData(InternalPacket *internalPacket, InternalPacketRefCountedData **refCounter, unsigned char *externallyAllocatedPtr, unsigned char *ourOffset) { internalPacket->allocationScheme=InternalPacket::REF_COUNTED; internalPacket->data=ourOffset; if (*refCounter==0) { *refCounter = refCountedDataPool.Allocate(_FILE_AND_LINE_); // *refCounter = RakNet::OP_NEW(_FILE_AND_LINE_); (*refCounter)->refCount=1; (*refCounter)->sharedDataBlock=externallyAllocatedPtr; } else (*refCounter)->refCount++; internalPacket->refCountedData=(*refCounter); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AllocInternalPacketData(InternalPacket *internalPacket, unsigned char *externallyAllocatedPtr) { internalPacket->allocationScheme=InternalPacket::NORMAL; internalPacket->data=externallyAllocatedPtr; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::AllocInternalPacketData(InternalPacket *internalPacket, unsigned int numBytes, bool allowStack, const char *file, unsigned int line) { if (allowStack && numBytes <= sizeof(internalPacket->stackData)) { internalPacket->allocationScheme=InternalPacket::STACK; internalPacket->data=internalPacket->stackData; } else { internalPacket->allocationScheme=InternalPacket::NORMAL; internalPacket->data=(unsigned char*) rakMalloc_Ex(numBytes,file,line); } } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::FreeInternalPacketData(InternalPacket *internalPacket, const char *file, unsigned int line) { if (internalPacket==0) return; if (internalPacket->allocationScheme==InternalPacket::REF_COUNTED) { if (internalPacket->refCountedData==0) return; internalPacket->refCountedData->refCount--; if (internalPacket->refCountedData->refCount==0) { rakFree_Ex(internalPacket->refCountedData->sharedDataBlock, file, line ); internalPacket->refCountedData->sharedDataBlock=0; // RakNet::OP_DELETE(internalPacket->refCountedData,file, line); refCountedDataPool.Release(internalPacket->refCountedData,file, line); internalPacket->refCountedData=0; } } else if (internalPacket->allocationScheme==InternalPacket::NORMAL) { if (internalPacket->data==0) return; rakFree_Ex(internalPacket->data, file, line ); internalPacket->data=0; } else { // Data was on stack internalPacket->data=0; } } //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::GetMaxDatagramSizeExcludingMessageHeaderBytes(void) { unsigned int val = congestionManager.GetMTU() - DatagramHeaderFormat::GetDataHeaderByteLength(); #if LIBCAT_SECURITY==1 if (useSecurity) val -= cat::AuthenticatedEncryption::OVERHEAD_BYTES; #endif return val; } //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::GetMaxDatagramSizeExcludingMessageHeaderBits(void) { return BYTES_TO_BITS(GetMaxDatagramSizeExcludingMessageHeaderBytes()); } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InitHeapWeights(void) { for (int priorityLevel=0; priorityLevel < NUMBER_OF_PRIORITIES; priorityLevel++) outgoingPacketBufferNextWeights[priorityLevel]=(1<0) { int peekPL = outgoingPacketBuffer.Peek()->priority; reliabilityHeapWeightType weight = outgoingPacketBuffer.PeekWeight(); reliabilityHeapWeightType min = weight - (1<