Backing up an unused program in case of future need

Dependencies:   mbed

Revision:
1:94282484baae
Parent:
0:09f915e6f9f6
Child:
2:06fa34661f19
--- a/server.cpp	Wed Apr 13 09:21:02 2016 +0000
+++ b/server.cpp	Fri Apr 15 09:03:54 2016 +0000
@@ -4,11 +4,20 @@
 #include  "log.h"
 #include "time.h"
 #include "wifi.h"
-#define BUFFER_SIZE 1024
+#define RECV_BUFFER_SIZE 1024
+#define SEND_BUFFER_SIZE  256
 #define SERVER_PORT 80
 
-static char recvbuffer[BUFFER_SIZE];
-static char sendbuffer[BUFFER_SIZE];
+static char recvbuffer[RECV_BUFFER_SIZE];
+static char sendbuffer[SEND_BUFFER_SIZE];
+
+#define WHAT_NOT_FOUND   0
+#define WHAT_BAD_REQUEST 1
+#define WHAT_BAD_METHOD  2
+#define WHAT_LED         3
+#define WHAT_LOG         4
+static int whatToSendToId[4];
+static int lineToSendToId[4]; //0 == do nothing; -1 == close
 
 void ServerInit(void) //Make sure this is only called after any other ids are reserved.
 {
@@ -17,84 +26,299 @@
         if (!EspIpdReserved[id])
         {
             EspIpdBuffer[id] = recvbuffer;
-            EspIpdBufferLen[id] = BUFFER_SIZE;
+            EspIpdBufferLen[id] = RECV_BUFFER_SIZE;
+        }
+        whatToSendToId[id] = 0;
+        lineToSendToId[id] = 0;
+    }
+}
+
+static int addChunk(int prevlen, char *text)
+{
+    strncpy(sendbuffer + prevlen, text, SEND_BUFFER_SIZE - prevlen);
+    int len = prevlen + strlen(text);
+    return len < SEND_BUFFER_SIZE ? len : SEND_BUFFER_SIZE;
+}
+static int fillChunk(char * text)
+{
+    strncpy(sendbuffer, text, SEND_BUFFER_SIZE);
+    int len = strlen(text);
+    return len < SEND_BUFFER_SIZE ? len : SEND_BUFFER_SIZE;
+}
+static int fillNotFound(int id)
+{
+    int len = fillChunk("HTTP/1.0 404 Not Found\r\n\r\n");
+    lineToSendToId[id] = -1;
+    return len;
+}
+static int fillBadRequest(int id)
+{
+    int len = fillChunk("HTTP/1.0 400 Bad Request\r\n\r\n");
+    lineToSendToId[id] = -1;
+    return len;
+}
+static int fillBadMethod(int id)
+{
+    int len = fillChunk("HTTP/1.0 405 Method Not Allowed\r\nAllow: GET\r\n\r\n");
+    lineToSendToId[id] = -1;
+    return len;
+}
+static int fillLogChunk() //Returns length. If length is less than the buffer size then that was the last chunk to send: that could mean a length of zero.
+{
+    static int enumerationStarted = false;
+    if (!enumerationStarted)
+    {
+        LogEnumerateStart();
+        enumerationStarted = true;
+    }
+    char* p = sendbuffer;
+    while (p < sendbuffer + SEND_BUFFER_SIZE)
+    {
+        int c = LogEnumerate();
+        if (c == EOF)
+        {
+            enumerationStarted = false;
+            break;
         }
+        *p++ = c;
+    }
+    return p - sendbuffer;
+}
+static char* header = 
+            "HTTP/1.0 200 OK\r\n"
+            "Content-Type: text/html; charset=ISO-8859-1\r\n"
+            "\r\n"
+            "<!DOCTYPE html>\r\n"
+            "<html>\r\n"
+            "<head>\r\n"
+            "<title>IoT mbed</title>\r\n"
+            "</head>\r\n"
+            "<body>\r\n";
+
+static int fillLog(int id)
+{
+    int len = 0;
+
+    switch (lineToSendToId[id])
+    {
+        case 1: len = fillChunk(header);                             lineToSendToId[id] += 1; break;
+        case 2: len = fillChunk("<code><pre>");                      lineToSendToId[id] += 1; break;
+        case 3: len = fillLogChunk();    if (len < SEND_BUFFER_SIZE) lineToSendToId[id] += 1; break; //only increments after the last chunk
+        case 4: len = fillChunk(
+            "</pre></code>\r\n"
+            "</body>\r\n"
+            "</html>\r\n");
+            lineToSendToId[id] = -1;
+            break;
+    }
+    return len;
+}
+
+static int fillLed(int id)
+{
+    int len;
+    switch (lineToSendToId[id])
+    {
+        case 1:
+            len = fillChunk(header);
+            lineToSendToId[id] += 1;
+            break;
+        case 2:
+            len = fillChunk(
+            "<form action='/' method='get'>\r\n"
+            "<input type='hidden' name='ledonoff'>\r\n");
+            lineToSendToId[id] += 1;
+            break;
+        case 3:
+            len = fillChunk("Led <input type='checkbox' name='led' value='on'");
+            if (Led1) len = addChunk(len, " checked='checked'");
+            len = addChunk(len, ">\r\n");
+            lineToSendToId[id] +=  1;
+            break;
+        case 4:
+            len = fillChunk(
+            "<input type='submit' value='Set'><br/>\r\n"
+            "</form>\r\n"
+            "</body>\r\n"
+            "</html>\r\n");
+            lineToSendToId[id] = -1;
+            break;
+    }
+    return len;
+}
+static int fillSendBuffer(int id)
+{
+    switch(whatToSendToId[id])
+    {
+        case WHAT_NOT_FOUND:   return fillNotFound(id);
+        case WHAT_BAD_REQUEST: return fillBadRequest(id);
+        case WHAT_BAD_METHOD:  return fillBadMethod(id);
+        case WHAT_LOG:         return fillLog(id);
+        case WHAT_LED:         return fillLed(id);
+        default:
+            LogF("No such 'whatToSendToId' %s", whatToSendToId[id]);
+            return -1;
     }
 }
