more TCP fixes, we should now be able to send large amounts of data through congestioned links.
- fixed BufferQueue's RemoveUntil. - reset SND.NXT on third duplicate ACK (fast retransmit). - on retransmit reset SND.NXT to SND.UNA (it will be updated back when we get good ACKs). - fixed effective window calculation. - relaxed SWS checking a bit, don't send partial packets on retransmission as the window might have been reduced due to congestion. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20769 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -183,17 +183,12 @@ BufferQueue::RemoveUntil(tcp_sequence sequence)
|
|||||||
{
|
{
|
||||||
TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence));
|
TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence));
|
||||||
|
|
||||||
fFirstSequence = sequence;
|
if (sequence < fFirstSequence)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
SegmentList::Iterator iterator = fList.GetIterator();
|
SegmentList::Iterator iterator = fList.GetIterator();
|
||||||
net_buffer *buffer = NULL;
|
net_buffer *buffer = NULL;
|
||||||
while ((buffer = iterator.Next()) != NULL) {
|
while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) {
|
||||||
if (sequence <= buffer->sequence) {
|
|
||||||
fFirstSequence = buffer->sequence;
|
|
||||||
// just in case there is a hole, how unlikely this may ever be
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sequence >= buffer->sequence + buffer->size) {
|
if (sequence >= buffer->sequence + buffer->size) {
|
||||||
// remove this buffer completely
|
// remove this buffer completely
|
||||||
iterator.Remove();
|
iterator.Remove();
|
||||||
@@ -209,9 +204,15 @@ BufferQueue::RemoveUntil(tcp_sequence sequence)
|
|||||||
buffer->sequence += size;
|
buffer->sequence += size;
|
||||||
fNumBytes -= size;
|
fNumBytes -= size;
|
||||||
fContiguousBytes -= size;
|
fContiguousBytes -= size;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fList.IsEmpty())
|
||||||
|
fFirstSequence = fLastSequence;
|
||||||
|
else
|
||||||
|
fFirstSequence = fList.Head()->sequence;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,12 +62,12 @@
|
|||||||
|
|
||||||
#ifdef PROBE_TCP
|
#ifdef PROBE_TCP
|
||||||
# define PROBE(buffer, window) \
|
# define PROBE(buffer, window) \
|
||||||
dprintf("TCP PROBE %llu %s %s %ld %lu %lu %lu %lu %lu %lu %lu %lu %llu\n", \
|
dprintf("TCP PROBE %llu %s %s %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %llu\n", \
|
||||||
system_time(), PrintAddress(&buffer->source), \
|
system_time(), PrintAddress(&buffer->source), \
|
||||||
PrintAddress(&buffer->destination), buffer->size, (uint32)fSendNext, \
|
PrintAddress(&buffer->destination), buffer->size, (uint32)fSendNext, \
|
||||||
(uint32)fSendUnacknowledged, fCongestionWindow, fSlowStartThreshold, \
|
(uint32)fSendUnacknowledged, fCongestionWindow, fSlowStartThreshold, \
|
||||||
window, fSendWindow, (uint32)(fSendMax - fSendUnacknowledged), \
|
window, fSendWindow, (uint32)(fSendMax - fSendUnacknowledged), \
|
||||||
fSendQueue.Used(), fRetransmitTimeout)
|
fSendQueue.Available(fSendNext), fSendQueue.Used(), fRetransmitTimeout)
|
||||||
#else
|
#else
|
||||||
# define PROBE(buffer, window) do { } while (0)
|
# define PROBE(buffer, window) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
@@ -1016,10 +1016,9 @@ TCPEndpoint::_ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
|||||||
// - the buffer is at least larger than half of the maximum send window, or
|
// - the buffer is at least larger than half of the maximum send window, or
|
||||||
// - we're retransmitting data
|
// - we're retransmitting data
|
||||||
if (length == segmentMaxSize
|
if (length == segmentMaxSize
|
||||||
|| ((flightSize == 0 || (fOptions & TCP_NODELAY) != 0)
|
|| (fOptions & TCP_NODELAY) != 0
|
||||||
&& tcp_sequence(fSendNext + length) == fSendQueue.LastSequence())
|
|| tcp_sequence(fSendNext + length) == fSendQueue.LastSequence()
|
||||||
|| (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2)
|
|| (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2))
|
||||||
|| fSendNext < fSendMax)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,16 +1090,27 @@ TCPEndpoint::_SendQueued(bool force)
|
|||||||
if (fCongestionWindow > 0)
|
if (fCongestionWindow > 0)
|
||||||
sendWindow = min_c(sendWindow, fCongestionWindow);
|
sendWindow = min_c(sendWindow, fCongestionWindow);
|
||||||
|
|
||||||
// a TCP may not send more data to the network than the
|
// SND.UNA SND.NXT SND.MAX
|
||||||
// currently unacknowledged sequence (SND.UNA) plus the
|
// | | |
|
||||||
// calculated send window.
|
// v v v
|
||||||
|
// -----------------------------------
|
||||||
|
// | effective window |
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Flight size represents the window of data which is currently in the
|
||||||
|
// ether. We should never send data such as the flight size becomes larger
|
||||||
|
// than the effective window. Note however that the effective window may be
|
||||||
|
// reduced (by congestion for instance), so at some point in time flight
|
||||||
|
// size may be larger than the currently calculated window.
|
||||||
|
|
||||||
uint32 flightSize = fSendMax - fSendUnacknowledged;
|
uint32 flightSize = fSendMax - fSendUnacknowledged;
|
||||||
if (flightSize > sendWindow) {
|
uint32 consumedWindow = fSendNext - fSendUnacknowledged;
|
||||||
|
|
||||||
|
if (consumedWindow > sendWindow) {
|
||||||
sendWindow = 0;
|
sendWindow = 0;
|
||||||
// TODO enter persist state? try to get a window update.
|
// TODO enter persist state? try to get a window update.
|
||||||
} else
|
} else
|
||||||
sendWindow -= flightSize;
|
sendWindow -= consumedWindow;
|
||||||
|
|
||||||
if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) {
|
if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) {
|
||||||
// send one byte of data to ask for a window update
|
// send one byte of data to ask for a window update
|
||||||
@@ -1158,6 +1168,9 @@ TCPEndpoint::_SendQueued(bool force)
|
|||||||
", ssthresh %lu", segment.flags, segment.sequence,
|
", ssthresh %lu", segment.flags, segment.sequence,
|
||||||
segment.acknowledge, segment.advertised_window,
|
segment.acknowledge, segment.advertised_window,
|
||||||
fCongestionWindow, fSlowStartThreshold);
|
fCongestionWindow, fSlowStartThreshold);
|
||||||
|
TRACE(" len %lu first %lu last %lu", segmentLength,
|
||||||
|
(uint32)fSendQueue.FirstSequence(),
|
||||||
|
(uint32)fSendQueue.LastSequence());
|
||||||
|
|
||||||
PROBE(buffer, sendWindow);
|
PROBE(buffer, sendWindow);
|
||||||
sendWindow -= buffer->size;
|
sendWindow -= buffer->size;
|
||||||
@@ -1219,17 +1232,6 @@ TCPEndpoint::_SendQueued(bool force)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
TCPEndpoint::_SendQueued(tcp_sequence sendNext)
|
|
||||||
{
|
|
||||||
tcp_sequence previousSendNext = fSendNext;
|
|
||||||
fSendNext = sendNext;
|
|
||||||
status_t status = _SendQueued();
|
|
||||||
fSendNext = previousSendNext;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
TCPEndpoint::_GetMSS(const sockaddr *address) const
|
TCPEndpoint::_GetMSS(const sockaddr *address) const
|
||||||
{
|
{
|
||||||
@@ -1693,7 +1695,8 @@ TCPEndpoint::_Retransmit()
|
|||||||
{
|
{
|
||||||
TRACE("Retransmit()");
|
TRACE("Retransmit()");
|
||||||
_ResetSlowStart();
|
_ResetSlowStart();
|
||||||
_SendQueued(fSendUnacknowledged);
|
fSendNext = fSendUnacknowledged;
|
||||||
|
_SendQueued();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1738,10 +1741,11 @@ TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment)
|
|||||||
_ResetSlowStart();
|
_ResetSlowStart();
|
||||||
fCongestionWindow = fSlowStartThreshold + 3
|
fCongestionWindow = fSlowStartThreshold + 3
|
||||||
* fSendMaxSegmentSize;
|
* fSendMaxSegmentSize;
|
||||||
|
fSendNext = segment.acknowledge;
|
||||||
} else if (fDuplicateAcknowledgeCount > 3)
|
} else if (fDuplicateAcknowledgeCount > 3)
|
||||||
fCongestionWindow += fSendMaxSegmentSize;
|
fCongestionWindow += fSendMaxSegmentSize;
|
||||||
|
|
||||||
_SendQueued(segment.acknowledge);
|
_SendQueued();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ class TCPEndpoint : public net_protocol {
|
|||||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||||
uint32 segmentMaxSize, uint32 flightSize);
|
uint32 segmentMaxSize, uint32 flightSize);
|
||||||
status_t _SendQueued(bool force = false);
|
status_t _SendQueued(bool force = false);
|
||||||
status_t _SendQueued(tcp_sequence sendNext);
|
|
||||||
int _GetMSS(const struct sockaddr *) const;
|
int _GetMSS(const struct sockaddr *) const;
|
||||||
status_t _ShutdownEgress(bool closing);
|
status_t _ShutdownEgress(bool closing);
|
||||||
ssize_t _AvailableData() const;
|
ssize_t _AvailableData() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user