Clean up HTTP webserver code in the Webserver project, so that it follows the uIP...
authorDean Camera <dean@fourwalledcubicle.com>
Sun, 31 Jan 2010 14:18:03 +0000 (14:18 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Sun, 31 Jan 2010 14:18:03 +0000 (14:18 +0000)
Projects/Webserver/Lib/DHCPApp.c
Projects/Webserver/Lib/HTTPServerApp.c
Projects/Webserver/Lib/HTTPServerApp.h
Projects/Webserver/Lib/uIPManagement.c
Projects/Webserver/Lib/uip/conf/apps-conf.h

index fe6c6f4..a687586 100644 (file)
@@ -86,7 +86,7 @@ void DHCPApp_Callback(void)
                                                         RequiredOptionList);                   \r
                        \r
                        /* Send the DHCP DISCOVER packet */\r
-                       uip_send(AppData, AppDataSize);\r
+                       uip_udp_send(AppDataSize);\r
 \r
                        /* Reset the timeout timer, progress to next state */\r
                        timer_reset(&DHCPTimer);\r
@@ -132,7 +132,7 @@ void DHCPApp_Callback(void)
                                                         &AppState->DHCPOffer_Data.ServerIP);\r
 \r
                        /* Send the DHCP REQUEST packet */\r
-                       uip_send(AppData, AppDataSize);\r
+                       uip_udp_send(AppDataSize);\r
                        \r
                        /* Reset the timeout timer, progress to next state */\r
                        timer_reset(&DHCPTimer);\r
index 5f0b2cf..7d29272 100644 (file)
@@ -34,6 +34,7 @@
  *  this will serve out files to HTTP clients.\r
  */\r
  \r
+#define  INCLUDE_FROM_HTTPSERVERAPP_C\r
 #include "HTTPServerApp.h"\r
 \r
 /** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the\r
@@ -92,159 +93,199 @@ void WebserverApp_Init(void)
  */\r
 void WebserverApp_Callback(void)\r
 {\r
-       uip_tcp_appstate_t* const AppState    = &uip_conn->appstate;\r
-       char*                     AppData     = (char*)uip_appdata;\r
-       uint16_t                  AppDataSize = 0;\r
+       uip_tcp_appstate_t* const AppState = &uip_conn->appstate;\r
 \r
        if (uip_aborted() || uip_timedout() || uip_closed())\r
        {\r
-               /* Check if the open file needs to be closed */\r
+               /* Connection is being terminated for some reason - close file handle if open */\r
                if (AppState->FileOpen)\r
                {\r
                        f_close(&AppState->FileHandle);\r
                        AppState->FileOpen = false;\r
                }\r
-\r
-               AppState->PrevState    = WEBSERVER_STATE_Closed;\r
-               AppState->CurrentState = WEBSERVER_STATE_Closed;\r
-\r
-               return;\r
+               \r
+               /* Lock to the closed state so that no further processing will occur on the connection */\r
+               AppState->CurrentState  = WEBSERVER_STATE_Closed;\r
+               AppState->NextState     = WEBSERVER_STATE_Closed;\r
        }\r
-       else if (uip_connected())\r
+\r
+       if (uip_connected())\r
        {\r
                /* New connection - initialize connection state values */\r
-               AppState->PrevState    = WEBSERVER_STATE_OpenRequestedFile;\r
-               AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;\r
-               AppState->FileOpen     = false;\r
+               AppState->CurrentState  = WEBSERVER_STATE_OpenRequestedFile;\r
+               AppState->NextState     = WEBSERVER_STATE_OpenRequestedFile;\r
+               AppState->FileOpen      = false;\r
+               AppState->ACKedFilePos  = 0;\r
+               AppState->SentChunkSize = 0;\r
        }\r
-       else if (uip_rexmit())\r
+\r
+       if (uip_acked())\r
        {\r
-               /* Re-try last state */\r
-               AppState->CurrentState = AppState->PrevState;\r
+               /* Add the amount of ACKed file data to the total sent file bytes counter */\r
+               AppState->ACKedFilePos += AppState->SentChunkSize;\r
+\r
+               /* Progress to the next state once the current state's data has been ACKed */\r
+               AppState->CurrentState = AppState->NextState;\r
        }\r
-       \r
-       switch (AppState->CurrentState)\r
+\r
+       if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll())\r
        {\r
-               case WEBSERVER_STATE_OpenRequestedFile:\r
-                       /* Wait for the packet containing the request header */\r
-                       if (uip_newdata())\r
-                       {\r
-                               char* RequestToken = strtok(AppData, " ");\r
-                       \r
-                               /* Must be a GET request, abort otherwise */\r
-                               if (strcmp(RequestToken, "GET") != 0)\r
-                               {\r
-                                       uip_abort();\r
-                                       break;\r
-                               }\r
-               \r
-                               char* RequestedFileName = strtok(NULL, " ");\r
-                               \r
-                               /* If the requested filename has more that just the leading '/' path in it, copy it over */\r
-                               if (strlen(RequestedFileName) > 1)\r
-                                 strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));\r
-                               else\r
-                                 strcpy(AppState->FileName, "index.htm");\r
-\r
-                               /* Ensure filename is null-terminated */\r
-                               AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;\r
+               switch (AppState->CurrentState)\r
+               {\r
+                       case WEBSERVER_STATE_OpenRequestedFile:\r
+                               Webserver_OpenRequestedFile();\r
+                               break;\r
+                       case WEBSERVER_STATE_SendResponseHeader:\r
+                               Webserver_SendResponseHeader();\r
+                               break;\r
+                       case WEBSERVER_STATE_SendMIMETypeHeader:\r
+                               Webserver_SendMIMETypeHeader(); \r
+                               break;\r
+                       case WEBSERVER_STATE_SendData:\r
+                               Webserver_SendData();\r
+                               break;\r
+                       case WEBSERVER_STATE_Closing:\r
+                               uip_close();\r
                                \r
-                               /* Try to open the file from the Dataflash disk */\r
-                               AppState->FileOpen       = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);\r
-                               AppState->CurrentFilePos = 0;\r
-\r
-                               AppState->PrevState    = WEBSERVER_STATE_OpenRequestedFile;\r
-                               AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;\r
-                       }\r
+                               AppState->NextState = WEBSERVER_STATE_Closed;\r
+                               break;\r
+               }                 \r
+       }               \r
+}\r
 \r
