/// \file /// /// This file is part of RakNet Copyright 2003 Kevin Jenkins. /// /// Usage of RakNet is subject to the appropriate license agreement. /// Creative Commons Licensees are subject to the /// license found at /// http://creativecommons.org/licenses/by-nc/2.5/ /// Single application licensees are subject to the license found at /// http://www.jenkinssoftware.com/SingleApplicationLicense.html /// Custom license users are subject to the terms therein. /// GPL license users are subject to the GNU General Public /// License as published by the Free /// Software Foundation; either version 2 of the License, or (at your /// option) any later version. #include "ReliabilityLayer.h" #include "GetTime.h" #include "SocketLayer.h" #include "PluginInterface.h" #include "RakAssert.h" #include "Rand.h" #include "MessageIdentifiers.h" #include static const int DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE=512; static const RakNetTimeNS MAX_TIME_BETWEEN_PACKETS= 350000; // 350 milliseconds static const RakNetTimeNS STARTING_TIME_BETWEEN_PACKETS=MAX_TIME_BETWEEN_PACKETS; static const RakNetTimeNS HISTOGRAM_RESTART_CYCLE=10000000; // Every 10 seconds reset the histogram static const long double TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_DEFAULT=.02; static const long double TIME_BETWEEN_PACKETS_DECREASE_MULTIPLIER_DEFAULT=.04; #ifdef _MSC_VER #pragma warning( push ) #endif #ifdef _WIN32 //#define _DEBUG_LOGGER #ifdef _DEBUG_LOGGER #include #endif #endif //#define DEBUG_SPLIT_PACKET_PROBLEMS #if defined (DEBUG_SPLIT_PACKET_PROBLEMS) static int waitFlag=-1; #endif using namespace RakNet; int SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data ) { if (key < data->splitPacketList[0]->splitPacketId) return -1; if (key == data->splitPacketList[0]->splitPacketId) return 0; return 1; } int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data ) { if (key < data->splitPacketIndex) return -1; if (key == data->splitPacketIndex) return 0; return 1; } //------------------------------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------------------------------- // Add 21 to the default MTU so if we encrypt it can hold potentially 21 more bytes of extra data + padding. ReliabilityLayer::ReliabilityLayer() : updateBitStream( DEFAULT_MTU_SIZE + 21 ) // preallocate the update bitstream so we can avoid a lot of reallocs at runtime { freeThreadedMemoryOnNextUpdate = false; #ifdef _DEBUG // Wait longer to disconnect in debug so I don't get disconnected while tracing timeoutTime=30000; #else timeoutTime=10000; #endif #ifndef _RELEASE maxSendBPS=minExtraPing=extraPingVariance=0; #endif InitializeVariables(); } //------------------------------------------------------------------------------------------------------- // Destructor //------------------------------------------------------------------------------------------------------- ReliabilityLayer::~ReliabilityLayer() { FreeMemory( true ); // Free all memory immediately } //------------------------------------------------------------------------------------------------------- // Resets the layer for reuse //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Reset( bool resetVariables ) { FreeMemory( true ); // true because making a memory reset pending in the update cycle causes resets after reconnects. Instead, just call Reset from a single thread if (resetVariables) InitializeVariables(); } //------------------------------------------------------------------------------------------------------- // Sets up encryption //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetEncryptionKey( const unsigned char* key ) { if ( key ) encryptor.SetKey( key ); else encryptor.UnsetKey(); } //------------------------------------------------------------------------------------------------------- // Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable packet //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetTimeoutTime( RakNetTime time ) { timeoutTime=time; } //------------------------------------------------------------------------------------------------------- // Returns the value passed to SetTimeoutTime. or the default if it was never called //------------------------------------------------------------------------------------------------------- RakNetTime ReliabilityLayer::GetTimeoutTime(void) { return timeoutTime; } //------------------------------------------------------------------------------------------------------- // Initialize the variables //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InitializeVariables( void ) { memset( waitingForOrderedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType)); memset( waitingForSequencedPacketReadIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( waitingForOrderedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( waitingForSequencedPacketWriteIndex, 0, NUMBER_OF_ORDERED_STREAMS * sizeof(OrderingIndexType) ); memset( &statistics, 0, sizeof( statistics ) ); statistics.connectionStartTime = RakNet::GetTime(); splitPacketId = 0; throughputCapCountdown=0; sendMessageNumberIndex = 0; internalOrderIndex=0; lastUpdateTime= RakNet::GetTimeNS(); lastTimeBetweenPacketsIncrease=lastTimeBetweenPacketsDecrease=0; remoteSystemTime=0; // lastPacketSendTime=retransmittedFrames=sentPackets=sentFrames=receivedPacketsCount=bytesSent=bytesReceived=0; nextAllowedThroughputSample=0; deadConnection = cheater = false; lastAckTime = 0; // ackPing=0; receivedPacketsBaseIndex=0; resetReceivedPackets=true; sendPacketCount=receivePacketCount=0; // SetPing( 1000 ); timeBetweenPackets=STARTING_TIME_BETWEEN_PACKETS; ackPingIndex=0; ackPingSum=(RakNetTimeNS)0; nextSendTime=lastUpdateTime; //nextLowestPingReset=(RakNetTimeNS)0; continuousSend=false; histogramStart=(RakNetTimeNS)0; histogramBitsSent=0; packetlossThisSample=backoffThisSample=false; packetlossThisSampleResendCount=0; // timeBetweenPacketsIncreaseMultiplier=TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_DEFAULT; // timeBetweenPacketsDecreaseMultiplier=TIME_BETWEEN_PACKETS_DECREASE_MULTIPLIER_DEFAULT; } //------------------------------------------------------------------------------------------------------- // Frees all allocated memory //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::FreeMemory( bool freeAllImmediately ) { if ( freeAllImmediately ) { FreeThreadedMemory(); FreeThreadSafeMemory(); } else { FreeThreadSafeMemory(); freeThreadedMemoryOnNextUpdate = true; } } void ReliabilityLayer::FreeThreadedMemory( void ) { } void ReliabilityLayer::FreeThreadSafeMemory( void ) { unsigned i,j; InternalPacket *internalPacket; for (i=0; i < splitPacketChannelList.Size(); i++) { for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { rakFree(splitPacketChannelList[i]->splitPacketList[j]->data); // internalPacketPool.Release( splitPacketChannelList[i]->splitPacketList[j] ); } delete splitPacketChannelList[i]; } splitPacketChannelList.Clear(); while ( outputQueue.Size() > 0 ) { internalPacket = outputQueue.Pop(); rakFree(internalPacket->data); // internalPacketPool.Release( internalPacket ); } outputQueue.ClearAndForceAllocation( 32 ); for ( i = 0; i < orderingList.Size(); i++ ) { if ( orderingList[ i ] ) { DataStructures::LinkedList* theList = orderingList[ i ]; if ( theList ) { while ( theList->Size() ) { internalPacket = orderingList[ i ]->Pop(); rakFree(internalPacket->data); // internalPacketPool.Release( internalPacket ); } delete theList; } } } orderingList.Clear(); //resendList.ForEachData(DeleteInternalPacket); resendList.Clear(); while ( resendQueue.Size() ) { // The resend Queue can have NULL pointer holes. This is so we can deallocate blocks without having to compress the array internalPacket = resendQueue.Pop(); if ( internalPacket ) { rakFree(internalPacket->data); // internalPacketPool.Release( internalPacket ); } } resendQueue.ClearAndForceAllocation( DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE ); for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { j = 0; for ( ; j < sendPacketSet[ i ].Size(); j++ ) { rakFree(( sendPacketSet[ i ] ) [ j ]->data); //internalPacketPool.Release( ( sendPacketSet[ i ] ) [ j ] ); } sendPacketSet[ i ].ClearAndForceAllocation( 32 ); // Preallocate the send lists so we don't do a bunch of reallocations unnecessarily } #ifndef _RELEASE for (unsigned i = 0; i < delayList.Size(); i++ ) delete delayList[ i ]; delayList.Clear(); #endif internalPacketPool.Clear(); acknowlegements.Clear(); } //------------------------------------------------------------------------------------------------------- // Packets are read directly from the socket layer and skip the reliability //layer because unconnected players do not use the reliability layer // This function takes packet data after a player has been confirmed as //connected. The game should not use that data directly // because some data is used internally, such as packet acknowledgment and //split packets //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffer, unsigned int length, SystemAddress systemAddress, DataStructures::List &messageHandlerList, int MTUSize ) { #ifdef _DEBUG assert( !( buffer == 0 ) ); #endif (void) MTUSize; if ( length <= 2 || buffer == 0 ) // Length of 1 is a connection request resend that we just ignore return true; //int numberOfAcksInFrame = 0; RakNetTimeNS time; bool indexFound; int count, size; MessageNumberType holeCount; unsigned i; bool hasAcks=false; // bool duplicatePacket; // bytesReceived+=length + UDP_HEADER_SIZE; UpdateThreadedMemory(); // decode this whole chunk if the decoder is defined. if ( encryptor.IsKeySet() ) { if ( encryptor.Decrypt( ( unsigned char* ) buffer, length, ( unsigned char* ) buffer, &length ) == false ) { statistics.bitsWithBadCRCReceived += length * 8; statistics.packetsWithBadCRCReceived++; return false; } } statistics.bitsReceived += length * 8; statistics.packetsReceived++; RakNet::BitStream socketData( (unsigned char*) buffer, length, false ); // Convert the incoming data to a bitstream for easy parsing time = RakNet::GetTimeNS(); DataStructures::RangeList incomingAcks; socketData.Read(hasAcks); if (hasAcks) { MessageNumberType messageNumber; RemoteSystemTimeType ourSystemTime; socketData.Read(ourSystemTime); if (incomingAcks.Deserialize(&socketData)==false) return false; for (i=0; iincomingAcks.ranges[i].maxIndex) { RakAssert(incomingAcks.ranges[i].minIndex<=incomingAcks.ranges[i].maxIndex); return false; } for (messageNumber=incomingAcks.ranges[i].minIndex; messageNumber >= incomingAcks.ranges[i].minIndex && messageNumber <= incomingAcks.ranges[i].maxIndex; messageNumber++) { hasAcks=true; // GOT ACK // SHOW - ack received // printf("Got Ack for %i\n",messageNumber); RemovePacketFromResendListAndDeleteOlderReliableSequenced( messageNumber, time ); #ifdef _DEBUG_LOGGER { char temp[256]; sprintf(temp, "%p: Got ack for %i. Resend queue size=%i\n", this, messageNumber, resendQueue.Size()); OutputDebugStr(temp); } #endif if ( resendList.IsEmpty() ) { lastAckTime = 0; // Not resending anything so clear this var so we don't drop the connection on not getting any more acks } else { lastAckTime = time; // Just got an ack. Record when we got it so we know the connection is alive } } } RakNetTimeNS rst = (RakNetTimeNS) ourSystemTime * (RakNetTimeNS) 1000; if (time >= rst) ackPing = time - rst; else ackPing=0; RakNetTimeNS avePing; if (ackPingSum==0) { // First time between packets is just the ping. timeBetweenPackets = ackPing; if (timeBetweenPackets > MAX_TIME_BETWEEN_PACKETS) timeBetweenPackets=MAX_TIME_BETWEEN_PACKETS; else if (timeBetweenPackets < (RakNetTimeNS)10000 ) timeBetweenPackets=(RakNetTimeNS)10000; ackPingSum=ackPing<<8; // Multiply by 256 for (int i=0; i < 256; i++) ackPingSamples[i]=ackPing; } avePing=ackPingSum>>8; // divide by 256 if (continuousSend && time >= nextAllowedThroughputSample) { // 10 milliseconds tolerance, because at small pings percentage fluctuations vary widely naturally bool pingLowering = ackPing <= avePing * (RakNetTimeNS)6 / (RakNetTimeNS)5 + (RakNetTimeNS)10000; // Only increase if the ping is lowering and there was no packetloss if (pingLowering==true && packetlossThisSample==false) { // Only count towards the average when ping declining and no packetloss the last sample. // Otherwise it eventually averages to when we get packetloss. ackPingSum-=ackPingSamples[ackPingIndex]; ackPingSamples[ackPingIndex]=ackPing; ackPingSum+=ackPing; ackPingIndex++; // Might wrap to 0 RakNetTimeNS diff; // Decrease time between packets by 2% diff = (RakNetTimeNS)ceil(((long double) timeBetweenPackets * TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_DEFAULT)); if (diff < timeBetweenPackets) { nextSendTime-=diff; timeBetweenPackets-=diff; } // printf("- CurPing: %i. AvePing: %i. Ploss=%.1f. Time between= %i\n", (RakNetTime)(ackPing/(RakNetTimeNS)1000), (RakNetTime)(avePing/(RakNetTimeNS)1000), 100.0f * ( float ) statistics.messagesTotalBitsResent / ( float ) statistics.totalBitsSent, timeBetweenPackets); lastTimeBetweenPacketsDecrease=time; } // Decrease if the ping is rising or we got packetloss for a new group of resends else if (pingLowering==false || backoffThisSample==true) // if (ackPing >= ((avePing*(RakNetTimeNS)4)/(RakNetTimeNS)3) + (RakNetTimeNS) 1000) // 1 milliseconds tolerance, because at small pings percentage fluctuations vary widely naturally { // Increase time between packets by 4% RakNetTimeNS diff = (RakNetTimeNS)ceil(((long double) timeBetweenPackets * TIME_BETWEEN_PACKETS_DECREASE_MULTIPLIER_DEFAULT)); nextSendTime+=diff; timeBetweenPackets+=diff; // printf("+ CurPing: %i. AvePing: %i. Ploss=%.1f. Time between = %i\n", (RakNetTime)(ackPing/(RakNetTimeNS)1000), (RakNetTime)(avePing/(RakNetTimeNS)1000), 100.0f * ( float ) statistics.messagesTotalBitsResent / ( float ) statistics.totalBitsSent,timeBetweenPackets); lastTimeBetweenPacketsIncrease=time; if (timeBetweenPackets > MAX_TIME_BETWEEN_PACKETS) { // Something wrong, perhaps the entire network clogged up, or a different path was taken. timeBetweenPackets=MAX_TIME_BETWEEN_PACKETS; } } packetlossThisSample=false; backoffThisSample=false; if (ackPing < 2000000) // 1 milliseconds tolerance, Otherwise we overreact at very small pings nextAllowedThroughputSample=time+ackPing + (RakNetTimeNS)1000; else // Don't resample over super long periods nextAllowedThroughputSample=time+200000; // printf("time=%i ",time); // printf("nextAllowedThroughputSample=%i\n",nextAllowedThroughputSample); } // else // printf("Continuous Send = false\n"); // if (ackPing < lowestPing) // lowestPing=ackPing; // if (time > nextLowestPingReset) // { // lowestPing=ackPing; // nextLowestPingReset=time+(RakNetTimeNS)60000000; // Once per minute, reset the lowest ping to account for high level ping changes. // } } bool hasRemoteSystemTime=false; socketData.Read(hasRemoteSystemTime); if (hasRemoteSystemTime) socketData.Read(remoteSystemTime); // Parse the bitstream to create an internal packet InternalPacket* internalPacket = CreateInternalPacketFromBitStream( &socketData, time ); if (internalPacket==0) return hasAcks; while ( internalPacket ) { for (i=0; i < messageHandlerList.Size(); i++) messageHandlerList[i]->OnInternalPacket(internalPacket, receivePacketCount, systemAddress, (RakNetTime)(time/(RakNetTimeNS)1000), false); { #ifdef _DEBUG_LOGGER { char temp[256]; sprintf(temp, "%p: Got packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength); OutputDebugStr(temp); } #endif // resetReceivedPackets is set from a non-threadsafe function. // We do the actual reset in this function so the data is not modified by multiple threads if (resetReceivedPackets) { hasReceivedPacketQueue.ClearAndForceAllocation(DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE); receivedPacketsBaseIndex=0; resetReceivedPackets=false; } /* // REMOVEME if (internalPacket->reliability==RELIABLE_ORDERED) { RakNet::BitStream bitStream; bitStream.Write((char*)internalPacket->data, BITS_TO_BYTES(internalPacket->dataBitLength)); bitStream.IgnoreBits(8); unsigned int receivedPacketNumber; bitStream.Read(receivedPacketNumber); printf("-- %i, OI=%i\n", receivedPacketNumber, internalPacket->orderingIndex); } */ // If the following conditional is true then this either a duplicate packet // or an older out of order packet // The subtraction unsigned overflow is intentional holeCount = (MessageNumberType)(internalPacket->messageNumber-receivedPacketsBaseIndex); const MessageNumberType typeRange = (MessageNumberType)-1; if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability == RELIABLE ) { #ifdef _DEBUG // printf("Sending ack for %i, rpbi=%i\n", internalPacket->messageNumber, receivedPacketsBaseIndex); #endif SendAcknowledgementPacket( internalPacket->messageNumber, time ); } if (holeCount==0) { // Got what we were expecting if (hasReceivedPacketQueue.Size()) hasReceivedPacketQueue.Pop(); ++receivedPacketsBaseIndex; } else if (holeCount > typeRange/2) { #ifdef _DEBUG // printf("under_holeCount=%i, pnum=%i, rpbi=%i\n", (int)holeCount, internalPacket->messageNumber, receivedPacketsBaseIndex); #endif // Underflow - got a packet we have already counted past statistics.duplicateMessagesReceived++; #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) if (internalPacket->splitPacketCount>0) printf("Underflow with hole count %i for split packet with ID %i\n",holeCount, internalPacket->splitPacketId); #endif // Duplicate packet rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } else if (holeCountmessageNumber, receivedPacketsBaseIndex); #endif // Got a higher count out of order packet that was missing in the sequence or we already got if (hasReceivedPacketQueue[holeCount]!=0) // non-zero means this is a hole { // Fill in the hole hasReceivedPacketQueue[holeCount]=0; // We got the packet at holeCount } else { #ifdef _DEBUG // printf("Duplicate, holeCount=%i, pnum=%i, rpbi=%i\n", (int)holeCount, internalPacket->messageNumber, receivedPacketsBaseIndex); #endif // Not a hole - just a duplicate packet statistics.duplicateMessagesReceived++; #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) if (internalPacket->splitPacketCount>0) printf("Duplicate hole count %i for split packet with ID %i\n",holeCount, internalPacket->splitPacketId); #endif // Duplicate packet rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } } else // holeCount>=receivedPackets.Size() { if (holeCount > 1000000) { #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) if (internalPacket->splitPacketCount>0) printf("High hole count %i for split packet with ID %i\n",holeCount, internalPacket->splitPacketId); #endif // Would crash due to out of memory! rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Got a higher count out of order packet whose messageNumber is higher than we have ever got #ifdef _DEBUG // printf("over_Buffered_holeCount=%i, pnum=%i, rpbi=%i\n", (int) holeCount, internalPacket->messageNumber, receivedPacketsBaseIndex); #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 (messageNumber - baseIndex) < queue size. // RakAssert(holeCount<10000); while ((MessageNumberType)(holeCount) > hasReceivedPacketQueue.Size()) hasReceivedPacketQueue.Push(time+(RakNetTimeNS)60 * (RakNetTimeNS)1000 * (RakNetTimeNS)1000); // Didn't get this packet - set the time to give up waiting hasReceivedPacketQueue.Push(0); // Got the packet #ifdef _DEBUG // If this assert hits then MessageNumberType has overflowed assert(hasReceivedPacketQueue.Size() < (unsigned int)((MessageNumberType)(-1))); #endif } // Pop all expired times. 0 means we got the packet, in which case we don't track this index either. while ( hasReceivedPacketQueue.Size()>0 && hasReceivedPacketQueue.Peek() < time ) { hasReceivedPacketQueue.Pop(); ++receivedPacketsBaseIndex; } statistics.messagesReceived++; // If the allocated buffer is > DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE and it is 3x greater than the number of elements actually being used if (hasReceivedPacketQueue.AllocationSize() > (unsigned int) DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE && hasReceivedPacketQueue.AllocationSize() > hasReceivedPacketQueue.Size() * 3) hasReceivedPacketQueue.Compress(); if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { // Invalid packet #ifdef _DEBUG // printf( "Got invalid packet\n" ); #endif rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } if ( IsOlderOrderedPacket( internalPacket->orderingIndex, waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] ) == false ) { statistics.sequencedMessagesInOrder++; // Is this a split packet? if ( internalPacket->splitPacketCount > 0 ) { // Generate the split // Verify some parameters to make sure we don't get junk data // Check for a rebuilt packet InsertIntoSplitPacketList( internalPacket, time ); // Sequenced internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time ); if ( internalPacket ) { // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1; // If there is a rebuilt packet, add it to the output queue outputQueue.Push( internalPacket ); internalPacket = 0; } // else don't have all the parts yet } else { // Update our index to the newest packet waitingForSequencedPacketReadIndex[ internalPacket->orderingChannel ] = internalPacket->orderingIndex + 1; // Not a split packet. Add the packet to the output queue outputQueue.Push( internalPacket ); internalPacket = 0; } } else { statistics.sequencedMessagesOutOfOrder++; // Older sequenced packet. Discard it rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Is this an unsequenced split packet? if ( internalPacket->splitPacketCount > 0 ) { // An unsequenced split packet. May be ordered though. // Check for a rebuilt packet if ( internalPacket->reliability != RELIABLE_ORDERED ) internalPacket->orderingChannel = 255; // Use 255 to designate not sequenced and not ordered InsertIntoSplitPacketList( internalPacket, time ); internalPacket = BuildPacketFromSplitPacketList( internalPacket->splitPacketId, time ); if ( internalPacket == 0 ) { // Don't have all the parts yet goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // else continue down to handle RELIABLE_ORDERED #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) printf("%i,", internalPacket->orderingIndex); #endif } if ( internalPacket->reliability == RELIABLE_ORDERED ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { #ifdef _DEBUG //printf("Got invalid ordering channel %i from packet %i\n", internalPacket->orderingChannel, internalPacket->messageNumber); #endif // Invalid packet rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } if ( waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] == internalPacket->orderingIndex ) { // Get the list to hold ordered packets for this stream DataStructures::LinkedList *orderingListAtOrderingStream; unsigned char orderingChannelCopy = internalPacket->orderingChannel; statistics.orderedMessagesInOrder++; // Show ordering index increment //printf("Pushing immediate packet %i with ordering index %i\n", internalPacket->messageNumber, internalPacket->orderingIndex ); // Push the packet for the user to read outputQueue.Push( internalPacket ); internalPacket = 0; // Don't reference this any longer since other threads access it // Wait for the next ordered packet in sequence waitingForOrderedPacketReadIndex[ orderingChannelCopy ] ++; // This wraps orderingListAtOrderingStream = GetOrderingListAtOrderingStream( orderingChannelCopy ); if ( orderingListAtOrderingStream != 0) { while ( orderingListAtOrderingStream->Size() > 0 ) { // Cycle through the list until nothing is found orderingListAtOrderingStream->Beginning(); indexFound=false; size=orderingListAtOrderingStream->Size(); count=0; while (count++ < size) { if ( orderingListAtOrderingStream->Peek()->orderingIndex == waitingForOrderedPacketReadIndex[ orderingChannelCopy ] ) { /* RakNet::BitStream temp(orderingListAtOrderingStream->Peek()->data, BITS_TO_BYTES(orderingListAtOrderingStream->Peek()->dataBitLength), false); temp.IgnoreBits(8); unsigned int receivedPacketNumber=0; temp.Read(receivedPacketNumber); printf("Receive: receivedPacketNumber=%i orderingIndex=%i waitingFor=%i\n", receivedPacketNumber, orderingListAtOrderingStream->Peek()->orderingIndex, waitingForOrderedPacketReadIndex[ orderingChannelCopy ]); */ //printf("Pushing delayed packet %i with ordering index %i. outputQueue.Size()==%i\n", orderingListAtOrderingStream->Peek()->messageNumber, orderingListAtOrderingStream->Peek()->orderingIndex, outputQueue.Size() ); outputQueue.Push( orderingListAtOrderingStream->Pop() ); waitingForOrderedPacketReadIndex[ orderingChannelCopy ]++; indexFound=true; } else (*orderingListAtOrderingStream)++; } if (indexFound==false) break; } } internalPacket = 0; } else { #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) if (internalPacket->splitPacketCount>0) printf("Split packet OOO. Waiting=%i. Got=%i\n", waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ], internalPacket->orderingIndex); waitFlag=internalPacket->splitPacketId; #endif // assert(waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] < internalPacket->orderingIndex); statistics.orderedMessagesOutOfOrder++; // This is a newer ordered packet than we are waiting for. Store it for future use AddToOrderingList( internalPacket ); } goto CONTINUE_SOCKET_DATA_PARSE_LOOP; } // Nothing special about this packet. Add it to the output queue outputQueue.Push( internalPacket ); internalPacket = 0; } // Used for a goto to jump to the next packet immediately CONTINUE_SOCKET_DATA_PARSE_LOOP: // Parse the bitstream to create an internal packet internalPacket = CreateInternalPacketFromBitStream( &socketData, time ); } /* if (numberOfAcksInFrame > 0) // if (time > lastWindowAdjustTime+ping) { // printf("Window size up\n"); windowSize+=1 + numberOfAcksInFrame/windowSize; if ( windowSize > MAXIMUM_WINDOW_SIZE ) windowSize = MAXIMUM_WINDOW_SIZE; //lastWindowAdjustTime=time; } //else // printf("No acks in frame\n"); */ /* // numberOfAcksInFrame>=windowSize means that all the packets we last sent from the resendList are cleared out // 11/17/05 - the problem with numberOfAcksInFrame >= windowSize is that if the entire frame is filled with resends but not all resends filled the frame // then the sender is limited by how many resends can fit in one frame if ( numberOfAcksInFrame >= windowSize && ( sendPacketSet[ SYSTEM_PRIORITY ].Size() > 0 || sendPacketSet[ HIGH_PRIORITY ].Size() > 0 || sendPacketSet[ MEDIUM_PRIORITY ].Size() > 0 ) ) { // reliabilityLayerMutexes[windowSize_MUTEX].Lock(); //printf("windowSize=%i lossyWindowSize=%i\n", windowSize, lossyWindowSize); if ( windowSize < lossyWindowSize || (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // Increases the window size slowly, testing for packetloss { // If we get a frame which clears out the resend queue after handling one or more acks, and we have packets waiting to go out, // and we didn't recently lose a packet then increase the window size by 1 windowSize++; if ( (time>lastWindowIncreaseSizeTime && time-lastWindowIncreaseSizeTime>lostPacketResendDelay*2) ) // The increase is to test for packetloss lastWindowIncreaseSizeTime = time; // If the window is so large that we couldn't possibly fit any more packets into the frame, then just leave it alone if ( windowSize > MAXIMUM_WINDOW_SIZE ) windowSize = MAXIMUM_WINDOW_SIZE; // SHOW - WINDOWING //else // printf("Increasing windowSize to %i. Lossy window size = %i\n", windowSize, lossyWindowSize); // If we are more than 5 over the lossy window size, increase the lossy window size by 1 if ( windowSize == MAXIMUM_WINDOW_SIZE || windowSize - lossyWindowSize > 5 ) lossyWindowSize++; } // reliabilityLayerMutexes[windowSize_MUTEX].Unlock(); } */ if (hasAcks) { UpdateWindowFromAck(time); } receivePacketCount++; return true; } //------------------------------------------------------------------------------------------------------- // This gets an end-user packet already parsed out. Returns number of BITS put into the buffer //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::Receive( unsigned char **data ) { // Wait until the clear occurs if (freeThreadedMemoryOnNextUpdate) return 0; InternalPacket * internalPacket; if ( outputQueue.Size() > 0 ) { // #ifdef _DEBUG // assert(bitStream->GetNumberOfBitsUsed()==0); // #endif internalPacket = outputQueue.Pop(); BitSize_t bitLength; *data = internalPacket->data; bitLength = internalPacket->dataBitLength; internalPacketPool.Release( 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, RakNetTimeNS currentTime ) { #ifdef _DEBUG assert( !( reliability > RELIABLE_SEQUENCED || reliability < 0 ) ); assert( !( priority > NUMBER_OF_PRIORITIES || priority < 0 ) ); assert( !( orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) ); assert( numberOfBitsToSend > 0 ); #endif // int a = BITS_TO_BYTES(numberOfBitsToSend); // Fix any bad parameters if ( reliability > RELIABLE_SEQUENCED || reliability < 0 ) reliability = RELIABLE; if ( priority > NUMBER_OF_PRIORITIES || priority < 0 ) priority = HIGH_PRIORITY; if ( orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) orderingChannel = 0; // For the first 60 seconds of a new connection, send everything reliable, so that acks arrive and available bandwidth can be determined. if (currentTime-(RakNetTimeNS)statistics.connectionStartTime*(RakNetTimeNS)1000 < (RakNetTimeNS)60000000) { if (reliability==UNRELIABLE) reliability=RELIABLE; else if (reliability==UNRELIABLE_SEQUENCED) reliability=RELIABLE_ORDERED; } unsigned int numberOfBytesToSend=(unsigned int) BITS_TO_BYTES(numberOfBitsToSend); if ( numberOfBitsToSend == 0 ) { #ifdef _DEBUG // printf( "Error!! ReliabilityLayer::Send bitStream->GetNumberOfBytesUsed()==0\n" ); #endif return false; } InternalPacket * internalPacket = internalPacketPool.Allocate(); if (internalPacket==0) { notifyOutOfMemory(__FILE__, __LINE__); return false; // Out of memory } //InternalPacket * internalPacket = sendPacketSet[priority].WriteLock(); #ifdef _DEBUG // Remove accessing undefined memory warning memset( internalPacket, 255, sizeof( InternalPacket ) ); #endif internalPacket->creationTime = currentTime; if ( makeDataCopy ) { internalPacket->data = (unsigned char*) rakMalloc( numberOfBytesToSend ); memcpy( internalPacket->data, data, numberOfBytesToSend ); // printf("Allocated %i\n", internalPacket->data); } else { // Allocated the data elsewhere, delete it in here internalPacket->data = ( unsigned char* ) data; // printf("Using Pre-Allocated %i\n", internalPacket->data); } internalPacket->dataBitLength = numberOfBitsToSend; internalPacket->nextActionTime = 0; // printf("%i\n", messageNumber); //internalPacket->messageNumber = sendMessageNumberIndex; internalPacket->messageNumber = (MessageNumberType) -1; internalPacket->messageNumberAssigned=false; internalPacket->messageInternalOrder = internalOrderIndex++; internalPacket->priority = priority; internalPacket->reliability = reliability; internalPacket->splitPacketCount = 0; // Calculate if I need to split the packet int headerLength = BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) ); unsigned int maxDataSize = MTUSize - UDP_HEADER_SIZE - headerLength; if ( encryptor.IsKeySet() ) maxDataSize -= 16; // Extra data for the encryptor bool splitPacket = numberOfBytesToSend > maxDataSize; // If a split packet, we might have to upgrade the reliability if ( splitPacket ) statistics.numberOfSplitMessages++; else statistics.numberOfUnsplitMessages++; // ++sendMessageNumberIndex; if ( internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == UNRELIABLE_SEQUENCED ) { // Assign the sequence stream and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = waitingForSequencedPacketWriteIndex[ orderingChannel ] ++; // This packet supersedes all other sequenced packets on the same ordering channel // Delete all packets in all send lists that are sequenced and on the same ordering channel // UPDATE: // Disabled. We don't have enough info to consistently do this. Sometimes newer data does supercede // older data such as with constantly declining health, but not in all cases. // For example, with sequenced unreliable sound packets just because you send a newer one doesn't mean you // don't need the older ones because the odds are they will still arrive in order /* for (int i=0; i < NUMBER_OF_PRIORITIES; i++) { DeleteSequencedPacketsInList(orderingChannel, sendQueue[i]); } */ } else if ( internalPacket->reliability == RELIABLE_ORDERED ) { // Assign the ordering channel and index internalPacket->orderingChannel = orderingChannel; internalPacket->orderingIndex = waitingForOrderedPacketWriteIndex[ orderingChannel ] ++; } if ( splitPacket ) // If it uses a secure header it will be generated here { // Must split the packet. This will also generate the SHA1 if it is required. It also adds it to the send list. //InternalPacket packetCopy; //memcpy(&packetCopy, internalPacket, sizeof(InternalPacket)); //sendPacketSet[priority].CancelWriteLock(internalPacket); //SplitPacket( &packetCopy, MTUSize ); SplitPacket( internalPacket, MTUSize ); //delete [] packetCopy.data; return true; } sendPacketSet[ internalPacket->priority ].Push( internalPacket ); // sendPacketSet[priority].WriteUnlock(); return true; } //------------------------------------------------------------------------------------------------------- // Run this once per game cycle. Handles internal lists and actually does the send //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::Update( SOCKET s, SystemAddress systemAddress, int MTUSize, RakNetTimeNS time, unsigned bitsPerSecondLimit, DataStructures::List &messageHandlerList ) { // Debug memory leaks /* if (0) { printf("orderingList.Size()=%i\n", orderingList.Size()); printf("outputQueue.Size()=%i\n", outputQueue.Size()); printf("acknowlegements.Size()=%i\n", acknowlegements.Size()); printf("resendList.Size()=%i\n", resendList.Size()); printf("resendQueue.Size()=%i\n", resendQueue.Size()); for (int i=0; i < NUMBER_OF_PRIORITIES; i++) printf("sendPacketSet[%i].Size()=%i\n", i, sendPacketSet[i].Size()); printf("splitPacketChannelList.Size()=%i\n", splitPacketChannelList.Size()); printf("hasReceivedPacketQueue.Size()=%i\n", hasReceivedPacketQueue.Size()); #ifndef _RELEASE printf("delayList.Size()=%i\n", delayList.Size()); #endif printf("internalPacketPool.GetAvailablePagesSize()=%i\n", internalPacketPool.GetAvailablePagesSize()); printf("internalPacketPool.GetUnavailablePagesSize()=%i\n", internalPacketPool.GetUnavailablePagesSize()); printf("internalPacketPool.GetMemoryPoolPageSize()=%i\n", internalPacketPool.GetMemoryPoolPageSize()); printf("sendMessageNumberIndex=%i\n", sendMessageNumberIndex); printf("deadConnection=%i\n", deadConnection); printf("cheater=%i\n", cheater); printf("splitPacketId=%i\n", splitPacketId); printf("blockWindowIncreaseUntilTime=%i\n", blockWindowIncreaseUntilTime); printf("receivedPacketsBaseIndex=%i\n", receivedPacketsBaseIndex); printf("lastUpdateTime=%I64u\n", lastUpdateTime); printf("timeBetweenPackets=%I64u\n", timeBetweenPackets); printf("nextSendTime=%I64u\n", nextSendTime); printf("ackPing=%I64u\n", ackPing); printf("ackPingSum=%I64u\n", ackPingSum); printf("ackPingIndex=%i\n", ackPingIndex); printf("continuousSend=%i\n", continuousSend); printf("sendPacketCount=%i\n", sendPacketCount); printf("receivePacketCount=%i\n", receivePacketCount); char buffer[10000]; StatisticsToString( &statistics, buffer, 2 ); printf("%s\n", buffer); } */ // This line is necessary because the timer isn't accurate if (time <= lastUpdateTime) { // Always set the last time in case of overflow lastUpdateTime=time; return; } RakNetTimeNS elapsed = time - lastUpdateTime; lastUpdateTime=time; UpdateThreadedMemory(); // Due to thread vagarities and the way I store the time to avoid slow calls to RakNet::GetTime // time may be less than lastAck if ( resendList.IsEmpty()==false && AckTimeout(time) ) { // SHOW - dead connection // printf("The connection has been lost.\n"); // We've waited a very long time for a reliable packet to get an ack and it never has deadConnection = true; return; } if (time >= histogramStart + HISTOGRAM_RESTART_CYCLE) { histogramStart=time; histogramBitsSent=0; } bool limitThroughput; if (bitsPerSecondLimit==0 || throughputCapCountdown <= 0) limitThroughput=false; else { throughputCapCountdown-=elapsed; if (throughputCapCountdown<0) { limitThroughput=false; throughputCapCountdown=0; } else { limitThroughput=true; continuousSend=false; // Blocked from sending due to throughput limit, so not sending continuously } } const int maxDataBitSize = BYTES_TO_BITS((MTUSize - UDP_HEADER_SIZE)); bool hitMTUCap; bool reliableDataSent; RakNetTimeNS usedTime; #ifdef _ENABLE_FLOW_CONTROL RakNetTimeNS availableTime; if (limitThroughput==false) { if (time >= nextSendTime) { hitMTUCap=false; usedTime=(RakNetTimeNS)0; availableTime = time - nextSendTime; if (availableTime > MAX_TIME_BETWEEN_PACKETS) availableTime=MAX_TIME_BETWEEN_PACKETS; while ( usedTime <= availableTime ) { #else while (1) { #endif (void) reliableDataSent; updateBitStream.Reset(); if ( GenerateDatagram( &updateBitStream, MTUSize, &reliableDataSent, time, systemAddress, &hitMTUCap, messageHandlerList ) ) { #ifndef _RELEASE if (minExtraPing > 0 || extraPingVariance > 0) { // Delay the send to simulate lag DataAndTime *dt; dt = new DataAndTime; memcpy( dt->data, updateBitStream.GetData(), (size_t) updateBitStream.GetNumberOfBytesUsed() ); dt->length = (unsigned int) updateBitStream.GetNumberOfBytesUsed(); dt->sendTime = time + (RakNetTimeNS)minExtraPing*1000; if (extraPingVariance > 0) dt->sendTime += ( randomMT() % (int)extraPingVariance ); delayList.Insert( dt ); } else #endif { SendBitStream( s, systemAddress, &updateBitStream ); } #ifdef _ENABLE_FLOW_CONTROL if (bitsPerSecondLimit > 0) { throughputCapCountdown+=(RakNetTimeNS)(1000000.0 * (double) updateBitStream.GetNumberOfBitsUsed() / (double) bitsPerSecondLimit); // Prevent sending a large burst and then doing nothing for a long time if (throughputCapCountdown>30000) break; } if (hitMTUCap) usedTime+=timeBetweenPackets; else usedTime+=(RakNetTimeNS)((long double) timeBetweenPackets * ((long double) updateBitStream.GetNumberOfBitsUsed() / (long double) maxDataBitSize)); #endif } else break; } #ifdef _ENABLE_FLOW_CONTROL if ( nextSendTime + MAX_TIME_BETWEEN_PACKETS < time ) { // Long time since last send nextSendTime=time+usedTime; continuousSend=false; } else { nextSendTime+=usedTime; if (nextSendTime>time) { continuousSend=true; } else { nextSendTime+=usedTime; if (nextSendTime0) { updateBitStream.Reset(); updateBitStream.Write(true); updateBitStream.Write(remoteSystemTime); BitSize_t bitsSent = acknowlegements.Serialize(&updateBitStream, (MTUSize-UDP_HEADER_SIZE)*8-1, true); statistics.acknowlegementBitsSent +=bitsSent; SendBitStream( s, systemAddress, &updateBitStream ); if (bitsPerSecondLimit > 0) { throughputCapCountdown+=(RakNetTimeNS)(1000000.0 * (double) updateBitStream.GetNumberOfBitsUsed() / (double) bitsPerSecondLimit); } } } } #endif #ifndef _RELEASE // Do any lagged sends unsigned i = 0; while ( i < delayList.Size() ) { if ( delayList[ i ]->sendTime < time ) { updateBitStream.Reset(); updateBitStream.Write( delayList[ i ]->data, delayList[ i ]->length ); // Send it now SendBitStream( s, systemAddress, &updateBitStream ); delete delayList[ i ]; if (i != delayList.Size() - 1) delayList[ i ] = delayList[ delayList.Size() - 1 ]; delayList.RemoveFromEnd(); } else i++; } #endif // 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( SOCKET s, SystemAddress systemAddress, RakNet::BitStream *bitStream ) { // SHOW - showing reliable flow // if (bitStream->GetNumberOfBytesUsed()>50) // printf("Sending %i bytes. sendQueue[0].Size()=%i, resendList.Size()=%i\n", bitStream->GetNumberOfBytesUsed(), sendQueue[0].Size(),resendList.Size()); unsigned int oldLength, length; // sentFrames++; #ifndef _RELEASE if (maxSendBPS>0) { // double chanceToLosePacket = (double)currentBandwidth / (double)maxSendBPS; // if (frandomMT() < (float)chanceToLosePacket) // return; } #endif // REMOVEME // if (frandomMT() < .15f) // return; // Encode the whole bitstream if the encoder is defined. if ( encryptor.IsKeySet() ) { length = (unsigned int) bitStream->GetNumberOfBytesUsed(); oldLength = length; encryptor.Encrypt( ( unsigned char* ) bitStream->GetData(), length, ( unsigned char* ) bitStream->GetData(), &length ); statistics.encryptionBitsSent = BYTES_TO_BITS( length - oldLength ); assert( ( length % 16 ) == 0 ); } else { length = (unsigned int) bitStream->GetNumberOfBytesUsed(); } statistics.packetsSent++; statistics.totalBitsSent += length * 8; histogramBitsSent += length * 8; //printf("total bits=%i length=%i\n", BITS_TO_BYTES(statistics.totalBitsSent), length); SocketLayer::Instance()->SendTo( s, ( char* ) bitStream->GetData(), length, systemAddress.binaryAddress, systemAddress.port ); // lastPacketSendTime=time; } //------------------------------------------------------------------------------------------------------- // Generates a datagram (coalesced packets) //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::GenerateDatagram( RakNet::BitStream *output, int MTUSize, bool *reliableDataSent, RakNetTimeNS time, SystemAddress systemAddress, bool *hitMTUCap, DataStructures::List &messageHandlerList ) { InternalPacket * internalPacket; // InternalPacket *temp; BitSize_t maxDataBitSize; BitSize_t reliableBits = 0; BitSize_t nextPacketBitLength; unsigned i, messageHandlerIndex; bool isReliable, onlySendUnreliable; //bool writeFalseToHeader; bool wroteAcks; bool wroteData; unsigned messagesSent=0; *hitMTUCap=false; maxDataBitSize = MTUSize - UDP_HEADER_SIZE; if ( encryptor.IsKeySet() ) maxDataBitSize -= 16; // Extra data for the encryptor maxDataBitSize <<= 3; *reliableDataSent = false; if (acknowlegements.Size()>0) { output->Write(true); output->Write(remoteSystemTime); messagesSent++; wroteAcks=true; statistics.acknowlegementBitsSent +=acknowlegements.Serialize(output, (MTUSize-UDP_HEADER_SIZE)*8-1, true); // writeFalseToHeader=false; } else { wroteAcks=false; output->Write(false); // writeFalseToHeader=true; } wroteData=false; while ( resendQueue.Size() > 0 ) { internalPacket = resendQueue.Peek(); RakAssert(internalPacket->messageNumberAssigned==true); // The resend Queue can have holes. This is so we can deallocate blocks without having to compress the array if ( internalPacket->nextActionTime == 0 ) { if (packetlossThisSampleResendCount>0) packetlossThisSampleResendCount--; resendQueue.Pop(); rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); continue; // This was a hole } if ( resendQueue.Peek()->nextActionTime < time ) { internalPacket = resendQueue.Pop(); nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength; if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize ) { resendQueue.PushAtHead( internalPacket ); // Not enough room to use this packet after all! *hitMTUCap=true; goto END_OF_GENERATE_FRAME; } RakAssert(internalPacket->priority >= 0); #ifdef _DEBUG_LOGGER { char temp[256]; sprintf(temp, "%p: Resending packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength); OutputDebugStr(temp); } #endif for (messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, sendPacketCount, systemAddress, (RakNetTime)(time/(RakNetTimeNS)1000), true); // Write to the output bitstream statistics.messageResends++; statistics.messageDataBitsResent += internalPacket->dataBitLength; // if (writeFalseToHeader) // { // output->Write(false); // writeFalseToHeader=false; // } if (wroteData==false) { wroteData=true; output->Write(true); // Write our own system time for ping calculations for flow control output->Write((RemoteSystemTimeType)(time / (RakNetTimeNS)1000)); } statistics.messagesTotalBitsResent += WriteToBitStreamFromInternalPacket( output, internalPacket, time ); internalPacket->packetNumber=sendPacketCount; messagesSent++; *reliableDataSent = true; statistics.packetsContainingOnlyAcknowlegementsAndResends++; // printf("internalPacket->messageNumber=%i time=%i timeBetween=%i\n", internalPacket->messageNumber, (RakNetTime)(time/(RakNetTimeNS)1000), (RakNetTime)(timeBetweenPackets/(RakNetTimeNS)1000)); // Using a one second resend for the 2nd resend on fixes abnormal disconnections due to flooding internalPacket->nextActionTime = time + (RakNetTimeNS)1000000; //printf("PACKETLOSS\n "); packetlossThisSample=true; //printf("packetlossThisSample=true\n"); if (packetlossThisSampleResendCount==0) { backoffThisSample=true; packetlossThisSampleResendCount=resendQueue.Size(); } else { packetlossThisSampleResendCount--; } // Put the packet back into the resend list at the correct spot // Don't make a copy since I'm reinserting an allocated struct InsertPacketIntoResendList( internalPacket, time, false, false ); } else { break; } } onlySendUnreliable = false; // From highest to lowest priority, fill up the output bitstream from the send lists for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { while ( sendPacketSet[ i ].Size() ) { internalPacket = sendPacketSet[ i ].Pop(); // REMOVEME // if (internalPacket->messageNumber > 30000) // { // int a=5; // } nextPacketBitLength = GetBitStreamHeaderLength( internalPacket ) + internalPacket->dataBitLength; if (unreliableTimeout!=0 && (internalPacket->reliability==UNRELIABLE || internalPacket->reliability==UNRELIABLE_SEQUENCED) && time > internalPacket->creationTime+(RakNetTimeNS)unreliableTimeout) { // Unreliable packets are deleted rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); continue; } if ( output->GetNumberOfBitsUsed() + nextPacketBitLength > maxDataBitSize ) { // This output won't fit. *hitMTUCap=true; sendPacketSet[ i ].PushAtHead( internalPacket ); // Push this back at the head so it is the next thing to go out break; } if ( internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) isReliable = true; else isReliable = false; // Write to the output bitstream statistics.messagesSent[ i ] ++; statistics.messageDataBitsSent[ i ] += internalPacket->dataBitLength; #ifdef _DEBUG_LOGGER { char temp[256]; sprintf(temp, "%p: Sending packet %i data: %i bitlen: %i\n", this, internalPacket->messageNumber, (unsigned char) internalPacket->data[0], internalPacket->dataBitLength); OutputDebugStr(temp); } #endif for (messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++) messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, sendPacketCount, systemAddress, (RakNetTime)(time/(RakNetTimeNS)1000), true); // if (writeFalseToHeader) // { // output->Write(false); // writeFalseToHeader=false; // } if (wroteData==false) { wroteData=true; output->Write(true); // Write our own system time for ping calculations for flow control output->Write((RemoteSystemTimeType)(time / (RakNetTimeNS)1000)); } // I assign the message number in the order the messages are sent, rather than the order they are created. // This fixes a bug where I was formerly creating a huge number of split packets, then sending on a different ordering channel on a higher priority. // This would cause a huge gap on the recipient for receivedPacketsBaseIndex causing performance problems and data timeout RakAssert(internalPacket->messageNumber==(MessageNumberType)-1); RakAssert(internalPacket->messageNumberAssigned==false); internalPacket->messageNumberAssigned=true; internalPacket->messageNumber=sendMessageNumberIndex; sendMessageNumberIndex++; #if defined (DEBUG_SPLIT_PACKET_PROBLEMS) // if (internalPacket->splitPacketId!=66) #endif statistics.messageTotalBitsSent[ i ] += WriteToBitStreamFromInternalPacket( output, internalPacket, time ); //output->PrintBits(); internalPacket->packetNumber=sendPacketCount; messagesSent++; if ( isReliable ) { // Reliable packets are saved to resend later reliableBits += internalPacket->dataBitLength; // printf("internalPacket->messageNumber=%i time=%i timeBetween=%i\n", internalPacket->messageNumber, (RakNetTime)(time/(RakNetTimeNS)1000), (RakNetTime)(timeBetweenPackets/(RakNetTimeNS)1000)); if (ackPingSum==0) internalPacket->nextActionTime = time + (RakNetTimeNS)1000000; else internalPacket->nextActionTime = time + (RakNetTimeNS)100000 + (ackPingSum>>7); #if defined (DEBUG_SPLIT_PACKET_PROBLEMS) // if (internalPacket->splitPacketId==66) // internalPacket->nextActionTime+=1000000; #endif resendList.Insert( internalPacket->messageNumber, internalPacket); //printf("ackTimeIncrement=%i\n", ackTimeIncrement/1000); InsertPacketIntoResendList( internalPacket, time, false, true); *reliableDataSent = true; } else { // Unreliable packets are deleted rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); } } } END_OF_GENERATE_FRAME: ; // if (output->GetNumberOfBitsUsed()>0) // { // Update the throttle with the header // bytesSent+=output->GetNumberOfBytesUsed() + UDP_HEADER_SIZE; //} if (wroteData==false) { output->Write(false); } if (wroteAcks || wroteData) sendPacketCount++; return wroteAcks || wroteData; } //------------------------------------------------------------------------------------------------------- // Are we waiting for any data to be sent out or be processed by the player? //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsOutgoingDataWaiting(void) { unsigned i; for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { if (sendPacketSet[ i ].Size() > 0) return true; } return acknowlegements.Size() > 0 || resendList.IsEmpty()==false;// || outputQueue.Size() > 0 || orderingList.Size() > 0 || splitPacketChannelList.Size() > 0; } bool ReliabilityLayer::IsReliableOutgoingDataWaiting(void) { unsigned i,j; for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { for (j=0; j < sendPacketSet[ i ].Size(); j++) { if (sendPacketSet[ i ][ j ]->reliability==RELIABLE_ORDERED || sendPacketSet[ i ][ j ]->reliability==RELIABLE_SEQUENCED || sendPacketSet[ i ][ j ]->reliability==RELIABLE) return true; } } return /*acknowlegements.Size() > 0 ||*/ resendList.IsEmpty()==false;// || outputQueue.Size() > 0 || orderingList.Size() > 0 || splitPacketChannelList.Size() > 0; } bool ReliabilityLayer::AreAcksWaiting(void) { return acknowlegements.Size() > 0; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::ApplyNetworkSimulator( double _maxSendBPS, RakNetTime _minExtraPing, RakNetTime _extraPingVariance ) { #ifndef _RELEASE maxSendBPS=_maxSendBPS; minExtraPing=_minExtraPing; extraPingVariance=_extraPingVariance; // if (ping < (unsigned int)(minExtraPing+extraPingVariance)*2) // ping=(minExtraPing+extraPingVariance)*2; #endif } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetSplitMessageProgressInterval(int interval) { splitMessageProgressInterval=interval; } //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SetUnreliableTimeout(RakNetTime timeoutMS) { unreliableTimeout=(RakNetTimeNS)timeoutMS*(RakNetTimeNS)1000; } //------------------------------------------------------------------------------------------------------- // This will return true if we should not send at this time //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsSendThrottled( int MTUSize ) { (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( RakNetTimeNS time ) { (void) time; } //------------------------------------------------------------------------------------------------------- // Increase the window size //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::UpdateWindowFromAck( RakNetTimeNS time ) { (void) time; } //------------------------------------------------------------------------------------------------------- // Does what the function name says //------------------------------------------------------------------------------------------------------- unsigned ReliabilityLayer::RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, RakNetTimeNS time ) { (void) time; InternalPacket * internalPacket; //InternalPacket *temp; PacketReliability reliability; // What type of reliability algorithm to use with this packet unsigned char orderingChannel; // What ordering channel this packet is on, if the reliability type uses ordering channels OrderingIndexType orderingIndex; // The ID used as identification for ordering channels // unsigned j; bool deleted; deleted=resendList.Delete(messageNumber, internalPacket); if (deleted) { reliability = internalPacket->reliability; orderingChannel = internalPacket->orderingChannel; orderingIndex = internalPacket->orderingIndex; // delete [] internalPacket->data; // internalPacketPool.ReleasePointer( internalPacket ); internalPacket->nextActionTime=0; // Will be freed in the update function return 0; // Rarely used and thus disabled for speed /* // If the deleted packet was reliable sequenced, also delete all older reliable sequenced resends on the same ordering channel. // This is because we no longer need to send these. if ( reliability == RELIABLE_SEQUENCED ) { unsigned j = 0; while ( j < resendList.Size() ) { internalPacket = resendList[ j ]; if ( internalPacket && internalPacket->reliability == RELIABLE_SEQUENCED && internalPacket->orderingChannel == orderingChannel && IsOlderOrderedPacket( internalPacket->orderingIndex, orderingIndex ) ) { // Delete the packet delete [] internalPacket->data; internalPacketPool.ReleasePointer( internalPacket ); resendList[ j ] = 0; // Generate a hole } j++; } } */ } else { statistics.duplicateAcknowlegementsReceived++; } return (unsigned)-1; } //------------------------------------------------------------------------------------------------------- // Acknowledge receipt of the packet with the specified messageNumber //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SendAcknowledgementPacket( const MessageNumberType messageNumber, RakNetTimeNS time ) { (void) time; statistics.acknowlegementsSent++; acknowlegements.Insert(messageNumber); } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and figure out how many header bits would be // written. Returns that number //------------------------------------------------------------------------------------------------------- int ReliabilityLayer::GetBitStreamHeaderLength( const InternalPacket *const internalPacket ) { #ifdef _DEBUG assert( internalPacket ); #endif int bitLength; bitLength=sizeof(MessageNumberType)*8; // Write the PacketReliability. This is encoded in 3 bits //bitStream->WriteBits((unsigned char*)&(internalPacket->reliability), 3, true); bitLength += 3; // If the reliability requires an ordering channel and ordering index, we Write those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) //bitStream->WriteBits((unsigned char*)&(internalPacket->orderingChannel), 5, true); bitLength+=5; // ordering index is one byte //bitStream->WriteCompressed(internalPacket->orderingIndex); bitLength+=sizeof(OrderingIndexType)*8; } // if (internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability==RELIABLE_SEQUENCED) // bitLength+=8*sizeof(RemoteSystemTimeType); // Write if this is a split packet (1 bit) bool isSplitPacket = internalPacket->splitPacketCount > 0; //bitStream->Write(isSplitPacket); bitLength += 1; if ( isSplitPacket ) { // split packet indices are two bytes (so one packet can be split up to 65535 // times - maximum packet size would be about 500 * 65535) //bitStream->Write(internalPacket->splitPacketId); //bitStream->WriteCompressed(internalPacket->splitPacketIndex); //bitStream->WriteCompressed(internalPacket->splitPacketCount); bitLength += (sizeof(SplitPacketIdType) + sizeof(SplitPacketIndexType) * 2) * 8; } // Write how many bits the packet data is. Stored in an unsigned short and // read from 16 bits //bitStream->WriteBits((unsigned char*)&(internalPacket->dataBitLength), 16, true); // Read how many bits the packet data is. Stored in 16 bits bitLength += 16; // Byte alignment //bitLength += 8 - ((bitLength -1) %8 + 1); return bitLength; } //------------------------------------------------------------------------------------------------------- // Parse an internalPacket and create a bitstream to represent this data //------------------------------------------------------------------------------------------------------- BitSize_t ReliabilityLayer::WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket, RakNetTimeNS curTime ) { (void) curTime; #ifdef _DEBUG assert( bitStream && internalPacket ); #endif BitSize_t start = bitStream->GetNumberOfBitsUsed(); const unsigned char c = (unsigned char) internalPacket->reliability; // testing //if (internalPacket->reliability==UNRELIABLE) // printf("Sending unreliable packet %i\n", internalPacket->messageNumber); //else if (internalPacket->reliability==RELIABLE_SEQUENCED || internalPacket->reliability==RELIABLE_ORDERED || internalPacket->reliability==RELIABLE) // printf("Sending reliable packet number %i\n", internalPacket->messageNumber); //bitStream->AlignWriteToByteBoundary(); // Write the message number (2 bytes) bitStream->Write( internalPacket->messageNumber ); // REMOVEME // if (internalPacket->messageNumber > 30000) // { // int a=5; // } // Acknowledgment packets have no more data than the messageNumber and whether it is anacknowledgment #ifdef _DEBUG assert( internalPacket->dataBitLength > 0 ); #endif // Write the PacketReliability. This is encoded in 3 bits bitStream->WriteBits( (const unsigned char *)&c, 3, true ); // If the reliability requires an ordering channel and ordering index, we Write those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) bitStream->WriteBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5, true ); // One or two bytes bitStream->Write( internalPacket->orderingIndex ); } // if (internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability==RELIABLE_SEQUENCED) //{ // // Write the time in reliable packets for flow control // bitStream->Write((RemoteSystemTimeType) (curTime/(RakNetTimeNS)1000)); // } // Write if this is a split packet (1 bit) bool isSplitPacket = internalPacket->splitPacketCount > 0; bitStream->Write( isSplitPacket ); if ( isSplitPacket ) { bitStream->Write( internalPacket->splitPacketId ); bitStream->WriteCompressed( internalPacket->splitPacketIndex ); bitStream->WriteCompressed( internalPacket->splitPacketCount ); } // Write how many bits the packet data is. Stored in 13 bits #ifdef _DEBUG assert( BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ); // I never send more than MTU_SIZE bytes #endif unsigned short length = ( unsigned short ) internalPacket->dataBitLength; // Ignore the 2 high bytes for WriteBits bitStream->WriteCompressed( length ); // Write the actual data. bitStream->WriteAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) ); //bitStream->WriteBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength); //printf("WRITE:\n"); //bitStream->PrintBits(); return bitStream->GetNumberOfBitsUsed() - start; } //------------------------------------------------------------------------------------------------------- // Parse a bitstream and create an internal packet to represent this data //------------------------------------------------------------------------------------------------------- InternalPacket* ReliabilityLayer::CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, RakNetTimeNS time ) { bool bitStreamSucceeded; InternalPacket* internalPacket; if ( bitStream->GetNumberOfUnreadBits() < (int) sizeof( internalPacket->messageNumber ) * 8 ) return 0; // leftover bits internalPacket = internalPacketPool.Allocate(); //printf("READ:\n"); //bitStream->PrintBits(); if (internalPacket==0) { // Out of memory RakAssert(0); return 0; } #ifdef _DEBUG // Remove accessing undefined memory error memset( internalPacket, 255, sizeof( InternalPacket ) ); #endif internalPacket->creationTime = time; //bitStream->AlignReadToByteBoundary(); // Read the packet number (4 bytes) bitStreamSucceeded = bitStream->Read( internalPacket->messageNumber ); // REMOVEME // if (internalPacket->messageNumber > 30000) // { // int a=5; // } #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif // Read the PacketReliability. This is encoded in 3 bits unsigned char reliability; bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) ( &( reliability ) ), 3 ); internalPacket->reliability = ( const PacketReliability ) reliability; #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets // assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } // If the reliability requires an ordering channel and ordering index, we read those. if ( internalPacket->reliability == UNRELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_SEQUENCED || internalPacket->reliability == RELIABLE_ORDERED ) { // ordering channel encoded in 5 bits (from 0 to 31) bitStreamSucceeded = bitStream->ReadBits( ( unsigned char* ) & ( internalPacket->orderingChannel ), 5 ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } bitStreamSucceeded = bitStream->Read( internalPacket->orderingIndex ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } } // if (internalPacket->reliability == RELIABLE || internalPacket->reliability == RELIABLE_ORDERED || internalPacket->reliability==RELIABLE_SEQUENCED) // { // // Read the time in reliable packets for flow control // bitStream->Read(internalPacket->remoteSystemTime); // } // Read if this is a split packet (1 bit) bool isSplitPacket; bitStreamSucceeded = bitStream->Read( isSplitPacket ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } if ( isSplitPacket ) { bitStreamSucceeded = bitStream->Read( internalPacket->splitPacketId ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets // assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketIndex ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } bitStreamSucceeded = bitStream->ReadCompressed( internalPacket->splitPacketCount ); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } } else internalPacket->splitPacketIndex = internalPacket->splitPacketCount = 0; // Optimization - do byte alignment here //unsigned char zero; //bitStream->ReadBits(&zero, 8 - (bitStream->GetNumberOfBitsUsed() %8)); //assert(zero==0); unsigned short length; bitStreamSucceeded = bitStream->ReadCompressed( length ); // Read into an unsigned short. Otherwise the data would be offset too high by two bytes #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { internalPacketPool.Release( internalPacket ); return 0; } internalPacket->dataBitLength = length; #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets arriving when the sender does not know we just connected, which is an unavoidable condition sometimes // assert( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ); #endif if ( ! ( internalPacket->dataBitLength > 0 && BITS_TO_BYTES( internalPacket->dataBitLength ) < MAXIMUM_MTU_SIZE ) ) { // 10/08/05 - internalPacket->data wasn't allocated yet // delete [] internalPacket->data; internalPacketPool.Release( internalPacket ); return 0; } // Allocate memory to hold our data internalPacket->data = (unsigned char*) rakMalloc( (size_t) BITS_TO_BYTES( internalPacket->dataBitLength ) ); //printf("Allocating %i\n", internalPacket->data); // Set the last byte to 0 so if ReadBits does not read a multiple of 8 the last bits are 0'ed out internalPacket->data[ BITS_TO_BYTES( internalPacket->dataBitLength ) - 1 ] = 0; // Read the data the packet holds bitStreamSucceeded = bitStream->ReadAlignedBytes( ( unsigned char* ) internalPacket->data, BITS_TO_BYTES( internalPacket->dataBitLength ) ); //bitStreamSucceeded = bitStream->ReadBits((unsigned char*)internalPacket->data, internalPacket->dataBitLength); #ifdef _DEBUG // 10/08/05 - Disabled assert since this hits from offline packets //assert( bitStreamSucceeded ); #endif if ( bitStreamSucceeded == false ) { rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); return 0; } // PRINTING UNRELIABLE STRINGS // if (internalPacket->data && internalPacket->dataBitLength>5*8) // printf("Received %s\n",internalPacket->data); return internalPacket; } //------------------------------------------------------------------------------------------------------- // Get the SHA1 code //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::GetSHA1( unsigned char * const buffer, unsigned int nbytes, char code[ SHA1_LENGTH ] ) { CSHA1 sha1; sha1.Reset(); sha1.Update( ( unsigned char* ) buffer, nbytes ); sha1.Final(); memcpy( code, sha1.GetHash(), SHA1_LENGTH ); } //------------------------------------------------------------------------------------------------------- // Check the SHA1 code //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::CheckSHA1( char code[ SHA1_LENGTH ], unsigned char * const buffer, unsigned int nbytes ) { char code2[ SHA1_LENGTH ]; GetSHA1( buffer, nbytes, code2 ); for ( int i = 0; i < SHA1_LENGTH; i++ ) if ( code[ i ] != code2[ i ] ) return false; return true; } //------------------------------------------------------------------------------------------------------- // Search the specified list for sequenced packets on the specified ordering // stream, optionally skipping those with splitPacketId, and delete them //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::List&theList, int splitPacketId ) { unsigned i = 0; while ( i < theList.Size() ) { if ( ( theList[ i ]->reliability == RELIABLE_SEQUENCED || theList[ i ]->reliability == UNRELIABLE_SEQUENCED ) && theList[ i ]->orderingChannel == orderingChannel && ( splitPacketId == -1 || theList[ i ]->splitPacketId != (unsigned int) splitPacketId ) ) { InternalPacket * internalPacket = theList[ i ]; theList.RemoveAtIndex( i ); rakFree(internalPacket->data); internalPacketPool.Release( 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 ]->orderingChannel == orderingChannel ) { internalPacket = theList[ i ]; theList.RemoveAtIndex( i ); rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); listSize--; } else i++; } } //------------------------------------------------------------------------------------------------------- // Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex ) { OrderingIndexType maxRange = (OrderingIndexType) -1; if ( waitingForPacketOrderingIndex > maxRange/2 ) { if ( newPacketOrderingIndex >= waitingForPacketOrderingIndex - maxRange/2+1 && newPacketOrderingIndex < waitingForPacketOrderingIndex ) { return true; } } else if ( newPacketOrderingIndex >= ( OrderingIndexType ) ( waitingForPacketOrderingIndex - (( OrderingIndexType ) maxRange/2+1) ) || newPacketOrderingIndex < waitingForPacketOrderingIndex ) { return true; } // Old packet return false; } //------------------------------------------------------------------------------------------------------- // Split the passed packet into chunks under MTU_SIZEbytes (including headers) and save those new chunks // Optimized version //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::SplitPacket( InternalPacket *internalPacket, int MTUSize ) { // Doing all sizes in bytes in this function so I don't write partial bytes with split packets internalPacket->splitPacketCount = 1; // This causes GetBitStreamHeaderLength to account for the split packet header unsigned int headerLength = (unsigned int) BITS_TO_BYTES( GetBitStreamHeaderLength( internalPacket ) ); unsigned int dataByteLength = (unsigned int) BITS_TO_BYTES( internalPacket->dataBitLength ); int maxDataSize; int maximumSendBlock, byteOffset, bytesToSend; SplitPacketIndexType splitPacketIndex; int i; InternalPacket **internalPacketArray; maxDataSize = MTUSize - UDP_HEADER_SIZE; if ( encryptor.IsKeySet() ) maxDataSize -= 16; // Extra data for the encryptor #ifdef _DEBUG // Make sure we need to split the packet to begin with assert( dataByteLength > maxDataSize - headerLength ); #endif // How much to send in the largest block maximumSendBlock = maxDataSize - headerLength; // Calculate how many packets we need to create internalPacket->splitPacketCount = ( ( dataByteLength - 1 ) / ( maximumSendBlock ) + 1 ); statistics.totalSplits += internalPacket->splitPacketCount; // Optimization // internalPacketArray = new InternalPacket*[internalPacket->splitPacketCount]; bool usedAlloca=false; #if !defined(_XBOX360) if (sizeof( InternalPacket* ) * internalPacket->splitPacketCount < MAX_ALLOCA_STACK_ALLOCATION) { internalPacketArray = ( InternalPacket** ) alloca( sizeof( InternalPacket* ) * internalPacket->splitPacketCount ); usedAlloca=true; } else #endif internalPacketArray = (InternalPacket**) rakMalloc( sizeof(InternalPacket*) * internalPacket->splitPacketCount ); for ( i = 0; i < ( int ) internalPacket->splitPacketCount; i++ ) { internalPacketArray[ i ] = internalPacketPool.Allocate(); //internalPacketArray[ i ] = (InternalPacket*) alloca( sizeof( InternalPacket ) ); // internalPacketArray[ i ] = sendPacketSet[internalPacket->priority].WriteLock(); memcpy( internalPacketArray[ i ], internalPacket, sizeof( InternalPacket ) ); } // This identifies which packet this is in the set splitPacketIndex = 0; // Do a loop to send out all the packets do { byteOffset = splitPacketIndex * maximumSendBlock; bytesToSend = dataByteLength - byteOffset; if ( bytesToSend > maximumSendBlock ) bytesToSend = maximumSendBlock; // Copy over our chunk of data internalPacketArray[ splitPacketIndex ]->data = (unsigned char*) rakMalloc( bytesToSend ); memcpy( internalPacketArray[ splitPacketIndex ]->data, internalPacket->data + byteOffset, bytesToSend ); if ( bytesToSend != maximumSendBlock ) internalPacketArray[ splitPacketIndex ]->dataBitLength = internalPacket->dataBitLength - splitPacketIndex * ( maximumSendBlock << 3 ); else internalPacketArray[ splitPacketIndex ]->dataBitLength = bytesToSend << 3; internalPacketArray[ splitPacketIndex ]->splitPacketIndex = splitPacketIndex; internalPacketArray[ splitPacketIndex ]->splitPacketId = splitPacketId; internalPacketArray[ splitPacketIndex ]->splitPacketCount = internalPacket->splitPacketCount; if ( splitPacketIndex > 0 ) // For the first split packet index we keep the messageNumber already assigned { // For every further packet we use a new messageNumber. // Note that all split packets are reliable // internalPacketArray[ splitPacketIndex ]->messageNumber = sendMessageNumberIndex; internalPacketArray[ splitPacketIndex ]->messageNumber = (MessageNumberType) -1; internalPacketArray[ splitPacketIndex ]->messageNumberAssigned=false; //if ( ++messageNumber == RECEIVED_PACKET_LOG_LENGTH ) // messageNumber = 0; // ++sendMessageNumberIndex; } // Add the new packet to send list at the correct priority // sendQueue[internalPacket->priority].Insert(newInternalPacket); // SHOW SPLIT PACKET GENERATION // if (splitPacketIndex % 100 == 0) // printf("splitPacketIndex=%i\n",splitPacketIndex); //} while(++splitPacketIndex < internalPacket->splitPacketCount); } while ( ++splitPacketIndex < internalPacket->splitPacketCount ); splitPacketId++; // It's ok if this wraps to 0 // InternalPacket *workingPacket; // Copy all the new packets into the split packet list for ( i = 0; i < ( int ) internalPacket->splitPacketCount; i++ ) { sendPacketSet[ internalPacket->priority ].Push( internalPacketArray[ i ] ); // workingPacket=sendPacketSet[internalPacket->priority].WriteLock(); // memcpy(workingPacket, internalPacketArray[ i ], sizeof(InternalPacket)); // sendPacketSet[internalPacket->priority].WriteUnlock(); } // Delete the original rakFree(internalPacket->data); internalPacketPool.Release( internalPacket ); if (usedAlloca==false) rakFree(internalPacketArray); } //------------------------------------------------------------------------------------------------------- // Insert a packet into the split packet list //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertIntoSplitPacketList( InternalPacket * internalPacket, RakNetTimeNS time ) { bool objectExists; unsigned index; index=splitPacketChannelList.GetIndexFromKey(internalPacket->splitPacketId, &objectExists); if (objectExists==false) { SplitPacketChannel *newChannel = new SplitPacketChannel; index=splitPacketChannelList.Insert(internalPacket->splitPacketId, newChannel, true); } splitPacketChannelList[index]->splitPacketList.Insert(internalPacket->splitPacketIndex, internalPacket, true); splitPacketChannelList[index]->lastUpdateTime=time; if (splitMessageProgressInterval && splitPacketChannelList[index]->splitPacketList[0]->splitPacketIndex==0 && splitPacketChannelList[index]->splitPacketList.Size()!=splitPacketChannelList[index]->splitPacketList[0]->splitPacketCount && (splitPacketChannelList[index]->splitPacketList.Size()%splitMessageProgressInterval)==0) { // printf("msgID=%i Progress %i/%i Partsize=%i\n", // splitPacketChannelList[index]->splitPacketList[0]->data[0], // splitPacketChannelList[index]->splitPacketList.Size(), // internalPacket->splitPacketCount, // BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength)); // Return ID_DOWNLOAD_PROGRESS // Write splitPacketIndex (SplitPacketIndexType) // Write splitPacketCount (SplitPacketIndexType) // Write byteLength (4) // Write data, splitPacketChannelList[index]->splitPacketList[0]->data InternalPacket *progressIndicator = internalPacketPool.Allocate(); unsigned int length = sizeof(MessageID) + sizeof(unsigned int)*2 + sizeof(unsigned int) + (unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength); progressIndicator->data = (unsigned char*) rakMalloc( length ); progressIndicator->dataBitLength=BYTES_TO_BITS(length); progressIndicator->data[0]=(MessageID)ID_DOWNLOAD_PROGRESS; unsigned int temp; temp=splitPacketChannelList[index]->splitPacketList.Size(); memcpy(progressIndicator->data+sizeof(MessageID), &temp, sizeof(unsigned int)); temp=(unsigned int)internalPacket->splitPacketCount; memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*1, &temp, sizeof(unsigned int)); temp=(unsigned int) BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength); memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*2, &temp, sizeof(unsigned int)); memcpy(progressIndicator->data+sizeof(MessageID)+sizeof(unsigned int)*3, splitPacketChannelList[index]->splitPacketList[0]->data, (size_t) BITS_TO_BYTES(splitPacketChannelList[index]->splitPacketList[0]->dataBitLength)); outputQueue.Push(progressIndicator); } } //------------------------------------------------------------------------------------------------------- // Take all split chunks with the specified splitPacketId and try to //reconstruct a packet. If we can, allocate and return it. Otherwise return 0 // Optimized version //------------------------------------------------------------------------------------------------------- InternalPacket * ReliabilityLayer::BuildPacketFromSplitPacketList( SplitPacketIdType splitPacketId, RakNetTimeNS time ) { unsigned i, j; unsigned byteProgress; InternalPacket * internalPacket; bool objectExists; i=splitPacketChannelList.GetIndexFromKey(splitPacketId, &objectExists); #ifdef _DEBUG assert(objectExists); #endif if (splitPacketChannelList[i]->splitPacketList.Size()==splitPacketChannelList[i]->splitPacketList[0]->splitPacketCount) { // Reconstruct internalPacket = CreateInternalPacketCopy( splitPacketChannelList[i]->splitPacketList[0], 0, 0, time ); internalPacket->dataBitLength=0; for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) internalPacket->dataBitLength+=splitPacketChannelList[i]->splitPacketList[j]->dataBitLength; internalPacket->data = (unsigned char*) rakMalloc( (size_t) BITS_TO_BYTES( internalPacket->dataBitLength ) ); byteProgress=0; for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { memcpy(internalPacket->data+byteProgress, splitPacketChannelList[i]->splitPacketList[j]->data, (size_t) BITS_TO_BYTES(splitPacketChannelList[i]->splitPacketList[j]->dataBitLength)); byteProgress+=(unsigned int) BITS_TO_BYTES(splitPacketChannelList[i]->splitPacketList[j]->dataBitLength); } for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { rakFree(splitPacketChannelList[i]->splitPacketList[j]->data); internalPacketPool.Release(splitPacketChannelList[i]->splitPacketList[j]); } delete splitPacketChannelList[i]; splitPacketChannelList.RemoveAtIndex(i); return internalPacket; } return 0; } // Delete any unreliable split packets that have long since expired void ReliabilityLayer::DeleteOldUnreliableSplitPackets( RakNetTimeNS time ) { unsigned i,j; i=0; while (i < splitPacketChannelList.Size()) { if (time > splitPacketChannelList[i]->lastUpdateTime + (RakNetTimeNS)timeoutTime*(RakNetTimeNS)1000 && (splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE || splitPacketChannelList[i]->splitPacketList[0]->reliability==UNRELIABLE_SEQUENCED)) { for (j=0; j < splitPacketChannelList[i]->splitPacketList.Size(); j++) { delete [] splitPacketChannelList[i]->splitPacketList[j]->data; internalPacketPool.Release(splitPacketChannelList[i]->splitPacketList[j]); } delete splitPacketChannelList[i]; splitPacketChannelList.RemoveAtIndex(i); #if defined(DEBUG_SPLIT_PACKET_PROBLEMS) printf("DeleteOldUnreliableSplitPackets called, split packet will never complete\n"); #endif } else i++; } } //------------------------------------------------------------------------------------------------------- // Creates a copy of the specified internal packet with data copied from the original starting at dataByteOffset for dataByteLength bytes. // Does not copy any split data parameters as that information is always generated does not have any reason to be copied //------------------------------------------------------------------------------------------------------- InternalPacket * ReliabilityLayer::CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, RakNetTimeNS time ) { InternalPacket * copy = internalPacketPool.Allocate(); #ifdef _DEBUG // Remove accessing undefined memory error memset( copy, 255, sizeof( InternalPacket ) ); #endif // Copy over our chunk of data if ( dataByteLength > 0 ) { copy->data = (unsigned char*) rakMalloc( BITS_TO_BYTES(dataByteLength ) ); memcpy( copy->data, original->data + dataByteOffset, dataByteLength ); } else copy->data = 0; copy->dataBitLength = dataByteLength << 3; copy->creationTime = time; copy->nextActionTime = 0; copy->orderingIndex = original->orderingIndex; copy->orderingChannel = original->orderingChannel; copy->messageNumber = original->messageNumber; copy->priority = original->priority; copy->reliability = original->reliability; // REMOVEME // if (copy->messageNumber > 30000) // { // int a=5; // } 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 ) { #ifdef _DEBUG assert( internalPacket->orderingChannel < NUMBER_OF_ORDERED_STREAMS ); #endif if ( internalPacket->orderingChannel >= NUMBER_OF_ORDERED_STREAMS ) { return; } DataStructures::LinkedList *theList; if ( internalPacket->orderingChannel >= orderingList.Size() || orderingList[ internalPacket->orderingChannel ] == 0 ) { // Need a linked list in this index orderingList.Replace( new DataStructures::LinkedList, 0, internalPacket->orderingChannel ); theList=orderingList[ internalPacket->orderingChannel ]; } else { // Have a linked list in this index if ( orderingList[ internalPacket->orderingChannel ]->Size() == 0 ) { theList=orderingList[ internalPacket->orderingChannel ]; } else { theList = GetOrderingListAtOrderingStream( internalPacket->orderingChannel ); } } theList->End(); theList->Add(internalPacket); } //------------------------------------------------------------------------------------------------------- // Inserts a packet into the resend list in order //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::InsertPacketIntoResendList( InternalPacket *internalPacket, RakNetTimeNS time, bool makeCopyOfInternalPacket, bool firstResend ) { // lastAckTime is the time we last got an acknowledgment - however we also initialize the value if this is the first resend and // either we never got an ack before or we are inserting into an empty resend queue if ( firstResend && (lastAckTime == 0 || resendList.IsEmpty())) { lastAckTime = time; // Start the timer for the ack of this packet if we aren't already waiting for an ack } if (makeCopyOfInternalPacket) { InternalPacket *pool=internalPacketPool.Allocate(); //printf("Adding %i\n", internalPacket->data); memcpy(pool, internalPacket, sizeof(InternalPacket)); resendQueue.Push( pool ); } else { resendQueue.Push( internalPacket ); } RakAssert(internalPacket->nextActionTime!=0); } //------------------------------------------------------------------------------------------------------- // If Read returns -1 and this returns true then a modified packet was detected //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsCheater( void ) const { return cheater; } //------------------------------------------------------------------------------------------------------- // Were you ever unable to deliver a packet despite retries? //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::IsDeadConnection( void ) const { return deadConnection; } //------------------------------------------------------------------------------------------------------- // Causes IsDeadConnection to return true //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::KillConnection( void ) { deadConnection=true; } //------------------------------------------------------------------------------------------------------- // Statistics //------------------------------------------------------------------------------------------------------- RakNetStatistics * const ReliabilityLayer::GetStatistics( void ) { unsigned i; for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { statistics.messageSendBuffer[i] = sendPacketSet[i].Size(); } statistics.acknowlegementsPending = acknowlegements.Size(); if (lastUpdateTime>histogramStart && histogramBitsSent >0) statistics.bitsPerSecond=(double)((long double)histogramBitsSent / ((long double) (lastUpdateTime-histogramStart) / 1000000.0f)); else statistics.bitsPerSecond=0.0; statistics.messagesWaitingForReassembly = 0; for (i=0; i < splitPacketChannelList.Size(); i++) statistics.messagesWaitingForReassembly+=splitPacketChannelList[i]->splitPacketList.Size(); statistics.internalOutputQueueSize = outputQueue.Size(); //statistics.lossySize = lossyWindowSize == MAXIMUM_WINDOW_SIZE + 1 ? 0 : lossyWindowSize; // statistics.lossySize=0; // The connection is full if we are continuously sending data and we had to throttle back recently. statistics.bandwidthExceeded = continuousSend && (lastUpdateTime-lastTimeBetweenPacketsIncrease) > (RakNetTimeNS) 1000000; statistics.messagesOnResendQueue = GetResendListDataSize(); return &statistics; } //------------------------------------------------------------------------------------------------------- // Returns the number of packets in the resend queue, not counting holes //------------------------------------------------------------------------------------------------------- unsigned int ReliabilityLayer::GetResendListDataSize(void) const { /* unsigned int i, count; for (count=0, i=0; i < resendList.Size(); i++) if (resendList[i]!=0) count++; return count; */ // Not accurate but thread-safe. The commented version might crash if the queue is cleared while we loop through it return resendList.Size(); } //------------------------------------------------------------------------------------------------------- // Process threaded commands //------------------------------------------------------------------------------------------------------- void ReliabilityLayer::UpdateThreadedMemory(void) { if ( freeThreadedMemoryOnNextUpdate ) { freeThreadedMemoryOnNextUpdate = false; FreeThreadedMemory(); } } //------------------------------------------------------------------------------------------------------- bool ReliabilityLayer::AckTimeout(RakNetTimeNS curTime) { return curTime > lastAckTime && lastAckTime && curTime - lastAckTime > (RakNetTimeNS)timeoutTime*1000; } //------------------------------------------------------------------------------------------------------- RakNetTimeNS ReliabilityLayer::GetNextSendTime(void) const { return nextSendTime; } //------------------------------------------------------------------------------------------------------- RakNetTimeNS ReliabilityLayer::GetTimeBetweenPackets(void) const { return timeBetweenPackets; } //------------------------------------------------------------------------------------------------------- RakNetTimeNS ReliabilityLayer::GetLastTimeBetweenPacketsDecrease(void) const { return lastTimeBetweenPacketsDecrease; } //------------------------------------------------------------------------------------------------------- RakNetTimeNS ReliabilityLayer::GetLastTimeBetweenPacketsIncrease(void) const { return lastTimeBetweenPacketsIncrease; } //------------------------------------------------------------------------------------------------------- RakNetTimeNS ReliabilityLayer::GetAckPing(void) const { return ackPing; } //------------------------------------------------------------------------------------------------------- /* int InternalPacketCompByInternalOrderIndex( InternalPacket * const &key, InternalPacket * const &data ) { int64_t holeCount = (key->messageInternalOrder-data->messageInternalOrder); int64_t absHoleCount = holeCount>0 ? holeCount : -holeCount; MessageNumberType typeRange = (MessageNumberType)-1; if (absHoleCount > typeRange/2) { if (holeCount>0) return -1; else if (holeCount<0) return 1; } else { if (holeCount>0) return 1; else if (holeCount<0) return -1; } if (key->splitPacketIndex>data->splitPacketIndex) return 1; if (key->splitPacketIndexsplitPacketIndex) return -1; return 0; } void ReliabilityLayer::GetUndeliveredMessages(RakNet::BitStream *messages, int MTUSize) { DataStructures::OrderedList undeliveredMessages; unsigned int i,j,k; for (i=0; i < resendQueue.Size(); i++) { if (resendQueue[i]->nextActionTime==0) continue; undeliveredMessages.Insert(resendQueue[i],resendQueue[i],true); } for ( i = 0; i < NUMBER_OF_PRIORITIES; i++ ) { for (j=0; j < sendPacketSet[ i ].Size(); j++) undeliveredMessages.Insert( sendPacketSet[ i ][ j ],sendPacketSet[ i ][ j ],true); } unsigned char zeroBlock[MAXIMUM_MTU_SIZE]; memset(zeroBlock,0,MAXIMUM_MTU_SIZE); unsigned int messagesConcatenated=0; uint64_t totalBitLength; BitSize_t oldWriteOffset; unsigned int lastSplitPacketIndex, lastSplitPacketId; messages->Reset(); messages->Write((unsigned int) undeliveredMessages.Size()); i=0; while (i < undeliveredMessages.Size()) { // Write message size if (undeliveredMessages[i]->splitPacketCount>0) { lastSplitPacketId=undeliveredMessages[i]->splitPacketId; lastSplitPacketIndex=0; j=i; totalBitLength=0; unsigned int headerLength = (unsigned int) BITS_TO_BYTES( GetBitStreamHeaderLength( undeliveredMessages[i] ) ); unsigned int maxDataSize = MTUSize - UDP_HEADER_SIZE; // How much to send in the largest block unsigned int maximumSendBlock = maxDataSize - headerLength; // Calculate the total bit length of all the messages, using the split MTU if not known while (j < undeliveredMessages.Size() && lastSplitPacketId==undeliveredMessages[j]->splitPacketId && undeliveredMessages[j]->splitPacketCount>0) { for (k=lastSplitPacketIndex; k < undeliveredMessages[j]->splitPacketIndex; k++) totalBitLength+=BYTES_TO_BITS(maximumSendBlock); totalBitLength+=undeliveredMessages[j]->dataBitLength; lastSplitPacketIndex=undeliveredMessages[j]->splitPacketIndex+1; j++; } messages->Write((unsigned int) BITS_TO_BYTES(totalBitLength)); while (i < undeliveredMessages.Size() && lastSplitPacketId==undeliveredMessages[i]->splitPacketId && undeliveredMessages[i]->splitPacketCount>0) { // Write blocks of 0 for unknown data for (j=lastSplitPacketIndex; j < undeliveredMessages[i]->splitPacketIndex; j++) messages->WriteAlignedBytes(zeroBlock,BITS_TO_BYTES(undeliveredMessages[i]->dataBitLength)); // Write the data messages->WriteAlignedBytes(undeliveredMessages[i]->data, BITS_TO_BYTES(undeliveredMessages[i]->dataBitLength)); lastSplitPacketIndex=undeliveredMessages[i]->splitPacketIndex+1; messagesConcatenated++; i++; } } else { messages->Write((unsigned int) BITS_TO_BYTES(undeliveredMessages[i]->dataBitLength)); // Write the data messages->WriteAlignedBytes(undeliveredMessages[i]->data, BITS_TO_BYTES(undeliveredMessages[i]->dataBitLength)); i++; } } oldWriteOffset=messages->GetWriteOffset(); messages->SetWriteOffset(0); messages->Write((unsigned int) undeliveredMessages.Size()-messagesConcatenated); messages->SetWriteOffset(oldWriteOffset); } */ //------------------------------------------------------------------------------------------------------- /* void ReliabilityLayer::SetDoFastThroughputReactions(bool fast) { if (fast) timeBetweenPacketsIncreaseMultiplier=TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_FAST; else timeBetweenPacketsIncreaseMultiplier=TIME_BETWEEN_PACKETS_INCREASE_MULTIPLIER_DEFAULT; } */ //------------------------------------------------------------------------------------------------------- #ifdef _MSC_VER #pragma warning( pop ) #endif