* 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:
@@ -56,8 +56,9 @@
|
|||||||
|
|
||||||
#ifdef TRACE_TCP
|
#ifdef TRACE_TCP
|
||||||
// the space before ', ##args' is important in order for this to work with cpp 2.95
|
// 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", \
|
# define TRACE(format, args...) dprintf("%ld: TCP [%llu] %p (%12s) " \
|
||||||
system_time(), this, name_for_state(fState) , ##args)
|
format "\n", find_thread(NULL), system_time(), this, \
|
||||||
|
name_for_state(fState) , ##args)
|
||||||
#else
|
#else
|
||||||
# define TRACE(args...) do { } while (0)
|
# define TRACE(args...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
@@ -280,9 +281,7 @@ TCPEndpoint::~TCPEndpoint()
|
|||||||
{
|
{
|
||||||
mutex_lock(&fLock);
|
mutex_lock(&fLock);
|
||||||
|
|
||||||
gStackModule->cancel_timer(&fRetransmitTimer);
|
_CancelConnectionTimers();
|
||||||
gStackModule->cancel_timer(&fPersistTimer);
|
|
||||||
gStackModule->cancel_timer(&fDelayedAcknowledgeTimer);
|
|
||||||
gStackModule->cancel_timer(&fTimeWaitTimer);
|
gStackModule->cancel_timer(&fTimeWaitTimer);
|
||||||
|
|
||||||
if (fManager) {
|
if (fManager) {
|
||||||
@@ -345,7 +344,7 @@ TCPEndpoint::Close()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t status = _ShutdownEgress(true);
|
status_t status = _Shutdown(true);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -366,7 +365,6 @@ TCPEndpoint::Close()
|
|||||||
fSendQueue.Used());
|
fSendQueue.Used());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do i need to wait until fState returns to CLOSED?
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +562,7 @@ TCPEndpoint::Shutdown(int direction)
|
|||||||
fFlags |= FLAG_NO_RECEIVE;
|
fFlags |= FLAG_NO_RECEIVE;
|
||||||
|
|
||||||
if (direction == SHUT_WR || direction == SHUT_RDWR)
|
if (direction == SHUT_WR || direction == SHUT_RDWR)
|
||||||
_ShutdownEgress(false);
|
_Shutdown(false);
|
||||||
|
|
||||||
return B_OK;
|
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
|
// #pragma mark - receive
|
||||||
|
|
||||||
|
|
||||||
@@ -955,7 +962,7 @@ TCPEndpoint::DumpInternalState() const
|
|||||||
void
|
void
|
||||||
TCPEndpoint::_HandleReset(status_t error)
|
TCPEndpoint::_HandleReset(status_t error)
|
||||||
{
|
{
|
||||||
gStackModule->cancel_timer(&fRetransmitTimer);
|
_CancelConnectionTimers();
|
||||||
|
|
||||||
socket->error = error;
|
socket->error = error;
|
||||||
fState = CLOSED;
|
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
|
// The fast path was not applicable, so we continue with the standard
|
||||||
// processing of the incoming segment
|
// processing of the incoming segment
|
||||||
|
|
||||||
if (fState != SYNCHRONIZE_SENT && fState != LISTEN && fState != CLOSED) {
|
ASSERT(fState != SYNCHRONIZE_SENT && fState != LISTEN);
|
||||||
// 1. check sequence number
|
|
||||||
|
if (fState != CLOSED && fState != TIME_WAIT) {
|
||||||
|
// Check sequence number
|
||||||
if (!segment_in_sequence(segment, buffer->size, fReceiveNext,
|
if (!segment_in_sequence(segment, buffer->size, fReceiveNext,
|
||||||
fReceiveWindow)) {
|
fReceiveWindow)) {
|
||||||
TRACE(" Receive(): segment out of window, next: %lu wnd: %lu",
|
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
|
status_t
|
||||||
TCPEndpoint::_ShutdownEgress(bool closing)
|
TCPEndpoint::_Shutdown(bool closing)
|
||||||
{
|
{
|
||||||
tcp_state previousState = fState;
|
tcp_state previousState = fState;
|
||||||
|
|
||||||
@@ -1452,15 +1464,16 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
size_t segmentLength = buffer->size;
|
size_t segmentLength = buffer->size;
|
||||||
|
|
||||||
if (segment.flags & TCP_FLAG_RESET) {
|
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
|
if (fLastAcknowledgeSent <= segment.sequence
|
||||||
&& tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
|
&& tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
|
||||||
+ fReceiveWindow)) {
|
+ fReceiveWindow)
|
||||||
|
&& fState != TIME_WAIT) {
|
||||||
status_t error;
|
status_t error;
|
||||||
if (fState == SYNCHRONIZE_RECEIVED)
|
if (fState == SYNCHRONIZE_RECEIVED)
|
||||||
error = ECONNREFUSED;
|
error = ECONNREFUSED;
|
||||||
else if (fState == CLOSING || fState == TIME_WAIT
|
else if (fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
||||||
|| fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
|
||||||
error = ENOTCONN;
|
error = ENOTCONN;
|
||||||
else
|
else
|
||||||
error = ECONNRESET;
|
error = ECONNRESET;
|
||||||
@@ -1582,6 +1595,7 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
_EnterTimeWait();
|
_EnterTimeWait();
|
||||||
return DROP;
|
return DROP;
|
||||||
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
||||||
|
_CancelConnectionTimers();
|
||||||
fState = CLOSED;
|
fState = CLOSED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1924,6 +1938,10 @@ TCPEndpoint::_PersistTimer(net_timer *timer, void *data)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// the timer might not have been canceled early enough
|
||||||
|
if (endpoint->State() == CLOSED)
|
||||||
|
return;
|
||||||
|
|
||||||
endpoint->_SendQueued(true);
|
endpoint->_SendQueued(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1937,6 +1955,10 @@ TCPEndpoint::_DelayedAcknowledgeTimer(struct net_timer *timer, void *data)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// the timer might not have been canceled early enough
|
||||||
|
if (endpoint->State() == CLOSED)
|
||||||
|
return;
|
||||||
|
|
||||||
endpoint->SendAcknowledge(true);
|
endpoint->SendAcknowledge(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,13 +87,14 @@ private:
|
|||||||
|
|
||||||
void _StartPersistTimer();
|
void _StartPersistTimer();
|
||||||
void _EnterTimeWait();
|
void _EnterTimeWait();
|
||||||
|
void _CancelConnectionTimers();
|
||||||
uint8 _CurrentFlags();
|
uint8 _CurrentFlags();
|
||||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||||
uint32 segmentMaxSize, uint32 flightSize);
|
uint32 segmentMaxSize, uint32 flightSize);
|
||||||
status_t _SendQueued(bool force = false);
|
status_t _SendQueued(bool force = false);
|
||||||
status_t _SendQueued(bool force, uint32 sendWindow);
|
status_t _SendQueued(bool force, uint32 sendWindow);
|
||||||
int _MaxSegmentSize(const struct sockaddr *) const;
|
int _MaxSegmentSize(const struct sockaddr *) const;
|
||||||
status_t _ShutdownEgress(bool closing);
|
status_t _Shutdown(bool closing);
|
||||||
ssize_t _AvailableData() const;
|
ssize_t _AvailableData() const;
|
||||||
void _NotifyReader();
|
void _NotifyReader();
|
||||||
bool _ShouldReceive() const;
|
bool _ShouldReceive() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user