Moved initial completed version of the Webserver project out of the Projects/Incomple...
[pub/lufa.git] / Projects / Webserver / Lib / WebserverApp.c
diff --git a/Projects/Webserver/Lib/WebserverApp.c b/Projects/Webserver/Lib/WebserverApp.c
new file mode 100644 (file)
index 0000000..6ac94d6
--- /dev/null
@@ -0,0 +1,143 @@
+/*\r
+             LUFA Library\r
+     Copyright (C) Dean Camera, 2010.\r
+              \r
+  dean [at] fourwalledcubicle [dot] com\r
+      www.fourwalledcubicle.com\r
+*/\r
+\r
+/*\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+\r
+  Permission to use, copy, modify, distribute, and sell this \r
+  software and its documentation for any purpose is hereby granted\r
+  without fee, provided that the above copyright notice appear in \r
+  all copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting \r
+  documentation, and that the name of the author not be used in \r
+  advertising or publicity pertaining to distribution of the \r
+  software without specific, written prior permission.\r
+\r
+  The author disclaim all warranties with regard to this\r
+  software, including all implied warranties of merchantability\r
+  and fitness.  In no event shall the author be liable for any\r
+  special, indirect or consequential damages or any damages\r
+  whatsoever resulting from loss of use, data or profits, whether\r
+  in an action of contract, negligence or other tortious action,\r
+  arising out of or in connection with the use or performance of\r
+  this software.\r
+*/\r
+\r
+/** \file\r
+ *\r
+ *  Simple HTTP Webserver Application. When connected to the uIP stack,\r
+ *  this will serve out files to HTTP clients.\r
+ */\r
\r
+#include "WebserverApp.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
+ *  given location, and gives extra connection information.\r
+ */\r
+char PROGMEM HTTP200Header[] = "HTTP/1.1 200 OK\r\n"\r
+                               "Server: LUFA RNDIS\r\n"\r
+                               "Content-type: text/html\r\n"\r
+                               "Connection: close\r\n\r\n";\r
+\r
+/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given\r
+ *  given URL is invalid, and gives extra error information.\r
+ */\r
+char PROGMEM HTTP404Header[] = "HTTP/1.1 404 Not Found\r\n"\r
+                               "Server: LUFA RNDIS\r\n"\r
+                               "Connection: close\r\n\r\n";\r
+\r
+/** HTTP page to serve to the host when a HTTP request is made. This page is too long for a single response, thus it is automatically\r
+ *  broken up into smaller blocks and sent as a series of packets each time the webserver application callback is run.\r
+ */\r
+char PROGMEM HTTPPage[]   = \r
+               "<html>"\r
+               "       <head>"\r
+               "               <title>"\r
+               "                       LUFA Webserver Demo"\r
+               "               </title>"\r
+               "       </head>"\r
+               "       <body>"\r
+               "               <h1>Hello from your USB AVR!</h1>"\r
+               "               <p>"\r
+               "                       Hello! Welcome to the LUFA RNDIS Demo Webserver test page, running on your USB AVR via the LUFA library and uIP TCP/IP network stack. This"\r
+               "           demonstrates a simple HTTP webserver serving out pages to HTTP clients."\r
+               "                       <br /><br />"\r
+               "                       <small>Project Information: <a href=\"http://www.fourwalledcubicle.com/LUFA.php\">http://www.fourwalledcubicle.com/LUFA.php</a>.</small>"\r
+               "                       <hr />"\r
+               "                       <i>LUFA Version: </i>" LUFA_VERSION_STRING\r
+               "               </p>"\r
+               "       </body>"\r
+               "</html>";\r
+\r
+/** Initialization function for the simple HTTP webserver. */\r
+void WebserverApp_Init(void)\r
+{\r
+       /* Listen on port 80 for HTTP connections from hosts */\r
+       uip_listen(HTONS(80));\r
+}\r
+\r
+/** uIP stack application callback for the simple HTTP webserver. This function must be called each time the\r
+ *  TCP/IP stack needs a TCP packet to be processed.\r
+ */\r
+void WebserverApp_Callback(void)\r
+{\r
+       char*    AppDataPtr  = (char*)uip_appdata;\r
+       uint16_t AppDataSize = 0;\r
+\r
+       if (uip_closed() || uip_aborted() || uip_timedout())\r
+       {\r
+               /* Terminated or completed connection - don't send any new data */\r
+               return;\r
+       }\r
+       else if (uip_connected())\r
+       {\r
+               /* New connection - initialize connection state and data pointer to the appropriate HTTP header */\r
+               uip_conn->appstate.SendPos      = HTTP200Header;\r
+               uip_conn->appstate.CurrentState = WEBSERVER_STATE_SendHeaders;\r
+       }\r
+\r
+       /* Calculate the maximum segment size and remaining data size */\r
+       uint16_t BytesRemaining = strlen_P(uip_conn->appstate.SendPos);\r
+       uint16_t MaxSegSize     = uip_mss();\r
+\r
+       /* No more bytes remaining in the current data being sent - progress to next data chunk or\r
+        * terminate the connection once all chunks are sent */\r
+       if (!(BytesRemaining))\r
+       {\r
+               /* Check which data chunk we are currently sending (header or data) */\r
+               if (uip_conn->appstate.CurrentState == WEBSERVER_STATE_SendHeaders)\r
+               {\r
+                       uip_conn->appstate.SendPos = HTTPPage;\r
+                       uip_conn->appstate.CurrentState = WEBSERVER_STATE_SendData;                     \r
+               }\r
+               else if (uip_conn->appstate.CurrentState == WEBSERVER_STATE_SendData)\r
+               {\r
+                       uip_close();\r
+                       uip_conn->appstate.CurrentState = WEBSERVER_STATE_Closed;\r
+               }\r
+                 \r
+               return;\r
+       }\r
+       else if (BytesRemaining > MaxSegSize)\r
+       {\r
+               /* More bytes remaining to send than the maximum segment size, send next chunk */\r
+               AppDataSize = MaxSegSize;\r
+       }\r
+       else\r
+       {\r
+               /* Less bytes than the segment size remaining, send all remaining bytes in the one packet */\r
+               AppDataSize = BytesRemaining;\r
+       }\r
+\r
+       /* Copy over the next data segment to the application buffer, advance send position pointer */\r
+       strncpy_P(uip_appdata, uip_conn->appstate.SendPos, AppDataSize);\r
+       uip_conn->appstate.SendPos += AppDataSize;\r
+\r
+       /* Send the data to the requesting host */\r
+       uip_send(AppDataPtr, AppDataSize);\r
+}\r