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:
56:35117a8b5c65
Parent:
55:e64b8b47a2b6
Child:
57:e0fb648acf48
--- a/tcp/tcp.cpp	Mon Nov 13 21:46:31 2017 +0000
+++ b/tcp/tcp.cpp	Tue Nov 14 17:43:08 2017 +0000
@@ -49,8 +49,8 @@
 static char*    pOptions;
 static char*    pData;
 static int      dataLength;
-static int positionInRequestStream;
-static int positionInReplyStream;
+static int positionInQuery;
+static int positionInReply;
 
 static uint16_t mss;
 
@@ -67,43 +67,34 @@
     if (SYN) Log(" SYN");
     if (FIN) Log(" FIN");
 }
-void TcpLogHeader(uint16_t calculatedChecksum, bool isSend)
+void TcpLogHeader(uint16_t calculatedChecksum)
 {
     if (NetTraceVerbose)
     {
         Log("TCP header\r\n");
-        LogF("  Source port      %hu\r\n",   srcPort);
-        LogF("  Destination port %hu\r\n",   dstPort);
-        if (isSend)
-        {
-            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("  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);
+        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);
+        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);
 
     }
     else
     {
         LogF("TCP   header %hu >>> %hu", srcPort, dstPort);
         logFlags();
-        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);
+        LogF(", seq %u, ack %u", positionInQuery, positionInReply);
         Log("\r\n");
     }
 }
