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
This commit is contained in:
parent
03d7f17e07
commit
ca1b900bdb
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -120,6 +120,21 @@ 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;
|
||||
@ -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));
|
||||
}
|
||||
|
||||
bufferHeader.Remove(headerLength);
|
||||
// we no longer need to keep the header around
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user