Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
57:e0fb648acf48
Parent:
56:35117a8b5c65
Child:
59:e0e556c8bd46
--- a/tcp/tcp.cpp	Tue Nov 14 17:43:08 2017 +0000
+++ b/tcp/tcp.cpp	Tue Nov 28 17:05:46 2017 +0000
@@ -72,29 +72,29 @@
     if (NetTraceVerbose)
     {
         Log("TCP header\r\n");
-        LogF("  Source port      %hu\r\n",      srcPort);
-        LogF("  Destination port %hu\r\n",      dstPort);
-        LogF("  Seq number       %u (%u)\r\n",  positionInQuery, seqnum);
-        LogF("  Ack number       %u (%u)\r\n",  positionInReply, acknum);
-        LogF("  Header size      %u\r\n",       headersize);
-        Log ("  Flags           "); logFlags(); Log("\r\n");
-        LogF("  Window           %hu\r\n",      window);
-        LogF("  Checksum (hex)   %04hX\r\n",    checksum);
-        LogF("  Calculated (hex) %04hX\r\n",    calculatedChecksum);
-        LogF("  Urgent pointer   %hu\r\n",      urgent);
-        LogF("  Option length    %d\r\n",       optionLength);
-        LogF("  Data length      %d\r\n",       dataLength);
-        LogF("  locIsn           %u\r\n",       pTcb->locIsn);
-        LogF("  remIsn           %u\r\n",       pTcb->remIsn);
-        LogF("  locSeq           %u\r\n",       pTcb->locSeq);
-        LogF("  remSeq           %u\r\n",       pTcb->remSeq);
+        Log("  Source port      "); LogF("%hu",     srcPort                ); Log("\r\n");
+        Log("  Destination port "); LogF("%hu",     dstPort                ); Log("\r\n");
+        Log("  Seq number       "); LogF("%u (%u)", positionInQuery, seqnum); Log("\r\n");
+        Log("  Ack number       "); LogF("%u (%u)", positionInReply, acknum); Log("\r\n");
+        Log("  Header size      "); LogF("%u",      headersize             ); Log("\r\n");
+        Log("  Flags           " ); logFlags(                              ); Log("\r\n");
+        Log("  Window           "); LogF("%hu",     window                 ); Log("\r\n");
+        Log("  Checksum (hex)   "); LogF("%04hX",   checksum               ); Log("\r\n");
+        Log("  Calculated (hex) "); LogF("%04hX",   calculatedChecksum     ); Log("\r\n");
+        Log("  Urgent pointer   "); LogF("%hu",     urgent                 ); Log("\r\n");
+        Log("  Option length    "); LogF("%d",      optionLength           ); Log("\r\n");
+        Log("  Data length      "); LogF("%u",      dataLength             ); Log("\r\n");
+        Log("  sendIsn          "); LogF("%u",      pTcb->sendIsn          ); Log("\r\n");
+        Log("  recvIsn          "); LogF("%u",      pTcb->recvIsn          ); Log("\r\n");
+        Log("  sentBytes        "); LogF("%u",      pTcb->sentBytes        ); Log("\r\n");
+        Log("  recdBytes        "); LogF("%u",      pTcb->recdBytes        ); Log("\r\n");
 
     }
     else
     {
         LogF("TCP   header %hu >>> %hu", srcPort, dstPort);
         logFlags();
-        LogF(", seq %u, ack %u", positionInQuery, positionInReply);
+        LogF(", query %u, reply %u", positionInQuery, positionInReply);
         Log("\r\n");
     }
 }
@@ -155,7 +155,7 @@
        checksum = NetToHost16(pHeader->checksum);
          urgent = NetToHost16(pHeader->urgent);
        pOptions = (char*)pPacket + 20;
-   optionLength = headersize - 20;
+   optionLength =     headersize - 20;
           pData = (char*)pPacket + headersize;
      dataLength =           size - headersize;
 }
@@ -205,6 +205,7 @@
     pTcb->state   = TCB_SYN_RECEIVED;
     pTcb->elapsed = TcbElapsed;
     pTcb->port    = srcPort;
+    pTcb->hadFin  = false;
         
     dataLength = 0;
     
