[haiku-commits] r38535 - haiku/trunk/src/system/boot/loader/net

  • From: andreas.faerber@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 5 Sep 2010 23:02:38 +0200 (CEST)

Author: andreasf
Date: 2010-09-05 23:02:38 +0200 (Sun, 05 Sep 2010)
New Revision: 38535
Changeset: http://dev.haiku-os.org/changeset/38535

Modified:
   haiku/trunk/src/system/boot/loader/net/TCP.cpp
Log:
boot_net: Various TCP fixes

Don't enqueue a packet whose sequence number matches the first one in queue
or is between the next and the acknowledged on. This would lead to packet
duplication in the queue and leftovers after dequeuing.

Optimize calculation of acknowledgement number for out-of-order reception.
If a single missing packet arrived, this could have resulted in a timeout
depending on the window size.

In case the connection is closed, do dequeue remaining packets. This would
have caused a read error after a unidirectional FIN.

Prepare a dynamic window size calculation.

Do checksum calculation before attempting to trace packet contents. I have
seen a few and couldn't spot an error in the checksum calculation.

More fine-grained control over trace output.
Trace the Maximum Segment Size option if present; break after End of Options.


Modified: haiku/trunk/src/system/boot/loader/net/TCP.cpp
===================================================================
--- haiku/trunk/src/system/boot/loader/net/TCP.cpp      2010-09-05 09:23:23 UTC 
(rev 38534)
+++ haiku/trunk/src/system/boot/loader/net/TCP.cpp      2010-09-05 21:02:38 UTC 
(rev 38535)
@@ -29,6 +29,8 @@
 
 //#define TRACE_TCP
 //#define TRACE_TCP_RANDOMNESS
+//#define TRACE_TCP_CHECKSUM
+//#define TRACE_TCP_QUEUE
 
 
 #ifdef TRACE_TCP
@@ -41,6 +43,16 @@
 #else
 #      define TRACE_PORT(x, ...) ;
 #endif
+#if defined(TRACE_TCP_CHECKSUM)
+#      define TRACE_CHECKSUM(x, ...) dprintf(x, ## __VA_ARGS__)
+#else
+#      define TRACE_CHECKSUM(x, ...) ;
+#endif
+#if defined(TRACE_TCP_QUEUE)
+#      define TRACE_QUEUE(x, ...) dprintf(x, ## __VA_ARGS__)
+#else
+#      define TRACE_QUEUE(x, ...) ;
+#endif
 
 
 static unsigned int
@@ -200,9 +212,18 @@
 uint16
 TCPSocket::WindowSize() const
 {
-       size_t windowSize = 2048;
-               // TODO Implement dynamic window size.
+       // TODO A large window size leads to read timeouts
+       // due to resends occuring too late.
+#if 0
+       size_t windowSize = 0xffff;
+       for (TCPPacket* packet = fFirstPacket;
+                       packet != NULL && windowSize > packet->DataSize();
+                       packet = packet->Next())
+               windowSize -= packet->DataSize();
        return windowSize;
+#else
+       return 4096;
+#endif
 }
 
 
@@ -293,13 +314,15 @@
                fTCPService->ProcessIncomingPackets();
                //_ResendQueue();
                packet = _PeekPacket();
-               if (packet != NULL && fRemoteState != TCP_SOCKET_STATE_OPEN)
+               if (packet == NULL && fRemoteState != TCP_SOCKET_STATE_OPEN)
                        return B_ERROR;
                if (packet == NULL && timeout > 0LL)
                        _Ack();
        } while (packet == NULL && system_time() - startTime < timeout);
        if (packet == NULL) {
+#ifdef TRACE_TCP_QUEUE
                _DumpQueue();
+#endif
                return (timeout == 0) ? B_WOULD_BLOCK : B_TIMED_OUT;
        }
        uint32 packetOffset = fNextSequence - packet->SequenceNumber();
@@ -343,10 +366,12 @@
                        fNextSequence += readBytes;
                } while (readBytes < bufferSize &&
                        system_time() - startTime < timeout);
+#ifdef TRACE_TCP_QUEUE
                if (readBytes < bufferSize) {
-                       dprintf("TCP: Unable to deliver more data!\n");
+                       TRACE_QUEUE("TCP: Unable to deliver more data!\n");
                        _DumpQueue();
                }
+#endif
        }
 
        return B_OK;
@@ -430,8 +455,8 @@
        // For now rather protect us against being flooded with packets already
        // acknowledged. "If it's important, they'll send it again."
        // TODO PAWS
