TCP: only set FIN after the send queue has been exausted and we are in a state that requires it.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20735 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-17 08:02:41 +00:00
parent 7d524fb79b
commit 5534294ca1
@@ -1037,13 +1037,11 @@ TCPEndpoint::_SendQueued(bool force)
} }
uint32 segmentLength = min_c((uint32)length, fSendMaxSegmentSize); uint32 segmentLength = min_c((uint32)length, fSendMaxSegmentSize);
if (tcp_sequence(fSendNext + segmentLength) > fSendUnacknowledged + available) {
// we'll still have data in the queue after the next write, so remove the FIN bool wantsFinish = segment.flags & TCP_FLAG_FINISH;
segment.flags &= ~TCP_FLAG_FINISH; segment.flags &= ~TCP_FLAG_FINISH;
}
size_t availableBytes = fReceiveQueue.Free(); size_t availableBytes = fReceiveQueue.Free();
if (fFlags & FLAG_OPTION_WINDOW_SCALE) if (fFlags & FLAG_OPTION_WINDOW_SCALE)
segment.advertised_window = availableBytes >> fReceiveWindowShift; segment.advertised_window = availableBytes >> fReceiveWindowShift;
else else
@@ -1054,7 +1052,8 @@ TCPEndpoint::_SendQueued(bool force)
while (true) { while (true) {
// Determine if we should really send this segment // Determine if we should really send this segment
if (!force && !_ShouldSendSegment(segment, segmentLength, outstandingAcknowledge)) { if (!force && !wantsFinish && !_ShouldSendSegment(segment,
segmentLength, outstandingAcknowledge)) {
if (fSendQueue.Available() if (fSendQueue.Available()
&& !gStackModule->is_timer_active(&fPersistTimer) && !gStackModule->is_timer_active(&fPersistTimer)
&& !gStackModule->is_timer_active(&fRetransmitTimer)) && !gStackModule->is_timer_active(&fRetransmitTimer))
@@ -1078,9 +1077,11 @@ TCPEndpoint::_SendQueued(bool force)
AddressModule()->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer); AddressModule()->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer);
uint32 size = buffer->size; uint32 size = buffer->size;
if (length > 0 && fSendNext + segmentLength == fSendQueue.LastSequence()) { if (fSendNext + segmentLength == fSendQueue.LastSequence()) {
// if we've emptied our send queue, set the PUSH flag if (wantsFinish)
segment.flags |= TCP_FLAG_PUSH; segment.flags |= TCP_FLAG_FINISH;
if (length > 0)
segment.flags |= TCP_FLAG_PUSH;
} }
segment.sequence = fSendNext; segment.sequence = fSendNext;
@@ -1351,8 +1352,6 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
gStackModule->set_timer(&fRetransmitTimer, 1000000LL); gStackModule->set_timer(&fRetransmitTimer, 1000000LL);
} }
_Acknowledged(segment.acknowledge);
if (segment.acknowledge > fSendQueue.LastSequence() if (segment.acknowledge > fSendQueue.LastSequence()
&& fState > ESTABLISHED) { && fState > ESTABLISHED) {
TRACE("Receive(): FIN has been acknowledged!"); TRACE("Receive(): FIN has been acknowledged!");
@@ -1364,7 +1363,7 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
case CLOSING: case CLOSING:
fState = TIME_WAIT; fState = TIME_WAIT;
_EnterTimeWait(); _EnterTimeWait();
break; return DROP;
case WAIT_FOR_FINISH_ACKNOWLEDGE: case WAIT_FOR_FINISH_ACKNOWLEDGE:
fState = CLOSED; fState = CLOSED;
break; break;
@@ -1373,6 +1372,9 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
break; break;
} }
} }
if (fState != CLOSED)
_Acknowledged(segment.acknowledge);
} }
} }
@@ -1408,7 +1410,8 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
// FIN implies PSH // FIN implies PSH
fReceiveQueue.SetPushPointer(); fReceiveQueue.SetPushPointer();
// RFC 793 states that we must send an ACK to FIN // we'll reply immediatly to the FIN if we are not
// transitioning to TIME WAIT so we immediatly ACK it.
action |= IMMEDIATE_ACKNOWLEDGE; action |= IMMEDIATE_ACKNOWLEDGE;
// other side is closing connection; change states // other side is closing connection; change states