@@ -222,7 +223,7 @@
 {
     pTcb->state   = TCB_ESTABLISHED;
     pTcb->elapsed = TcbElapsed;
-    pTcb->todo     = 0;
+    pTcb->todo    = 0;
 }
 static void handleEstablishedConnection()
 {    
@@ -241,8 +242,9 @@
     
     if (dataLength < mss) //If a part packet then there can be no more to send
     {
-        FIN = true;                 //Inform the client that we have no more to send after this
-        pTcb->state = TCB_CLOSING;  //Start closing
+        FIN = true;       //Inform the client that we have no more to send after this
+        if (pTcb->hadFin) pTcb->state = TCB_ACK_WAIT; //Passive close
+        else              pTcb->state = TCB_FIN_WAIT; //Active close
     }
     else
     {
@@ -262,12 +264,35 @@
     headersize = 20;
     dataLength = 0;
     
-    pTcb->state  = TCB_CLOSED;
+    pTcb->state  = TCB_EMPTY;
 }
 
 int TcpHandleReceivedPacket(void (*traceback)(void), int* pSize, void* pPacket)
 {
     pTraceback = traceback;
+    doTrace = false;
+    
+    //Filter out unwanted links
+    switch (dstPort)
+    {
+        case 80:
+            if (HttpTrace)
+            {
+                if (NetTraceNewLine) Log("\r\n");
+                LogTime("HTTP server request\r\n");
+                doTrace = true;
+            }
+            break;
+            
+        default:
+            if (TcpTrace)
+            {
+                if (NetTraceNewLine) Log("\r\n");
+                LogTimeF("TCP unknown port %d\r\n", dstPort);
+                if (NetTraceStack) pTraceback();
+            }
+            return DO_NOTHING; //Ignore unknown ports
+    }
     
     //Get the Transmission Control Block
     pTcb = TcbGetExisting(srcPort);
@@ -276,8 +301,9 @@
     {
         if (TcpTrace)
         {
+            if (NetTraceNewLine) Log("\r\n");
             LogTime("TCP no more tcbs are available\r\n");
-            pTraceback(); //This will already include the TCP header
+            if (NetTraceStack) pTraceback();
         }
         return DO_NOTHING; //Bomb out if no more tcbs are available
     }
@@ -285,66 +311,56 @@
     //Handle request to reset
     if (RST)
     {
-        pTcb->state  = TCB_CLOSED; //Reset connection
-        return DO_NOTHING;         //Don't reply
+        if (TcpTrace)
+        {
+            if (NetTraceNewLine) Log("\r\n");
+            LogTime("TCP received reset - resetting TCB\r\n");
+            if (NetTraceStack) pTraceback();
+        }
+        pTcb->state  = TCB_EMPTY; //Reset connection
+        return DO_NOTHING;        //Don't reply
     }
     
     //Handle request to synchronise
     if (SYN)
     {
-        pTcb->remIsn = seqnum;
-        pTcb->remSeq = pTcb->remIsn;
-        pTcb->locIsn = TcbGetIsn();
-        pTcb->locSeq = pTcb->locIsn;
-        acknum       = pTcb->locIsn;
-    }
-    
-    //Check the sequence is not lost or out of order
-    if (seqnum != pTcb->remSeq)
-    {
-        LogTimeF("TCP had sequence %u but expected %u\r\n", seqnum, pTcb->remSeq);
+        pTcb->recvIsn   = seqnum;
+        pTcb->recdBytes = 0;
+        pTcb->sendIsn   = TcbGetIsn();
+        pTcb->sentBytes = 0;
+        acknum          = pTcb->sendIsn;
     }
     
-    //Check the remote host has received all bytes
-    if (acknum != pTcb->locSeq)
-    {
-        LogTimeF("TCP acknowledged %u but expected %u\r\n", acknum, pTcb->locSeq);
-    }
-
-    positionInQuery = seqnum - pTcb->remIsn;
-    positionInReply = acknum - pTcb->locIsn;
-
-    //Filter out unwanted links
-    switch (dstPort)
+    //Calculate positions
+    positionInQuery = seqnum - pTcb->recvIsn;
+    positionInReply = acknum - pTcb->sendIsn;
+    
+    //Check packet sequences
+    if (positionInQuery != pTcb->recdBytes || positionInReply != pTcb->sentBytes)
     {
-        case 80:
-            doTrace = HttpTrace;
-            if (doTrace)
-            {
-                if (NetTraceNewLine) Log("\r\n");
-                LogTime("HTTP server request\r\n");
-            }
-            break;
+        if (TcpTrace)
+        {
+            if (NetTraceNewLine) Log("\r\n");
+            LogTime("TCP received packet");      
+            if (positionInQuery != pTcb->recdBytes) LogF(": starting at byte %u rather than %u so data reread"  , positionInQuery, pTcb->recdBytes);        
+            if (positionInReply != pTcb->sentBytes) LogF(": acknowledging byte %u rather than %u so data resent", positionInReply, pTcb->sentBytes);
+            Log("\r\n");
             
-        default:
-            doTrace = TcpTrace;
-            if (doTrace)
-            {
-                if (NetTraceNewLine) Log("\r\n");
-                LogTimeF("TCP unknown port %d\r\n", dstPort);
-            }
-            return DO_NOTHING; //Ignore unknown ports
+            if (NetTraceStack) pTraceback();
+            doTrace = true;
+        }
+        pTcb->recdBytes = positionInQuery;
+        pTcb->sentBytes = positionInReply;
     }
     if (doTrace && NetTraceStack) pTraceback(); //This will already include the TCP header
     
-    if (SYN) pTcb->remSeq += 1;          //Add one to acknowledge the SYN
-             pTcb->remSeq += dataLength; //Add the number of bytes received
-    if (FIN) pTcb->remSeq += 1;          //Add one to acknowledge the FIN
-    acknum = pTcb->remSeq;               //Set up the acknowledgement field ready to send
+    if (SYN) pTcb->recdBytes += 1;            //Add one to acknowledge the SYN
+             pTcb->recdBytes += dataLength;   //Add the number of bytes received
+    if (FIN) pTcb->recdBytes += 1;            //Add one to acknowledge the FIN
 
     switch (pTcb->state)
     {
-        case TCB_CLOSED:
+        case TCB_EMPTY:
             if (!SYN) { resetConnection("received other than a SYN when connection closed"); break; }
             startConnection();
             break;
@@ -356,27 +372,39 @@
             return DO_NOTHING;
             
         case TCB_ESTABLISHED:
-            if (!ACK) { resetConnection("received other than an ACK during established conection"); break; } 
+            if (!ACK) { resetConnection("received other than an ACK during established conection"); break; }
+            if (FIN) pTcb->hadFin = true; //When reply is all sent only a passive close is needed
             handleEstablishedConnection();
             break;
             
-        case TCB_CLOSING:
+        case TCB_FIN_WAIT: //End of active close
             if (!FIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close.
             closeConnection();
             break;
+            
+        case TCB_ACK_WAIT: //End of passive close
+            if (!ACK) { resetConnection("received other than an ACK when closing half open connection"); break; } 
+            pTcb->state = TCB_EMPTY;
+            return DO_NOTHING;
     }
     
-    seqnum = pTcb->locSeq;               //Set the sequence number to the first byte of this message
-    if (SYN) pTcb->locSeq += 1;          //Add one to acknowledge the SYN
-             pTcb->locSeq += dataLength; //Record the next sequence number
-    if (FIN) pTcb->locSeq += 1;          //Add one to acknowledge the FIN
+    positionInReply = pTcb->recdBytes;       //Set up the acknowledgement field ready to send
+    positionInQuery = pTcb->sentBytes;       //Record the start of the query before adding the bytes sent
+    
+    //Keep a record of where we expect the next packet send to start
+    if (SYN) pTcb->sentBytes += 1;           //Add one to acknowledge the SYN
+             pTcb->sentBytes += dataLength;  //Record the next sequence number
+    if (FIN) pTcb->sentBytes += 1;           //Add one to acknowledge the FIN
 
-    positionInQuery = seqnum - pTcb->locIsn;
-    positionInReply = acknum - pTcb->remIsn;
+    //Specify the start of the data being sent and acknowledge the data received
+    seqnum = positionInQuery + pTcb->sendIsn;
+    acknum = positionInReply + pTcb->recvIsn;
     
+    //Swap the ports for the reply
     srcPort = dstPort;
     dstPort = pTcb->port;
     
+    //Calculate the size of the reply
     *pSize = dataLength + headersize;
         
     return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack);