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 <[email protected]>

Helps with #13769 but does not fix it completely (upload gets
farther but still stalls.)
This commit is contained in:
A-star-ayush
2017-12-04 15:12:03 -05:00
committed by Augustin Cavalier
parent a88944c86e
commit bf1a86c199
2 changed files with 25 additions and 16 deletions
@@ -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;
@@ -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;