A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Revision:
55:e64b8b47a2b6
Parent:
54:84ef2b29cf7e
Child:
56:35117a8b5c65
--- a/tcp/tcp.cpp	Mon Nov 13 08:06:55 2017 +0000
+++ b/tcp/tcp.cpp	Mon Nov 13 21:46:31 2017 +0000
@@ -11,6 +11,7 @@
 #define MAX_MSS 536 //This is 576 - 20 - 20
 
 bool TcpTrace = false;
+static bool doTrace = false;
 
 __packed struct header
 {
@@ -48,9 +49,10 @@
 static char*    pOptions;
 static char*    pData;
 static int      dataLength;
-static uint16_t mss;
+static int positionInRequestStream;
+static int positionInReplyStream;
 
-static bool     isSend = false;
+static uint16_t mss;
 
 static void (*pTraceback)(void);
 
@@ -65,7 +67,7 @@
     if (SYN) Log(" SYN");
     if (FIN) Log(" FIN");
 }
-void TcpLogHeader(uint16_t calculatedChecksum)
+void TcpLogHeader(uint16_t calculatedChecksum, bool isSend)
 {
     if (NetTraceVerbose)
     {
@@ -74,13 +76,13 @@
         LogF("  Destination port %hu\r\n",   dstPort);
         if (isSend)
         {
-            LogF("  Sequence number  %u (%u)\r\n",  seqnum - pTcb->locIsn, seqnum);
-            LogF("  Ack number       %u (%u)\r\n",  acknum - pTcb->remIsn, acknum);
+            LogF("  Loc Seq number  %u (%u)\r\n",  seqnum - pTcb->locIsn, seqnum);
+            LogF("  Rem Ack number  %u (%u)\r\n",  acknum - pTcb->remIsn, acknum);
         }
         else
         {
-            LogF("  Sequence number  %u (%u)\r\n",  seqnum - pTcb->remIsn, seqnum);
-            LogF("  Ack number       %u (%u)\r\n",  acknum - pTcb->locIsn, acknum);
+            LogF("  Rem Seq number  %u (%u)\r\n",  seqnum - pTcb->remIsn, seqnum);
+            LogF("  Loc Ack number  %u (%u)\r\n",  acknum - pTcb->locIsn, acknum);
         }
         LogF("  Header size      %u\r\n",    headersize);
         Log ("  Flags           "); logFlags(); Log("\r\n");
@@ -100,8 +102,8 @@
     {
         LogF("TCP   header %hu >>> %hu", srcPort, dstPort);
         logFlags();
-        if (isSend) LogF(", seq %u, ack %u", seqnum - pTcb->locIsn, acknum - pTcb->remIsn);
-        else        LogF(", seq %u, ack %u", seqnum - pTcb->remIsn, acknum - pTcb->locIsn);
+        if (isSend) LogF(", loc seq %u, rem ack %u", seqnum - pTcb->locIsn, acknum - pTcb->remIsn);
+        else        LogF(", rem seq %u, loc ack %u", seqnum - pTcb->remIsn, acknum - pTcb->locIsn);
         Log("\r\n");
     }
 }
@@ -190,19 +192,24 @@
     
     pHeader->checksum   = 0;
 }
