diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 6f7ac8643d..e0943a63f8 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -40,8 +40,7 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); - _rtt = _synInterval * 10; - _rttVariance = _rtt / 2; + resetRTT(); // set the initial RTT and flow window size on congestion control object _congestionControl->setRTT(_rtt); @@ -64,6 +63,11 @@ Connection::~Connection() { } } +void Connection::resetRTT() { + _rtt = _synInterval * 10; + _rttVariance = _rtt / 2; +} + SendQueue& Connection::getSendQueue() { if (!_sendQueue) { // Lasily create send queue @@ -120,13 +124,15 @@ void Connection::sync() { // we send out a periodic ACK every rate control interval sendACK(); - // check if we need to re-transmit a loss list - // we do this if it has been longer than the current nakInterval since we last sent - auto now = high_resolution_clock::now(); - - if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { - // Send a timeout NAK packet - sendTimeoutNAK(); + if (_lossList.getLength() > 0) { + // check if we need to re-transmit a loss list + // we do this if it has been longer than the current nakInterval since we last sent + auto now = high_resolution_clock::now(); + + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { + // Send a timeout NAK packet + sendTimeoutNAK(); + } } } } @@ -349,7 +355,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _nakInterval += (int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond)); } - // the NAK interval is at least the _minNAKInterval but might be the estimated timeout + // the NAK interval is at least the _minNAKInterval but might be the value calculated above, if that is larger _nakInterval = std::max(_nakInterval, _minNAKInterval); } @@ -614,6 +620,9 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::processHandshake(std::unique_ptr controlPacket) { + // server sent us a handshake - we need to assume this means state should be reset + resetReceiveState(); + // immediately respond with a handshake ACK static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); _parentSocket->writeBasePacket(*handshakeACK, _destination); @@ -640,6 +649,39 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) _stats.record(ConnectionStats::Stats::ReceivedTimeoutNAK); } +void Connection::resetReceiveState() { + // TODO: this should also reset any queued messages we might be processing + + // reset all SequenceNumber member variables back to default + SequenceNumber defaultSequenceNumber; + + _lastReceivedSequenceNumber = defaultSequenceNumber; + + _lastReceivedAcknowledgedACK = defaultSequenceNumber; + _currentACKSubSequenceNumber = defaultSequenceNumber; + + _lastSentACK = defaultSequenceNumber; + + // clear the loss list and _lastNAKTime + _lossList.clear(); + _lastNAKTime = high_resolution_clock::time_point(); + + // the _nakInterval need not be reset, that will happen on loss + + // clear sync variables + _hasReceivedFirstPacket = false; + + _acksDuringSYN = 1; + _lightACKsDuringSYN = 1; + _packetsSinceACK = 0; + + // reset RTT to initial value + resetRTT(); + + // clear the intervals in the receive window + _receiveWindow.reset(); +} + void Connection::updateRTT(int rtt) { // This updates the RTT using exponential weighted moving average // This is the Jacobson's forumla for RTT estimation diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b37801a90f..0babfb76e1 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -93,6 +93,9 @@ private: void processHandshake(std::unique_ptr controlPacket); void processHandshakeACK(std::unique_ptr controlPacket); + void resetReceiveState(); + void resetRTT(); + SendQueue& getSendQueue(); SequenceNumber nextACK() const; void updateRTT(int rtt); @@ -103,7 +106,7 @@ private: int _synInterval; // Periodical Rate Control Interval, in microseconds - int _nakInterval; // NAK timeout interval, in microseconds + int _nakInterval { -1 }; // NAK timeout interval, in microseconds, set on loss int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms std::chrono::high_resolution_clock::time_point _lastNAKTime; diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 5c389f6d26..00eb43c7e6 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -31,6 +31,11 @@ PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals } +void PacketTimeWindow::reset() { + _packetIntervals.assign(_numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS); + _probeIntervals.assign(_numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS); +} + template int median(Iterator begin, Iterator end) { // use std::nth_element to grab the middle - for an even number of elements this is the upper middle diff --git a/libraries/networking/src/udt/PacketTimeWindow.h b/libraries/networking/src/udt/PacketTimeWindow.h index 25e3df8a43..a8a4e0c8b5 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.h +++ b/libraries/networking/src/udt/PacketTimeWindow.h @@ -29,6 +29,8 @@ public: int32_t getPacketReceiveSpeed() const; int32_t getEstimatedBandwidth() const; + + void reset(); private: int _numPacketIntervals { 0 }; // the number of packet intervals to store int _numProbeIntervals { 0 }; // the number of probe intervals to store