From ae535be5ce441c452fd6442070c86c200d093394 Mon Sep 17 00:00:00 2001 From: Luke1410 Date: Sat, 2 Jun 2018 17:18:19 +0200 Subject: [PATCH 1/2] - fix issue in DS_RangeList RangeNodeComp() not correctly taking the whole range into account - added new RangeList::IsWithinRange() method - several changes to RangeList::Deserialize() to prevent invalid RangeLists being constructed from a bitstream (incl. preventing overlapping and duplicated ranges) --- Source/DS_RangeList.h | 70 ++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/Source/DS_RangeList.h b/Source/DS_RangeList.h index 2e6c97554..ba795a735 100644 --- a/Source/DS_RangeList.h +++ b/Source/DS_RangeList.h @@ -40,9 +40,9 @@ namespace DataStructures { if (ab.maxIndex) + return 1; + return 0; } template @@ -53,12 +53,16 @@ namespace DataStructures ~RangeList(); void Insert(range_type index); void Clear(void); + bool IsWithinRange(range_type value) const; unsigned Size(void) const; unsigned RangeSum(void) const; RakNet::BitSize_t Serialize(RakNet::BitStream *in, RakNet::BitSize_t maxBits, bool clearSerialized); bool Deserialize(RakNet::BitStream *out); DataStructures::OrderedList , RangeNodeComp > ranges; + + private: + bool DeserializeSingleRange(RakNet::BitStream *out, range_type& min, range_type& max); }; template @@ -118,28 +122,51 @@ namespace DataStructures unsigned short count; out->AlignReadToByteBoundary(); out->Read(count); - unsigned short i; + range_type absMin; range_type min,max; - unsigned char maxEqualToMin=0; - for (i=0; i < count; i++) + if (count == 0) { + return true; + } + + if (!DeserializeSingleRange(out, min, max)) { + return false; + } + ranges.InsertAtEnd(RangeNode(min, max), _FILE_AND_LINE_); + + for (unsigned short i = 1; i < count; i++) { - out->Read(maxEqualToMin); - if (out->Read(min)==false) + absMin = max; + + if (!DeserializeSingleRange(out, min, max)) { return false; - if (maxEqualToMin==false) - { - if (out->Read(max)==false) - return false; - if (max(min, max), _FILE_AND_LINE_); + } + return true; + } + template + bool RangeList::DeserializeSingleRange(RakNet::BitStream *out, range_type& min, range_type& max) + { + unsigned char maxEqualToMin; - ranges.InsertAtEnd(RangeNode(min,max), _FILE_AND_LINE_); + out->Read(maxEqualToMin); + if (out->Read(min) == false) + return false; + if (maxEqualToMin == false) + { + if (out->Read(max) == false) + return false; + if (max < min) + return false; } + else + max = min; + return true; } @@ -223,6 +250,15 @@ namespace DataStructures ranges.Clear(true, _FILE_AND_LINE_); } + template + bool RangeList::IsWithinRange(range_type value) const + { + bool objectExists; + // not interested in the return value + (void)ranges.GetIndexFromKey(value, &objectExists); + return objectExists; + } + template unsigned RangeList::Size(void) const { From d760b7da9bd347ca1793b3c9937053db803eab04 Mon Sep 17 00:00:00 2001 From: Luke1410 Date: Sat, 2 Jun 2018 17:19:17 +0200 Subject: [PATCH 2/2] - reduce complexity of ACK-processing to O(n) - early out when processing ACK/NAK ranges, if end of datagram history reached --- Source/ReliabilityLayer.cpp | 52 +++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/Source/ReliabilityLayer.cpp b/Source/ReliabilityLayer.cpp index dbeb17b94..17d84aee3 100644 --- a/Source/ReliabilityLayer.cpp +++ b/Source/ReliabilityLayer.cpp @@ -733,6 +733,24 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( return false; } + + unsigned int k = 0; + while (k < unreliableWithAckReceiptHistory.Size()) { + if (incomingAcks.IsWithinRange(unreliableWithAckReceiptHistory[k].datagramNumber)) { + InternalPacket *ackReceipt = AllocateFromInternalPacketPool(); + AllocInternalPacketData(ackReceipt, 5, false, _FILE_AND_LINE_); + ackReceipt->dataBitLength = BYTES_TO_BITS(5); + ackReceipt->data[0] = (MessageID)ID_SND_RECEIPT_ACKED; + memcpy(ackReceipt->data + sizeof(MessageID), &unreliableWithAckReceiptHistory[k].sendReceiptSerial, sizeof(uint32_t)); + outputQueue.Push(ackReceipt, _FILE_AND_LINE_); + // Remove, swap with last + unreliableWithAckReceiptHistory.RemoveAtIndex(k); + } + else { + k++; + } + } + for (i=0; iincomingAcks.ranges[i].maxIndex || (incomingAcks.ranges[i].maxIndex == (uint24_t)(0xFFFFFFFF))) @@ -745,30 +763,14 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( } for (datagramNumber=incomingAcks.ranges[i].minIndex; datagramNumber >= incomingAcks.ranges[i].minIndex && datagramNumber <= incomingAcks.ranges[i].maxIndex; datagramNumber++) { - CCTimeType whenSent; - - if (unreliableWithAckReceiptHistory.Size()>0) - { - unsigned int k=0; - while (k < unreliableWithAckReceiptHistory.Size()) - { - if (unreliableWithAckReceiptHistory[k].datagramNumber == datagramNumber) - { - InternalPacket *ackReceipt = AllocateFromInternalPacketPool(); - AllocInternalPacketData(ackReceipt, 5, false, _FILE_AND_LINE_ ); - ackReceipt->dataBitLength=BYTES_TO_BITS(5); - ackReceipt->data[0]=(MessageID)ID_SND_RECEIPT_ACKED; - memcpy(ackReceipt->data+sizeof(MessageID), &unreliableWithAckReceiptHistory[k].sendReceiptSerial, sizeof(uint32_t)); - outputQueue.Push(ackReceipt, _FILE_AND_LINE_ ); - - // Remove, swap with last - unreliableWithAckReceiptHistory.RemoveAtIndex(k); - } - else - k++; - } + const DatagramSequenceNumberType offsetIntoList = datagramNumber - datagramHistoryPopCount; + if (offsetIntoList >= datagramHistory.Size()) { + // reached the end of the datagramHistory list - hence, we are done + receivePacketCount++; + return true; } + CCTimeType whenSent; MessageNumberNode *messageNumberNode = GetMessageNumberNodeByDatagramIndex(datagramNumber, &whenSent); if (messageNumberNode) { @@ -835,6 +837,12 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( // REMOVEME // printf("%p NAK %i\n", this, dhf.datagramNumber.val); + const DatagramSequenceNumberType offsetIntoList = messageNumber - datagramHistoryPopCount; + if (offsetIntoList >= datagramHistory.Size()) { + // reached the end of the datagramHistory list - hence, we are done + receivePacketCount++; + return true; + } CCTimeType timeSent; MessageNumberNode *messageNumberNode = GetMessageNumberNodeByDatagramIndex(messageNumber, &timeSent);