* Added _CancelConnectionTimers() that does what its name suggests, and is
now used from various places that previously did not cancel all timers they should have. * When a connection moves to the CLOSED state, it should cancel all timers; this prevents from sending a reset at the end of a connection. * If the persist/delayed acknowledge timers were canceled too late, they might still have tried to send something (which would eventually cause a reset sent to the peer). * Follow RFC 1337 with respect to time wait assassination prevention (ie. we now ignore resets from peers in time wait state). * _SegmentReceived() must not check the sequence of a time wait connection; it prevented sending a reset when that was due (a new connection request would time out, instead of fail immediately). * Also, that method must never be called in the LISTEN or SYNCHRONIZE_SENT states, so we don't need to check for those. * We don't have to wait in Close() until the connection is actually closed - removed a TODO. TCP should handle this internally. * Renamed _ShutdownEgress() to _Shutdown(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25219 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
42759f5626
commit
05bc1e8973
@ -56,8 +56,9 @@
|
||||
|
||||
#ifdef TRACE_TCP
|
||||
// the space before ', ##args' is important in order for this to work with cpp 2.95
|
||||
# define TRACE(format, args...) dprintf("TCP [%llu] %p (%12s) " format "\n", \
|
||||
system_time(), this, name_for_state(fState) , ##args)
|
||||
# define TRACE(format, args...) dprintf("%ld: TCP [%llu] %p (%12s) " \
|
||||
format "\n", find_thread(NULL), system_time(), this, \
|
||||
name_for_state(fState) , ##args)
|
||||
#else
|
||||
# define TRACE(args...) do { } while (0)
|
||||
#endif
|
||||
@ -280,9 +281,7 @@ TCPEndpoint::~TCPEndpoint()
|
||||
{
|
||||
mutex_lock(&fLock);
|
||||
|
||||
gStackModule->cancel_timer(&fRetransmitTimer);
|
||||
gStackModule->cancel_timer(&fPersistTimer);
|
||||
gStackModule->cancel_timer(&fDelayedAcknowledgeTimer);
|
||||
_CancelConnectionTimers();
|
||||
gStackModule->cancel_timer(&fTimeWaitTimer);
|
||||
|
||||
if (fManager) {
|
||||
@ -345,7 +344,7 @@ TCPEndpoint::Close()
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t status = _ShutdownEgress(true);
|
||||
status_t status = _Shutdown(true);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
@ -366,7 +365,6 @@ TCPEndpoint::Close()
|
||||
fSendQueue.Used());
|
||||
}
|
||||
|
||||
// TODO: do i need to wait until fState returns to CLOSED?
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -564,7 +562,7 @@ TCPEndpoint::Shutdown(int direction)
|
||||
fFlags |= FLAG_NO_RECEIVE;
|
||||
|
||||
if (direction == SHUT_WR || direction == SHUT_RDWR)
|
||||
_ShutdownEgress(false);
|
||||
_Shutdown(false);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -848,6 +846,15 @@ TCPEndpoint::UpdateTimeWait()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TCPEndpoint::_CancelConnectionTimers()
|
||||
{
|
||||
gStackModule->cancel_timer(&fRetransmitTimer);
|
||||
gStackModule->cancel_timer(&fPersistTimer);
|
||||
gStackModule->cancel_timer(&fDelayedAcknowledgeTimer);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - receive
|
||||
|
||||
|
||||
@ -955,7 +962,7 @@ TCPEndpoint::DumpInternalState() const
|
||||
void
|
||||
TCPEndpoint::_HandleReset(status_t error)
|
||||
{
|
||||
gStackModule->cancel_timer(&fRetransmitTimer);
|
||||
_CancelConnectionTimers();
|
||||
|
||||
socket->error = error;
|
||||
fState = CLOSED;
|
||||
@ -1088,8 +1095,10 @@ TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
|
||||
// The fast path was not applicable, so we continue with the standard
|
||||
// processing of the incoming segment
|
||||
|
||||
if (fState != SYNCHRONIZE_SENT && fState != LISTEN && fState != CLOSED) {
|
||||
// 1. check sequence number
|
||||
ASSERT(fState != SYNCHRONIZE_SENT && fState != LISTEN);
|
||||
|
||||
if (fState != CLOSED && fState != TIME_WAIT) {
|
||||
// Check sequence number
|
||||
if (!segment_in_sequence(segment, buffer->size, fReceiveNext,
|
||||
fReceiveWindow)) {
|
||||
TRACE(" Receive(): segment out of window, next: %lu wnd: %lu",
|
||||
@ -1382,8 +1391,11 @@ TCPEndpoint::_MaxSegmentSize(const sockaddr *address) const
|
||||
}
|
||||
|
||||
|
||||
/*! Sends the FIN flag to the peer when the connection is still open.
|
||||
Moves the endpoint to the next state depending on where it was.
|
||||
*/
|
||||
status_t
|
||||
TCPEndpoint::_ShutdownEgress(bool closing)
|
||||
TCPEndpoint::_Shutdown(bool closing)
|
||||
{
|
||||
tcp_state previousState = fState;
|
||||
|
||||
@ -1452,15 +1464,16 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
size_t segmentLength = buffer->size;
|
||||
|
||||
if (segment.flags & TCP_FLAG_RESET) {
|
||||
// is this a valid reset?
|
||||
// Is this a valid reset?
|
||||
// We generally ignore resets in time wait state (see RFC 1337)
|
||||
if (fLastAcknowledgeSent <= segment.sequence
|
||||
&& tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
|
||||
+ fReceiveWindow)) {
|
||||
+ fReceiveWindow)
|
||||
&& fState != TIME_WAIT) {
|
||||
status_t error;
|
||||
if (fState == SYNCHRONIZE_RECEIVED)
|
||||
error = ECONNREFUSED;
|
||||
else if (fState == CLOSING || fState == TIME_WAIT
|
||||
|| fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
||||
else if (fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
||||
error = ENOTCONN;
|
||||
else
|
||||
error = ECONNRESET;
|
||||
@ -1582,6 +1595,7 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
|
||||
_EnterTimeWait();
|
||||
return DROP;
|
||||
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
||||
_CancelConnectionTimers();
|
||||
fState = CLOSED;
|
||||
break;
|
||||
|
||||
@ -1924,6 +1938,10 @@ TCPEndpoint::_PersistTimer(net_timer *timer, void *data)
|
||||
if (!locker.IsLocked())
|
||||
return;
|
||||
|
||||
// the timer might not have been canceled early enough
|
||||
if (endpoint->State() == CLOSED)
|
||||
return;
|
||||
|
||||
endpoint->_SendQueued(true);
|
||||
}
|
||||
|
||||
@ -1937,6 +1955,10 @@ TCPEndpoint::_DelayedAcknowledgeTimer(struct net_timer *timer, void *data)
|
||||
if (!locker.IsLocked())
|
||||
return;
|
||||
|
||||
// the timer might not have been canceled early enough
|
||||
if (endpoint->State() == CLOSED)
|
||||
return;
|
||||
|
||||
endpoint->SendAcknowledge(true);
|
||||
}
|
||||
|
||||
|
@ -87,13 +87,14 @@ private:
|
||||
|
||||
void _StartPersistTimer();
|
||||
void _EnterTimeWait();
|
||||
void _CancelConnectionTimers();
|
||||
uint8 _CurrentFlags();
|
||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||
uint32 segmentMaxSize, uint32 flightSize);
|
||||
status_t _SendQueued(bool force = false);
|
||||
status_t _SendQueued(bool force, uint32 sendWindow);
|
||||
int _MaxSegmentSize(const struct sockaddr *) const;
|
||||
status_t _ShutdownEgress(bool closing);
|
||||
status_t _Shutdown(bool closing);
|
||||
ssize_t _AvailableData() const;
|
||||
void _NotifyReader();
|
||||
bool _ShouldReceive() const;
|
||||
|
Loading…
Reference in New Issue
Block a user