+static void makeRST()
+{
+    dataLength = 0;
+    headersize = 20;
+    seqnum = acknum;
+    acknum = 0;
+    ACK = false;
+    PSH = false;
+    RST = true;
+    SYN = false;
+    FIN = false;
+}
 static int stateClosed()
 {
     if (!SYN)    //Reset if anything other than a request to establish conection from client
     {
-        dataLength = 0;
-        headersize = 20;
-        seqnum = acknum;
-        acknum = 0;
-        ACK = false;                    //Send RST
-        PSH = false;
-        RST = true;
-        SYN = false;
-        FIN = false;
+        if (TcpTrace) LogTimeF("TCP did not received other than a SYN when closed - sent reset.\r\n");
+        makeRST();
         return 1;        
     }
     
@@ -211,17 +218,7 @@
     pTcb->state   = TCB_SYN_RECEIVED;
     pTcb->elapsed = TcbElapsed;
     pTcb->port    = srcPort;
-    pTcb->locIsn  = TcbGetIsn();
-    pTcb->locSeq  = pTcb->locIsn;  
-    pTcb->remIsn  = seqnum;
-    pTcb->remSeq  = pTcb->remIsn;
-    
-    pTcb->remSeq += 1;             //Add one to acknowledge the SYN
-    acknum = pTcb->remSeq;
-    
-    seqnum = pTcb->locSeq;         //Set the sequence number to the first byte of this message
-    pTcb->locSeq += 1;             //Add one to the next sequence number as we are sending a SYN
-    
+        
     dataLength = 0;
     
     mss = MAX_MSS;                 //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20
@@ -238,7 +235,7 @@
 }
 static int stateSynReceived()
 {
-    if (dataLength) LogTimeF("%d bytes data received before TCB established\r\n", dataLength);
+    if (dataLength) LogTimeF("%d bytes data received before TCB established - ignoring\r\n", dataLength);
     if (ACK)
     {
         pTcb->state   = TCB_ESTABLISHED;
@@ -252,32 +249,23 @@
     if (!ACK) return 0;              //Ignore any packets which don't contain an ACK
     
     //Handle reception of data
-    pTcb->remSeq = seqnum + dataLength;
-    acknum = pTcb->remSeq;      //Set the ack num to the next byte expected from the client
-    int positionInRequestStream = seqnum - pTcb->remIsn - 1;
-    int positionInReplyStream   = pTcb->locSeq - pTcb->locIsn - 1;
     char* pRequestStream = pData;
     char* pReplyStream   = pOptions;
 
-    HttpHandleRequest(pTraceback, &dataLength, pRequestStream, positionInRequestStream, pReplyStream, positionInReplyStream, mss, &pTcb->todo);
+    HttpHandleRequest(&dataLength, pRequestStream, positionInRequestStream - 1, pReplyStream, positionInReplyStream - 1, mss, &pTcb->todo);
     
     //Rearrange the buffers
     headersize = 20;
     pData = pReplyStream;
-    
-    seqnum = pTcb->locSeq;      //Set the sequence number to the first byte of this message
-    
+        
     ACK = true;                 //Send ACK
     RST = false;
     SYN = false;
     PSH = false;
     
-    pTcb->locSeq += dataLength; //Record the next sequence number
-    
     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->locSeq += 1;          //Record the FIN in the sequence
         pTcb->state = TCB_CLOSING;  //Start closing
     }
 
@@ -287,13 +275,7 @@
 static int stateClosing()
 {
     if (!FIN) return 0;       //Ignore any packets which don't contain a FIN
-    
-    pTcb->remSeq += 1;        //Add one to acknowledge the FIN
-    acknum = pTcb->remSeq;
-    
-    seqnum = pTcb->locSeq;    //Set the sequence number to the first byte of this message
-                              //but don't change it for the next
-    
+        
     ACK = true;               //Send ACK
     PSH = false;
     RST = false;
@@ -311,7 +293,8 @@
 int TcpHandleReceivedPacket(void (*traceback)(void), int* pSize, void* pPacket)
 {
     pTraceback = traceback;
-    isSend = false;
+    
+    //Get the Transmission Control Block
     pTcb = TcbGetExisting(srcPort);
     if (!pTcb)  pTcb = TcbGetEmpty();
     if (!pTcb)
@@ -319,59 +302,71 @@
         if (TcpTrace)
         {
             LogTime("TCP no more tcbs are available\r\n");
-            traceback(); //This will already include the TCP header
+            pTraceback(); //This will already include the TCP header
         }
         return DO_NOTHING; //Bomb out if no more tcbs are available
     }
 
+    //Handle request to reset
     if (RST)
     {
         pTcb->state  = TCB_CLOSED; //Reset connection
         return DO_NOTHING;         //Bomb out
     }
+    
+    //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);
+    }
+    
+    //Check the remote host has received all bytes
+    if (acknum != pTcb->locSeq)
+    {
+        LogTimeF("TCP acknowledged %u but expected %u\r\n", acknum, pTcb->locSeq);
+    }
+
+    positionInRequestStream = seqnum - pTcb->remIsn;
+    positionInReplyStream   = acknum - pTcb->locIsn;
 
     //Filter out unwanted links
     switch (dstPort)
     {
-        case 80: break;
-        default:
-            if (TcpTrace)
+        case 80:
+            doTrace = HttpTrace;
+            if (doTrace)
             {
-                LogTimeF("TCP unknown port %d\r\n", dstPort);
-                traceback(); //This will already include the TCP header
+                if (NetTraceNewLine) Log("\r\n");
+                LogTime("HTTP server request\r\n");
             }
-            return DO_NOTHING; //This needs to become a reset
-    }
-    
-    if (TcpTrace)
-    {
-        if (!SYN && (int32_t)(seqnum - pTcb->remSeq))
-        {
-            LogTime("TCP");
-            logFlags();
-            LogF(" off=%d seq num=%u expected=%u packet length %d from port %u\r\n", (int32_t)(seqnum - pTcb->remSeq), seqnum, pTcb->remSeq, *pSize, srcPort);
-        }
+            break;
+            
+        default:
+            doTrace = TcpTrace;
+            if (doTrace)
+            {
+                if (NetTraceNewLine) Log("\r\n");
+                LogTimeF("TCP unknown port %d\r\n", dstPort);
+            }
+            return DO_NOTHING; //Ignore unknown ports
     }
-    //Drop duplicate packets
-    /*
-    if (!TCB_CLOSED && (int32_t)(seqnum - pTcb->remSeq) < 0)
-    {
-        if (TcpTrace)
-        {
-            LogTimeF("TCP Dropped duplicate seq num=%d expected=%d packet length %d from port %u\r\n", seqnum, pTcb->remSeq, *pSize, srcPort);
-            traceback();
-        }
-        return DO_NOTHING;
-    }
-    */
-    if (TcpTrace)
-    {
-        if (NetTraceNewLine) Log("\r\n");
-        LogF("TCP server request\r\n");
-        traceback();
-    }
+    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
 
-    isSend = true;
     switch (pTcb->state)
     {
         case TCB_CLOSED:       if (stateClosed     ()) break; return DO_NOTHING;
@@ -380,11 +375,17 @@
         case TCB_CLOSING:      if (stateClosing    ()) break; 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
+
+    
     srcPort = dstPort;
     dstPort = pTcb->port;
     
     *pSize = dataLength + headersize;
         
-    return ActionMakeFromDestAndTrace(UNICAST, TcpTrace && NetTraceStack);
+    return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack);
 
 }