-       if (packet->SequenceNumber() < fNextSequence) {
-               TRACE("TCPSocket::ProcessPacket(): not queuing due to 
wraparound\n");
+       if (packet->SequenceNumber() < fAcknowledgeNumber) {
+               TRACE_QUEUE("TCPSocket::ProcessPacket(): not queuing due to 
wraparound\n");
                delete packet;
                return;
        }
@@ -450,18 +475,23 @@
        } else if (fFirstPacket->SequenceNumber() > packet->SequenceNumber()) {
                // enqueue in front
                TRACE("TCPSocket::ProcessPacket(): enqueue in front\n");
-               dprintf("TCP: Enqueuing %lx - %lx in front!\n",
+               TRACE_QUEUE("TCP: Enqueuing %lx - %lx in front! (next is 
%lx)\n",
                        packet->SequenceNumber(),
-                       packet->SequenceNumber() + packet->DataSize() - 1);
+                       packet->SequenceNumber() + packet->DataSize() - 1,
+                       fNextSequence);
                packet->SetNext(fFirstPacket);
                fFirstPacket = packet;
+       } else if (fFirstPacket->SequenceNumber() == packet->SequenceNumber()) {
+               TRACE_QUEUE("%s(): dropping due to identical first packet\n", 
__func__);
+               delete packet;
+               return;
        } else {
                // enqueue in middle
                TRACE("TCPSocket::ProcessPacket(): enqueue in middle\n");
                for (TCPPacket* queuedPacket = fFirstPacket; queuedPacket != 
NULL;
                                queuedPacket = queuedPacket->Next()) {
                        if (queuedPacket->SequenceNumber() == 
packet->SequenceNumber()) {
-                               TRACE("TCPSocket::EnqueuePacket(): TCP packet 
dropped\n");
+                               TRACE_QUEUE("TCPSocket::EnqueuePacket(): TCP 
packet dropped\n");
                                // we may be waiting for a previous packet
                                delete packet;
                                return;
@@ -474,10 +504,10 @@
                        }
                }
        }
-       if (packet->SequenceNumber() == fAcknowledgeNumber)
+       while (packet != NULL && packet->SequenceNumber() == 
fAcknowledgeNumber) {
                fAcknowledgeNumber = packet->SequenceNumber() + 
packet->DataSize();
-                       // XXX Might be greater than that in case we already 
received
-                       // following packets. Either check the queue or use ECN.
+               packet = packet->Next();
+       }
 }
 
 
@@ -527,6 +557,7 @@
                        return nextPacket;
                }
        }
+       TRACE_QUEUE("dequeue failed!\n");
        return NULL;
 }
 
@@ -542,8 +573,10 @@
                return error;
        if (packet->SequenceNumber() == fSequenceNumber)
                fSequenceNumber += packet->DataSize();
+
        if (enqueue)
                _EnqueueOutgoingPacket(packet);
+
        return B_OK;
 }
 
@@ -577,25 +610,29 @@
 }
 
 
+#ifdef TRACE_TCP_QUEUE
+
 inline void
 TCPSocket::_DumpQueue()
 {
+       TRACE_QUEUE("TCP: waiting for %lx (ack'ed %lx)\n", fNextSequence, 
fAcknowledgeNumber);
        if (fFirstPacket == NULL)
-               dprintf("TCP: Queue is empty.\n");
+               TRACE_QUEUE("TCP: Queue is empty.\n");
        else {
-               dprintf("TCP: waiting for %lx\n", fNextSequence);
                for (TCPPacket* packet = fFirstPacket; packet != NULL;
                                packet = packet->Next()) {
-                       dprintf("TCP: Queue: %lx\n", packet->SequenceNumber());
+                       TRACE_QUEUE("TCP: Queue: %lx\n", 
packet->SequenceNumber());
                }
        }
        if (fFirstSentPacket != NULL)
-               dprintf("TCP: Send queue is non-empty.\n");
+               TRACE_QUEUE("TCP: Send queue is non-empty.\n");
        else
-               dprintf("TCP: Send queue is empty.\n");
+               TRACE_QUEUE("TCP: Send queue is empty.\n");
 }
 
+#endif
 
+
 status_t
 TCPSocket::_Ack()
 {
@@ -681,6 +718,15 @@
                return;
 
        const tcp_header* header = (const tcp_header*)data;
+
+       uint16 chksum = _ChecksumData(data, size, sourceIP, destinationIP);
+       if (chksum != 0) {
+               TRACE_CHECKSUM("TCPService::HandleIPPacket(): invalid checksum "
+                       "(%04x vs. %04x), padding %lu\n",
+                       header->checksum, chksum, size % 2);
+               return;
+       }
+
        uint16 source = ntohs(header->source);
        uint16 destination = ntohs(header->destination);
        uint32 sequenceNumber = ntohl(header->seqNumber);
@@ -696,22 +742,20 @@
                uint8* option = (uint8*)data + sizeof(tcp_header);
                while ((uint32*)option < (uint32*)data + header->dataOffset) {
                        uint8 optionKind = option[0];
+                       if (optionKind == 0)
+                               break;
                        uint8 optionLength = 1;
-                       if (optionKind > 1)
+                       if (optionKind > 1) {
                                optionLength = option[1];
-                       TRACE("\tTCP option kind %u, length %u\n",
-                               optionKind, optionLength);
+                               TRACE("\tTCP option kind %u, length %u\n",
+                                       optionKind, optionLength);
+                               if (optionKind == 2)
+                                       TRACE("\tTCP MSS = %04hu\n", 
*(uint16_t*)&option[2]);
+                       }
                        option += optionLength;
                }
        }
 
-       uint16 chksum = _ChecksumData(data, size, sourceIP, destinationIP);
-       if (chksum != 0) {
-               TRACE("TCPService::HandleIPPacket(): invalid checksum (%04x)\n",
-                       header->checksum);
-               return;
-       }
-
        TCPSocket* socket = _FindSocket(destinationIP, destination);
        if (socket == NULL) {
                // TODO If SYN, answer with RST?


Other related posts:

  • » [haiku-commits] r38535 - haiku/trunk/src/system/boot/loader/net - andreas . faerber