-                       break;\r
-               case WEBSERVER_STATE_SendResponseHeader:\r
                      /* Determine what HTTP header should be sent to the client */\r
-                       if (AppState->FileOpen)\r
-                       {\r
-                               AppDataSize = strlen_P(HTTP200Header);\r
-                               strncpy_P(AppData, HTTP200Header, AppDataSize);\r
-                       }\r
-                       else\r
-                       {\r
-                               AppDataSize = strlen_P(HTTP404Header);\r
-                               strncpy_P(AppData, HTTP404Header, AppDataSize);\r
-                       }\r
+/** HTTP Server State handler for the Request Process state. This state manages the processing of incomming HTTP\r
+ *  GET requests to the server from the receiving HTTP client.\r
+ */\r
+static void Webserver_OpenRequestedFile(void)\r
+{\r
+       uip_tcp_appstate_t* const AppState    = &uip_conn->appstate;\r
+       char*                     AppData     = (char*)uip_appdata;\r
+       \r
+       /* No HTTP header received from the client, abort processing */\r
+       if (!(uip_newdata()))\r
+         return;\r
+         \r
+       char* RequestToken = strtok(AppData, " ");\r
                        \r
-                       AppState->PrevState    = WEBSERVER_STATE_SendResponseHeader;\r
-                       AppState->CurrentState = WEBSERVER_STATE_SendMIMETypeHeader;\r
-                       break;\r
-               case WEBSERVER_STATE_SendMIMETypeHeader:\r
-                       /* File must have been found and opened for MIME header to be sent */\r
-                       if (AppState->FileOpen)\r
-                       {\r
-                               char* Extension = strpbrk(AppState->FileName, ".");\r
-                               \r
-                               /* Check to see if a file extension was found for the requested filename */\r
-                               if (Extension != NULL)\r
-                               {\r
-                                       /* Look through the MIME type list, copy over the required MIME type if found */\r
-                                       for (int i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++)\r
-                                       {\r
-                                               if (strcmp_P(&Extension[1], MIMETypes[i].Extension) == 0)\r
-                                               {\r
-                                                       AppDataSize = strlen_P(MIMETypes[i].MIMEType);\r
-                                                       strncpy_P(AppData, MIMETypes[i].MIMEType, AppDataSize);                                         \r
-                                                       break;\r
-                                               }\r
-                                       } \r
-                               }\r
-\r
-                               /* Check if a MIME type was found and copied to the output buffer */\r
-                               if (!(AppDataSize))\r
-                               {\r
-                                       /* MIME type not found - copy over the default MIME type */\r
-                                       AppDataSize = strlen_P(DefaultMIMEType);\r
-                                       strncpy_P(AppData, DefaultMIMEType, AppDataSize);                               \r
-                               }\r
-                               \r
-                               /* Add the end-of line terminator and end-of-headers terminator after the MIME type */\r
-                               strncpy(&AppData[AppDataSize], "\r\n\r\n", sizeof("\r\n\r\n"));\r
-                               AppDataSize += (sizeof("\r\n\r\n") - 1);\r
-                       }\r
-                               \r
-                       AppState->PrevState    = WEBSERVER_STATE_SendMIMETypeHeader;\r
-                       AppState->CurrentState = WEBSERVER_STATE_SendData;                              \r
-                       break;\r
-               case WEBSERVER_STATE_SendData:\r
-                       /* If end of file/file not open, progress to the close state */\r
-                       if (!(AppState->FileOpen) && !(uip_rexmit()))\r
-                       {\r
-                               f_close(&AppState->FileHandle);\r
-                               uip_close();\r
+       /* Must be a GET request, abort otherwise */\r
+       if (strcmp(RequestToken, "GET") != 0)\r
+       {\r
+               uip_abort();\r
+               return;\r
+       }\r
 \r
-                               AppState->PrevState    = WEBSERVER_STATE_Closed;\r
-                               AppState->CurrentState = WEBSERVER_STATE_Closed;\r
-                               break;\r
-                       }\r
+       char* RequestedFileName = strtok(NULL, " ");\r
+       \r
+       /* If the requested filename has more that just the leading '/' path in it, copy it over */\r
+       if (strlen(RequestedFileName) > 1)\r
+         strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));\r
+       else\r
+         strcpy(AppState->FileName, "index.htm");\r
 \r
