* If a new buffer had its last part in common with an existing larger buffer,

BufferQueue::Add() tried to remove a negative amount of bytes. This could
  bring a download to a complete halt (as could the other one due to the list
  link mixup).
* While the RTT computation still seems to work not that good (with a drop quote
  of 50% I would easily reach retransmit timeouts of 80 secs), TCP should now
  work a lot better on a flaky connection.
* Renamed _GetMSS() to _MaxSegmentSize().
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22677 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-10-23 10:42:46 +00:00
parent c76695a275
commit 1d0b34faae
4 changed files with 32 additions and 19 deletions
@@ -72,7 +72,8 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
{ {
TRACE(("BufferQueue@%p::Add(buffer %p, size %lu, sequence %lu)\n", TRACE(("BufferQueue@%p::Add(buffer %p, size %lu, sequence %lu)\n",
this, buffer, buffer->size, (uint32)sequence)); this, buffer, buffer->size, (uint32)sequence));
TRACE((" in: first: %lu, last: %lu, num: %lu, cont: %lu\n", (uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes)); TRACE((" in: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes));
buffer->sequence = sequence; buffer->sequence = sequence;
@@ -80,14 +81,18 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
// we usually just add the buffer to the end of the queue // we usually just add the buffer to the end of the queue
fList.Add(buffer); fList.Add(buffer);
if (sequence == fLastSequence && fLastSequence - fFirstSequence == fNumBytes) { if (sequence == fLastSequence
// there is no hole in the buffer, we can make the whole buffer available && fLastSequence - fFirstSequence == fNumBytes) {
// there is no hole in the buffer, we can make the whole buffer
// available
fContiguousBytes += buffer->size; fContiguousBytes += buffer->size;
} }
fLastSequence = sequence + buffer->size; fLastSequence = sequence + buffer->size;
fNumBytes += buffer->size; fNumBytes += buffer->size;
TRACE((" out0: first: %lu, last: %lu, num: %lu, cont: %lu\n", (uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes));
TRACE((" out0: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes));
return; return;
} }
@@ -100,7 +105,7 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
sequence = fFirstSequence; sequence = fFirstSequence;
} }
// find for the place where to insert the buffer into the queue // find the place where to insert the buffer into the queue
SegmentList::ReverseIterator iterator = fList.GetReverseIterator(); SegmentList::ReverseIterator iterator = fList.GetReverseIterator();
net_buffer *previous = NULL; net_buffer *previous = NULL;
@@ -117,9 +122,9 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
// check if we have duplicate data, and remove it if that is the case // check if we have duplicate data, and remove it if that is the case
if (previous != NULL) { if (previous != NULL) {
if (sequence == previous->sequence) { if (sequence == previous->sequence) {
// we already have at least part of this data - ignore new data whenever // we already have at least part of this data - ignore new data
// it makes sense (because some TCP implementations send bogus data when // whenever it makes sense (because some TCP implementations send
// probing the window) // bogus data when probing the window)
if (previous->size >= buffer->size) { if (previous->size >= buffer->size) {
gBufferModule->free(buffer); gBufferModule->free(buffer);
buffer = NULL; buffer = NULL;
@@ -127,8 +132,10 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
fList.Remove(previous); fList.Remove(previous);
gBufferModule->free(previous); gBufferModule->free(previous);
} }
} else if (tcp_sequence(previous->sequence + previous->size) > sequence) } else if (tcp_sequence(previous->sequence + previous->size) > sequence) {
gBufferModule->remove_header(buffer, previous->sequence + previous->size - sequence); gBufferModule->remove_header(buffer,
previous->sequence + previous->size - sequence);
}
} }
if (buffer != NULL && next != NULL if (buffer != NULL && next != NULL
@@ -140,12 +147,15 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
fList.Remove(remove); fList.Remove(remove);
gBufferModule->free(remove); gBufferModule->free(remove);
} else } else {
gBufferModule->remove_trailer(buffer, next->sequence - (sequence + buffer->size)); gBufferModule->remove_trailer(buffer,
sequence + buffer->size - next->sequence);
}
} }
if (buffer == NULL) { if (buffer == NULL) {
TRACE((" out1: first: %lu, last: %lu, num: %lu, cont: %lu\n", (uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes)); TRACE((" out1: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes));
return; return;
} }
@@ -164,10 +174,12 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
fContiguousBytes += buffer->size; fContiguousBytes += buffer->size;
buffer = (struct net_buffer *)buffer->link.next; buffer = (struct net_buffer *)buffer->link.next;
} while (buffer != NULL && fFirstSequence + fContiguousBytes == buffer->sequence); } while (buffer != NULL
&& fFirstSequence + fContiguousBytes == buffer->sequence);
} }
TRACE((" out2: first: %lu, last: %lu, num: %lu, cont: %lu\n", (uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes)); TRACE((" out2: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes));
} }
@@ -64,7 +64,7 @@
#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 %lu %llu\n", \ dprintf("TCP PROBE %llu %s %s %ld snxt %lu suna %lu cw %lu sst %lu win %lu swin %lu smax-suna %lu savail %lu sqused %lu rto %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, \
@@ -1320,7 +1320,7 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
int int
TCPEndpoint::_GetMSS(const sockaddr *address) const TCPEndpoint::_MaxSegmentSize(const sockaddr *address) const
{ {
return next->module->get_mtu(next, address) - sizeof(tcp_header); return next->module->get_mtu(next, address) - sizeof(tcp_header);
} }
@@ -1714,7 +1714,7 @@ TCPEndpoint::_PrepareSendPath(const sockaddr *peer)
// we are counting the SYN here // we are counting the SYN here
fSendQueue.SetInitialSequence(fSendNext + 1); fSendQueue.SetInitialSequence(fSendNext + 1);
fReceiveMaxSegmentSize = _GetMSS(peer); fReceiveMaxSegmentSize = _MaxSegmentSize(peer);
// Compute the window shift we advertise to our peer - if it doesn't support // Compute the window shift we advertise to our peer - if it doesn't support
// this option, this will be reset to 0 (when its SYN is received) // this option, this will be reset to 0 (when its SYN is received)
@@ -94,7 +94,7 @@ class TCPEndpoint : public net_protocol, public ProtocolSocket {
uint32 segmentMaxSize, uint32 flightSize); uint32 segmentMaxSize, uint32 flightSize);
status_t _SendQueued(bool force = false); status_t _SendQueued(bool force = false);
status_t _SendQueued(bool force, uint32 sendWindow); status_t _SendQueued(bool force, uint32 sendWindow);
int _GetMSS(const struct sockaddr *) const; int _MaxSegmentSize(const struct sockaddr *) const;
status_t _ShutdownEgress(bool closing); status_t _ShutdownEgress(bool closing);
ssize_t _AvailableData() const; ssize_t _AvailableData() const;
void _NotifyReader(); void _NotifyReader();
@@ -30,6 +30,7 @@
#include <NetBufferUtilities.h> #include <NetBufferUtilities.h>
#include <NetUtilities.h> #include <NetUtilities.h>
//#define TRACE_TCP //#define TRACE_TCP
#ifdef TRACE_TCP #ifdef TRACE_TCP
# define TRACE(x) dprintf x # define TRACE(x) dprintf x