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
This commit is contained in:
Hugo Santos
2007-04-05 22:42:45 +00:00
parent a5d8483183
commit d86f48f3f5
3 changed files with 54 additions and 38 deletions
@@ -490,7 +490,8 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
} }
if ((fFlags & FLAG_NO_RECEIVE) != 0 && fReceiveQueue.Available() == 0) { 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; *_buffer = NULL;
return B_OK; 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) // TODO: add support for urgent data (MSG_OOB)
size_t dataNeeded = socket->receive.low_water_mark; 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) if (flags & MSG_WAITALL)
dataNeeded = numBytes; dataNeeded = numBytes;
@@ -509,10 +513,6 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
&& (fFlags & FLAG_NO_RECEIVE) == 0) { && (fFlags & FLAG_NO_RECEIVE) == 0) {
locker.Unlock(); 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, status_t status = acquire_sem_etc(fReceiveLock, 1,
B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout); B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
@@ -543,7 +543,7 @@ TCPEndpoint::ReadAvailable()
TRACE("ReadAvailable()"); TRACE("ReadAvailable()");
RecursiveLocker locker(fLock); 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(fSendLock, 1, B_DO_NOT_RESCHEDULE);
release_sem_etc(fReceiveLock, 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 // TODO: this is not enough - we need to use B_RELEASE_ALL
gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); _NotifyReader();
} else { } else {
// simultaneous open // simultaneous open
fState = SYNCHRONIZE_RECEIVED; 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); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
// TODO: real conditional locking needed! // TODO: real conditional locking needed!
gSocketModule->notify(socket, B_SELECT_READ, _NotifyReader();
fReceiveQueue.Available());
return KEEP | ACKNOWLEDGE; return KEEP | ACKNOWLEDGE;
} }
} }
} }
// The fast path was not applicable, so we continue with the standard processing // The fast path was not applicable, so we continue with the standard
// of the incoming segment // processing of the incoming segment
// First have a look at the data being sent
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) < fLastAcknowledgeSent + fReceiveWindow) { && tcp_sequence(segment.sequence)
< (fLastAcknowledgeSent + fReceiveWindow)) {
if (fState == SYNCHRONIZE_RECEIVED) { if (fState == SYNCHRONIZE_RECEIVED) {
// TODO: if we came from SYN-SENT signal connection refused // TODO: if we came from SYN-SENT signal connection refused
// and remove all segments from tx queue // 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) { if (fState != TIME_WAIT && fReceiveQueue.Available() > 0) {
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
// TODO: real conditional locking needed! // TODO: real conditional locking needed!
gSocketModule->notify(socket, B_SELECT_READ, 1); _NotifyReader();
} else { } else {
return DELETE | DROP; return DELETE | DROP;
} }
@@ -854,14 +852,15 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
return DROP; return DROP;
} }
if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0 if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0
|| (fState == SYNCHRONIZE_RECEIVED || (fState == SYNCHRONIZE_RECEIVED
&& (fInitialReceiveSequence > segment.sequence && (fInitialReceiveSequence > segment.sequence
|| (segment.flags & TCP_FLAG_ACKNOWLEDGE) != 0 || (segment.flags & TCP_FLAG_ACKNOWLEDGE) != 0
&& (fSendUnacknowledged > segment.acknowledge && (fSendUnacknowledged > segment.acknowledge
|| fSendMax < segment.acknowledge)))) { || fSendMax < segment.acknowledge)))) {
// reset the connection - either the initial SYN was faulty, or we received // reset the connection - either the initial SYN was faulty, or we
// a SYN within the data stream // received a SYN within the data stream
return DROP | RESET; return DROP | RESET;
} }
@@ -872,7 +871,8 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
int32 drop = fReceiveNext - segment.sequence; int32 drop = fReceiveNext - segment.sequence;
if (drop > 0) { if (drop > 0) {
if ((uint32)drop > buffer->size 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 // don't accidently remove a FIN we shouldn't remove
segment.flags &= ~TCP_FLAG_FINISH; segment.flags &= ~TCP_FLAG_FINISH;
drop = buffer->size; 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(fSendLock, 1, B_DO_NOT_RESCHEDULE);
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
// TODO: real conditional locking needed! // TODO: real conditional locking needed!
gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); _NotifyReader();
} }
if (fSendMax < segment.acknowledge || fState == TIME_WAIT) if (fSendMax < segment.acknowledge || fState == TIME_WAIT)
@@ -994,7 +994,15 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
if (advertisedWindow > fSendMaxWindow) if (advertisedWindow > fSendMaxWindow)
fSendMaxWindow = advertisedWindow; 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 // TODO: ignore data *after* FIN
if (segment.flags & TCP_FLAG_FINISH) { 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); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
// TODO: real conditional locking needed! // TODO: real conditional locking needed!
gSocketModule->notify(socket, B_SELECT_READ, _AvailableBytesOrDisconnect()); _NotifyReader();
// other side is closing connection; change states // other side is closing connection; change states
switch (fState) { switch (fState) {
@@ -1044,7 +1052,7 @@ TCPEndpoint::Receive(tcp_segment_header &segment, net_buffer *buffer)
release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(fReceiveLock, 1, B_DO_NOT_RESCHEDULE);
// TODO: real conditional locking needed! // TODO: real conditional locking needed!
gSocketModule->notify(socket, B_SELECT_READ, fReceiveQueue.Available()); _NotifyReader();
} else } else
gBufferModule->free(buffer); 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 status_t
TCPEndpoint::_ShutdownEgress(bool closing) 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 // #pragma mark - timer
@@ -66,8 +66,9 @@ class TCPEndpoint : public net_protocol {
bool outstandingAcknowledge); bool outstandingAcknowledge);
status_t _SendQueued(bool force = false); status_t _SendQueued(bool force = false);
int _GetMSS(const struct sockaddr *) const; int _GetMSS(const struct sockaddr *) const;
ssize_t _AvailableBytesOrDisconnect() const;
status_t _ShutdownEgress(bool closing); status_t _ShutdownEgress(bool closing);
ssize_t _AvailableData() const;
void _NotifyReader();
static void _TimeWaitTimer(net_timer *timer, void *data); static void _TimeWaitTimer(net_timer *timer, void *data);
static void _RetransmitTimer(net_timer *timer, void *data); static void _RetransmitTimer(net_timer *timer, void *data);
@@ -764,7 +764,7 @@ UdpEndpoint::_Deactivate()
status_t status_t
UdpEndpoint::SendData(net_buffer *buffer, net_route *route) UdpEndpoint::SendData(net_buffer *buffer, net_route *route)
{ {
if (buffer->size > 0xffff) if (buffer->size > (0xffff - sizeof(udp_header)))
return EMSGSIZE; return EMSGSIZE;
buffer->protocol = IPPROTO_UDP; buffer->protocol = IPPROTO_UDP;