RealtimeCompLab2

Dependencies:   mbed

Fork of PPP-Blinky by Nicolas Nackel

Revision:
38:ab582987926e
Parent:
37:2e6689f8b181
Child:
39:b90183d35f1e
--- a/main.cpp	Thu Jan 05 10:37:48 2017 +0000
+++ b/main.cpp	Thu Jan 05 17:12:57 2017 +0000
@@ -47,25 +47,21 @@
 
 // a structure to keep all our ppp globals in
 struct pppType {
-    int online;
-    int ident;
-    int sync;
-    unsigned int seq;
-    int crc;
-    int ledState;
-    int oldFlags;
+    int online; // we hunt for a PPP connection if this is zero
+    int ident; // our IP ident value
+    unsigned int seq; // our TCP sequence number
+    int crc; // for calculating IP and TCP CRCs
+    int ledState; // state of LED1
     struct {
         char * buf;
         volatile int head;
         volatile int tail;
-        int total;
-    } rx; // serial port buffer
+    } rx; // serial port objects
     struct {
-        int id;
-        int len;
-        int crc;
-        char * buf;
-    } pkt; // ppp buffer
+        int len; // number of bytes in buffer
+        int crc; // PPP CRC (frame check)
+        char * buf; // the actual buffer
+    } pkt; // ppp buffer objects
 };
 
 pppType ppp; // our global - definitely not thread safe
@@ -77,14 +73,11 @@
     ppp.rx.buf=rxbuf;
     ppp.rx.tail=0;
     ppp.rx.head=0;
-    ppp.rx.total=0;
     ppp.pkt.buf=frbuf;
     ppp.pkt.len=0;
     ppp.ident=0;
-    ppp.sync=0;
     ppp.seq=1000;
     ppp.ledState=0;
-    ppp.oldFlags=0;
 }
 
 void crcReset()
@@ -142,11 +135,9 @@
     } else return -1;
 }
 
-void scanForConnectString(); // scan for connect attempts from pc
-
 void processFrame(int start, int end)   // process received frame
 {
-    led1Toggle(); // change led1 state when frames are received
+    led1Toggle(); // change led1 state on every frame we receive
     if(start==end) {
         pc.putc(0x7e);
         return;
@@ -184,9 +175,9 @@
     }
 }
 
