* BufferQueue::Free() no longer will return negative values. As is, the max

bytes restriction is only a soft limit. This fixes stalling TCP connections
  because everything received would be out of window once this happened.
* Added a TODO to look into TCP's window management - it doesn't seem to be
  right.
* Fixed build with tracing turned on.
* Made the fNumber member of tcp_sequence private.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35468 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-02-15 13:27:26 +00:00
parent 10cb62616f
commit 965abdebd5
4 changed files with 82 additions and 64 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -59,7 +59,8 @@ BufferQueue::SetMaxBytes(size_t maxBytes)
void void
BufferQueue::SetInitialSequence(tcp_sequence sequence) BufferQueue::SetInitialSequence(tcp_sequence sequence)
{ {
TRACE(("BufferQueue@%p::SetInitialSequence(%lu)\n", this, (uint32)sequence)); TRACE(("BufferQueue@%p::SetInitialSequence(%lu)\n", this,
sequence.Number()));
fFirstSequence = fLastSequence = sequence; fFirstSequence = fLastSequence = sequence;
} }
@ -77,9 +78,9 @@ void
BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence) 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, sequence.Number()));
TRACE((" in: first: %lu, last: %lu, num: %lu, cont: %lu\n", TRACE((" in: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
fContiguousBytes)); fContiguousBytes));
VERIFY(); VERIFY();
@ -112,7 +113,7 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
fNumBytes += buffer->size; fNumBytes += buffer->size;
TRACE((" out0: first: %lu, last: %lu, num: %lu, cont: %lu\n", TRACE((" out0: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
fContiguousBytes)); fContiguousBytes));
VERIFY(); VERIFY();
return; return;
@ -190,7 +191,7 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
if (buffer == NULL) { if (buffer == NULL) {
TRACE((" out1: first: %lu, last: %lu, num: %lu, cont: %lu\n", TRACE((" out1: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
fContiguousBytes)); fContiguousBytes));
VERIFY(); VERIFY();
return; return;
@ -217,7 +218,8 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
} }
TRACE((" out2: first: %lu, last: %lu, num: %lu, cont: %lu\n", TRACE((" out2: first: %lu, last: %lu, num: %lu, cont: %lu\n",
(uint32)fFirstSequence, (uint32)fLastSequence, fNumBytes, fContiguousBytes)); fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
fContiguousBytes));
VERIFY(); VERIFY();
} }
@ -230,7 +232,8 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
status_t status_t
BufferQueue::RemoveUntil(tcp_sequence sequence) BufferQueue::RemoveUntil(tcp_sequence sequence)
{ {
TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence)); TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this,
sequence.Number()));
VERIFY(); VERIFY();
if (sequence < fFirstSequence) if (sequence < fFirstSequence)
@ -280,7 +283,7 @@ status_t
BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes)
{ {
TRACE(("BufferQueue@%p::Get(sequence %lu, bytes %lu)\n", this, TRACE(("BufferQueue@%p::Get(sequence %lu, bytes %lu)\n", this,
(uint32)sequence, bytes)); sequence.Number(), bytes));
VERIFY(); VERIFY();
if (bytes == 0) if (bytes == 0)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -23,61 +23,74 @@ typedef DoublyLinkedList<struct net_buffer,
class BufferQueue { class BufferQueue {
public: public:
BufferQueue(size_t maxBytes); BufferQueue(size_t maxBytes);
~BufferQueue(); ~BufferQueue();
void SetMaxBytes(size_t maxBytes); void SetMaxBytes(size_t maxBytes);
void SetInitialSequence(tcp_sequence sequence); void SetInitialSequence(tcp_sequence sequence);
void Add(net_buffer* buffer); void Add(net_buffer* buffer);
void Add(net_buffer* buffer, tcp_sequence sequence); void Add(net_buffer* buffer, tcp_sequence sequence);
status_t RemoveUntil(tcp_sequence sequence); status_t RemoveUntil(tcp_sequence sequence);
status_t Get(net_buffer* buffer, tcp_sequence sequence, status_t Get(net_buffer* buffer, tcp_sequence sequence,
size_t bytes); size_t bytes);
status_t Get(size_t bytes, bool remove, status_t Get(size_t bytes, bool remove,
net_buffer** _buffer); net_buffer** _buffer);
size_t Available() const { return fContiguousBytes; } size_t Available() const { return fContiguousBytes; }
size_t Available(tcp_sequence sequence) const; size_t Available(tcp_sequence sequence) const;
inline size_t PushedData() const; inline size_t PushedData() const;
void SetPushPointer(); void SetPushPointer();
size_t Used() const { return fNumBytes; } size_t Used() const { return fNumBytes; }
size_t Free() const { return fMaxBytes - fNumBytes; } inline size_t Free() const;
size_t Size() const { return fMaxBytes; } size_t Size() const { return fMaxBytes; }
bool IsContiguous() const bool IsContiguous() const
{ return fNumBytes == fContiguousBytes; } { return fNumBytes == fContiguousBytes; }
tcp_sequence FirstSequence() const { return fFirstSequence; } tcp_sequence FirstSequence() const { return fFirstSequence; }
tcp_sequence LastSequence() const { return fLastSequence; } tcp_sequence LastSequence() const { return fLastSequence; }
tcp_sequence NextSequence() const tcp_sequence NextSequence() const
{ return fFirstSequence + fContiguousBytes; } { return fFirstSequence + fContiguousBytes; }
#if DEBUG_BUFFER_QUEUE #if DEBUG_BUFFER_QUEUE
void Verify() const; void Verify() const;
void Dump() const; void Dump() const;
#endif #endif
private: private:
SegmentList fList; SegmentList fList;
size_t fMaxBytes; size_t fMaxBytes;
size_t fNumBytes; size_t fNumBytes;
size_t fContiguousBytes; size_t fContiguousBytes;
tcp_sequence fFirstSequence; tcp_sequence fFirstSequence;
tcp_sequence fLastSequence; tcp_sequence fLastSequence;
tcp_sequence fPushPointer; tcp_sequence fPushPointer;
}; };
size_t size_t
BufferQueue::PushedData() const BufferQueue::PushedData() const
{ {
// we must check if fPushPointer is not 0 here due to // We must check if fPushPointer is not 0 here due to
// tcp_sequence's special handling of > // tcp_sequence's special handling of >
return fPushPointer != 0 && fPushPointer > fFirstSequence return fPushPointer != 0 && fPushPointer > fFirstSequence
? (fPushPointer - fFirstSequence).Number() : 0; ? (fPushPointer - fFirstSequence).Number() : 0;
} }
size_t
BufferQueue::Free() const
{
// Max bytes is a soft limit, so it can be lower than the actual amount of
// data in the queue. TCP should never advertize a window outside the max
// buffer size, though.
if (fMaxBytes > fNumBytes)
return fMaxBytes - fNumBytes;
return 0;
}
#endif // BUFFER_QUEUE_H #endif // BUFFER_QUEUE_H

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -411,7 +411,8 @@ WaitList::Signal()
TCPEndpoint::TCPEndpoint(net_socket* socket) TCPEndpoint::TCPEndpoint(net_socket* socket)
: ProtocolSocket(socket), :
ProtocolSocket(socket),
fManager(NULL), fManager(NULL),
fReceiveList("tcp receive"), fReceiveList("tcp receive"),
fSendList("tcp send"), fSendList("tcp send"),
@ -1301,7 +1302,7 @@ TCPEndpoint::_AddData(tcp_segment_header& segment, net_buffer* buffer)
fReceiveNext = fReceiveQueue.NextSequence(); fReceiveNext = fReceiveQueue.NextSequence();
TRACE(" _AddData(): adding data, receive next = %lu. Now have %lu bytes.", TRACE(" _AddData(): adding data, receive next = %lu. Now have %lu bytes.",
(uint32)fReceiveNext, fReceiveQueue.Available()); fReceiveNext.Number(), fReceiveQueue.Available());
if (segment.flags & TCP_FLAG_PUSH) if (segment.flags & TCP_FLAG_PUSH)
fReceiveQueue.SetPushPointer(); fReceiveQueue.SetPushPointer();
@ -1515,8 +1516,8 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, net_buffer* buffer)
if (!segment_in_sequence(segment, segmentLength, fReceiveNext, if (!segment_in_sequence(segment, segmentLength, fReceiveNext,
fReceiveWindow)) { fReceiveWindow)) {
TRACE(" Receive(): segment out of window, next: %lu wnd: %lu", TRACE(" Receive(): segment out of window, next: %lu wnd: %lu",
(uint32)fReceiveNext, fReceiveWindow); fReceiveNext.Number(), fReceiveWindow);
if (segment.flags & TCP_FLAG_RESET) { if ((segment.flags & TCP_FLAG_RESET) != 0) {
// TODO: this doesn't look right - review! // TODO: this doesn't look right - review!
return DROP; return DROP;
} }
@ -1524,7 +1525,7 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, net_buffer* buffer)
} }
} }
if (segment.flags & TCP_FLAG_RESET) { if ((segment.flags & TCP_FLAG_RESET) != 0) {
// Is this a valid reset? // Is this a valid reset?
// We generally ignore resets in time wait state (see RFC 1337) // We generally ignore resets in time wait state (see RFC 1337)
if (fLastAcknowledgeSent <= segment.sequence if (fLastAcknowledgeSent <= segment.sequence
@ -1556,9 +1557,11 @@ TCPEndpoint::_Receive(tcp_segment_header& segment, net_buffer* buffer)
return DROP | RESET; return DROP | RESET;
} }
// TODO: Check this! Why do we advertize a window outside of what we should
// buffer?
fReceiveWindow = max_c(fReceiveQueue.Free(), fReceiveWindow); fReceiveWindow = max_c(fReceiveQueue.Free(), fReceiveWindow);
// the window must not shrink // the window must not shrink
// trim buffer to be within the receive window // trim buffer to be within the receive window
int32 drop = (int32)(fReceiveNext - segment.sequence).Number(); int32 drop = (int32)(fReceiveNext - segment.sequence).Number();
if (drop > 0) { if (drop > 0) {
@ -1959,7 +1962,7 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
if (consumedWindow > sendWindow) { 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 -= consumedWindow; sendWindow -= consumedWindow;
@ -2019,8 +2022,8 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
PrintAddress(buffer->destination), segment.flags, segment.sequence, PrintAddress(buffer->destination), segment.flags, segment.sequence,
segment.acknowledge, segment.advertised_window, segment.acknowledge, segment.advertised_window,
fCongestionWindow, fSlowStartThreshold, segmentLength, fCongestionWindow, fSlowStartThreshold, segmentLength,
(uint32)fSendQueue.FirstSequence(), fSendQueue.FirstSequence().Number(),
(uint32)fSendQueue.LastSequence()); fSendQueue.LastSequence().Number());
T(Send(this, segment, buffer, fSendQueue.FirstSequence(), T(Send(this, segment, buffer, fSendQueue.FirstSequence(),
fSendQueue.LastSequence())); fSendQueue.LastSequence()));

View File

@ -108,8 +108,7 @@ public:
return fNumber - 1; return fNumber - 1;
} }
// Conceptually private, but used in global operators. private:
//private:
uint32 fNumber; uint32 fNumber;
}; };
@ -120,56 +119,56 @@ public:
inline bool inline bool
operator>(tcp_sequence a, tcp_sequence b) operator>(tcp_sequence a, tcp_sequence b)
{ {
return (int32)(a.fNumber - b.fNumber) > 0; return (int32)(a.Number() - b.Number()) > 0;
} }
inline bool inline bool
operator>=(tcp_sequence a, tcp_sequence b) operator>=(tcp_sequence a, tcp_sequence b)
{ {
return (int32)(a.fNumber - b.fNumber) >= 0; return (int32)(a.Number() - b.Number()) >= 0;
} }
inline bool inline bool
operator<(tcp_sequence a, tcp_sequence b) operator<(tcp_sequence a, tcp_sequence b)
{ {
return (int32)(a.fNumber - b.fNumber) < 0; return (int32)(a.Number() - b.Number()) < 0;
} }
inline bool inline bool
operator<=(tcp_sequence a, tcp_sequence b) operator<=(tcp_sequence a, tcp_sequence b)
{ {
return (int32)(a.fNumber - b.fNumber) <= 0; return (int32)(a.Number() - b.Number()) <= 0;
} }
inline tcp_sequence inline tcp_sequence
operator+(tcp_sequence a, tcp_sequence b) operator+(tcp_sequence a, tcp_sequence b)
{ {
return a.fNumber + b.fNumber; return a.Number() + b.Number();
} }
inline tcp_sequence inline tcp_sequence
operator-(tcp_sequence a, tcp_sequence b) operator-(tcp_sequence a, tcp_sequence b)
{ {
return a.fNumber - b.fNumber; return a.Number() - b.Number();
} }
inline bool inline bool
operator!=(tcp_sequence a, tcp_sequence b) operator!=(tcp_sequence a, tcp_sequence b)
{ {
return a.fNumber != b.fNumber; return a.Number() != b.Number();
} }
inline bool inline bool
operator==(tcp_sequence a, tcp_sequence b) operator==(tcp_sequence a, tcp_sequence b)
{ {
return a.fNumber == b.fNumber; return a.Number() == b.Number();
} }