-                       uint16_t MaxSegSize = uip_mss();\r
-                       \r
-                       /* Return file pointer to the last ACKed position */\r
-                       f_lseek(&AppState->FileHandle, AppState->CurrentFilePos);\r
+       /* Ensure filename is null-terminated */\r
+       AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;\r
+       \r
+       /* Try to open the file from the Dataflash disk */\r
+       AppState->FileOpen     = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);\r
+\r
+       /* Lock to the SendResponseHeader state until connection terminated */\r
+       AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;\r
+       AppState->NextState    = WEBSERVER_STATE_SendResponseHeader;\r
+}\r
+\r
+/** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of\r
+ *  the HTTP response header to the receiving HTTP client.\r
+ */\r
+static void Webserver_SendResponseHeader(void)\r
+{\r
+       uip_tcp_appstate_t* const AppState    = &uip_conn->appstate;\r
+       char*                     AppData     = (char*)uip_appdata;\r
+\r
+       char*    HeaderToSend;\r
+       uint16_t HeaderLength;\r
+\r
+       /* Determine what HTTP header should be sent to the client */\r
+       if (AppState->FileOpen)\r
+       {\r
+               HeaderToSend = HTTP200Header;\r
+               AppState->NextState = WEBSERVER_STATE_SendMIMETypeHeader;\r
+       }\r
+       else\r
+       {\r
+               HeaderToSend = HTTP404Header;\r
+               AppState->NextState = WEBSERVER_STATE_Closing;\r
+       }\r
+\r
+       HeaderLength = strlen_P(HeaderToSend);\r
+       strncpy_P(AppData, HeaderToSend, HeaderLength);\r
+       uip_send(AppData, HeaderLength);\r
+}\r
+\r
+/** HTTP Server State handler for the MIME Header Send state. This state manages the transmission of the file\r
+ *  MIME type header for the requested file to the receiving HTTP client.\r
+ */\r
+static void Webserver_SendMIMETypeHeader(void)\r
+{\r
+       uip_tcp_appstate_t* const AppState    = &uip_conn->appstate;\r
+       char*                     AppData     = (char*)uip_appdata;\r
 \r
-                       /* Read the next chunk of data from the open file */\r
-                       f_read(&AppState->FileHandle, AppData, MaxSegSize, &AppDataSize);\r
+       char*    Extension        = strpbrk(AppState->FileName, ".");\r
+       uint16_t MIMEHeaderLength = 0;\r
 \r
-                       /* If we are not re-transmitting a lost segment, advance file position */\r
-                       if (uip_acked() && !(uip_rexmit()))\r
+       /* Check to see if a file extension was found for the requested filename */\r
+       if (Extension != NULL)\r
+       {\r
+               /* Look through the MIME type list, copy over the required MIME type if found */\r
+               for (int i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++)\r
+               {\r
+                       if (strcmp_P(&Extension[1], MIMETypes[i].Extension) == 0)\r
                        {\r
-                               AppState->FileOpen = (AppDataSize > 0);\r
-                               AppState->CurrentFilePos += AppDataSize;\r
+                               MIMEHeaderLength = strlen_P(MIMETypes[i].MIMEType);\r
+                               strncpy_P(AppData, MIMETypes[i].MIMEType, MIMEHeaderLength);                                            \r
+                               break;\r
                        }\r
-                       \r
-                       /* Stay in the SendData state if retransmission is required until all data sent */\r
-                       AppState->PrevState = WEBSERVER_STATE_SendData;\r
+               } \r
+       }\r
 \r
-                       break;\r
+       /* Check if a MIME type was found and copied to the output buffer */\r
+       if (!(MIMEHeaderLength))\r
+       {\r
+               /* MIME type not found - copy over the default MIME type */\r
+               MIMEHeaderLength = strlen_P(DefaultMIMEType);\r
+               strncpy_P(AppData, DefaultMIMEType, MIMEHeaderLength);\r
        }\r
+       \r
+       /* Add the end-of line terminator and end-of-headers terminator after the MIME type */\r
+       strncpy(&AppData[MIMEHeaderLength], "\r\n\r\n", sizeof("\r\n\r\n"));\r
+       MIMEHeaderLength += (sizeof("\r\n\r\n") - 1);\r
+       \r
+       /* Send the MIME header to the receiving client */\r
+       uip_send(AppData, MIMEHeaderLength);\r
+       \r
+       /* When the MIME header is ACKed, progress to the data send stage */\r
+       AppState->NextState = WEBSERVER_STATE_SendData;\r
+}\r
 \r