-// Note - the hex output of dumpframe can be imported into WireShark
-// Copy the frame's hex output from your terminal program and save as a text file
-// In WireShark, use "Import Hex File". Options are No Offset, protocol=PPP.
+// Note - the hex output of dumpFrame() can be imported into WireShark
+// Capture the frame's hex output in your terminal program and save as a text file
+// In WireShark, use "Import Hex File". Options are: Offset=None, Protocol=PPP.
 void dumpFrame()
 {
     for(int i=0; i<ppp.pkt.len; i++) debug(("%02x ", ppp.pkt.buf[i]));
@@ -197,13 +188,13 @@
 {
     if ( (ch<0x20) || (ch==0x7d) || (ch==0x7e) ) {
         pc.putc(0x7d);
-        pc.putc(ch^0x20);
+        pc.putc(ch^0x20);  // three characters need special handling
     } else {
         pc.putc(ch);
     }
 }
 
-void sendFrame()
+void sendFrame() // send one PPP frame in HDLC format
 {
     int crc = crcBuf(ppp.pkt.buf, ppp.pkt.len-2); // update crc
     ppp.pkt.buf[ ppp.pkt.len-2 ] = (~crc>>0); // fcs lo (crc)
@@ -303,7 +294,7 @@
     int sum=0;
     int placeHolder;
     if (len&1) {
-        placeHolder = ptr[len-1];    // when length is odd zero stuff
+        placeHolder = ptr[len-1];    // when length is odd stuff in a zero byte
         ptr[len-1]=0;
     }
     for (int i=0; i<len/2; i++) {
@@ -438,8 +429,8 @@
     snprintf(srcIP,16, "%d.%d.%d.%d", srcAdr[0],srcAdr[1],srcAdr[2],srcAdr[3]);
     char dstIP [16];
     snprintf(dstIP,16, "%d.%d.%d.%d", dstAdr[0],dstAdr[1],dstAdr[2],dstAdr[3]);
-    debug(("IP %s %s v%d h%d d%d e%d L%d ",srcIP,dstIP,versionIP,headerSizeIP,dscpIP,ecnIP,packetLength));
-    if (v1) debug(("i%04x f%d t%d p%d C%04x\n",identIP,flagsIP,ttlIP,protocolIP,checksumIP));
+    if (v0) debug(("IP %s %s v%d h%d d%d e%d L%d ",srcIP,dstIP,versionIP,headerSizeIP,dscpIP,ecnIP,packetLength));
+    if (v0) debug(("i%04x f%d t%d p%d C%04x\n",identIP,flagsIP,ttlIP,protocolIP,checksumIP));
 }
 
 void dumpHeaderTCP()
@@ -512,27 +503,35 @@
 #define TCP_FLAG_RST (1<<2)
 #define TCP_FLAG_FIN (1<<0)
 
-    // A sparse TCP flag interpreter that implements basic TCP connections from a single source
+    // A sparse TCP flag interpreter that implements simple TCP connections from a single source
+    // Clients are allowed ONE push packet, after which the link is closed with a FIN flag in the ACK packet
+    // This strategy allows web browsers, netcat and curl to work ok while keeping the state machine simple
 
     int dataLen = 0; // most of our responses will have zero TCP data, only a header
-    int flagsOut = TCP_FLAG_ACK; // the default case is an ack
-    int fastResponse = 0; // normally we wait 200ms before sending but this can make it faster
+    int flagsOut = TCP_FLAG_ACK; // the default case is an ACK packet
+    int fastResponse = 0; // normally you wait 200ms before sending a packet but this can make it faster
+
+    if (ppp.seq != ack) {
+        ppp.seq = ack;    // if their sequence number is different than our calculation we adopt their version
+    }
 
     if ( ((flagsTCP & ~TCP_FLAG_ACK) == 0) && ((flagsTCP & TCP_FLAG_ACK) != 0) ) {
-        if (incomingLen == 0) return; // no new data
-    } else if ( (flagsTCP & TCP_FLAG_FIN) != 0 ) { // got FIN
-        if ((ppp.oldFlags & TCP_FLAG_FIN) !=0) return;
-        seq++; // increase sequence by 1 for FIN and SYNC
-    } else if ( (flagsTCP & TCP_FLAG_SYN) != 0 ) { // got SYN
+        if (incomingLen == 0) { // ignore - just an empty ack packet
+            return;
+        }
+    } else if ( (flagsTCP & TCP_FLAG_SYN) != 0 ) { // got SYN flag
         flagsOut = TCP_FLAG_SYN | TCP_FLAG_ACK; // do a syn-ack
-        seq++; // increase sequency by for FIN and SYN
-    } else if ( (flagsTCP & TCP_FLAG_PSH) != 0 ) { // they are pushing data
-        fastResponse = 1; // we can response fast to a push
-        // It's a push - let's check the data for an HTTP home page GET request
+        seq++; // for SYN flag we have to increase sequence by 1
+    } else if ( (flagsTCP & TCP_FLAG_FIN) != 0 ) { // got FIN flag
+        seq++; // for FIN flag we have to increase sequence by 1
+    } else if ( (flagsTCP & TCP_FLAG_PSH) != 0 ) { // got PSH flag (push)
+        flagsOut = TCP_FLAG_ACK | TCP_FLAG_FIN; // for every push we answer once AND close the link
+        fastResponse = 1; // we can respond fast to a push
+        // It's a push, so let's check the incoming data for an HTTP GET request
         if ( strncmp(dataStart, "GET / HTTP/1.1", 14) == 0) {
             dataLen = 15*32; // this block has to hold the web page below, but keep it under 1k
-            memset(dataStart,'x', dataLen ); // initialize the block
-            int n=1; // number of bytes we have printed so far
+            memset(dataStart,'x', dataLen ); // initialize the data block
+            int n=0; // number of bytes we have printed so far
             n=n+sprintf(n+dataStart,"HTTP/1.1 200 OK\r\nServer: PPP-Blinky\r\n"); // http header
             n=n+sprintf(n+dataStart,"Content-Length: 376\r\n"); // http header
             n=n+sprintf(n+dataStart,"Content-Type: text/html; charset=us-ascii\r\n\r\n"); // http header
@@ -547,11 +546,11 @@
             if (v0) {
                 debug(("HTTP GET dataLen %d*32=%d Header %d Content-Length %d Total %d Margin %d\n",dataLen/32,dataLen,nHeader,contentLength,n,dataLen-n));
             }
-        } else if ( strncmp(dataStart, "GET /", 4) == 0) { // all other files get 404 not found
-            dataLen = 5*32; // this block has to hold the web page below, but keep it under 1k
-            memset(dataStart,'x', dataLen ); // initialize the block
-            int n=0;
-            n=n+sprintf(n+dataStart,"HTTP/1.1 200 OK\r\nServer: PPP-Blinky\r\n"); // http header
+        } else if ( strncmp(dataStart, "GET /", 4) == 0) { // all other HTTP GET requests get 404 Not Found response
+            dataLen = 5*32; // block size for File not found webpage
+            memset(dataStart,'x', dataLen ); // initialize the data block
+            int n=0; // number of bytes we have printed so far
+            n=n+sprintf(n+dataStart,"HTTP/1.1 400 Not Found\r\nServer: PPP-Blinky\r\n"); // http header
             n=n+sprintf(n+dataStart,"Content-Length: 58\r\n"); // http header
             n=n+sprintf(n+dataStart,"Content-Type: text/html; charset=us-ascii\r\n\r\n"); // http header
             int nHeader=n; // byte total of all headers
@@ -563,80 +562,80 @@
                 debug(("HTTP GET dataLen %d*32=%d Header %d Content-Length %d Total %d Margin %d\n",dataLen/32,dataLen,nHeader,contentLength,n,dataLen-n));
             }
         } else {
-            dataLen=0;
+            dataLen=0; // we did not find a valid HTTP request, so just ACK with zero data
         }
     } else {
-        dataLen=0;
+        dataLen=0; // it's not any TCP Flag Combo that needs special handling
     }
 
-    // All the flag checking is now donw
-
-    ppp.oldFlags = flagsTCP; // remember the flags for the next round
-
-    // Now we have to recalculate all the header sizes
+    // All the TCP flag handling is now done
 
-    ack = seq + incomingLen; // acknowledge the number of bytes they sent by adding it to seq
-    seq = ppp.seq;
+    // Now we have to recalculate all the header sizes, swap IP address/port source and destination, and do the IP and TCP checksums
 
-    char src[4];
-    char dst[4];
+    char src[4]; // temp hold
+    char dst[4]; // temp hold
     memcpy(src, srcAdr,4);
     memcpy(dst, dstAdr,4);
     memcpy(srcAdr, dst,4);
     memcpy(dstAdr, src,4); // swap ip address source/dest
-    char psrc[2];
-    char pdst[2];
+
+    char psrc[2]; // temp hold
+    char pdst[2]; // temp hold
     memcpy(psrc, srctcp,2);
     memcpy(pdst, dsttcp,2);
     memcpy(srctcp, pdst,2);
     memcpy(dsttcp, psrc,2); // swap ip port source/dest
 
-    int newPacketSize = headerSizeIP + headerSizeTCP + dataLen;
+    ack = seq + incomingLen; // acknowledge the number of bytes that they sent by adding it to "our" sequence number
+    seq = ppp.seq; // set up the sequence number we have to respond with
+
+    acktcp[0]=ack>>24;
+    acktcp[1]=ack>>16;
+    acktcp[2]=ack>>8;
+    acktcp[3]=ack>>0; // save ack
+
+    seqtcp[0]=seq>>24;
+    seqtcp[1]=seq>>16;
+    seqtcp[2]=seq>>8;
+    seqtcp[3]=seq>>0; // save seq
+
+    flagbitstcp[1] = flagsOut; // set up the new flags
+
+    int newPacketSize = headerSizeIP + headerSizeTCP + dataLen; // calculate size of the outgoing packet
     pktLen[0] = (newPacketSize>>8);
     pktLen[1]=newPacketSize; // ip total packet size
     ppp.pkt.len = newPacketSize+6; // ppp packet length
     tcpSize = headerSizeTCP + dataLen; // tcp packet size
 
-    flagbitstcp[1] = flagsOut; // set up the new flags
-
-    acktcp[0]=ack>>24;
-    acktcp[1]=ack>>16;
-    acktcp[2]=ack>>8;
-    acktcp[3]=ack>>0; // save ack
-    seqtcp[0]=seq>>24;
-    seqtcp[1]=seq>>16;
-    seqtcp[2]=seq>>8;
-    seqtcp[3]=seq>>0; // save seq
-
-
-    // redo all the header stuff
+    // the header is all set up, now do the IP and TCP checksums
 
     headercheck[0]=0;
     headercheck[1]=0;
     headerCheckSum(); // redo the ip header checksum
-    char pseudoHeader[12];
+
+    char pseudoHeader[12]; // we are building a fake TCP header
     int sum;
-    char temp[12]; // for the terrible pseudoheader checksum
     memcpy( pseudoHeader+0, srcAdr, 8); // source and destination addresses.
     pseudoHeader[8]=0;
     pseudoHeader[9]=protocol[0];
     pseudoHeader[10]=tcpSize>>8;
     pseudoHeader[11]=tcpSize;
-    memcpy(temp, s-12, 12); // keep a copy
-    memcpy( s-12, pseudoHeader, 12); // put the header on the tcp packet
+    char temp[12]; // temporary storage for the 12 bytes that are in the way
+    memcpy(temp, s-12, 12); // save the 12 bytes that are in the way
+    memcpy( s-12, pseudoHeader, 12); // copy in the fake header
     checksumtcp[0]=0;
     checksumtcp[1]=0;
-    sum=dataCheckSum(s-12,tcpSize+12); // update TCP checksum
+    sum=dataCheckSum(s-12,tcpSize+12); // calculate the TCP checksum
     checksumtcp[0]=sum>>8;
     checksumtcp[1]=sum;
-    memcpy( s-12, temp, 12); // overwrite the pseudoheader
+    memcpy( s-12, temp, 12); // restore the 12 bytes that the fake header overwrote
     if (fastResponse==1) {
         fastResponse=0; // reset and skip 200 ms wait
     } else {
-        wait(0.2); // wait 200 ms before sending packet
+        wait(0.2); // normally, you wait 200 ms before sending a TCP packet
     }
-    sendFrame(); // return the TCP packet
-    ppp.seq = ppp.seq + dataLen; // increase OUR sequence by outgoing data length - for the next round
+    sendFrame(); // All done! Send the TCP packet
+    ppp.seq = ppp.seq + dataLen; // increase OUR sequence by the outgoing data length - for the next round
 }
 
 void dumpDataTCP()