From bf1a86c199f81b436c5b2f72342f8d56fc59450b Mon Sep 17 00:00:00 2001 From: A-star-ayush Date: Mon, 4 Dec 2017 23:01:02 +0530 Subject: [PATCH] TCP: Fixed RTO update and dup ACKs generation. i) there was an integer promotion problem in updating the retransmission timeout : a signed int was being divided by an unsigned int. This was causing the values to overflow. Thus leading to huge values for timeout which manifested in the perception of pause in data flow. ii) for an ack to be recognised as a duplicate ack, the advertised window must remain same. This was not taken care of in the code so I added it. Signed-off-by: Augustin Cavalier Helps with #13769 but does not fix it completely (upload gets farther but still stalls.) --- .../network/protocols/tcp/TCPEndpoint.cpp | 38 +++++++++++-------- .../network/protocols/tcp/TCPEndpoint.h | 3 +- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index e3194da423..007f772aa9 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -445,6 +445,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket) fSmoothedRoundTripTime(0), fRoundTripVariation(0), fSendTime(0), + fRoundTripStartSequence(0), fRetransmitTimeout(TCP_INITIAL_RTT), fReceivedTimestamp(0), fCongestionWindow(0), @@ -2035,6 +2036,10 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow) } size_t availableBytes = fReceiveQueue.Free(); + // window size must remain same for duplicate acknowledgements + if (!fReceiveQueue.IsContiguous()) + availableBytes = (fReceiveMaxAdvertised - fReceiveNext).Number(); + if (fFlags & FLAG_OPTION_WINDOW_SCALE) segment.advertised_window = availableBytes >> fReceiveWindowShift; else @@ -2189,8 +2194,11 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow) return status; } - if (fSendTime == 0 && (segmentLength != 0 || (segment.flags & TCP_FLAG_SYNCHRONIZE ) == 1)) + if (fSendTime == 0 && !retransmit + && (segmentLength != 0 || (segment.flags & TCP_FLAG_SYNCHRONIZE) !=0)) { fSendTime = tcp_now(); + fRoundTripStartSequence = segment.sequence; + } if (shouldStartRetransmitTimer && size > 0) { TRACE("starting initial retransmit timer of: %" B_PRIdBIGTIME, @@ -2280,6 +2288,8 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment) uint32 bytesAcknowledged = segment.acknowledge - fSendUnacknowledged.Number(); fPreviousHighestAcknowledge = fSendUnacknowledged; fSendUnacknowledged = segment.acknowledge; + uint32 flightSize = (fSendMax - fSendUnacknowledged).Number(); + int32 expectedSamples = flightSize / (fSendMaxSegmentSize << 1); if (fPreviousHighestAcknowledge > fSendUnacknowledged) { // need to update the recover variable upon a sequence wraparound @@ -2320,22 +2330,17 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment) fSendNext = fSendUnacknowledged; if (fFlags & FLAG_OPTION_TIMESTAMP) { - uint32 flightSize = (fSendMax - fSendUnacknowledged).Number(); _UpdateRoundTripTime(tcp_diff_timestamp(segment.timestamp_reply), - 1 + ((flightSize - 1) / (fSendMaxSegmentSize << 1))); - } - - // Karn's algorithm: RTT measurement must not be made using segments that were retransmitted - else if (fSendTime > 1 && fSendNext == fSendMax) { + expectedSamples > 0 ? expectedSamples : 1); + } else if (fSendTime != 0 && fRoundTripStartSequence < segment.acknowledge) { _UpdateRoundTripTime(tcp_diff_timestamp(fSendTime), 1); - fSendTime = 1; + fSendTime = 0; } if (fSendUnacknowledged == fSendMax) { TRACE("all acknowledged, cancelling retransmission timer."); gStackModule->cancel_timer(&fRetransmitTimer); T(TimerSet(this, "retransmit", -1)); - fSendTime = 0; } else { TRACE("data acknowledged, resetting retransmission timer to: %" B_PRIdBIGTIME, fRetransmitTimeout); @@ -2383,23 +2388,26 @@ TCPEndpoint::_Retransmit() void -TCPEndpoint::_UpdateRoundTripTime(int32 roundTripTime, uint32 expectedSamples) +TCPEndpoint::_UpdateRoundTripTime(int32 roundTripTime, int32 expectedSamples) { if(fSmoothedRoundTripTime == 0) { fSmoothedRoundTripTime = roundTripTime; - fRoundTripVariation = roundTripTime >> 1; - fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, fRoundTripVariation << 2)) + fRoundTripVariation = roundTripTime / 2; + fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, fRoundTripVariation * 4)) * kTimestampFactor; } else { int32 delta = fSmoothedRoundTripTime - roundTripTime; if (delta < 0) delta = -delta; - fRoundTripVariation += ((delta - fRoundTripVariation) >> 2) / expectedSamples; - fSmoothedRoundTripTime += ((roundTripTime - fSmoothedRoundTripTime) >> 3) / expectedSamples; - fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, fRoundTripVariation << 2)) + fRoundTripVariation += (delta - fRoundTripVariation) / (expectedSamples * 4); + fSmoothedRoundTripTime += (roundTripTime - fSmoothedRoundTripTime) / (expectedSamples * 8); + fRetransmitTimeout = (fSmoothedRoundTripTime + max_c(100, fRoundTripVariation * 4)) * kTimestampFactor; } + if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT) + fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT; + if (fRetransmitTimeout < TCP_MIN_RETRANSMIT_TIMEOUT) fRetransmitTimeout = TCP_MIN_RETRANSMIT_TIMEOUT; diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index 6a62e07708..e73cef0252 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -106,7 +106,7 @@ private: status_t _PrepareSendPath(const sockaddr* peer); void _Acknowledged(tcp_segment_header& segment); void _Retransmit(); - void _UpdateRoundTripTime(int32 roundTripTime, uint32 expectedSamples); + void _UpdateRoundTripTime(int32 roundTripTime, int32 expectedSamples); void _ResetSlowStart(); void _DuplicateAcknowledge(tcp_segment_header& segment); @@ -171,6 +171,7 @@ private: int32 fSmoothedRoundTripTime; int32 fRoundTripVariation; uint32 fSendTime; + tcp_sequence fRoundTripStartSequence; bigtime_t fRetransmitTimeout; uint32 fReceivedTimestamp;