-int ServerStatus = AT_NONE;
-int ServerMain(void)
+static int splitRequest(char** ppMethod, char** ppPath, char** ppQuery, int *pLenMethod, int *pLenPath, int *pLenQuery) //returns 1 if malformed request; 0 if ok
 {
+    char* p  = recvbuffer;
+    char* pE = recvbuffer + RECV_BUFFER_SIZE;
+    
+    *ppMethod   = NULL;
+    *ppPath     = NULL;
+    *ppQuery    = NULL;
+    *pLenMethod = 0;
+    *pLenPath   = 0;
+    *pLenQuery  = 0;
 
-    if (!AtBusy() && WifiStarted() && ServerStatus != AT_SUCCESS) AtStartServer(SERVER_PORT, &ServerStatus);
-        
-    static int needToSendId = -1;
-    static int needToCloseId  = -1;
+    while (*p == ' ')                   //Loop to non space
+    {
+        if (p == pE)     return -1;
+        if (*p < ' ')    return -1;
+        if (*p >= 0x7f)  return -1;
+        p++;
+    }
+    *ppMethod = p;                      //Record the start of the method GET or POST
+ 
+    while (*p != ' ')                   //Loop to a space
+    {
+        if (p == pE)     return -1;
+        if (*p < ' ')    return -1;
+        if (*p >= 0x7f)  return -1;
+        p++;
+    }
+    *pLenMethod = p - *ppMethod;        //Record the length of the method GET or POST
     
-    if (EspDataAvailable == ESP_AVAILABLE && !EspIpdReserved[EspIpdId])
+
+    while (*p == ' ')         //Loop to non space
+    {
+        if (p == pE)     return -1;
+        if (*p < ' ')    return -1;
+        if (*p >= 0x7f)  return -1;
+        p++;
+    }
+    *ppPath = p;                        //Record the start of the file part of the url
+    
+    while (*p != ' ')                   //Loop to space
+    {
+        if (p == pE)     return -1;
+        if (*p < ' ')    return -1;
+        if (*p >= 0x7f)  return -1;
+        if (*p == '?')  *ppQuery = p + 1;
+        p++;
+    }
+
+    if (*ppQuery)                       //Calulate length of the file and query parts
     {
-        needToSendId = EspIpdId;
-        char method[10];
-        char url[20];
-        char file[20];
-        char query[20];
-        sscanf(recvbuffer, "%s %s ", method, url);
-        sscanf(url, "%[^?]?%s", file, query);
-        if (strcmp(file, "/favicon.ico") == 0)
-            strcpy(sendbuffer, "HTTP/1.0 404 Not Found\r\n\r\n");
-        else if (strcmp(file, "/log") == 0)
+        *pLenPath  = *ppQuery - *ppPath - 1;
+        *pLenQuery = p - *ppQuery;
+    }
+    else
+    {
+        *pLenPath = p - *ppPath;
+        *pLenQuery = 0;
+    }
+    
+    return 0;
+}
+int compare(char* mem, int len, char* str) //Returns true if same and false if not
+{
+    if (strlen(str) != len) return false;
+    if (memcmp(mem, str, len)) return false;
+    return true;
+}
+static int recvMain()
+{
+    //Wait for data to be available oneshot
+    if (EspDataAvailable != ESP_AVAILABLE) return 0;
+    
+    //Ignore ids that have been reserved elsewhere (ie NTP)
+    if (EspIpdReserved[EspIpdId]) return 0;
+    
+    //Set up the next line to send to be the first
+    lineToSendToId[EspIpdId] = 1;
+    
+    char* pMethod;
+    char* pPath;
+    char* pQuery;
+    int lenMethod;
+    int lenQuery;
+    int lenPath;
+    int r = splitRequest(&pMethod, &pPath, &pQuery, &lenMethod, &lenPath, &lenQuery);
+    if (r)
+    {
+        whatToSendToId[EspIpdId] = WHAT_BAD_REQUEST;
+        return 0;
+    }
+
+    if (!compare(pMethod, lenMethod, "GET"))
+    {
+        whatToSendToId[EspIpdId] = WHAT_BAD_METHOD;
+        return 0;
+    }
+    
+    if (compare(pPath, lenPath, "/"))
+    {
+        if (pQuery)
         {
-            strcpy(sendbuffer, "HTTP/1.0 200 OK\r\n");
-            strcat(sendbuffer, "\r\n");
-            strcat(sendbuffer, "<html>\r\n");
-            strcat(sendbuffer, "<body>\r\n");
-            strcat(sendbuffer, "<code><pre>");
-            LogEnumerateStart();
-            char* p = sendbuffer;
-            while(*p) p++; //Move to the end of string
-            while (1)
-            {
-                int c = LogEnumerate();
-                if (c == EOF) break;
-                *p++ = c;
-            }
-            *p = 0; //Add back the end of string
-            strcat(sendbuffer, "</pre></code>");
-            strcat(sendbuffer, "</body>\r\n");
-            strcat(sendbuffer, "</html>\r\n");
+             if (compare(pQuery, lenQuery, "ledonoff=&led=on")) Led1 = 1;
+             if (compare(pQuery, lenQuery, "ledonoff="       )) Led1 = 0;
         }
-        else
+        whatToSendToId[EspIpdId] = WHAT_LED;
+        return 0;
+    }
+    
+    if (compare(pPath, lenPath, "/log"))
+    {
+        whatToSendToId[EspIpdId] = WHAT_LOG;
+        return 0;
+    }
+    
+    whatToSendToId[EspIpdId] = WHAT_NOT_FOUND;
+    return 0;
+}
+static int sendMain()
+{
+    //Do nothing if a command is already in progress
+    if (AtBusy()) return 0;
+    
+    //Send data. Do each id in turn to avoid interleaved calls to fillers like LogEnumerate which are not reentrant.
+    for(int id = 0; id < 4; id++)
+    {
+        if (lineToSendToId[id] > 0)
         {
-            if (strcmp(query, "ledonoff=&led=on") == 0) Led1 = 1;
-            if (strcmp(query, "ledonoff="       ) == 0) Led1 = 0;
-            strcpy(sendbuffer, "HTTP/1.0 200 OK\r\n");
-            strcat(sendbuffer, "\r\n");
-            strcat(sendbuffer, "<html>\r\n");
-            strcat(sendbuffer, "<body>\r\n");
-            strcat(sendbuffer, "<form action='/' method='get'>\r\n");
-            strcat(sendbuffer, "<input type='hidden' name='ledonoff'>\r\n");
-            if (Led1) strcat(sendbuffer, "Led <input type='checkbox' name='led' value='on' checked='checked'>\r\n");
-            else      strcat(sendbuffer, "Led <input type='checkbox' name='led' value='on'>\r\n");
-            strcat(sendbuffer, "<input type='submit' value='Set'><br/>\r\n");
-            strcat(sendbuffer, "</form>\r\n");
-            strcat(sendbuffer, "</body>\r\n");
-            strcat(sendbuffer, "</html>\r\n");
-//            sprintf(sendbuffer, "Received a %s request for %s and query %s\r\n", method, file, query);
+            int length = fillSendBuffer(id);
+            if (length < 0) return -1;
+            if (length > 0) AtSendData(id, length, sendbuffer, NULL);
+        }
+        else if (lineToSendToId[id] < 0)
+        {
+            AtClose(id, NULL);
+            lineToSendToId[id] = 0;
         }
     }
 
-    if (!AtBusy() && needToSendId >= 0)
-    {
-        AtSendData(needToSendId, strlen(sendbuffer), sendbuffer, NULL);
-        needToCloseId = needToSendId;
-        needToSendId = -1;
-    }
+    return 0;
+}
+int startMain()
+{
+    //Do nothing if a command is already in progress
+    if (AtBusy()) return 0;
+    
+    //Do nothing until WiFi is running
+    if (!WifiStarted()) return 0;
     
-    if (!AtBusy() && needToCloseId >= 0)
-    {
-        AtClose(needToCloseId, NULL);
-        needToCloseId = -1;
-    }
-    
+    //Start the server if not started
+    static int startServerReply = AT_NONE;
+    if (startServerReply != AT_SUCCESS) AtStartServer(SERVER_PORT, &startServerReply);
+    return 0;
+}
+int ServerMain()
+{
+    if (startMain()) return -1;
+    if ( recvMain()) return -1;
+    if ( sendMain()) return -1;
     
     return 0;
 }
\ No newline at end of file