From ca1b900bdb8cd280418ade417a2f81b5b4b50a91 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Mon, 16 Apr 2007 03:19:59 +0000 Subject: [PATCH] support RFC 1323's TCP Timestamps (we are still not updating our estimator though). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20719 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/TCPEndpoint.cpp | 46 ++++++++++++++++++- .../network/protocols/tcp/TCPEndpoint.h | 5 ++ .../kernel/network/protocols/tcp/tcp.cpp | 30 ++++++++---- .../kernel/network/protocols/tcp/tcp.h | 24 +++++++--- 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index e3195df452..2e034410dd 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -179,6 +179,8 @@ TCPEndpoint::TCPEndpoint(net_socket *socket) fReceiveMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE), fReceiveQueue(socket->receive.buffer_size), fRoundTripTime(TCP_INITIAL_RTT), + fReceivedTSval(0), + fUsingTimestamps(false), fState(CLOSED), fFlags(0), //FLAG_OPTION_WINDOW_SHIFT), fError(B_OK), @@ -363,6 +365,10 @@ TCPEndpoint::Connect(const struct sockaddr *address) fSendMax = fInitialSendSequence; 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 status = _SendQueued(); if (status != B_OK) { @@ -794,6 +800,8 @@ TCPEndpoint::ListenReceive(tcp_segment_header &segment, net_buffer *buffer) TRACE(" ListenReceive() created new endpoint %p", endpoint); + endpoint->_UpdateTimestamps(segment, 0, false); + // send SYN+ACK status_t status = endpoint->_SendQueued(); @@ -866,10 +874,12 @@ TCPEndpoint::SynchronizeSentReceive(tcp_segment_header &segment, net_buffer *buf fState = SYNCHRONIZE_RECEIVED; } + _UpdateTimestamps(segment, 0, false); + segment.flags &= ~TCP_FLAG_SYNCHRONIZE; // we handled this flag now, it must not be set for further processing - return Receive(segment, buffer) | IMMEDIATE_ACKNOWLEDGE; + return _Receive(segment, buffer) | IMMEDIATE_ACKNOWLEDGE; } @@ -892,6 +902,9 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) && fReceiveNext == segment.sequence && advertisedWindow > 0 && advertisedWindow == fSendWindow && fSendNext == fSendMax) { + + _UpdateTimestamps(segment, buffer->size, true); + if (buffer->size == 0) { // this is a pure acknowledge segment - we're on the sending end if (fSendUnacknowledged < segment.acknowledge @@ -1047,6 +1060,13 @@ TCPEndpoint::_SendQueued(bool force) tcp_segment_header segment; segment.flags = _CurrentFlags(); + segment.urgent_offset = 0; + + if (fUsingTimestamps) { + segment.has_timestamps = true; + segment.TSecr = fReceivedTSval; + segment.TSval = system_time(); + } uint32 sendWindow = fSendWindow; uint32 available = fSendQueue.Available(fSendNext); @@ -1172,6 +1192,9 @@ TCPEndpoint::_SendQueued(bool force) return status; } + if (segment.flags & TCP_FLAG_ACKNOWLEDGE) + fLastAcknowledgeSent = segment.acknowledge; + length -= segmentLength; if (length == 0) break; @@ -1257,6 +1280,8 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer) { uint32 advertisedWindow = (uint32)segment.advertised_window << fSendWindowShift; + size_t segmentLength = buffer->size; + if (segment.flags & TCP_FLAG_RESET) { // is this a valid reset? if (fLastAcknowledgeSent <= segment.sequence @@ -1449,6 +1474,7 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer) } if (segment.flags & TCP_FLAG_FINISH) { + segmentLength++; if (fState != CLOSED && fState != LISTEN && fState != SYNCHRONIZE_SENT) { TRACE("Receive(): peer is finishing connection!"); fReceiveNext++; @@ -1486,12 +1512,30 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer) if (buffer->size > 0 || (segment.flags & TCP_FLAG_SYNCHRONIZE) != 0) action |= ACKNOWLEDGE; + _UpdateTimestamps(segment, segmentLength, true); + TRACE("Receive() Action %ld", action); return action; } +void +TCPEndpoint::_UpdateTimestamps(tcp_segment_header &segment, size_t segmentLength, + bool checkSequence) +{ + fUsingTimestamps = segment.has_timestamps; + + if (fUsingTimestamps) { + tcp_sequence sequence(segment.sequence); + + if (!checkSequence || (fLastAcknowledgeSent >= sequence + && fLastAcknowledgeSent < (sequence + segmentLength))) + fReceivedTSval = segment.TSval; + } +} + + // #pragma mark - timer diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index 7b3cfb4ecc..3bf5a6761a 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -95,6 +95,8 @@ class TCPEndpoint : public net_protocol { void _NotifyReader(); bool _ShouldReceive() const; int32 _Receive(tcp_segment_header& segment, net_buffer *buffer); + void _UpdateTimestamps(tcp_segment_header& segment, + size_t segmentLength, bool checkSequence); static void _TimeWaitTimer(net_timer *timer, void *data); static void _RetransmitTimer(net_timer *timer, void *data); @@ -146,6 +148,9 @@ class TCPEndpoint : public net_protocol { uint32 fTrackingSequence; bool fTracking; + uint32 fReceivedTSval; + bool fUsingTimestamps; + uint32 fCongestionWindow; uint32 fSlowStartThreshold; diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index 6a2a406f26..03c28ccfef 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -120,11 +120,26 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize) option->max_segment_size = htons(segment.max_segment_size); bump_option(option, length); } + + if (segment.has_timestamps && length + 12 < bufferSize) { + // two NOPs so the timestamps get aligned to a 4 byte boundary + option->kind = TCP_OPTION_NOP; + bump_option(option, length); + option->kind = TCP_OPTION_NOP; + bump_option(option, length); + option->kind = TCP_OPTION_TIMESTAMP; + option->length = 10; + option->timestamp.TSval = htonl(segment.TSval); + // TSecr is opaque to us, we send it as we received it. + option->timestamp.TSecr = segment.TSecr; + bump_option(option, length); + } + if (segment.has_window_shift && length + 4 < bufferSize) { // insert one NOP so that the subsequent data is aligned on a 4 byte boundary option->kind = TCP_OPTION_NOP; bump_option(option, length); - + option->kind = TCP_OPTION_WINDOW_SHIFT; option->length = 3; option->window_shift = segment.window_shift; @@ -171,8 +186,7 @@ add_tcp_header(net_address_module_info *addressModule, header.flags = segment.flags; header.advertised_window = htons(segment.advertised_window); header.checksum = 0; - header.urgent_offset = 0; - // TODO: urgent pointer not yet supported + header.urgent_offset = segment.urgent_offset; // we must detach before calculating the checksum as we may // not have a contiguous buffer. @@ -226,7 +240,9 @@ process_options(tcp_segment_header &segment, net_buffer *buffer, int32 size) length = 3; break; case TCP_OPTION_TIMESTAMP: - // TODO: support timestamp! + segment.has_timestamps = true; + segment.TSval = option->timestamp.TSval; + segment.TSecr = ntohl(option->timestamp.TSecr); length = 10; break; @@ -515,11 +531,7 @@ tcp_receive_data(net_buffer *buffer) segment.advertised_window = header.AdvertisedWindow(); segment.urgent_offset = header.UrgentOffset(); segment.flags = header.flags; - if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0) { - // for now, we only process the options in the SYN segment - // TODO: when we support timestamps, they could be handled specifically - process_options(segment, buffer, headerLength - sizeof(tcp_header)); - } + process_options(segment, buffer, headerLength - sizeof(tcp_header)); bufferHeader.Remove(headerLength); // we no longer need to keep the header around diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.h b/src/add-ons/kernel/network/protocols/tcp/tcp.h index 33640e55c5..48e9122124 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.h +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.h @@ -112,9 +112,11 @@ struct tcp_option { union { uint8 window_shift; uint16 max_segment_size; - uint32 timestamp; + struct { + uint32 TSval; + uint32 TSecr; + } timestamp; }; - uint32 timestamp_reply; } _PACKED; enum tcp_option_kind { @@ -128,18 +130,28 @@ enum tcp_option_kind { #define TCP_MAX_WINDOW_SHIFT 14 struct tcp_segment_header { - tcp_segment_header() : has_window_shift(false), window_shift(0), max_segment_size(0) {} - // constructor zeros options + tcp_segment_header() + : + window_shift(0), + max_segment_size(0), + has_window_shift(false), + has_timestamps(false) + {} uint32 sequence; uint32 acknowledge; uint16 advertised_window; uint16 urgent_offset; uint8 flags; - uint8 has_window_shift : 1; - uint8 window_shift : 7; + uint8 window_shift; uint16 max_segment_size; + uint32 TSval; + uint32 TSecr; + + bool has_window_shift : 1; + bool has_timestamps : 1; + bool AcknowledgeOnly() const { return (flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_RESET