fixed another TCP issue: if we were in TIME_WAIT and we received a retransmission or delayed ack, TCP would wrongly bindly immediatly acknowledge.
* Moved TIME_WAIT and CLOSED handling to common Receive() path that does Sequence checking and further tests. * Moved setting FLAG_NO_RECEIVE to the end of Receive() when FIN is set so we can check for NO_RECEIVE before processing the segment text just after processing FIN. * Added a new action DELETE to be used when in TIME_WAIT and we receive a good RST git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20572 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
2cff90bf94
commit
f2893088ba
@ -203,6 +203,7 @@ TCPEndpoint::Free()
|
||||
if (fState <= SYNCHRONIZE_SENT || fState == TIME_WAIT)
|
||||
return B_OK;
|
||||
|
||||
// we are only interested in the timer, not in changing state
|
||||
_EnterTimeWait();
|
||||
return B_BUSY;
|
||||
// we'll be freed later when the 2MSL timer expires
|
||||
@ -821,13 +822,26 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
// is this a valid reset?
|
||||
if (fLastAcknowledgeSent <= segment.sequence
|
||||
&& tcp_sequence(segment.sequence) < fLastAcknowledgeSent + fReceiveWindow) {
|
||||
// TODO: close connection depending on state
|
||||
if (fState == SYNCHRONIZE_RECEIVED) {
|
||||
// TODO: if we came from SYN-SENT signal connection refused
|
||||
// and remove all segments from tx queue
|
||||
} else if (fState == ESTABLISHED || fState == FINISH_SENT
|
||||
|| fState == FINISH_RECEIVED || fState == FINISH_ACKNOWLEDGED) {
|
||||
// TODO: RFC 793 states that on ESTABLISHED, FIN-WAIT{1,2}
|
||||
// or CLOSE-WAIT "All segment queues should be
|
||||
// flushed".
|
||||
}
|
||||
|
||||
if (fState != TIME_WAIT && fReceiveQueue.Available() > 0) {
|
||||
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
|
||||
// TODO: real conditional locking needed!
|
||||
gSocketModule->notify(socket, B_SELECT_READ, 1);
|
||||
} else {
|
||||
return DELETE | DROP;
|
||||
}
|
||||
|
||||
fError = ECONNREFUSED;
|
||||
fState = CLOSED;
|
||||
|
||||
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
|
||||
// TODO: real conditional locking needed!
|
||||
gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available());
|
||||
}
|
||||
|
||||
return DROP;
|
||||
@ -904,7 +918,8 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
// TODO: real conditional locking needed!
|
||||
gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available());
|
||||
}
|
||||
if (fSendMax < segment.acknowledge)
|
||||
|
||||
if (fSendMax < segment.acknowledge || fState == TIME_WAIT)
|
||||
return DROP | IMMEDIATE_ACKNOWLEDGE;
|
||||
if (fSendUnacknowledged >= segment.acknowledge) {
|
||||
// this is a duplicate acknowledge
|
||||
@ -977,7 +992,6 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
if (segment.flags & TCP_FLAG_FINISH) {
|
||||
TRACE("Receive(): peer is finishing connection!");
|
||||
fReceiveNext++;
|
||||
fFlags |= FLAG_NO_RECEIVE;
|
||||
|
||||
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
|
||||
// TODO: real conditional locking needed!
|
||||
@ -1015,7 +1029,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
// state machine is done switching states and the data is good.
|
||||
// put it in the receive buffer
|
||||
|
||||
if (buffer->size > 0) {
|
||||
if (buffer->size > 0 && (fFlags & FLAG_NO_RECEIVE) == 0) {
|
||||
fReceiveQueue.Add(buffer, segment.sequence);
|
||||
fReceiveNext += buffer->size;
|
||||
TRACE("Receive(): adding data, receive next = %lu!", (uint32)fReceiveNext);
|
||||
@ -1029,6 +1043,9 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
if (segment.flags & TCP_FLAG_PUSH)
|
||||
fReceiveQueue.SetPushPointer(fReceiveQueue.LastSequence());
|
||||
|
||||
if (segment.flags & TCP_FLAG_FINISH)
|
||||
fFlags |= FLAG_NO_RECEIVE;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
|
@ -555,12 +555,6 @@ tcp_receive_data(net_buffer *buffer)
|
||||
TRACE(("Endpoint %p in state %s\n", endpoint, name_for_state(endpoint->State())));
|
||||
|
||||
switch (endpoint->State()) {
|
||||
case TIME_WAIT:
|
||||
segmentAction |= IMMEDIATE_ACKNOWLEDGE;
|
||||
case CLOSED:
|
||||
endpoint->UpdateTimeWait();
|
||||
break;
|
||||
|
||||
case LISTEN:
|
||||
segmentAction = endpoint->ListenReceive(segment, buffer);
|
||||
break;
|
||||
@ -576,6 +570,8 @@ tcp_receive_data(net_buffer *buffer)
|
||||
case FINISH_SENT:
|
||||
case FINISH_ACKNOWLEDGED:
|
||||
case CLOSING:
|
||||
case TIME_WAIT:
|
||||
case CLOSED:
|
||||
segmentAction = endpoint->Receive(segment, buffer);
|
||||
break;
|
||||
}
|
||||
@ -585,6 +581,8 @@ tcp_receive_data(net_buffer *buffer)
|
||||
endpoint->SendAcknowledge();
|
||||
else if (segmentAction & ACKNOWLEDGE)
|
||||
endpoint->DelayedAcknowledge();
|
||||
else if (segmentAction & DELETE)
|
||||
gSocketModule->delete_socket(endpoint->socket);
|
||||
} else if ((segment.flags & TCP_FLAG_RESET) == 0)
|
||||
segmentAction = DROP | RESET;
|
||||
|
||||
|
@ -153,6 +153,7 @@ enum tcp_segment_action {
|
||||
RESET = 0x02,
|
||||
ACKNOWLEDGE = 0x04,
|
||||
IMMEDIATE_ACKNOWLEDGE = 0x08,
|
||||
DELETE = 0x10,
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user