@@ -147,27 +138,26 @@
 {
     struct header* pHeader = (header*)pPacket;
                         
-            srcPort = NetToHost16(pHeader->srcPort);
-            dstPort = NetToHost16(pHeader->dstPort);
-             seqnum = NetToHost32(pHeader->seqnum);
-             acknum = NetToHost32(pHeader->acknum);
-         headersize =            (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4
-              flags =             pHeader->flags;
-                URG = flags & 0x20; //indicates that the Urgent pointer field is significant
-                ACK = flags & 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
-                PSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application.
-                RST = flags & 0x04; //Reset the connection
-                SYN = flags & 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
-                FIN = flags & 0x01; //No more data from sender
-    
-             window = NetToHost16(pHeader->window);
-           checksum = NetToHost16(pHeader->checksum);
-             urgent = NetToHost16(pHeader->urgent);
-           pOptions = (char*)pPacket + 20;
-       optionLength = headersize - 20;
+        srcPort = NetToHost16(pHeader->srcPort);
+        dstPort = NetToHost16(pHeader->dstPort);
+         seqnum = NetToHost32(pHeader->seqnum);
+         acknum = NetToHost32(pHeader->acknum);
+     headersize =            (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4
+          flags =             pHeader->flags;
+            URG = flags & 0x20; //indicates that the Urgent pointer field is significant
+            ACK = flags & 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
+            PSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application.
+            RST = flags & 0x04; //Reset the connection
+            SYN = flags & 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
+            FIN = flags & 0x01; //No more data from sender
 
-                  pData = (char*)pPacket + headersize;
-             dataLength =           size - headersize;
+         window = NetToHost16(pHeader->window);
+       checksum = NetToHost16(pHeader->checksum);
+         urgent = NetToHost16(pHeader->urgent);
+       pOptions = (char*)pPacket + 20;
+   optionLength = headersize - 20;
+          pData = (char*)pPacket + headersize;
+     dataLength =           size - headersize;
 }
 
 void TcpMakeHeader(int size, void* pPacket)
@@ -180,39 +170,36 @@
     pHeader->acknum     = NetToHost32(acknum); //This is the sequence number we expect in the next message
     pHeader->dataOffset = headersize << 2;     //Same as dividing by 4 to get bytes and left shifting by 4 bits
     flags = 0;
-    if(URG) flags |= 0x20; //indicates that the Urgent pointer field is significant
-    if(ACK) flags |= 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
-    if(PSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application.
-    if(RST) flags |= 0x04; //Reset the connection
-    if(SYN) flags |= 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
-    if(FIN) flags |= 0x01; //No more data from sender
+    if (URG) flags |= 0x20; //indicates that the Urgent pointer field is significant
+    if (ACK) flags |= 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
+    if (PSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application.
+    if (RST) flags |= 0x04; //Reset the connection
+    if (SYN) flags |= 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
+    if (FIN) flags |= 0x01; //No more data from sender
     pHeader->flags      = flags;
     pHeader->window     = NetToHost16(window);
     pHeader->urgent     = NetToHost16(urgent);
     
     pHeader->checksum   = 0;
 }
-static void makeRST()
+static void resetConnection(char* message)
 {
+    if (TcpTrace)
+    {
+        LogTime("TCP ");
+        Log(message);
+        Log("\r\n");
+    }
     dataLength = 0;
     headersize = 20;
-    seqnum = acknum;
-    acknum = 0;
     ACK = false;
     PSH = false;
     RST = true;
     SYN = false;
     FIN = false;
 }
-static int stateClosed()
+static void startConnection()
 {
-    if (!SYN)    //Reset if anything other than a request to establish conection from client
-    {
-        if (TcpTrace) LogTimeF("TCP did not received other than a SYN when closed - sent reset.\r\n");
-        makeRST();
-        return 1;        
-    }
-    
     readOptions();                 //Get the MSS
     pTcb->mss     = mss;
     pTcb->state   = TCB_SYN_RECEIVED;
@@ -230,31 +217,20 @@
     RST = false;
     SYN = true;
     FIN = false;
-    
-    return 1;
 }
-static int stateSynReceived()
+static void establishConnection()
 {
-    if (dataLength) LogTimeF("%d bytes data received before TCB established - ignoring\r\n", dataLength);
-    if (ACK)
-    {
-        pTcb->state   = TCB_ESTABLISHED;
-        pTcb->elapsed = TcbElapsed;
-        pTcb->todo     = 0;
-    }
-    return 0;
+    pTcb->state   = TCB_ESTABLISHED;
+    pTcb->elapsed = TcbElapsed;
+    pTcb->todo     = 0;
 }
-static int stateEstablished()
-{
-    if (!ACK) return 0;              //Ignore any packets which don't contain an ACK
-    
-    //Handle reception of data
+static void handleEstablishedConnection()
+{    
     char* pRequestStream = pData;
     char* pReplyStream   = pOptions;
 
-    HttpHandleRequest(&dataLength, pRequestStream, positionInRequestStream - 1, pReplyStream, positionInReplyStream - 1, mss, &pTcb->todo);
+    HttpHandleRequest(&dataLength, pRequestStream, positionInQuery - 1, pReplyStream, positionInReply - 1, mss, &pTcb->todo);
     
-    //Rearrange the buffers
     headersize = 20;
     pData = pReplyStream;
         
@@ -268,14 +244,15 @@
         FIN = true;                 //Inform the client that we have no more to send after this
         pTcb->state = TCB_CLOSING;  //Start closing
     }
+    else
+    {
+        FIN = false;
+    }
 
     pTcb->elapsed = TcbElapsed;
-    return 1;
 }
-static int stateClosing()
-{
-    if (!FIN) return 0;       //Ignore any packets which don't contain a FIN
-        
+static void closeConnection()
+{        
     ACK = true;               //Send ACK
     PSH = false;
     RST = false;
@@ -286,8 +263,6 @@
     dataLength = 0;
     
     pTcb->state  = TCB_CLOSED;
-    
-    return 1;
 }
 
 int TcpHandleReceivedPacket(void (*traceback)(void), int* pSize, void* pPacket)
@@ -311,7 +286,7 @@
     if (RST)
     {
         pTcb->state  = TCB_CLOSED; //Reset connection
-        return DO_NOTHING;         //Bomb out
+        return DO_NOTHING;         //Don't reply
     }
     
     //Handle request to synchronise
@@ -336,8 +311,8 @@
         LogTimeF("TCP acknowledged %u but expected %u\r\n", acknum, pTcb->locSeq);
     }
 
-    positionInRequestStream = seqnum - pTcb->remIsn;
-    positionInReplyStream   = acknum - pTcb->locIsn;
+    positionInQuery = seqnum - pTcb->remIsn;
+    positionInReply = acknum - pTcb->locIsn;
 
     //Filter out unwanted links
     switch (dstPort)
@@ -369,10 +344,26 @@
 
     switch (pTcb->state)
     {
-        case TCB_CLOSED:       if (stateClosed     ()) break; return DO_NOTHING;
-        case TCB_SYN_RECEIVED: if (stateSynReceived()) break; return DO_NOTHING;
-        case TCB_ESTABLISHED:  if (stateEstablished()) break; return DO_NOTHING;
-        case TCB_CLOSING:      if (stateClosing    ()) break; return DO_NOTHING;
+        case TCB_CLOSED:
+            if (!SYN) { resetConnection("received other than a SYN when connection closed"); break; }
+            startConnection();
+            break;
+            
+        case TCB_SYN_RECEIVED:
+            if (dataLength) { resetConnection("data received before connection established"); break; }
+            if (!ACK)       { resetConnection("received other than an ACK before connection established"); break; }
+            establishConnection();
+            return DO_NOTHING;
+            
+        case TCB_ESTABLISHED:
+            if (!ACK) { resetConnection("received other than an ACK during established conection"); break; } 
+            handleEstablishedConnection();
+            break;
+            
+        case TCB_CLOSING:
+            if (!FIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close.
+            closeConnection();
+            break;
     }
     
     seqnum = pTcb->locSeq;               //Set the sequence number to the first byte of this message
@@ -380,6 +371,8 @@
              pTcb->locSeq += dataLength; //Record the next sequence number
     if (FIN) pTcb->locSeq += 1;          //Add one to acknowledge the FIN
 
+    positionInQuery = seqnum - pTcb->locIsn;
+    positionInReply = acknum - pTcb->remIsn;
     
     srcPort = dstPort;
     dstPort = pTcb->port;