From d86f48f3f5a6ca5039ee8f2190c97906d976f2d1 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Thu, 5 Apr 2007 22:42:45 +0000 Subject: [PATCH] tiny TCP cleanups, move the read notifications to _NotifyReader(). - Also fixed the buffer size check in UDP's SendData() since UDP's length field includes the size of the header we need to check that as well. IPv4 is correct since we check for the size after prepending the header (due to it being possibly already included). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20592 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/TCPEndpoint.cpp | 87 +++++++++++-------- .../network/protocols/tcp/TCPEndpoint.h | 3 +- .../kernel/network/protocols/udp/udp.cpp | 2 +- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index 1a4853360b..c1c714b9e9 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -490,7 +490,8 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer) } if ((fFlags & FLAG_NO_RECEIVE) != 0 && fReceiveQueue.Available() == 0) { - // there is no data left in the queue, and we can't receive anything, anymore + // there is no data left in the queue, and we can't receive anything, + // anymore *_buffer = NULL; return B_OK; } @@ -499,6 +500,9 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer) // TODO: add support for urgent data (MSG_OOB) size_t dataNeeded = socket->receive.low_water_mark; + + // When MSG_WAITALL is set then the function should block + // until the full amount of data can be returned. if (flags & MSG_WAITALL) dataNeeded = numBytes; @@ -509,10 +513,6 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer) && (fFlags & FLAG_NO_RECEIVE) == 0) { locker.Unlock(); - // Open Group Base Specification states that when - // MSG_WAITALL is set then the function should - // block until the full amount of data can be returned. - status_t status = acquire_sem_etc(fReceiveLock, 1, B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout); @@ -543,7 +543,7 @@ TCPEndpoint::ReadAvailable() TRACE("ReadAvailable()"); RecursiveLocker locker(fLock); - return _AvailableBytesOrDisconnect(); + return _AvailableData(); } @@ -740,7 +740,7 @@ TCPEndpoint::SynchronizeSentReceive(tcp_segment_header &segment, net_buffer *buf release_sem_etc(fSendLock, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); // TODO: this is not enough - we need to use B_RELEASE_ALL - gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); + _NotifyReader(); } else { // simultaneous open fState = SYNCHRONIZE_RECEIVED; @@ -813,23 +813,21 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); // TODO: real conditional locking needed! - gSocketModule->notify(socket, B_SELECT_READ, - fReceiveQueue.Available()); + _NotifyReader(); return KEEP | ACKNOWLEDGE; } } } - // The fast path was not applicable, so we continue with the standard processing - // of the incoming segment - - // First have a look at the data being sent + // The fast path was not applicable, so we continue with the standard + // processing of the incoming segment if (segment.flags & TCP_FLAG_RESET) { // is this a valid reset? if (fLastAcknowledgeSent <= segment.sequence - && tcp_sequence(segment.sequence) < fLastAcknowledgeSent + fReceiveWindow) { + && tcp_sequence(segment.sequence) + < (fLastAcknowledgeSent + fReceiveWindow)) { if (fState == SYNCHRONIZE_RECEIVED) { // TODO: if we came from SYN-SENT signal connection refused // and remove all segments from tx queue @@ -843,7 +841,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) 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); + _NotifyReader(); } else { return DELETE | DROP; } @@ -854,14 +852,15 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) return DROP; } + if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0 || (fState == SYNCHRONIZE_RECEIVED && (fInitialReceiveSequence > segment.sequence || (segment.flags & TCP_FLAG_ACKNOWLEDGE) != 0 && (fSendUnacknowledged > segment.acknowledge || fSendMax < segment.acknowledge)))) { - // reset the connection - either the initial SYN was faulty, or we received - // a SYN within the data stream + // reset the connection - either the initial SYN was faulty, or we + // received a SYN within the data stream return DROP | RESET; } @@ -872,7 +871,8 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) int32 drop = fReceiveNext - segment.sequence; if (drop > 0) { if ((uint32)drop > buffer->size - || ((uint32)drop == buffer->size && (segment.flags & TCP_FLAG_FINISH) == 0)) { + || ((uint32)drop == buffer->size + && (segment.flags & TCP_FLAG_FINISH) == 0)) { // don't accidently remove a FIN we shouldn't remove segment.flags &= ~TCP_FLAG_FINISH; drop = buffer->size; @@ -924,7 +924,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) release_sem_etc(fSendLock, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); // TODO: real conditional locking needed! - gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); + _NotifyReader(); } if (fSendMax < segment.acknowledge || fState == TIME_WAIT) @@ -994,7 +994,15 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) if (advertisedWindow > fSendMaxWindow) fSendMaxWindow = advertisedWindow; - // TODO: process urgent data! + if (segment.flags & TCP_FLAG_URGENT) { + if (fState == ESTABLISHED || fState == FINISH_SENT + || fState == FINISH_ACKNOWLEDGED) { + // TODO: Handle urgent data: + // - RCV.UP <- max(RCV.UP, SEG.UP) + // - signal the user that urgent data is available (SIGURG) + } + } + // TODO: ignore data *after* FIN if (segment.flags & TCP_FLAG_FINISH) { @@ -1003,7 +1011,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); // TODO: real conditional locking needed! - gSocketModule->notify(socket, B_SELECT_READ, _AvailableBytesOrDisconnect()); + _NotifyReader(); // other side is closing connection; change states switch (fState) { @@ -1044,7 +1052,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer) release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); // TODO: real conditional locking needed! - gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); + _NotifyReader(); } else gBufferModule->free(buffer); @@ -1293,20 +1301,6 @@ TCPEndpoint::_GetMSS(const sockaddr *address) const } -ssize_t -TCPEndpoint::_AvailableBytesOrDisconnect() const -{ - size_t availableBytes = fReceiveQueue.Available(); - if (availableBytes > 0) - return availableBytes; - - if ((fFlags & FLAG_NO_RECEIVE) != 0) - return ENOTCONN; - - return 0; -} - - status_t TCPEndpoint::_ShutdownEgress(bool closing) { @@ -1333,6 +1327,27 @@ TCPEndpoint::_ShutdownEgress(bool closing) } +ssize_t +TCPEndpoint::_AvailableData() const +{ + ssize_t availableData = fReceiveQueue.Available(); + + // FLAG_NO_RECEIVE is set whenever the socket is in a state + // where read() would be non-blocking and return 0. + if ((fFlags & FLAG_NO_RECEIVE) && availableData == 0) + return ENOTCONN; + + return availableData; +} + + +void +TCPEndpoint::_NotifyReader() +{ + gSocketModule->notify(socket, B_SELECT_READ, _AvailableData()); +} + + // #pragma mark - timer diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index cff1a1ecab..3d5f4fa2ce 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -66,8 +66,9 @@ class TCPEndpoint : public net_protocol { bool outstandingAcknowledge); status_t _SendQueued(bool force = false); int _GetMSS(const struct sockaddr *) const; - ssize_t _AvailableBytesOrDisconnect() const; status_t _ShutdownEgress(bool closing); + ssize_t _AvailableData() const; + void _NotifyReader(); static void _TimeWaitTimer(net_timer *timer, void *data); static void _RetransmitTimer(net_timer *timer, void *data); diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index 2a8007c42f..e64d8bc117 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -764,7 +764,7 @@ UdpEndpoint::_Deactivate() status_t UdpEndpoint::SendData(net_buffer *buffer, net_route *route) { - if (buffer->size > 0xffff) + if (buffer->size > (0xffff - sizeof(udp_header))) return EMSGSIZE; buffer->protocol = IPPROTO_UDP;