-       /* If data has been loaded into the application buffer by the server, send it to the client */\r
-       if (AppDataSize)\r
-         uip_send(AppData, AppDataSize);\r
+/** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks\r
+ *  to the receiving HTTP client.\r
+ */\r
+static void Webserver_SendData(void)\r
+{\r
+       uip_tcp_appstate_t* const AppState    = &uip_conn->appstate;\r
+       char*                     AppData     = (char*)uip_appdata;\r
+\r
+       /* Must determine the maximum segment size to determine maximum file chunk size */\r
+       uint16_t MaxSegmentSize = uip_mss();\r
+\r
+       /* Return file pointer to the last ACKed position */\r
+       f_lseek(&AppState->FileHandle, AppState->ACKedFilePos);\r
+       \r
+       /* Read the next chunk of data from the open file */\r
+       f_read(&AppState->FileHandle, AppData, MaxSegmentSize, &AppState->SentChunkSize);\r
+       \r
+       /* Send the next file chunk to the receiving client */\r
+       uip_send(AppData, AppState->SentChunkSize);\r
+                       \r
+       /* Check if we are at the last chunk of the file, if so next ACK should close the connection */\r
+       AppState->NextState = (MaxSegmentSize != AppState->SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData;\r
 }\r
index 1ab64b3..91956ce 100644 (file)
@@ -50,8 +50,9 @@
                        WEBSERVER_STATE_OpenRequestedFile, /** Currently opening requested file */\r
                        WEBSERVER_STATE_SendResponseHeader, /**< Currently sending HTTP response headers to the client */\r
                        WEBSERVER_STATE_SendMIMETypeHeader, /**< Currently sending HTTP MIME type header to the client */\r
-                       WEBSERVER_STATE_SendData,    /**< Currently sending HTTP page data to the client */\r
-                       WEBSERVER_STATE_Closed,      /**< Connection closed after all data sent */\r
+                       WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */\r
+                       WEBSERVER_STATE_Closing, /**< Ready to close the connection to the client */\r
+                       WEBSERVER_STATE_Closed, /**< Connection closed after all data sent */\r
                };\r
                \r
        /* Type Defines: */\r
                void WebserverApp_Init(void);\r
                void WebserverApp_Callback(void);\r
                \r
+               #if defined(INCLUDE_FROM_HTTPSERVERAPP_C)\r
+                       static void Webserver_OpenRequestedFile(void);\r
+                       static void Webserver_SendResponseHeader(void);\r
+                       static void Webserver_SendMIMETypeHeader(void);\r
+                       static void Webserver_SendData(void);\r
+               #endif\r
+               \r
 #endif\r
index c816dea..44da609 100644 (file)
@@ -52,7 +52,7 @@ void uIPManagement_Init(void)
 {\r
        /* uIP Timing Initialization */\r
        clock_init();\r
-       timer_set(&ConnectionTimer, CLOCK_SECOND / 2);\r
+       timer_set(&ConnectionTimer, CLOCK_SECOND / 10);\r
        timer_set(&ARPTimer, CLOCK_SECOND * 10);        \r
 \r
        /* uIP Stack Initialization */\r
index 540fc33..0060f1f 100644 (file)
@@ -5,13 +5,14 @@
 \r
        typedef struct\r
        {\r
-               uint8_t PrevState;\r
-               uint8_t CurrentState;\r
+               uint8_t  CurrentState;\r
+               uint8_t  NextState;\r
                \r
-               FIL     FileHandle;\r
-               char    FileName[50];\r
-               bool    FileOpen;\r
-               uint32_t CurrentFilePos;\r
+               char     FileName[30];\r
+               FIL      FileHandle;\r
+               bool     FileOpen;\r
+               uint32_t ACKedFilePos;\r
+               uint16_t SentChunkSize;\r
        } uip_tcp_appstate_t;\r
 \r
        typedef struct\r