597 lines
27 KiB
C++
597 lines
27 KiB
C++
/*
|
|
* Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
/// \file
|
|
/// \brief \b [Internal] Datagram reliable, ordered, unordered and sequenced sends. Flow control. Message splitting, reassembly, and coalescence.
|
|
///
|
|
|
|
|
|
#ifndef __RELIABILITY_LAYER_H
|
|
#define __RELIABILITY_LAYER_H
|
|
|
|
#include "RakMemoryOverride.hpp"
|
|
#include "MTUSize.hpp"
|
|
#include "DS_LinkedList.hpp"
|
|
#include "DS_List.hpp"
|
|
#include "SocketLayer.hpp"
|
|
#include "PacketPriority.hpp"
|
|
#include "DS_Queue.hpp"
|
|
#include "BitStream.hpp"
|
|
#include "InternalPacket.hpp"
|
|
#include "RakNetStatistics.hpp"
|
|
#include "DR_SHA1.hpp"
|
|
#include "DS_OrderedList.hpp"
|
|
#include "DS_RangeList.hpp"
|
|
#include "DS_BPlusTree.hpp"
|
|
#include "DS_MemoryPool.hpp"
|
|
#include "RakNetDefines.hpp"
|
|
#include "DS_Heap.hpp"
|
|
#include "BitStream.hpp"
|
|
#include "NativeFeatureIncludes.hpp"
|
|
#include "SecureHandshake.hpp"
|
|
#include "PluginInterface2.hpp"
|
|
#include "Rand.hpp"
|
|
#include "RakNetSocket2.hpp"
|
|
|
|
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
|
|
#include "CCRakNetUDT.hpp"
|
|
#define INCLUDE_TIMESTAMP_WITH_DATAGRAMS 1
|
|
#else
|
|
#include "CCRakNetSlidingWindow.hpp"
|
|
#define INCLUDE_TIMESTAMP_WITH_DATAGRAMS 0
|
|
#endif
|
|
|
|
/// Number of ordered streams available. You can use up to 32 ordered streams
|
|
#define NUMBER_OF_ORDERED_STREAMS 32 // 2^5
|
|
|
|
#define RESEND_TREE_ORDER 32
|
|
|
|
namespace RakNet {
|
|
|
|
/// Forward declarations
|
|
class PluginInterface2;
|
|
class RakNetRandom;
|
|
typedef uint64_t reliabilityHeapWeightType;
|
|
|
|
// int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data );
|
|
struct SplitPacketChannel//<SplitPacketChannel>
|
|
{
|
|
CCTimeType lastUpdateTime;
|
|
|
|
DataStructures::List<InternalPacket*> splitPacketList;
|
|
|
|
#if PREALLOCATE_LARGE_MESSAGES==1
|
|
InternalPacket *returnedPacket;
|
|
bool gotFirstPacket;
|
|
unsigned int stride;
|
|
unsigned int splitPacketsArrived;
|
|
#else
|
|
// This is here for progress notifications, since progress notifications return the first packet data, if available
|
|
InternalPacket *firstPacket;
|
|
#endif
|
|
|
|
};
|
|
int RAK_DLL_EXPORT SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data );
|
|
|
|
// Helper class
|
|
struct BPSTracker
|
|
{
|
|
BPSTracker();
|
|
~BPSTracker();
|
|
void Reset(const char *file, unsigned int line);
|
|
inline void Push1(CCTimeType time, uint64_t value1) {dataQueue.Push(TimeAndValue2(time,value1),_FILE_AND_LINE_); total1+=value1; lastSec1+=value1;}
|
|
// void Push2(RakNet::TimeUS time, uint64_t value1, uint64_t value2);
|
|
inline uint64_t GetBPS1(CCTimeType time) {(void) time; return lastSec1;}
|
|
inline uint64_t GetBPS1Threadsafe(CCTimeType time) {(void) time; return lastSec1;}
|
|
// uint64_t GetBPS2(RakNetTimeUS time);
|
|
// void GetBPS1And2(RakNetTimeUS time, uint64_t &out1, uint64_t &out2);
|
|
uint64_t GetTotal1(void) const;
|
|
// uint64_t GetTotal2(void) const;
|
|
|
|
struct TimeAndValue2
|
|
{
|
|
TimeAndValue2();
|
|
~TimeAndValue2();
|
|
TimeAndValue2(CCTimeType t, uint64_t v1);
|
|
// TimeAndValue2(RakNet::TimeUS t, uint64_t v1, uint64_t v2);
|
|
// uint64_t value1, value2;
|
|
uint64_t value1;
|
|
CCTimeType time;
|
|
};
|
|
|
|
uint64_t total1, lastSec1;
|
|
// uint64_t total2, lastSec2;
|
|
DataStructures::Queue<TimeAndValue2> dataQueue;
|
|
void ClearExpired1(CCTimeType time);
|
|
// void ClearExpired2(RakNet::TimeUS time);
|
|
};
|
|
|
|
/// Datagram reliable, ordered, unordered and sequenced sends. Flow control. Message splitting, reassembly, and coalescence.
|
|
class ReliabilityLayer//<ReliabilityLayer>
|
|
{
|
|
public:
|
|
|
|
// Constructor
|
|
ReliabilityLayer();
|
|
|
|
// Destructor
|
|
~ReliabilityLayer();
|
|
|
|
/// Resets the layer for reuse
|
|
void Reset( bool resetVariables, int MTUSize, bool _useSecurity );
|
|
|
|
/// Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable packet
|
|
/// Default time is 10,000 or 10 seconds in release and 30,000 or 30 seconds in debug.
|
|
/// \param[in] time Time, in MS
|
|
void SetTimeoutTime( RakNet::TimeMS time );
|
|
|
|
/// Returns the value passed to SetTimeoutTime. or the default if it was never called
|
|
/// \param[out] the value passed to SetTimeoutTime
|
|
RakNet::TimeMS GetTimeoutTime(void);
|
|
|
|
/// 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.
|
|
/// \param[in] buffer The socket data
|
|
/// \param[in] length The length of the socket data
|
|
/// \param[in] systemAddress The player that this data is from
|
|
/// \param[in] messageHandlerList A list of registered plugins
|
|
/// \param[in] MTUSize maximum datagram size
|
|
/// \retval true Success
|
|
/// \retval false Modified packet
|
|
bool HandleSocketReceiveFromConnectedPlayer(
|
|
const char *buffer, unsigned int length, SystemAddress &systemAddress, DataStructures::List<PluginInterface2*> &messageHandlerList, int MTUSize,
|
|
RakNetSocket2 *s, RakNetRandom *rnr, CCTimeType timeRead, BitStream &updateBitStream);
|
|
|
|
/// This allocates bytes and writes a user-level message to those bytes.
|
|
/// \param[out] data The message
|
|
/// \return Returns number of BITS put into the buffer
|
|
BitSize_t Receive( unsigned char**data );
|
|
|
|
/// Puts data on the send queue
|
|
/// \param[in] data The data to send
|
|
/// \param[in] numberOfBitsToSend The length of \a data in bits
|
|
/// \param[in] priority The priority level for the send
|
|
/// \param[in] reliability The reliability type for the send
|
|
/// \param[in] orderingChannel 0 to 31. Specifies what channel to use, for relational ordering and sequencing of packets.
|
|
/// \param[in] makeDataCopy If true \a data will be copied. Otherwise, only a pointer will be stored.
|
|
/// \param[in] MTUSize maximum datagram size
|
|
/// \param[in] currentTime Current time, as per RakNet::GetTimeMS()
|
|
/// \param[in] receipt This number will be returned back with ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS and is only returned with the reliability types that contain RECEIPT in the name
|
|
/// \return True or false for success or failure.
|
|
bool Send( char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, CCTimeType currentTime, uint32_t receipt );
|
|
|
|
/// Call once per game cycle. Handles internal lists and actually does the send.
|
|
/// \param[in] s the communication end point
|
|
/// \param[in] systemAddress The Unique Player Identifier who shouldhave sent some packets
|
|
/// \param[in] MTUSize maximum datagram size
|
|
/// \param[in] time current system time
|
|
/// \param[in] maxBitsPerSecond if non-zero, enforces that outgoing bandwidth does not exceed this amount
|
|
/// \param[in] messageHandlerList A list of registered plugins
|
|
void Update( RakNetSocket2 *s, SystemAddress &systemAddress, int MTUSize, CCTimeType time,
|
|
unsigned bitsPerSecondLimit,
|
|
DataStructures::List<PluginInterface2*> &messageHandlerList,
|
|
RakNetRandom *rnr, BitStream &updateBitStream);
|
|
|
|
/// Were you ever unable to deliver a packet despite retries?
|
|
/// \return true means the connection has been lost. Otherwise not.
|
|
bool IsDeadConnection( void ) const;
|
|
|
|
/// Causes IsDeadConnection to return true
|
|
void KillConnection(void);
|
|
|
|
/// Get Statistics
|
|
/// \return A pointer to a static struct, filled out with current statistical information.
|
|
RakNetStatistics * GetStatistics( RakNetStatistics *rns );
|
|
|
|
///Are we waiting for any data to be sent out or be processed by the player?
|
|
bool IsOutgoingDataWaiting(void);
|
|
bool AreAcksWaiting(void);
|
|
|
|
// Set outgoing lag and packet loss properties
|
|
void ApplyNetworkSimulator( double _maxSendBPS, RakNet::TimeMS _minExtraPing, RakNet::TimeMS _extraPingVariance );
|
|
|
|
/// Returns if you previously called ApplyNetworkSimulator
|
|
/// \return If you previously called ApplyNetworkSimulator
|
|
bool IsNetworkSimulatorActive( void );
|
|
|
|
void SetSplitMessageProgressInterval(int interval);
|
|
void SetUnreliableTimeout(RakNet::TimeMS timeoutMS);
|
|
/// Has a lot of time passed since the last ack
|
|
bool AckTimeout(RakNet::Time curTime);
|
|
CCTimeType GetNextSendTime(void) const;
|
|
CCTimeType GetTimeBetweenPackets(void) const;
|
|
#if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1
|
|
CCTimeType GetAckPing(void) const;
|
|
#endif
|
|
RakNet::TimeMS GetTimeLastDatagramArrived(void) const {return timeLastDatagramArrived;}
|
|
|
|
// If true, will update time between packets quickly based on ping calculations
|
|
//void SetDoFastThroughputReactions(bool fast);
|
|
|
|
// Encoded as numMessages[unsigned int], message1BitLength[unsigned int], message1Data (aligned), ...
|
|
//void GetUndeliveredMessages(RakNet::BitStream *messages, int MTUSize);
|
|
|
|
private:
|
|
/// Send the contents of a bitstream to the socket
|
|
/// \param[in] s The socket used for sending data
|
|
/// \param[in] systemAddress The address and port to send to
|
|
/// \param[in] bitStream The data to send.
|
|
void SendBitStream( RakNetSocket2 *s, SystemAddress &systemAddress, RakNet::BitStream *bitStream, RakNetRandom *rnr, CCTimeType currentTime);
|
|
|
|
///Parse an internalPacket and create a bitstream to represent this data
|
|
/// \return Returns number of bits used
|
|
BitSize_t WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket, CCTimeType curTime );
|
|
|
|
|
|
/// Parse a bitstream and create an internal packet to represent this data
|
|
InternalPacket* CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, CCTimeType time );
|
|
|
|
/// Does what the function name says
|
|
unsigned RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, CCTimeType time, DataStructures::List<PluginInterface2*> &messageHandlerList, const SystemAddress &systemAddress );
|
|
|
|
/// Acknowledge receipt of the packet with the specified messageNumber
|
|
void SendAcknowledgementPacket( const DatagramSequenceNumberType messageNumber, CCTimeType time);
|
|
|
|
/// This will return true if we should not send at this time
|
|
bool IsSendThrottled( int MTUSize );
|
|
|
|
/// We lost a packet
|
|
void UpdateWindowFromPacketloss( CCTimeType time );
|
|
|
|
/// Increase the window size
|
|
void UpdateWindowFromAck( CCTimeType time );
|
|
|
|
/// Parse an internalPacket and figure out how many header bits would be written. Returns that number
|
|
BitSize_t GetMaxMessageHeaderLengthBits( void );
|
|
BitSize_t GetMessageHeaderLengthBits( const InternalPacket *const internalPacket );
|
|
|
|
/// Get the SHA1 code
|
|
void GetSHA1( unsigned char * const buffer, unsigned int nbytes, char code[ SHA1_LENGTH ] );
|
|
|
|
/// Check the SHA1 code
|
|
bool CheckSHA1( char code[ SHA1_LENGTH ], unsigned char * const buffer, unsigned int nbytes );
|
|
|
|
/// Search the specified list for sequenced packets on the specified ordering channel, optionally skipping those with splitPacketId, and delete them
|
|
// void DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::List<InternalPacket*>&theList, int splitPacketId = -1 );
|
|
|
|
/// Search the specified list for sequenced packets with a value less than orderingIndex and delete them
|
|
// void DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::Queue<InternalPacket*>&theList );
|
|
|
|
/// Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex
|
|
bool IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex );
|
|
|
|
/// Split the passed packet into chunks under MTU_SIZE bytes (including headers) and save those new chunks
|
|
void SplitPacket( InternalPacket *internalPacket );
|
|
|
|
/// Insert a packet into the split packet list
|
|
void InsertIntoSplitPacketList( InternalPacket * internalPacket, CCTimeType time );
|
|
|
|
/// Take all split chunks with the specified splitPacketId and try to reconstruct a packet. If we can, allocate and return it. Otherwise return 0
|
|
InternalPacket * BuildPacketFromSplitPacketList( SplitPacketIdType splitPacketId, CCTimeType time,
|
|
RakNetSocket2 *s, SystemAddress &systemAddress, RakNetRandom *rnr, BitStream &updateBitStream);
|
|
InternalPacket * BuildPacketFromSplitPacketList( SplitPacketChannel *splitPacketChannel, CCTimeType time );
|
|
|
|
/// Delete any unreliable split packets that have long since expired
|
|
//void DeleteOldUnreliableSplitPackets( CCTimeType time );
|
|
|
|
/// 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 * CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, CCTimeType time );
|
|
|
|
/// Get the specified ordering list
|
|
// DataStructures::LinkedList<InternalPacket*> *GetOrderingListAtOrderingStream( unsigned char orderingChannel );
|
|
|
|
/// Add the internal packet to the ordering list in order based on order index
|
|
// void AddToOrderingList( InternalPacket * internalPacket );
|
|
|
|
/// Inserts a packet into the resend list in order
|
|
void InsertPacketIntoResendList( InternalPacket *internalPacket, CCTimeType time, bool firstResend, bool modifyUnacknowledgedBytes );
|
|
|
|
/// Memory handling
|
|
void FreeMemory( bool freeAllImmediately );
|
|
|
|
/// Memory handling
|
|
void FreeThreadSafeMemory( void );
|
|
|
|
// Initialize the variables
|
|
void InitializeVariables( void );
|
|
|
|
/// Given the current time, is this time so old that we should consider it a timeout?
|
|
bool IsExpiredTime(unsigned int input, CCTimeType currentTime) const;
|
|
|
|
// Make it so we don't do resends within a minimum threshold of time
|
|
void UpdateNextActionTime(void);
|
|
|
|
|
|
/// Does this packet number represent a packet that was skipped (out of order?)
|
|
//unsigned int IsReceivedPacketHole(unsigned int input, RakNet::TimeMS currentTime) const;
|
|
|
|
/// Skip an element in the received packets list
|
|
//unsigned int MakeReceivedPacketHole(unsigned int input) const;
|
|
|
|
/// How many elements are waiting to be resent?
|
|
unsigned int GetResendListDataSize(void) const;
|
|
|
|
/// Update all memory which is not threadsafe
|
|
void UpdateThreadedMemory(void);
|
|
|
|
void CalculateHistogramAckSize(void);
|
|
|
|
// Used ONLY for RELIABLE_ORDERED
|
|
// RELIABLE_SEQUENCED just returns the newest one
|
|
// DataStructures::List<DataStructures::LinkedList<InternalPacket*>*> orderingList;
|
|
DataStructures::Queue<InternalPacket*> outputQueue;
|
|
int splitMessageProgressInterval;
|
|
CCTimeType unreliableTimeout;
|
|
|
|
struct MessageNumberNode
|
|
{
|
|
DatagramSequenceNumberType messageNumber;
|
|
MessageNumberNode *next;
|
|
};
|
|
struct DatagramHistoryNode
|
|
{
|
|
DatagramHistoryNode() {}
|
|
DatagramHistoryNode(MessageNumberNode *_head, CCTimeType ts
|
|
) :
|
|
head(_head), timeSent(ts)
|
|
{}
|
|
MessageNumberNode *head;
|
|
CCTimeType timeSent;
|
|
};
|
|
// Queue length is programmatically restricted to DATAGRAM_MESSAGE_ID_ARRAY_LENGTH
|
|
// This is essentially an O(1) lookup to get a DatagramHistoryNode given an index
|
|
// datagramHistory holds a linked list of MessageNumberNode. Each MessageNumberNode refers to one element in resendList which can be cleared on an ack.
|
|
DataStructures::Queue<DatagramHistoryNode> datagramHistory;
|
|
DataStructures::MemoryPool<MessageNumberNode> datagramHistoryMessagePool;
|
|
|
|
struct UnreliableWithAckReceiptNode
|
|
{
|
|
UnreliableWithAckReceiptNode() {}
|
|
UnreliableWithAckReceiptNode(DatagramSequenceNumberType _datagramNumber, uint32_t _sendReceiptSerial, RakNet::TimeUS _nextActionTime) :
|
|
datagramNumber(_datagramNumber), sendReceiptSerial(_sendReceiptSerial), nextActionTime(_nextActionTime)
|
|
{}
|
|
DatagramSequenceNumberType datagramNumber;
|
|
uint32_t sendReceiptSerial;
|
|
RakNet::TimeUS nextActionTime;
|
|
};
|
|
DataStructures::List<UnreliableWithAckReceiptNode> unreliableWithAckReceiptHistory;
|
|
|
|
void RemoveFromDatagramHistory(DatagramSequenceNumberType index);
|
|
MessageNumberNode* GetMessageNumberNodeByDatagramIndex(DatagramSequenceNumberType index, CCTimeType *timeSent);
|
|
void AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, CCTimeType timeSent);
|
|
MessageNumberNode* AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, DatagramSequenceNumberType messageNumber, CCTimeType timeSent);
|
|
MessageNumberNode* AddSubsequentToDatagramHistory(MessageNumberNode *messageNumberNode, DatagramSequenceNumberType messageNumber);
|
|
DatagramSequenceNumberType datagramHistoryPopCount;
|
|
|
|
DataStructures::MemoryPool<InternalPacket> internalPacketPool;
|
|
// DataStructures::BPlusTree<DatagramSequenceNumberType, InternalPacket*, RESEND_TREE_ORDER> resendTree;
|
|
InternalPacket *resendBuffer[RESEND_BUFFER_ARRAY_LENGTH];
|
|
InternalPacket *resendLinkedListHead;
|
|
InternalPacket *unreliableLinkedListHead;
|
|
void RemoveFromUnreliableLinkedList(InternalPacket *internalPacket);
|
|
void AddToUnreliableLinkedList(InternalPacket *internalPacket);
|
|
// unsigned int numPacketsOnResendBuffer;
|
|
//unsigned int blockWindowIncreaseUntilTime;
|
|
// DataStructures::RangeList<DatagramSequenceNumberType> acknowlegements;
|
|
// Resend list is a tree of packets we need to resend
|
|
|
|
// Set to the current time when the resend queue is no longer empty
|
|
// Set to zero when it becomes empty
|
|
// Set to the current time if it is not zero, and we get incoming data
|
|
// If the current time - timeResendQueueNonEmpty is greater than a threshold, we are disconnected
|
|
// CCTimeType timeResendQueueNonEmpty;
|
|
RakNet::TimeMS timeLastDatagramArrived;
|
|
|
|
|
|
// If we backoff due to packetloss, don't remeasure until all waiting resends have gone out or else we overcount
|
|
// bool packetlossThisSample;
|
|
// int backoffThisSample;
|
|
// unsigned packetlossThisSampleResendCount;
|
|
// CCTimeType lastPacketlossTime;
|
|
|
|
//DataStructures::Queue<InternalPacket*> sendPacketSet[ NUMBER_OF_PRIORITIES ];
|
|
DataStructures::Heap<reliabilityHeapWeightType, InternalPacket*, false> outgoingPacketBuffer;
|
|
reliabilityHeapWeightType outgoingPacketBufferNextWeights[NUMBER_OF_PRIORITIES];
|
|
void InitHeapWeights(void);
|
|
reliabilityHeapWeightType GetNextWeight(int priorityLevel);
|
|
// unsigned int messageInSendBuffer[NUMBER_OF_PRIORITIES];
|
|
// double bytesInSendBuffer[NUMBER_OF_PRIORITIES];
|
|
|
|
|
|
DataStructures::OrderedList<SplitPacketIdType, SplitPacketChannel*, SplitPacketChannelComp> splitPacketChannelList;
|
|
|
|
MessageNumberType sendReliableMessageNumberIndex;
|
|
MessageNumberType internalOrderIndex;
|
|
//unsigned int windowSize;
|
|
//RakNet::BitStream updateBitStream;
|
|
bool deadConnection, cheater;
|
|
SplitPacketIdType splitPacketId;
|
|
RakNet::TimeMS timeoutTime; // How long to wait in MS before timing someone out
|
|
//int MAX_AVERAGE_PACKETS_PER_SECOND; // Name says it all
|
|
// int RECEIVED_PACKET_LOG_LENGTH, requestedReceivedPacketLogLength; // How big the receivedPackets array is
|
|
// unsigned int *receivedPackets;
|
|
RakNetStatistics statistics;
|
|
|
|
// Algorithm for blending ordered and sequenced on the same channel:
|
|
// 1. Each ordered message transmits OrderingIndexType orderedWriteIndex. There are NUMBER_OF_ORDERED_STREAMS independent values of these. The value
|
|
// starts at 0. Every time an ordered message is sent, the value increments by 1
|
|
// 2. Each sequenced message contains the current value of orderedWriteIndex for that channel, and additionally OrderingIndexType sequencedWriteIndex.
|
|
// sequencedWriteIndex resets to 0 every time orderedWriteIndex increments. It increments by 1 every time a sequenced message is sent.
|
|
// 3. The receiver maintains the next expected value for the orderedWriteIndex, stored in orderedReadIndex.
|
|
// 4. As messages arrive:
|
|
// If a message has the current ordering index, and is sequenced, and is < the current highest sequence value, discard
|
|
// If a message has the current ordering index, and is sequenced, and is >= the current highest sequence value, return immediately
|
|
// If a message has a greater ordering index, and is sequenced or ordered, buffer it
|
|
// If a message has the current ordering index, and is ordered, buffer, then push off messages from buffer
|
|
// 5. Pushing off messages from buffer:
|
|
// Messages in buffer are put in a minheap. The value of each node is calculated such that messages are returned:
|
|
// A. (lowest ordering index, lowest sequence index)
|
|
// B. (lowest ordering index, no sequence index)
|
|
// Messages are pushed off until the heap is empty, or the next message to be returned does not preserve the ordered index
|
|
// For an empty heap, the heap weight should start at the lowest value based on the next expected ordering index, to avoid variable overflow
|
|
|
|
// Sender increments this by 1 for every ordered message sent
|
|
OrderingIndexType orderedWriteIndex[NUMBER_OF_ORDERED_STREAMS];
|
|
// Sender increments by 1 for every sequenced message sent. Resets to 0 when an ordered message is sent
|
|
OrderingIndexType sequencedWriteIndex[NUMBER_OF_ORDERED_STREAMS];
|
|
// Next expected index for ordered messages.
|
|
OrderingIndexType orderedReadIndex[NUMBER_OF_ORDERED_STREAMS];
|
|
// Highest value received for sequencedWriteIndex for the current value of orderedReadIndex on the same channel.
|
|
OrderingIndexType highestSequencedReadIndex[NUMBER_OF_ORDERED_STREAMS];
|
|
DataStructures::Heap<reliabilityHeapWeightType, InternalPacket*, false> orderingHeaps[NUMBER_OF_ORDERED_STREAMS];
|
|
OrderingIndexType heapIndexOffsets[NUMBER_OF_ORDERED_STREAMS];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CCTimeType histogramStart;
|
|
// unsigned histogramBitsSent;
|
|
|
|
|
|
/// Memory-efficient receivedPackets algorithm:
|
|
/// receivedPacketsBaseIndex is the packet number we are expecting
|
|
/// Everything under receivedPacketsBaseIndex is a packet we already got
|
|
/// Everything over receivedPacketsBaseIndex is stored in hasReceivedPacketQueue
|
|
/// It stores the time to stop waiting for a particular packet number, where the packet number is receivedPacketsBaseIndex + the index into the queue
|
|
/// If 0, we got got that packet. Otherwise, the time to give up waiting for that packet.
|
|
/// If we get a packet number where (receivedPacketsBaseIndex-packetNumber) is less than half the range of receivedPacketsBaseIndex then it is a duplicate
|
|
/// Otherwise, it is a duplicate packet (and ignore it).
|
|
// DataStructures::Queue<CCTimeType> hasReceivedPacketQueue;
|
|
DataStructures::Queue<bool> hasReceivedPacketQueue;
|
|
DatagramSequenceNumberType receivedPacketsBaseIndex;
|
|
bool resetReceivedPackets;
|
|
|
|
CCTimeType lastUpdateTime;
|
|
CCTimeType timeBetweenPackets, nextSendTime;
|
|
#if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1
|
|
CCTimeType ackPing;
|
|
#endif
|
|
// CCTimeType ackPingSamples[ACK_PING_SAMPLES_SIZE]; // Must be range of unsigned char to wrap ackPingIndex properly
|
|
CCTimeType ackPingSum;
|
|
unsigned char ackPingIndex;
|
|
//CCTimeType nextLowestPingReset;
|
|
RemoteSystemTimeType remoteSystemTime;
|
|
// bool continuousSend;
|
|
// CCTimeType lastTimeBetweenPacketsIncrease,lastTimeBetweenPacketsDecrease;
|
|
// Limit changes in throughput to once per ping - otherwise even if lag starts we don't know about it
|
|
// In the meantime the connection is flooded and overrun.
|
|
CCTimeType nextAllowedThroughputSample;
|
|
bool bandwidthExceededStatistic;
|
|
|
|
// If Update::maxBitsPerSecond > 0, then throughputCapCountdown is used as a timer to prevent sends for some amount of time after each send, depending on
|
|
// the amount of data sent
|
|
long long throughputCapCountdown;
|
|
|
|
unsigned receivePacketCount;
|
|
|
|
#ifdef _DEBUG
|
|
struct DataAndTime//<InternalPacket>
|
|
{
|
|
RakNetSocket2 *s;
|
|
char data[ MAXIMUM_MTU_SIZE ];
|
|
unsigned int length;
|
|
RakNet::TimeMS sendTime;
|
|
// SystemAddress systemAddress;
|
|
unsigned short remotePortRakNetWasStartedOn_PS3;
|
|
unsigned int extraSocketOptions;
|
|
};
|
|
DataStructures::Queue<DataAndTime*> delayList;
|
|
|
|
// Internet simulator
|
|
double packetloss;
|
|
RakNet::TimeMS minExtraPing, extraPingVariance;
|
|
#endif
|
|
|
|
CCTimeType elapsedTimeSinceLastUpdate;
|
|
|
|
CCTimeType nextAckTimeToSend;
|
|
|
|
|
|
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
|
|
RakNet::CCRakNetSlidingWindow congestionManager;
|
|
#else
|
|
RakNet::CCRakNetUDT congestionManager;
|
|
#endif
|
|
|
|
|
|
uint32_t unacknowledgedBytes;
|
|
|
|
bool ResendBufferOverflow(void) const;
|
|
void ValidateResendList(void) const;
|
|
void ResetPacketsAndDatagrams(void);
|
|
void PushPacket(CCTimeType time, InternalPacket *internalPacket, bool isReliable);
|
|
void PushDatagram(void);
|
|
bool TagMostRecentPushAsSecondOfPacketPair(void);
|
|
void ClearPacketsAndDatagrams(void);
|
|
void MoveToListHead(InternalPacket *internalPacket);
|
|
void RemoveFromList(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes);
|
|
void AddToListTail(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes);
|
|
void PopListHead(bool modifyUnacknowledgedBytes);
|
|
bool IsResendQueueEmpty(void) const;
|
|
void SortSplitPacketList(DataStructures::List<InternalPacket*> &data, unsigned int leftEdge, unsigned int rightEdge) const;
|
|
void SendACKs(RakNetSocket2 *s, SystemAddress &systemAddress, CCTimeType time, RakNetRandom *rnr, BitStream &updateBitStream);
|
|
|
|
DataStructures::List<InternalPacket*> packetsToSendThisUpdate;
|
|
DataStructures::List<bool> packetsToDeallocThisUpdate;
|
|
// boundary is in packetsToSendThisUpdate, inclusive
|
|
DataStructures::List<unsigned int> packetsToSendThisUpdateDatagramBoundaries;
|
|
DataStructures::List<bool> datagramsToSendThisUpdateIsPair;
|
|
DataStructures::List<unsigned int> datagramSizesInBytes;
|
|
BitSize_t datagramSizeSoFar;
|
|
BitSize_t allDatagramSizesSoFar;
|
|
double totalUserDataBytesAcked;
|
|
CCTimeType timeOfLastContinualSend;
|
|
CCTimeType timeToNextUnreliableCull;
|
|
|
|
// This doesn't need to be a member, but I do it to avoid reallocations
|
|
DataStructures::RangeList<DatagramSequenceNumberType> incomingAcks;
|
|
|
|
// Every 16 datagrams, we make sure the 17th datagram goes out the same update tick, and is the same size as the 16th
|
|
int countdownToNextPacketPair;
|
|
InternalPacket* AllocateFromInternalPacketPool(void);
|
|
void ReleaseToInternalPacketPool(InternalPacket *ip);
|
|
|
|
DataStructures::RangeList<DatagramSequenceNumberType> acknowlegements;
|
|
DataStructures::RangeList<DatagramSequenceNumberType> NAKs;
|
|
bool remoteSystemNeedsBAndAS;
|
|
|
|
unsigned int GetMaxDatagramSizeExcludingMessageHeaderBytes(void);
|
|
BitSize_t GetMaxDatagramSizeExcludingMessageHeaderBits(void);
|
|
|
|
// ourOffset refers to a section within externallyAllocatedPtr. Do not deallocate externallyAllocatedPtr until all references are lost
|
|
void AllocInternalPacketData(InternalPacket *internalPacket, InternalPacketRefCountedData **refCounter, unsigned char *externallyAllocatedPtr, unsigned char *ourOffset);
|
|
// Set the data pointer to externallyAllocatedPtr, do not allocate
|
|
void AllocInternalPacketData(InternalPacket *internalPacket, unsigned char *externallyAllocatedPtr);
|
|
// Allocate new
|
|
void AllocInternalPacketData(InternalPacket *internalPacket, unsigned int numBytes, bool allowStack, const char *file, unsigned int line);
|
|
void FreeInternalPacketData(InternalPacket *internalPacket, const char *file, unsigned int line);
|
|
DataStructures::MemoryPool<InternalPacketRefCountedData> refCountedDataPool;
|
|
|
|
BPSTracker bpsMetrics[RNS_PER_SECOND_METRICS_COUNT];
|
|
CCTimeType lastBpsClear;
|
|
|
|
#if LIBCAT_SECURITY==1
|
|
public:
|
|
cat::AuthenticatedEncryption* GetAuthenticatedEncryption(void) { return &auth_enc; }
|
|
|
|
protected:
|
|
cat::AuthenticatedEncryption auth_enc;
|
|
bool useSecurity;
|
|
#endif // LIBCAT_SECURITY
|
|
};
|
|
|
|
} // namespace RakNet
|
|
|
|
#endif
|