support TCP Window Scale on sent segments.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20729 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-17 01:07:58 +00:00
parent 31ebfe61e4
commit 58bef2f444
2 changed files with 43 additions and 43 deletions
@@ -61,7 +61,7 @@
// constants for the fFlags field // constants for the fFlags field
enum { enum {
FLAG_OPTION_WINDOW_SHIFT = 0x01, FLAG_OPTION_WINDOW_SCALE = 0x01,
FLAG_OPTION_TIMESTAMP = 0x02, FLAG_OPTION_TIMESTAMP = 0x02,
// TODO: Should FLAG_NO_RECEIVE apply as well to received connections? // TODO: Should FLAG_NO_RECEIVE apply as well to received connections?
// That is, what is expected from accept() after a shutdown() // That is, what is expected from accept() after a shutdown()
@@ -180,9 +180,8 @@ TCPEndpoint::TCPEndpoint(net_socket *socket)
fReceiveQueue(socket->receive.buffer_size), fReceiveQueue(socket->receive.buffer_size),
fRoundTripTime(TCP_INITIAL_RTT), fRoundTripTime(TCP_INITIAL_RTT),
fReceivedTSval(0), fReceivedTSval(0),
fUsingTimestamps(false),
fState(CLOSED), fState(CLOSED),
fFlags(0), //FLAG_OPTION_WINDOW_SHIFT), fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP),
fError(B_OK), fError(B_OK),
fSpawned(false) fSpawned(false)
{ {
@@ -366,10 +365,6 @@ TCPEndpoint::Connect(const struct sockaddr *address)
fSendMax = fInitialSendSequence; fSendMax = fInitialSendSequence;
fSendQueue.SetInitialSequence(fSendNext + 1); fSendQueue.SetInitialSequence(fSendNext + 1);
// try to use timestamps, if the peer doesn't reply with the TS
// option as well we'll stop using them.
fUsingTimestamps = true;
// send SYN // send SYN
status = _SendQueued(); status = _SendQueued();
if (status != B_OK) { if (status != B_OK) {
@@ -693,7 +688,7 @@ TCPEndpoint::DelayedAcknowledge()
if (gStackModule->cancel_timer(&fDelayedAcknowledgeTimer)) { if (gStackModule->cancel_timer(&fDelayedAcknowledgeTimer)) {
// timer was active, send an ACK now (with the exception above, // timer was active, send an ACK now (with the exception above,
// we send every other ACK) // we send every other ACK)
return _SendQueued(); return SendAcknowledge();
} }
gStackModule->set_timer(&fDelayedAcknowledgeTimer, TCP_DELAYED_ACKNOWLEDGE_TIMEOUT); gStackModule->set_timer(&fDelayedAcknowledgeTimer, TCP_DELAYED_ACKNOWLEDGE_TIMEOUT);
@@ -808,10 +803,10 @@ TCPEndpoint::Spawn(TCPEndpoint *parent, tcp_segment_header &segment,
else else
fReceiveMaxSegmentSize = TCP_DEFAULT_MAX_SEGMENT_SIZE; fReceiveMaxSegmentSize = TCP_DEFAULT_MAX_SEGMENT_SIZE;
if (segment.has_window_shift) { if (segment.has_window_shift) {
fFlags |= FLAG_OPTION_WINDOW_SHIFT; fFlags |= FLAG_OPTION_WINDOW_SCALE;
fSendWindowShift = segment.window_shift; fSendWindowShift = segment.window_shift;
} else { } else {
fFlags &= ~FLAG_OPTION_WINDOW_SHIFT; fFlags &= ~FLAG_OPTION_WINDOW_SCALE;
fReceiveWindowShift = 0; fReceiveWindowShift = 0;
} }
} }
@@ -865,10 +860,10 @@ TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment, net_buffer *bu
else else
fReceiveMaxSegmentSize = TCP_DEFAULT_MAX_SEGMENT_SIZE; fReceiveMaxSegmentSize = TCP_DEFAULT_MAX_SEGMENT_SIZE;
if (segment.has_window_shift) { if (segment.has_window_shift) {
fFlags |= FLAG_OPTION_WINDOW_SHIFT; fFlags |= FLAG_OPTION_WINDOW_SCALE;
fSendWindowShift = segment.window_shift; fSendWindowShift = segment.window_shift;
} else { } else {
fFlags &= ~FLAG_OPTION_WINDOW_SHIFT; fFlags &= ~FLAG_OPTION_WINDOW_SCALE;
fReceiveWindowShift = 0; fReceiveWindowShift = 0;
} }
@@ -975,18 +970,9 @@ TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
&& fReceiveQueue.IsContiguous() && fReceiveQueue.IsContiguous()
&& fReceiveQueue.Free() >= buffer->size && fReceiveQueue.Free() >= buffer->size
&& !(fFlags & FLAG_NO_RECEIVE)) { && !(fFlags & FLAG_NO_RECEIVE)) {
TRACE("Receive(): header prediction receive!"); _AddData(segment, buffer);
// we're on the receiving end of the connection, and this segment
// is the one we were expecting, in-sequence
fReceiveNext += buffer->size;
TRACE("Receive(): receive next = %lu", (uint32)fReceiveNext);
fReceiveQueue.Add(buffer, segment.sequence);
if (segment.flags & TCP_FLAG_PUSH)
fReceiveQueue.SetPushPointer();
_NotifyReader(); _NotifyReader();
return KEEP | ((segment.flags & TCP_FLAG_PUSH) ?
return KEEP | (segment.flags & TCP_FLAG_PUSH ?
IMMEDIATE_ACKNOWLEDGE : ACKNOWLEDGE); IMMEDIATE_ACKNOWLEDGE : ACKNOWLEDGE);
} }
} }
@@ -1104,10 +1090,10 @@ TCPEndpoint::_SendQueued(bool force)
segment.flags = _CurrentFlags(); segment.flags = _CurrentFlags();
segment.urgent_offset = 0; segment.urgent_offset = 0;
if (fUsingTimestamps) { if (fOptions & FLAG_OPTION_TIMESTAMP) {
segment.has_timestamps = true; segment.has_timestamps = true;
segment.TSecr = fReceivedTSval; segment.TSecr = fReceivedTSval;
segment.TSval = system_time(); segment.TSval = 0;
} }
uint32 sendWindow = fSendWindow; uint32 sendWindow = fSendWindow;
@@ -1138,8 +1124,13 @@ TCPEndpoint::_SendQueued(bool force)
segment.flags &= ~TCP_FLAG_FINISH; segment.flags &= ~TCP_FLAG_FINISH;
} }
segment.advertised_window = min_c(65535, fReceiveQueue.Free()); size_t availableBytes = fReceiveQueue.Free();
// TODO: support shift option!
if (fOptions & FLAG_OPTION_WINDOW_SCALE)
segment.advertised_window = availableBytes >> fReceiveWindowShift;
else
segment.advertised_window = min_c(TCP_MAX_WINDOW, availableBytes);
segment.acknowledge = fReceiveNext; segment.acknowledge = fReceiveNext;
segment.urgent_offset = 0; segment.urgent_offset = 0;
@@ -1150,7 +1141,6 @@ TCPEndpoint::_SendQueued(bool force)
&& !gStackModule->is_timer_active(&fPersistTimer) && !gStackModule->is_timer_active(&fPersistTimer)
&& !gStackModule->is_timer_active(&fRetransmitTimer)) && !gStackModule->is_timer_active(&fRetransmitTimer))
_StartPersistTimer(); _StartPersistTimer();
return B_OK; return B_OK;
} }
@@ -1181,7 +1171,7 @@ TCPEndpoint::_SendQueued(bool force)
&& (fOptions & TCP_NOOPT) == 0) { && (fOptions & TCP_NOOPT) == 0) {
// add connection establishment options // add connection establishment options
segment.max_segment_size = fReceiveMaxSegmentSize; segment.max_segment_size = fReceiveMaxSegmentSize;
if ((fFlags & FLAG_OPTION_WINDOW_SHIFT) != 0) { if (fFlags & FLAG_OPTION_WINDOW_SCALE) {
segment.has_window_shift = true; segment.has_window_shift = true;
segment.window_shift = fReceiveWindowShift; segment.window_shift = fReceiveWindowShift;
} }
@@ -1487,17 +1477,10 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
bool notify = false; bool notify = false;
if (buffer->size > 0 && _ShouldReceive()) { if (buffer->size > 0 && _ShouldReceive()) {
fReceiveQueue.Add(buffer, segment.sequence); _AddData(segment, buffer);
fReceiveNext += buffer->size;
notify = true; notify = true;
TRACE("Receive(): adding data, receive next = %lu. Now have %lu bytes.", } else
(uint32)fReceiveNext, fReceiveQueue.Available());
if (segment.flags & TCP_FLAG_PUSH)
fReceiveQueue.SetPushPointer();
} else {
action = (action & ~KEEP) | DROP; action = (action & ~KEEP) | DROP;
}
if (segment.flags & TCP_FLAG_FINISH) { if (segment.flags & TCP_FLAG_FINISH) {
segmentLength++; segmentLength++;
@@ -1550,9 +1533,12 @@ void
TCPEndpoint::_UpdateTimestamps(tcp_segment_header &segment, size_t segmentLength, TCPEndpoint::_UpdateTimestamps(tcp_segment_header &segment, size_t segmentLength,
bool checkSequence) bool checkSequence)
{ {
fUsingTimestamps = segment.has_timestamps; if (segment.has_timestamps)
fOptions |= FLAG_OPTION_TIMESTAMP;
else
fOptions &= ~FLAG_OPTION_TIMESTAMP;
if (fUsingTimestamps) { if (fOptions & FLAG_OPTION_TIMESTAMP) {
tcp_sequence sequence(segment.sequence); tcp_sequence sequence(segment.sequence);
if (!checkSequence || (fLastAcknowledgeSent >= sequence if (!checkSequence || (fLastAcknowledgeSent >= sequence
@@ -1589,6 +1575,20 @@ TCPEndpoint::_WaitForEstablished(RecursiveLocker &locker, bigtime_t timeout)
} }
void
TCPEndpoint::_AddData(tcp_segment_header &segment, net_buffer *buffer)
{
fReceiveNext += buffer->size;
fReceiveQueue.Add(buffer, segment.sequence);
TRACE(" _AddData(): adding data, receive next = %lu. Now have %lu bytes.",
(uint32)fReceiveNext, fReceiveQueue.Available());
if (segment.flags & TCP_FLAG_PUSH)
fReceiveQueue.SetPushPointer();
}
// #pragma mark - timer // #pragma mark - timer
@@ -1629,7 +1629,7 @@ TCPEndpoint::_DelayedAcknowledgeTimer(struct net_timer *timer, void *data)
if (!locker.IsLocked()) if (!locker.IsLocked())
return; return;
endpoint->_SendQueued(true); endpoint->SendAcknowledge();
} }
@@ -101,6 +101,7 @@ class TCPEndpoint : public net_protocol {
size_t segmentLength, bool checkSequence); size_t segmentLength, bool checkSequence);
void _MarkEstablished(); void _MarkEstablished();
status_t _WaitForEstablished(RecursiveLocker &lock, bigtime_t timeout); status_t _WaitForEstablished(RecursiveLocker &lock, bigtime_t timeout);
void _AddData(tcp_segment_header &segment, net_buffer *buffer);
static void _TimeWaitTimer(net_timer *timer, void *data); static void _TimeWaitTimer(net_timer *timer, void *data);
static void _RetransmitTimer(net_timer *timer, void *data); static void _RetransmitTimer(net_timer *timer, void *data);
@@ -153,7 +154,6 @@ class TCPEndpoint : public net_protocol {
bool fTracking; bool fTracking;
uint32 fReceivedTSval; uint32 fReceivedTSval;
bool fUsingTimestamps;
uint32 fCongestionWindow; uint32 fCongestionWindow;
uint32 fSlowStartThreshold; uint32 fSlowStartThreshold;