* TCP must not lock the endpoint's lock in _TimeWaitTimer() - it will deadlock

with its destructor when the socket is deleted. This effectively stopped all
  network timers from working. This will not only fix bug #1693, but also many
  other networking problems I've seen so far.
* Minor cleanup (mostly line breaks, strange indenting and superfluous
  parentheses).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23251 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-01-05 13:45:31 +00:00
parent ec2bf719e8
commit 4547914087
@@ -459,8 +459,10 @@ TCPEndpoint::Accept(struct net_socket **_acceptedSocket)
locker.Lock(); locker.Lock();
status = gSocketModule->dequeue_connected(socket, _acceptedSocket); status = gSocketModule->dequeue_connected(socket, _acceptedSocket);
#ifdef TRACE_TCP
if (status == B_OK) if (status == B_OK)
TRACE(" Accept() returning %p", (*_acceptedSocket)->first_protocol); TRACE(" Accept() returning %p", (*_acceptedSocket)->first_protocol);
#endif
} while (status < B_OK); } while (status < B_OK);
return status; return status;
@@ -551,11 +553,11 @@ TCPEndpoint::SendData(net_buffer *buffer)
if (fState == CLOSED) if (fState == CLOSED)
return ENOTCONN; return ENOTCONN;
else if (fState == LISTEN) { if (fState == LISTEN)
return EDESTADDRREQ; return EDESTADDRREQ;
} else if (fState == FINISH_SENT || fState == FINISH_ACKNOWLEDGED if (fState == FINISH_SENT || fState == FINISH_ACKNOWLEDGED
|| fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE || fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE
|| fState == TIME_WAIT) { || fState == TIME_WAIT) {
// TODO: send SIGPIPE signal to app? // TODO: send SIGPIPE signal to app?
return EPIPE; return EPIPE;
} }
@@ -651,15 +653,15 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
while (true) { while (true) {
if (fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE if (fState == CLOSING || fState == WAIT_FOR_FINISH_ACKNOWLEDGE
|| fState == TIME_WAIT) { || fState == TIME_WAIT) {
// ``Connection closing''. // ``Connection closing''.
return B_OK; return B_OK;
} }
if (fReceiveQueue.Available() > 0) { if (fReceiveQueue.Available() > 0) {
if (fReceiveQueue.Available() >= dataNeeded || if (fReceiveQueue.Available() >= dataNeeded
((fReceiveQueue.PushedData() > 0) || (fReceiveQueue.PushedData() > 0
&& (fReceiveQueue.PushedData() >= fReceiveQueue.Available()))) && fReceiveQueue.PushedData() >= fReceiveQueue.Available()))
break; break;
} else if (fState == FINISH_RECEIVED) { } else if (fState == FINISH_RECEIVED) {
// ``If no text is awaiting delivery, the RECEIVE will // ``If no text is awaiting delivery, the RECEIVE will
@@ -667,7 +669,7 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
return B_OK; return B_OK;
} }
if ((flags & MSG_DONTWAIT) || (socket->receive.timeout == 0)) if ((flags & MSG_DONTWAIT) != 0 || socket->receive.timeout == 0)
return B_WOULD_BLOCK; return B_WOULD_BLOCK;
status_t status = fReceiveList.Wait(locker, timeout, false); status_t status = fReceiveList.Wait(locker, timeout, false);
@@ -677,7 +679,7 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
// available. So we actually check if there is data, and if so, // available. So we actually check if there is data, and if so,
// push it to the user. // push it to the user.
if ((status == B_TIMED_OUT || status == B_INTERRUPTED) if ((status == B_TIMED_OUT || status == B_INTERRUPTED)
&& fReceiveQueue.Available() > 0) && fReceiveQueue.Available() > 0)
break; break;
return posix_error(status); return posix_error(status);
@@ -772,7 +774,8 @@ TCPEndpoint::DelayedAcknowledge()
return SendAcknowledge(true); return SendAcknowledge(true);
} }
gStackModule->set_timer(&fDelayedAcknowledgeTimer, TCP_DELAYED_ACKNOWLEDGE_TIMEOUT); gStackModule->set_timer(&fDelayedAcknowledgeTimer,
TCP_DELAYED_ACKNOWLEDGE_TIMEOUT);
return B_OK; return B_OK;
} }
@@ -794,6 +797,7 @@ TCPEndpoint::_StartPersistTimer()
void void
TCPEndpoint::_EnterTimeWait() TCPEndpoint::_EnterTimeWait()
{ {
TRACE("_EnterTimeWait()\n");
gStackModule->set_timer(&fTimeWaitTimer, TCP_MAX_SEGMENT_LIFETIME << 1); gStackModule->set_timer(&fTimeWaitTimer, TCP_MAX_SEGMENT_LIFETIME << 1);
} }
@@ -910,7 +914,8 @@ TCPEndpoint::DumpInternalState() const
int32 int32
TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment, net_buffer *buffer) TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment,
net_buffer *buffer)
{ {
TRACE("SynchronizeSentReceive()"); TRACE("SynchronizeSentReceive()");
@@ -993,7 +998,8 @@ TCPEndpoint::SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
int32 int32
TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer) TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
{ {
uint32 advertisedWindow = (uint32)segment.advertised_window << fSendWindowShift; uint32 advertisedWindow = (uint32)segment.advertised_window
<< fSendWindowShift;
// First, handle the most common case for uni-directional data transfer // First, handle the most common case for uni-directional data transfer
// (known as header prediction - the segment must not change the window, // (known as header prediction - the segment must not change the window,
@@ -1004,7 +1010,6 @@ TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
&& fReceiveNext == segment.sequence && fReceiveNext == segment.sequence
&& advertisedWindow > 0 && advertisedWindow == fSendWindow && advertisedWindow > 0 && advertisedWindow == fSendWindow
&& fSendNext == fSendMax) { && fSendNext == fSendMax) {
_UpdateTimestamps(segment, buffer->size); _UpdateTimestamps(segment, buffer->size);
if (buffer->size == 0) { if (buffer->size == 0) {
@@ -1020,8 +1025,9 @@ TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
&& !(fFlags & FLAG_NO_RECEIVE)) { && !(fFlags & FLAG_NO_RECEIVE)) {
if (_AddData(segment, buffer)) if (_AddData(segment, buffer))
_NotifyReader(); _NotifyReader();
return KEEP | ((segment.flags & TCP_FLAG_PUSH) ?
IMMEDIATE_ACKNOWLEDGE : ACKNOWLEDGE); return KEEP | ((segment.flags & TCP_FLAG_PUSH) != 0
? IMMEDIATE_ACKNOWLEDGE : ACKNOWLEDGE);
} }
} }
@@ -1108,7 +1114,8 @@ TCPEndpoint::_ShouldSendSegment(tcp_segment_header &segment, uint32 length,
return true; return true;
} }
if ((segment.flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_RESET)) != 0) if ((segment.flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH
| TCP_FLAG_RESET)) != 0)
return true; return true;
// there is no reason to send a segment just now // there is no reason to send a segment just now
@@ -1140,14 +1147,14 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
tcp_segment_header segment(_CurrentFlags()); tcp_segment_header segment(_CurrentFlags());
if ((fOptions & TCP_NOOPT) == 0) { if ((fOptions & TCP_NOOPT) == 0) {
if (fFlags & FLAG_OPTION_TIMESTAMP) { if ((fFlags & FLAG_OPTION_TIMESTAMP) != 0) {
segment.options |= TCP_HAS_TIMESTAMPS; segment.options |= TCP_HAS_TIMESTAMPS;
segment.timestamp_reply = fReceivedTimestamp; segment.timestamp_reply = fReceivedTimestamp;
segment.timestamp_value = tcp_now(); segment.timestamp_value = tcp_now();
} }
if ((segment.flags & TCP_FLAG_SYNCHRONIZE) if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0
&& (fSendNext == fInitialSendSequence)) { && fSendNext == fInitialSendSequence) {
// add connection establishment options // add connection establishment options
segment.max_segment_size = fReceiveMaxSegmentSize; segment.max_segment_size = fReceiveMaxSegmentSize;
if (fFlags & FLAG_OPTION_WINDOW_SCALE) { if (fFlags & FLAG_OPTION_WINDOW_SCALE) {
@@ -1294,7 +1301,8 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
fLastAcknowledgeSent = segment.acknowledge; fLastAcknowledgeSent = segment.acknowledge;
length -= segmentLength; length -= segmentLength;
segment.flags &= ~(TCP_FLAG_SYNCHRONIZE | TCP_FLAG_RESET | TCP_FLAG_FINISH); segment.flags &= ~(TCP_FLAG_SYNCHRONIZE | TCP_FLAG_RESET
| TCP_FLAG_FINISH);
} while (length > 0); } while (length > 0);
// if we sent data from the beggining of the send queue, // if we sent data from the beggining of the send queue,
@@ -1348,7 +1356,7 @@ TCPEndpoint::_AvailableData() const
// sockets. // sockets.
if (fState == LISTEN) if (fState == LISTEN)
return gSocketModule->count_connected(socket); return gSocketModule->count_connected(socket);
else if (fState == SYNCHRONIZE_SENT) if (fState == SYNCHRONIZE_SENT)
return 0; return 0;
ssize_t availableData = fReceiveQueue.Available(); ssize_t availableData = fReceiveQueue.Available();
@@ -1375,26 +1383,27 @@ TCPEndpoint::_ShouldReceive() const
return false; return false;
return fState == ESTABLISHED || fState == FINISH_SENT return fState == ESTABLISHED || fState == FINISH_SENT
|| fState == FINISH_ACKNOWLEDGED; || fState == FINISH_ACKNOWLEDGED;
} }
int32 int32
TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer) TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
{ {
uint32 advertisedWindow = (uint32)segment.advertised_window << fSendWindowShift; uint32 advertisedWindow = (uint32)segment.advertised_window
<< fSendWindowShift;
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?
if (fLastAcknowledgeSent <= segment.sequence if (fLastAcknowledgeSent <= segment.sequence
&& tcp_sequence(segment.sequence) && tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
< (fLastAcknowledgeSent + fReceiveWindow)) { + fReceiveWindow)) {
if (fState == SYNCHRONIZE_RECEIVED) if (fState == SYNCHRONIZE_RECEIVED)
fError = ECONNREFUSED; fError = ECONNREFUSED;
else if (fState == CLOSING || fState == TIME_WAIT else if (fState == CLOSING || fState == TIME_WAIT
|| fState == WAIT_FOR_FINISH_ACKNOWLEDGE) || fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
fError = ENOTCONN; fError = ENOTCONN;
else else
fError = ECONNRESET; fError = ECONNRESET;
@@ -1461,9 +1470,12 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
gBufferModule->remove_trailer(buffer, drop); gBufferModule->remove_trailer(buffer, drop);
} }
if (advertisedWindow > fSendWindow) #ifdef TRACE_TCP
if (advertisedWindow > fSendWindow) {
TRACE(" Receive(): Window update %lu -> %lu", fSendWindow, TRACE(" Receive(): Window update %lu -> %lu", fSendWindow,
advertisedWindow); advertisedWindow);
}
#endif
fSendWindow = advertisedWindow; fSendWindow = advertisedWindow;
if (advertisedWindow > fSendMaxWindow) if (advertisedWindow > fSendMaxWindow)
@@ -1598,8 +1610,8 @@ TCPEndpoint::_UpdateTimestamps(tcp_segment_header &segment,
if (fFlags & FLAG_OPTION_TIMESTAMP) { if (fFlags & FLAG_OPTION_TIMESTAMP) {
tcp_sequence sequence(segment.sequence); tcp_sequence sequence(segment.sequence);
if ((fLastAcknowledgeSent >= sequence if (fLastAcknowledgeSent >= sequence
&& fLastAcknowledgeSent < (sequence + segmentLength))) && fLastAcknowledgeSent < (sequence + segmentLength))
fReceivedTimestamp = segment.timestamp_value; fReceivedTimestamp = segment.timestamp_value;
} }
} }
@@ -1793,8 +1805,8 @@ TCPEndpoint::_UpdateSRTT(int32 roundTripTime)
rtt -= (fRoundTripDeviation / 4); rtt -= (fRoundTripDeviation / 4);
fRoundTripDeviation += rtt; fRoundTripDeviation += rtt;
fRetransmitTimeout = ((fRoundTripTime / 4 + fRetransmitTimeout = ((fRoundTripTime / 4 + fRoundTripDeviation) / 2)
fRoundTripDeviation) / 2) * kTimestampFactor; * kTimestampFactor;
TRACE(" RTO is now %llu (after rtt %ldms)", fRetransmitTimeout, TRACE(" RTO is now %llu (after rtt %ldms)", fRetransmitTimeout,
roundTripTime); roundTripTime);
@@ -1813,11 +1825,10 @@ TCPEndpoint::_ResetSlowStart()
void void
TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment) TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment)
{ {
fDuplicateAcknowledgeCount++; if (++fDuplicateAcknowledgeCount < 3)
if (fDuplicateAcknowledgeCount < 3)
return; return;
else if (fDuplicateAcknowledgeCount == 3) {
if (fDuplicateAcknowledgeCount == 3) {
_ResetSlowStart(); _ResetSlowStart();
fCongestionWindow = fSlowStartThreshold + 3 fCongestionWindow = fSlowStartThreshold + 3
* fSendMaxSegmentSize; * fSendMaxSegmentSize;
@@ -1876,9 +1887,6 @@ TCPEndpoint::_TimeWaitTimer(struct net_timer *timer, void *data)
{ {
TCPEndpoint *endpoint = (TCPEndpoint *)data; TCPEndpoint *endpoint = (TCPEndpoint *)data;
if (mutex_lock(&endpoint->fLock) < B_OK)
return;
gSocketModule->delete_socket(endpoint->socket); gSocketModule->delete_socket(endpoint->socket);
} }