mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 01:57:00 +02:00
159 lines
No EOL
6.2 KiB
C++
159 lines
No EOL
6.2 KiB
C++
//
|
|
// SequenceNumberStats.cpp
|
|
// libraries/networking/src
|
|
//
|
|
// Created by Yixin Wang on 6/25/2014
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "SequenceNumbersStats.h"
|
|
|
|
#include <limits>
|
|
|
|
SequenceNumberStats::SequenceNumberStats()
|
|
: _lastReceived(std::numeric_limits<quint16>::max()),
|
|
_missingSet(),
|
|
_numReceived(0),
|
|
_numUnreasonable(0),
|
|
_numEarly(0),
|
|
_numLate(0),
|
|
_numLost(0),
|
|
_numRecovered(0),
|
|
_numDuplicate(0)
|
|
{
|
|
}
|
|
|
|
void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, const bool wantExtraDebugging) {
|
|
|
|
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
|
static const int MAX_REASONABLE_SEQUENCE_GAP = 1000; // this must be less than UINT16_RANGE / 2 for rollover handling to work
|
|
|
|
_numReceived++;
|
|
|
|
// determine our expected sequence number... handle rollover appropriately
|
|
quint16 expected = _numReceived > 0 ? _lastReceived + (quint16)1 : incoming;
|
|
|
|
if (incoming == expected) { // on time
|
|
_lastReceived = incoming;
|
|
} else { // out of order
|
|
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "out of order... got:" << incoming << "expected:" << expected;
|
|
}
|
|
|
|
int incomingInt = (int)incoming;
|
|
int expectedInt = (int)expected;
|
|
|
|
// check if the gap between incoming and expected is reasonable, taking possible rollover into consideration
|
|
int absGap = std::abs(incomingInt - expectedInt);
|
|
if (absGap >= UINT16_RANGE - MAX_REASONABLE_SEQUENCE_GAP) {
|
|
// rollover likely occurred between incoming and expected.
|
|
// correct the larger of the two so that it's within [-UINT16_RANGE, -1] while the other remains within [0, UINT16_RANGE-1]
|
|
if (incomingInt > expectedInt) {
|
|
incomingInt -= UINT16_RANGE;
|
|
} else {
|
|
expectedInt -= UINT16_RANGE;
|
|
}
|
|
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
|
|
// ignore packet if gap is unreasonable
|
|
qDebug() << "ignoring unreasonable packet... sequence:" << incoming
|
|
<< "previous:" << _lastReceived;
|
|
_numUnreasonable++;
|
|
return;
|
|
}
|
|
|
|
// now that rollover has been corrected for (if it occurred), incoming and expected can be
|
|
// compared to each other directly, though one of them might be negative
|
|
if (incomingInt > expectedInt) { // early
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "this packet is earlier than expected...";
|
|
qDebug() << ">>>>>>>> missing gap=" << (incomingInt - expectedInt);
|
|
}
|
|
|
|
_numEarly++;
|
|
_numLost += (incomingInt - expectedInt);
|
|
|
|
// add all sequence numbers that were skipped to the missing sequence numbers list
|
|
for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) {
|
|
_missingSet.insert((quint16)(missingInt < 0 ? missingInt + UINT16_RANGE : missingInt));
|
|
}
|
|
_lastReceived = incoming;
|
|
} else { // late
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "this packet is later than expected...";
|
|
}
|
|
_numLate++;
|
|
|
|
// remove this from missing sequence number if it's in there
|
|
if (_missingSet.remove(incoming)) {
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "found it in _missingSet";
|
|
}
|
|
_numLost--;
|
|
_numRecovered++;
|
|
} else {
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate";
|
|
}
|
|
_numDuplicate++;
|
|
}
|
|
|
|
// do not update _incomingLastSequence; it shouldn't become smaller
|
|
}
|
|
}
|
|
|
|
// prune missing sequence list if it gets too big; sequence numbers that are older than MAX_REASONABLE_SEQUENCE_GAP
|
|
// will be removed.
|
|
if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) {
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "_missingSet is too large! size:" << _missingSet.size();
|
|
}
|
|
|
|
// some older sequence numbers may be from before a rollover point; this must be handled.
|
|
// some sequence numbers in this list may be larger than _incomingLastSequence, indicating that they were received
|
|
// before the most recent rollover.
|
|
int cutoff = (int)_lastReceived - MAX_REASONABLE_SEQUENCE_GAP;
|
|
if (cutoff >= 0) {
|
|
quint16 nonRolloverCutoff = (quint16)cutoff;
|
|
QSet<quint16>::iterator i = _missingSet.begin();
|
|
while (i != _missingSet.end()) {
|
|
quint16 missing = *i;
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "checking item:" << missing << "is it in need of pruning?";
|
|
qDebug() << "old age cutoff:" << nonRolloverCutoff;
|
|
}
|
|
|
|
if (missing > _lastReceived || missing < nonRolloverCutoff) {
|
|
i = _missingSet.erase(i);
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "pruning really old missing sequence:" << missing;
|
|
}
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
} else {
|
|
quint16 rolloverCutoff = (quint16)(cutoff + UINT16_RANGE);
|
|
QSet<quint16>::iterator i = _missingSet.begin();
|
|
while (i != _missingSet.end()) {
|
|
quint16 missing = *i;
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "checking item:" << missing << "is it in need of pruning?";
|
|
qDebug() << "old age cutoff:" << rolloverCutoff;
|
|
}
|
|
|
|
if (missing > _lastReceived && missing < rolloverCutoff) {
|
|
i = _missingSet.erase(i);
|
|
if (wantExtraDebugging) {
|
|
qDebug() << "pruning really old missing sequence:" << missing;
|
|
}
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |