aboutsummaryrefslogtreecommitdiffstats
path: root/Projects
diff options
context:
space:
mode:
authorDean Camera <dean@fourwalledcubicle.com>2010-01-31 14:18:03 +0000
committerDean Camera <dean@fourwalledcubicle.com>2010-01-31 14:18:03 +0000
commitbb1a036f097602a70ce219915db28dea616b76a8 (patch)
tree550409f4053fb7bcb4f7cbfebf02d69545447d7a /Projects
parent331e8dece66e632ef3f91b052674948fd74e62a1 (diff)
downloadlufa-bb1a036f097602a70ce219915db28dea616b76a8.tar.gz
lufa-bb1a036f097602a70ce219915db28dea616b76a8.tar.bz2
lufa-bb1a036f097602a70ce219915db28dea616b76a8.zip
Clean up HTTP webserver code in the Webserver project, so that it follows the uIP application structure guidelines and uses cleaner state machine based code.
Diffstat (limited to 'Projects')
-rw-r--r--Projects/Webserver/Lib/DHCPApp.c4
-rw-r--r--Projects/Webserver/Lib/HTTPServerApp.c297
-rw-r--r--Projects/Webserver/Lib/HTTPServerApp.h12
-rw-r--r--Projects/Webserver/Lib/uIPManagement.c2
-rw-r--r--Projects/Webserver/Lib/uip/conf/apps-conf.h13
5 files changed, 189 insertions, 139 deletions
diff --git a/Projects/Webserver/Lib/DHCPApp.c b/Projects/Webserver/Lib/DHCPApp.c
index fe6c6f457..a687586ad 100644
--- a/Projects/Webserver/Lib/DHCPApp.c
+++ b/Projects/Webserver/Lib/DHCPApp.c
@@ -86,7 +86,7 @@ void DHCPApp_Callback(void)
RequiredOptionList);
/* Send the DHCP DISCOVER packet */
- uip_send(AppData, AppDataSize);
+ uip_udp_send(AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
@@ -132,7 +132,7 @@ void DHCPApp_Callback(void)
&AppState->DHCPOffer_Data.ServerIP);
/* Send the DHCP REQUEST packet */
- uip_send(AppData, AppDataSize);
+ uip_udp_send(AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
diff --git a/Projects/Webserver/Lib/HTTPServerApp.c b/Projects/Webserver/Lib/HTTPServerApp.c
index 5f0b2cfcd..7d29272b8 100644
--- a/Projects/Webserver/Lib/HTTPServerApp.c
+++ b/Projects/Webserver/Lib/HTTPServerApp.c
@@ -34,6 +34,7 @@
* this will serve out files to HTTP clients.
*/
+#define INCLUDE_FROM_HTTPSERVERAPP_C
#include "HTTPServerApp.h"
/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
@@ -92,159 +93,199 @@ void WebserverApp_Init(void)
*/
void WebserverApp_Callback(void)
{
- uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
- char* AppData = (char*)uip_appdata;
- uint16_t AppDataSize = 0;
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
if (uip_aborted() || uip_timedout() || uip_closed())
{
- /* Check if the open file needs to be closed */
+ /* Connection is being terminated for some reason - close file handle if open */
if (AppState->FileOpen)
{
f_close(&AppState->FileHandle);
AppState->FileOpen = false;
}
-
- AppState->PrevState = WEBSERVER_STATE_Closed;
- AppState->CurrentState = WEBSERVER_STATE_Closed;
-
- return;
+
+ /* Lock to the closed state so that no further processing will occur on the connection */
+ AppState->CurrentState = WEBSERVER_STATE_Closed;
+ AppState->NextState = WEBSERVER_STATE_Closed;
}
- else if (uip_connected())
+
+ if (uip_connected())
{
/* New connection - initialize connection state values */
- AppState->PrevState = WEBSERVER_STATE_OpenRequestedFile;
- AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;
- AppState->FileOpen = false;
+ AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;
+ AppState->NextState = WEBSERVER_STATE_OpenRequestedFile;
+ AppState->FileOpen = false;
+ AppState->ACKedFilePos = 0;
+ AppState->SentChunkSize = 0;
}
- else if (uip_rexmit())
+
+ if (uip_acked())
{
- /* Re-try last state */
- AppState->CurrentState = AppState->PrevState;
+ /* Add the amount of ACKed file data to the total sent file bytes counter */
+ AppState->ACKedFilePos += AppState->SentChunkSize;
+
+ /* Progress to the next state once the current state's data has been ACKed */
+ AppState->CurrentState = AppState->NextState;
}
-
- switch (AppState->CurrentState)
+
+ if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll())
{
- case WEBSERVER_STATE_OpenRequestedFile:
- /* Wait for the packet containing the request header */
- if (uip_newdata())
- {
- char* RequestToken = strtok(AppData, " ");
-
- /* Must be a GET request, abort otherwise */
- if (strcmp(RequestToken, "GET") != 0)
- {
- uip_abort();
- break;
- }
-
- char* RequestedFileName = strtok(NULL, " ");
-
- /* If the requested filename has more that just the leading '/' path in it, copy it over */
- if (strlen(RequestedFileName) > 1)
- strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));
- else
- strcpy(AppState->FileName, "index.htm");
-
- /* Ensure filename is null-terminated */
- AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;
+ switch (AppState->CurrentState)
+ {
+ case WEBSERVER_STATE_OpenRequestedFile:
+ Webserver_OpenRequestedFile();
+ break;
+ case WEBSERVER_STATE_SendResponseHeader:
+ Webserver_SendResponseHeader();
+ break;
+ case WEBSERVER_STATE_SendMIMETypeHeader:
+ Webserver_SendMIMETypeHeader();
+ break;
+ case WEBSERVER_STATE_SendData:
+ Webserver_SendData();
+ break;
+ case WEBSERVER_STATE_Closing:
+ uip_close();
- /* Try to open the file from the Dataflash disk */
- AppState->FileOpen = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);
- AppState->CurrentFilePos = 0;
-
- AppState->PrevState = WEBSERVER_STATE_OpenRequestedFile;
- AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;
- }
+ AppState->NextState = WEBSERVER_STATE_Closed;
+ break;
+ }
+ }
+}
- break;
- case WEBSERVER_STATE_SendResponseHeader:
- /* Determine what HTTP header should be sent to the client */
- if (AppState->FileOpen)
- {
- AppDataSize = strlen_P(HTTP200Header);
- strncpy_P(AppData, HTTP200Header, AppDataSize);
- }
- else
- {
- AppDataSize = strlen_P(HTTP404Header);
- strncpy_P(AppData, HTTP404Header, AppDataSize);
- }
+/** HTTP Server State handler for the Request Process state. This state manages the processing of incomming HTTP
+ * GET requests to the server from the receiving HTTP client.
+ */
+static void Webserver_OpenRequestedFile(void)
+{
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
+ char* AppData = (char*)uip_appdata;
+
+ /* No HTTP header received from the client, abort processing */
+ if (!(uip_newdata()))
+ return;
+
+ char* RequestToken = strtok(AppData, " ");
- AppState->PrevState = WEBSERVER_STATE_SendResponseHeader;
- AppState->CurrentState = WEBSERVER_STATE_SendMIMETypeHeader;
- break;
- case WEBSERVER_STATE_SendMIMETypeHeader:
- /* File must have been found and opened for MIME header to be sent */
- if (AppState->FileOpen)
- {
- char* Extension = strpbrk(AppState->FileName, ".");
-
- /* Check to see if a file extension was found for the requested filename */
- if (Extension != NULL)
- {
- /* Look through the MIME type list, copy over the required MIME type if found */
- for (int i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++)
- {
- if (strcmp_P(&Extension[1], MIMETypes[i].Extension) == 0)
- {
- AppDataSize = strlen_P(MIMETypes[i].MIMEType);
- strncpy_P(AppData, MIMETypes[i].MIMEType, AppDataSize);
- break;
- }
- }
- }
-
- /* Check if a MIME type was found and copied to the output buffer */
- if (!(AppDataSize))
- {
- /* MIME type not found - copy over the default MIME type */
- AppDataSize = strlen_P(DefaultMIMEType);
- strncpy_P(AppData, DefaultMIMEType, AppDataSize);
- }
-
- /* Add the end-of line terminator and end-of-headers terminator after the MIME type */
- strncpy(&AppData[AppDataSize], "\r\n\r\n", sizeof("\r\n\r\n"));
- AppDataSize += (sizeof("\r\n\r\n") - 1);
- }
-
- AppState->PrevState = WEBSERVER_STATE_SendMIMETypeHeader;
- AppState->CurrentState = WEBSERVER_STATE_SendData;
- break;
- case WEBSERVER_STATE_SendData:
- /* If end of file/file not open, progress to the close state */
- if (!(AppState->FileOpen) && !(uip_rexmit()))
- {
- f_close(&AppState->FileHandle);
- uip_close();
+ /* Must be a GET request, abort otherwise */
+ if (strcmp(RequestToken, "GET") != 0)
+ {
+ uip_abort();
+ return;
+ }
- AppState->PrevState = WEBSERVER_STATE_Closed;
- AppState->CurrentState = WEBSERVER_STATE_Closed;
- break;
- }
+ char* RequestedFileName = strtok(NULL, " ");
+
+ /* If the requested filename has more that just the leading '/' path in it, copy it over */
+ if (strlen(RequestedFileName) > 1)
+ strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));
+ else
+ strcpy(AppState->FileName, "index.htm");
- uint16_t MaxSegSize = uip_mss();
-
- /* Return file pointer to the last ACKed position */
- f_lseek(&AppState->FileHandle, AppState->CurrentFilePos);
+ /* Ensure filename is null-terminated */
+ AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;
+
+ /* Try to open the file from the Dataflash disk */
+ AppState->FileOpen = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);
+
+ /* Lock to the SendResponseHeader state until connection terminated */
+ AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;
+ AppState->NextState = WEBSERVER_STATE_SendResponseHeader;
+}
+
+/** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of
+ * the HTTP response header to the receiving HTTP client.
+ */
+static void Webserver_SendResponseHeader(void)
+{
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
+ char* AppData = (char*)uip_appdata;
+
+ char* HeaderToSend;
+ uint16_t HeaderLength;
+
+ /* Determine what HTTP header should be sent to the client */
+ if (AppState->FileOpen)
+ {
+ HeaderToSend = HTTP200Header;
+ AppState->NextState = WEBSERVER_STATE_SendMIMETypeHeader;
+ }
+ else
+ {
+ HeaderToSend = HTTP404Header;
+ AppState->NextState = WEBSERVER_STATE_Closing;
+ }
+
+ HeaderLength = strlen_P(HeaderToSend);
+ strncpy_P(AppData, HeaderToSend, HeaderLength);
+ uip_send(AppData, HeaderLength);
+}
+
+/** HTTP Server State handler for the MIME Header Send state. This state manages the transmission of the file
+ * MIME type header for the requested file to the receiving HTTP client.
+ */
+static void Webserver_SendMIMETypeHeader(void)
+{
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
+ char* AppData = (char*)uip_appdata;
- /* Read the next chunk of data from the open file */
- f_read(&AppState->FileHandle, AppData, MaxSegSize, &AppDataSize);
+ char* Extension = strpbrk(AppState->FileName, ".");
+ uint16_t MIMEHeaderLength = 0;
- /* If we are not re-transmitting a lost segment, advance file position */
- if (uip_acked() && !(uip_rexmit()))
+ /* Check to see if a file extension was found for the requested filename */
+ if (Extension != NULL)
+ {
+ /* Look through the MIME type list, copy over the required MIME type if found */
+ for (int i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++)
+ {
+ if (strcmp_P(&Extension[1], MIMETypes[i].Extension) == 0)
{
- AppState->FileOpen = (AppDataSize > 0);
- AppState->CurrentFilePos += AppDataSize;
+ MIMEHeaderLength = strlen_P(MIMETypes[i].MIMEType);
+ strncpy_P(AppData, MIMETypes[i].MIMEType, MIMEHeaderLength);
+ break;
}
-
- /* Stay in the SendData state if retransmission is required until all data sent */
- AppState->PrevState = WEBSERVER_STATE_SendData;
+ }
+ }
- break;
+ /* Check if a MIME type was found and copied to the output buffer */
+ if (!(MIMEHeaderLength))
+ {
+ /* MIME type not found - copy over the default MIME type */
+ MIMEHeaderLength = strlen_P(DefaultMIMEType);
+ strncpy_P(AppData, DefaultMIMEType, MIMEHeaderLength);
}
+
+ /* Add the end-of line terminator and end-of-headers terminator after the MIME type */
+ strncpy(&AppData[MIMEHeaderLength], "\r\n\r\n", sizeof("\r\n\r\n"));
+ MIMEHeaderLength += (sizeof("\r\n\r\n") - 1);
+
+ /* Send the MIME header to the receiving client */
+ uip_send(AppData, MIMEHeaderLength);
+
+ /* When the MIME header is ACKed, progress to the data send stage */
+ AppState->NextState = WEBSERVER_STATE_SendData;
+}
- /* If data has been loaded into the application buffer by the server, send it to the client */
- if (AppDataSize)
- uip_send(AppData, AppDataSize);
+/** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks
+ * to the receiving HTTP client.
+ */
+static void Webserver_SendData(void)
+{
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
+ char* AppData = (char*)uip_appdata;
+
+ /* Must determine the maximum segment size to determine maximum file chunk size */
+ uint16_t MaxSegmentSize = uip_mss();
+
+ /* Return file pointer to the last ACKed position */
+ f_lseek(&AppState->FileHandle, AppState->ACKedFilePos);
+
+ /* Read the next chunk of data from the open file */
+ f_read(&AppState->FileHandle, AppData, MaxSegmentSize, &AppState->SentChunkSize);
+
+ /* Send the next file chunk to the receiving client */
+ uip_send(AppData, AppState->SentChunkSize);
+
+ /* Check if we are at the last chunk of the file, if so next ACK should close the connection */
+ AppState->NextState = (MaxSegmentSize != AppState->SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData;
}
diff --git a/Projects/Webserver/Lib/HTTPServerApp.h b/Projects/Webserver/Lib/HTTPServerApp.h
index 1ab64b323..91956ce07 100644
--- a/Projects/Webserver/Lib/HTTPServerApp.h
+++ b/Projects/Webserver/Lib/HTTPServerApp.h
@@ -50,8 +50,9 @@
WEBSERVER_STATE_OpenRequestedFile, /** Currently opening requested file */
WEBSERVER_STATE_SendResponseHeader, /**< Currently sending HTTP response headers to the client */
WEBSERVER_STATE_SendMIMETypeHeader, /**< Currently sending HTTP MIME type header to the client */
- WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */
- WEBSERVER_STATE_Closed, /**< Connection closed after all data sent */
+ WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */
+ WEBSERVER_STATE_Closing, /**< Ready to close the connection to the client */
+ WEBSERVER_STATE_Closed, /**< Connection closed after all data sent */
};
/* Type Defines: */
@@ -70,4 +71,11 @@
void WebserverApp_Init(void);
void WebserverApp_Callback(void);
+ #if defined(INCLUDE_FROM_HTTPSERVERAPP_C)
+ static void Webserver_OpenRequestedFile(void);
+ static void Webserver_SendResponseHeader(void);
+ static void Webserver_SendMIMETypeHeader(void);
+ static void Webserver_SendData(void);
+ #endif
+
#endif
diff --git a/Projects/Webserver/Lib/uIPManagement.c b/Projects/Webserver/Lib/uIPManagement.c
index c816dea6c..44da609dd 100644
--- a/Projects/Webserver/Lib/uIPManagement.c
+++ b/Projects/Webserver/Lib/uIPManagement.c
@@ -52,7 +52,7 @@ void uIPManagement_Init(void)
{
/* uIP Timing Initialization */
clock_init();
- timer_set(&ConnectionTimer, CLOCK_SECOND / 2);
+ timer_set(&ConnectionTimer, CLOCK_SECOND / 10);
timer_set(&ARPTimer, CLOCK_SECOND * 10);
/* uIP Stack Initialization */
diff --git a/Projects/Webserver/Lib/uip/conf/apps-conf.h b/Projects/Webserver/Lib/uip/conf/apps-conf.h
index 540fc33a8..0060f1f4c 100644
--- a/Projects/Webserver/Lib/uip/conf/apps-conf.h
+++ b/Projects/Webserver/Lib/uip/conf/apps-conf.h
@@ -5,13 +5,14 @@
typedef struct
{
- uint8_t PrevState;
- uint8_t CurrentState;
+ uint8_t CurrentState;
+ uint8_t NextState;
- FIL FileHandle;
- char FileName[50];
- bool FileOpen;
- uint32_t CurrentFilePos;
+ char FileName[30];
+ FIL FileHandle;
+ bool FileOpen;
+ uint32_t ACKedFilePos;
+ uint16_t SentChunkSize;
} uip_tcp_appstate_t;
typedef struct