MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

webserver.c

Go to the documentation of this file.
00001 /*********************************************************************************
00002 
00003  Copyright 2006-2008 MakingThings
00004 
00005  Licensed under the Apache License, 
00006  Version 2.0 (the "License"); you may not use this file except in compliance 
00007  with the License. You may obtain a copy of the License at
00008 
00009  http://www.apache.org/licenses/LICENSE-2.0 
00010  
00011  Unless required by applicable law or agreed to in writing, software distributed
00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
00014  the specific language governing permissions and limitations under the License.
00015 
00016 *********************************************************************************/
00017 
00018 
00019 /** \file webserver.c 
00020   Functions for implementing a WebServer on the Make Controller Board.
00021 */
00022 
00023 #include "config.h" // MakingThings.
00024 #ifdef MAKE_CTRL_NETWORK
00025 
00026 /* Standard includes. */
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031 
00032 #include "network.h"
00033 
00034 #define HANDLERS_MAX        5
00035 #define REQUEST_SIZE_MAX  256
00036 #define RESPONSE_SIZE_MAX 1000
00037 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: "
00038 #define HTTP_CONTENT_HTML "text/html\r\n\r\n"
00039 #define HTTP_CONTENT_PLAIN "text/plain\r\n\r\n"
00040 #define HTTP_PORT   ( 80 )
00041 
00042 #define HTML_OS_START \
00043 "<BR>Make Magazine - MakingThings<BR><H1>MAKE Controller Kit</H1>"
00044 
00045 void WebServerTask( void *p );
00046 
00047 typedef struct WebServerHandlerS
00048 {
00049   char* address;
00050   int (*handler)( char* requestType, char* address,  char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len ); 
00051 } WebServerHandler;
00052 
00053 typedef struct WebServerHandlersS
00054 {
00055   int count;
00056   WebServerHandler handlers[ HANDLERS_MAX ];
00057 } WebServerHandlers_;
00058 
00059 WebServerHandlers_* WebServerHandlers = NULL;
00060 
00061 typedef struct WebServerS
00062 {
00063   int hits;
00064   void* serverTask;
00065   void *serverSocket;
00066   void *requestSocket;
00067   int listenPort;
00068   bool changeListenPort;
00069   char request[ REQUEST_SIZE_MAX ];
00070   char response[ RESPONSE_SIZE_MAX ];
00071 } WebServer_;
00072 
00073 WebServer_* WebServer = NULL;
00074 
00075 #include "webserver.h"
00076 #include "analogin.h"
00077 #include "system.h"
00078 
00079 #include "FreeRTOS.h"
00080 #include "task.h"
00081 
00082 int TestHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len );
00083 
00084 static int WebServer_WriteResponseOk_( char* content, void* socket );
00085 
00086 
00087 /** \defgroup webserver Web Server
00088   A simple Web Server
00089 
00090   This Web Server implementation is based on the \ref ServerSocket and \ref Socket functions defined
00091   in \ref Sockets.  When started, a ServerSocket is opened and set to listen on port 80.
00092 
00093   When the server receives a request, it checks the incoming address against a list of handlers.
00094   If the request address matches, the handler is invoked and checking stops.  Users can add their own
00095   handlers to return custom information - see WebServer_Route().  Most of the rest of the WebServer 
00096   system provides helpful functions for generating and parsing HTML.
00097 
00098   There is a single default/test handler that will handle any requests that are not otherwise handled.  This
00099   is about the simplest demo possible of how to write a handler - it simply prints out some text and a count
00100   of how pages it has served.  There are more handler examples further down this page, and in the mcbuilder 
00101   examples.  Take a look at TestHandler() in webserver.c to see its source.
00102 
00103   To access the web server type the IP address of your board into a web browser, optionally followed by
00104   the address of any handlers you've registered, ie \b 192.168.1.200/myhandler.  
00105 
00106   \ingroup Libraries
00107   @{
00108 */
00109 
00110 /**
00111   Start the WebServer up, listening on port 80.
00112   See WebServer_Route() for info on how to register handlers for certain requests.
00113   @param active An integer specifying the active state - 1 (on) or 0 (off).
00114   @return CONTROLLER_OK (0) on success or the appropriate error if not
00115 
00116   \b Example
00117   \code
00118   // fire up the webserver
00119   WebServer_SetActive(true);
00120   \endcode
00121 */
00122 int WebServer_SetActive( int active )
00123 {
00124   if ( active )
00125   {
00126     if ( WebServer == NULL )
00127     {
00128       WebServer = MallocWait( sizeof( WebServer_ ), 100 );
00129       WebServer->hits = 0;
00130       WebServer->serverSocket = NULL;
00131       WebServer->requestSocket = NULL;
00132       WebServer->changeListenPort = false;
00133       WebServer->listenPort = HTTP_PORT; // default to 80
00134       #ifdef CROSSWORKS_BUILD
00135       int stacksize = 800;
00136       #else
00137       int stacksize = 1800;
00138       #endif // CROSSWORKS_BUILD
00139       WebServer->serverTask = TaskCreate( WebServerTask, "WebServ", stacksize, NULL, 4 );
00140       if ( WebServer->serverTask == NULL )
00141       {
00142         Free( WebServer );
00143         WebServer = NULL;
00144         return CONTROLLER_ERROR_CANT_START_TASK;
00145       }
00146     }
00147   }
00148   else
00149   {
00150     if( WebServer != NULL )
00151     {
00152       if ( WebServer->serverTask != NULL )
00153         TaskDelete( WebServer->serverTask );
00154       if ( WebServer->serverSocket != NULL )
00155         ServerSocketClose( WebServer->serverSocket );
00156       if ( WebServer->requestSocket != NULL )
00157         SocketClose( WebServer->requestSocket );
00158   
00159       Free( WebServer );
00160       WebServer = NULL;
00161     }
00162   }
00163   return CONTROLLER_OK;
00164 }
00165 
00166 /**
00167   Read the active state of the WebServer subsystem.
00168   @return State - 1/non-zero (on) or 0 (off).
00169 */
00170 int  WebServer_GetActive( void )
00171 {
00172   return ( WebServer != NULL ) ? 1 : 0;
00173 }
00174 
00175 /**
00176   Set the port that the webserver should listen on for new connections.
00177   Note that this does not immediately take effect - because the webserver
00178   (if it's open) is already listening on a port, it will only take effect
00179   after it serves one last request on that port.
00180   @param port The new port to listen on.
00181   @return 0 on success.
00182 
00183   \b Example
00184   \code
00185   // listen on a non-standard port for HTTP
00186   WebServer_SetListenPort(8080);
00187   \endcode
00188 */
00189 int WebServer_SetListenPort( int port )
00190 {
00191   WebServer->listenPort = port;
00192   return CONTROLLER_OK;
00193 }
00194 
00195 /**
00196   Get the port that the webserver is currently listening on.
00197   @return The port number.
00198 
00199   \b Example
00200   \code
00201   int currentPort = WebServer_GetListenPort( );
00202   \endcode
00203 */
00204 int WebServer_GetListenPort( void )
00205 {
00206   return WebServer->listenPort;
00207 }
00208 
00209 /**
00210   Adds a route handler to the WebServer.
00211 
00212   This function binds an address fragment (e.g. "/", "/adcs", etc.) to a handler
00213   that will be called when the address matches.  Matching ignores characters in the 
00214   incoming address that are beyond the end of the address specified to this function.
00215   The first function to match the address will receive all the traffic and no more 
00216   handlers will be checked.  Thus if a handler is set up to match "/images" it will match
00217   "/images" and "/images/logo.png" and so on.  Also if there is a subseqent handler 
00218   set to match "/images/diagram" it will never be called since the prior handler
00219   will match the entire "/images" space.  You can register your handlers prior to firing up
00220   the webserver system.
00221 
00222   The handler will be called with the request type specified (usually "GET" or  "POST"), 
00223   the incoming address ( "/device/0", "/images/logo.png", etc.) A buffer (and max length) is passed in that
00224   can be used to receive the rest of the message if necessary. Then there will be 
00225   the socket which will take the response and a helpful large buffer or specified length
00226   which can be used to build strings.
00227 
00228   At the time the handler is called, only the first line of the request has been read.  It is used
00229   to determine the request type and the address requested.  If you need to process the request further
00230   its contents may be read into a buffer (the request buffer passed in is good once the request type 
00231   address have been used since they're in there initially).  The SocketReadLine( ) function is 
00232   convenient to read a line of the request at a time.
00233 
00234   The handler itself must first write the response using one of WebServer_WriteResponseOkHTML() for
00235   sending HTML or WebServer_WriteResponseOkPlain() for returning plain text.  
00236   These send the appropriate HTTP header (for example "HTTP/1.0 200 OK\r\nContent-type:text/html\r\n\r\n").
00237   All responses may be simply written to the Socket, but several helpers are provided to assist in the 
00238   construction of simple web pages (for example WebServer_WriteHeader(), WebServer_WriteBodyStart(), etc.). 
00239   
00240   The handler should return non-zero if it handled the response appropriately or 0 if not, in which case
00241   the webserver will check for matches with other handlers that can handle it.
00242   @param address An string specify the addresses to match.
00243   @param handler pointer to a handler function that will be called when the address is matched.
00244   @return CONTROLLER_OK (=0) on success or the appropriate error if not
00245 
00246   Here is an example of how to register a handler:
00247   \code
00248 // now requests at MyBoardsIPAddress/my/handler will be handled by MyHandler
00249 WebServer_Route( "/my/handler", MyHandler );
00250   \endcode
00251 
00252   And here is an example handler, printing out some simple info in response to any request.
00253   \code
00254 int MyHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, 
00255                  void* socket, char* buffer, int len )
00256 {
00257   (void)requestType;
00258   (void)address;
00259   WebServer_WriteResponseOkHTML( socket );
00260   WebServer_WriteHeader( true, socket, buffer, len );
00261   WebServer_WriteBodyStart( address, socket, buffer, len );
00262   snprintf( buffer, len, "<H1>TEST</H1>%d hits", WebServer->hits );
00263   SocketWrite( socket, buffer, strlen( buffer ) );
00264   WebServer_WriteBodyEnd( socket );
00265   return true;
00266 }
00267   \endcode
00268 */
00269 int WebServer_Route( char* address, 
00270                     int (*handler)( char* requestType, char* address, char* requestBuffer, 
00271                     int requestMaxSize, void* socket, char* buffer, int len ) )
00272 {
00273   if ( WebServerHandlers == NULL )
00274   {
00275     WebServerHandlers = MallocWait( sizeof( WebServerHandlers_ ), 100 );    
00276     if ( WebServerHandlers != NULL )
00277       WebServerHandlers->count = 0;
00278   }
00279   if ( WebServerHandlers != NULL )
00280   {
00281     if ( WebServerHandlers->count < HANDLERS_MAX )
00282     {
00283       WebServerHandler* hp = &WebServerHandlers->handlers[ WebServerHandlers->count++ ];
00284       hp->address = address;
00285       hp->handler = handler;
00286       return CONTROLLER_OK;
00287     }
00288    return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
00289   }
00290 
00291   return CONTROLLER_ERROR_NOT_OPEN;
00292 }
00293 
00294 
00295 /**
00296   Writes the HTTP OK message and sets the content type to HTML.
00297   This will typically be the first thing you write out in your handler.
00298   Also see WebServer_WriteResponseOkPlain() to set your response type to plain text.
00299   @param socket The socket to write to
00300   @return non-zero on success, zero on failure.
00301 
00302   \b Example
00303   \code
00304   int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00305                       int requestMaxSize, void* socket, char* buffer, int len )
00306   {
00307     WebServer_WriteResponseOkHTML(socket); // write the response out first
00308     // ... continue processing ...
00309   }
00310   \endcode
00311 */
00312 int WebServer_WriteResponseOkHTML( void* socket )
00313 {
00314   //return WebServer_WriteResponseOk_( socket, HTTP_CONTENT_HTML );
00315   int written = 0;
00316   int ret = 0;
00317   ret = SocketWrite( socket, HTTP_OK, strlen( HTTP_OK ) );
00318   if( !ret )
00319     return 0;
00320   else
00321     written += ret;
00322 
00323   ret = SocketWrite( socket, HTTP_CONTENT_HTML, strlen( HTTP_CONTENT_HTML ) );
00324   if( !ret )
00325     return 0;
00326   else
00327     written += ret;
00328 
00329   return written;
00330 }
00331   
00332 /**
00333   Writes the HTTP OK message and sets the content type to plain text.
00334   This will typically be the first thing you write out in your handler.
00335   Also see WebServer_WriteResponseOkHTML() to set your response type to HTML.
00336   @param socket The socket to write to.
00337   @return non-zero on success, zero on failure.
00338 
00339   \b Example
00340   \code
00341   int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00342                       int requestMaxSize, void* socket, char* buffer, int len )
00343   {
00344     WebServer_WriteResponseOkPlain(socket); // write the response out first
00345     // ... continue processing ...
00346   }
00347   \endcode
00348 */
00349 int WebServer_WriteResponseOkPlain( void* socket )
00350 {
00351   return WebServer_WriteResponseOk_( socket, HTTP_CONTENT_PLAIN );
00352 }
00353 
00354 /**
00355   Writes the HTML header.
00356   Should be preceded by a call to WebServer_WriteResponseOkHTML(). 
00357   See WebServer_Route() for a more complete example.
00358   @param includeCSS A flag signalling the inclusion of a very simple CSS header 
00359   refining h1 and body text slightly.
00360   @param socket The socket to write to
00361   @param buffer Helper buffer which the function can use.  Should be at least 300 bytes.
00362   @param len Helper buffer length
00363   @return non-zero on success, zero on failure.
00364   \todo more parameterization
00365 
00366   \b Example
00367   \code
00368   int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00369                       int requestMaxSize, void* socket, char* buffer, int len )
00370   {
00371     // ... usually write out the OK response first ...
00372     WebServer_WriteHeader(true, socket, buffer, len); // write the header, including simple CSS
00373     // ... continue processing ...
00374   }
00375   \endcode
00376 */
00377 int WebServer_WriteHeader( int includeCSS, void* socket, char* buffer, int len )
00378 {
00379   (void)buffer;
00380   (void)len;
00381   char* headerStart = "<HTML>\r\n<HEAD>";
00382   char* headerEnd = "\r\n</HEAD>";
00383   char* style = "\r\n<STYLE type=\"text/css\"><!--\
00384 body { font-family: Arial, Helvetica, sans-serif; } \
00385 h1 { font-family: Arial, Helvetica, sans-serif; font-weight: bold; }\
00386 --></STYLE>";
00387 
00388   strcpy( buffer, headerStart );
00389   if ( includeCSS )
00390     strcat( buffer, style );
00391   strcat( buffer, headerEnd );
00392   return SocketWrite( socket, buffer, strlen( buffer ) );
00393 }
00394 
00395 /**
00396   Writes the start of the BODY tag.
00397   Should be preceded by a call to WebServer_WriteHeader().  Also writes a light grey background.
00398   You can optionally specify that you'd like the page to automatically refresh itself once 
00399   a second by passing in the address to reload to \b reloadAddress.  See WebServer_Route() for a more complete example.
00400   @param reloadAddress A string signaling the address of a 1 second reload request.  If it is NULL, no reload is requested.
00401   @param socket The socket to write to.
00402   @param buffer Helper buffer which the function can use.  Should be at least 300 bytes.  This is usually the buffer
00403   passed into your handler as \b buffer.
00404   @param len Helper buffer length.  Also usually passed into your handler as \b len.
00405   \todo more parameterization of the tag
00406 
00407   \b Example
00408   \code
00409   int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00410                       int requestMaxSize, void* socket, char* buffer, int len )
00411   {
00412     // ... usually write out the OK response and the header first ...
00413     WebServer_WriteBodyStart(0, socket, buffer, len); // write the body start, with no reload
00414     // ... continue processing ...
00415   }
00416   \endcode
00417 */
00418 int WebServer_WriteBodyStart( char* reloadAddress, void* socket, char* buffer, int len )
00419 {
00420   (void)buffer;
00421   (void)len;
00422   char* bodyStart = "\r\n<BODY";
00423   char* bodyEnd = " bgcolor=\"#eeeeee\">\r\n";
00424 
00425   char* reloadStart = " onLoad=\"window.setTimeout(&quot;location.href='";
00426   char* reloadEnd = "'&quot;,1000)\"";
00427   strcpy( buffer, bodyStart );
00428   if ( reloadAddress )
00429   {
00430     strcat( buffer, reloadStart  );
00431     strcat( buffer, reloadAddress  );
00432     strcat( buffer, reloadEnd  );
00433   }
00434   strcat( buffer, bodyEnd  );
00435   return SocketWrite( socket, buffer, strlen( buffer ) );
00436 }
00437 
00438 /**
00439   Writes the end of the Body tag - and the final end of HTML tag.
00440   Should be preceded by writes to the socket with the content of the page - 
00441   this is often the last thing done in a handler.  See WebServer_Route() for a more complete example.
00442   @param socket The socket to write to
00443   @return non-zero on success, zero on failure.
00444 
00445   \b Example
00446   \code
00447   int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00448                       int requestMaxSize, void* socket, char* buffer, int len )
00449   {
00450     // ... other code actually doing interesting things ...
00451     WebServer_WriteBodyEnd(socket); // now we're all done
00452     return 1;
00453   }
00454   \endcode
00455 */
00456 int WebServer_WriteBodyEnd( void* socket )
00457 {
00458   char* bodyEnd = "\r\n</BODY>\r\n</HTML>";
00459 
00460   return SocketWrite( socket, bodyEnd, strlen( bodyEnd ) );
00461 }
00462 
00463 /**
00464   Set the data of an incoming HTTP POST request to the given buffer.
00465   This is designed to be used from within a custom handler.  An incoming HTTP request will have some number of
00466   lines of header information, and this function will read through them until getting to the body of the message.
00467   It will then store the contents of the body in the given buffer, null-terminating the end of the data.
00468 
00469   It's usually convenient to set the POST data in the requestBuffer since it's already allocated.
00470 
00471   \b Example
00472   \code
00473 int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00474                       int requestMaxSize, void* socket, char* buffer, int len )
00475 {
00476   // ... other setup here ...
00477 
00478   if ( strncmp( requestType, "POST", 4 ) == 0 ) // if the request is indeed a POST
00479   {
00480     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) ) // set the POST data in the requestBuffer
00481     {
00482       // process the data in any way you like.
00483       // here, we're expecting a form and we want to grab the info out of it
00484       formElements = WebServer_ParseFormElements( requestBuffer, &form );
00485     }
00486   }
00487 
00488   // ... write out the response here ...
00489 }
00490   \endcode
00491   @param socket The socket from the incoming request
00492   @param requestBuffer A pointer to the buffer to store the data in.
00493   @param maxSize The maximum amount of data to be placed in the buffer.
00494   @return true on success, false on failure
00495 */
00496 bool WebServer_GetPostData( void *socket, char *requestBuffer, int maxSize )
00497 {
00498   bool retval = false;
00499   // keep reading lines of the HTTP header until we get CRLF which signifies the end of the
00500   // header and the start of the body data.  If we see the contentlength along the way, keep that.
00501   int contentLength = 0;
00502   int bufferLength = 0;
00503   while ( ( bufferLength = SocketReadLine( socket, requestBuffer, maxSize ) ) )
00504   {
00505     if ( strncmp( requestBuffer, "\r\n", 2 ) == 0 )
00506       break;
00507     if ( strncmp( requestBuffer, "Content-Length", 14 ) == 0 )
00508       contentLength = atoi( &requestBuffer[ 15 ] );
00509   }
00510   
00511   // now we should be down to the HTTP POST data
00512   // if there's any data, get up into it
00513   if ( contentLength > 0 && bufferLength > 0 )
00514   {  
00515     int bufferRead = 0;
00516     int lengthToRead;
00517     int avail = SocketBytesAvailable(socket);
00518     if(avail > maxSize)
00519       lengthToRead = maxSize - 1;
00520     else
00521       lengthToRead = avail;
00522     char *rbp = requestBuffer;
00523     // read all that the socket has to offer...may come in chunks, so keep going until there's none left
00524     while ( ( bufferLength = SocketRead( socket, rbp, lengthToRead ) ) )
00525     {
00526       bufferRead += bufferLength;
00527       rbp += bufferLength;
00528       lengthToRead -= bufferLength;
00529       if ( bufferRead >= contentLength )
00530         break;
00531     }
00532     requestBuffer[ bufferRead ] = 0; // null-terminate the request
00533     retval = true;
00534   }
00535   return retval;
00536 }
00537 
00538 /**
00539   Extract the elements of an HTML form into key/value pairs.
00540   This is designed to be used from within a custom handler.  HTML forms can be sent via either the HTTP GET 
00541   or POST methods.  The \b request parameter must be set to the start of the form data, which is 
00542   located in a different place for each method.  In the \b GET case, we need to check if there are any 
00543   form elements, as indicated by a \b ? after the URL address.  In the \b POST case, we can use 
00544   WebServer_GetPostData() to find the beginning of the POST data for us.
00545 
00546   Note that the HtmlForm structure will simply point to the elements in the request buffer, so as soon as
00547   the buffer is deleted or out of scope, the form data is no longer valid.
00548 
00549   \b Example
00550   \code
00551 int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
00552                       int requestMaxSize, void* socket, char* buffer, int len )
00553 {
00554   // ... other setup here ...
00555   
00556   int formElements = 0;
00557   HtmlForm form;
00558   form.count = 0;
00559   
00560   // determine the kind of request - GET or POST
00561   if ( strncmp( requestType, "GET", 3 ) == 0 )
00562   {
00563     char *p = strchr( requestBuffer, '?' ); // if GET, see if there's a ?
00564     if( p != NULL ) // if we didn't find a ?, there were no form elements
00565       formElements = WebServer_ParseFormElements( p+1, &form );
00566     // we have to send "p + 1" since the form data starts right after the ?
00567   }
00568   else if ( strncmp( requestType, "POST", 4 ) == 0 )
00569   {
00570     // make sure we're pointing at the POST data and if it looks good, process it
00571     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) )
00572       formElements = WebServer_ParseFormElements( requestBuffer, &form );
00573   }
00574 
00575   // ... write out the response here ...
00576 }
00577   \endcode
00578   @param request A pointer to the form data
00579   @param form The HtmlForm structure to populate with elements
00580   @return The number of form elements found
00581 */
00582 int WebServer_ParseFormElements( char *request, HtmlForm *form )
00583 {
00584   int count = 0;
00585   bool cont = true;
00586   char *p = request;
00587   char* endp;
00588 
00589   do
00590   {
00591     endp = strchr( p, '=' );
00592     *endp = 0;
00593     form->elements[form->count].key = p;
00594     
00595     p = ++endp;
00596     endp = strchr( p, '&' ); // look for the next element
00597     if( endp == NULL ) // there is no next element, do this one and then be done
00598     {
00599       endp = strchr( p, 0 );
00600       cont = false;
00601     }
00602     *endp = 0;
00603 
00604     // if the value was empty, we'll either get the & if there are more elements, or 0 if we're at the end
00605     if( *(p+1) == '&' || *(p+1) == 0 )
00606       form->elements[form->count].value = 0;
00607     else
00608       form->elements[form->count].value = p;
00609     p = ++endp;
00610   
00611     form->count++;
00612     count++;
00613   } while( cont == true );
00614 
00615   return count;
00616 }
00617 
00618 /** @}
00619 */
00620 
00621 int TestHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len )
00622 {
00623   (void)requestType;
00624   (void)address;
00625   (void)requestBuffer;
00626   (void)requestMaxSize;
00627   WebServer_WriteResponseOkHTML( socket );
00628   WebServer_WriteHeader( true, socket, buffer, len );
00629   WebServer_WriteBodyStart( address, socket, buffer, len );
00630   snprintf( buffer, len, "<H1>Make Controller Web Server Test</H1> %d happy pages served...", WebServer->hits );
00631   SocketWrite( socket, buffer, strlen( buffer ) );
00632   WebServer_WriteBodyEnd( socket );
00633   return true;
00634 }
00635 
00636 void WebServer_Demo( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len );
00637 static void WebServer_ProcessRequest( void* requestSocket );
00638 static void WebServer_CreateServerSocket( void );
00639 static char* WebServer_GetRequestAddress( char* request, int length, char** requestType );
00640 
00641 void WebServer_ProcessRequest( void* requestSocket )
00642 {
00643   char* requestType = 0;
00644   char* address = 0;
00645   int i;
00646   int responded;
00647 
00648   SocketReadLine( requestSocket, WebServer->request, REQUEST_SIZE_MAX ); 
00649   address = WebServer_GetRequestAddress( WebServer->request, REQUEST_SIZE_MAX, &requestType );
00650 
00651   responded = false;
00652   if ( WebServerHandlers != NULL )
00653   {
00654     for ( i = 0; i < WebServerHandlers->count; i++ )
00655     {
00656       WebServerHandler* hp = &WebServerHandlers->handlers[ i ];
00657       if ( strncmp( hp->address, address, strlen( hp->address ) ) == 0 )
00658       {
00659         responded = (*hp->handler)( requestType, address, WebServer->request, REQUEST_SIZE_MAX, requestSocket, WebServer->response, RESPONSE_SIZE_MAX );
00660         if ( responded )
00661           break;
00662       }
00663     }
00664   }
00665   if(!responded)
00666     TestHandler(requestType, address, WebServer->request, REQUEST_SIZE_MAX, requestSocket, WebServer->response, RESPONSE_SIZE_MAX);
00667 
00668   SocketClose( requestSocket );
00669 }
00670 
00671 void WebServer_Demo( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len )
00672 {
00673   (void)address;
00674   char temp[100];
00675 
00676   if( !WebServer_WriteResponseOkHTML( socket ) )
00677     return;
00678 
00679   if( !WebServer_WriteHeader( true, socket, buffer, len ) )
00680     return;
00681 
00682   if( !WebServer_WriteBodyStart( 0, socket, buffer, len ) )
00683     return;
00684   
00685   int formElements = 0;
00686   HtmlForm form;
00687   form.count = 0;
00688   
00689   // if this request is an HTTP GET
00690   if ( strncmp( requestType, "GET", 3 ) == 0 )
00691   {
00692     char *p = strchr( requestBuffer, '?' );
00693     if( p != NULL ) // if we didn't find a ?, then there were no form elements
00694       formElements = WebServer_ParseFormElements( p+1, &form );
00695   }
00696   
00697   // if this request is an HTTP POST
00698   if ( strncmp( requestType, "POST", 4 ) == 0 )
00699   {
00700     // make sure we're pointing at the POST data and if it looks good, process it
00701     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) )
00702       formElements = WebServer_ParseFormElements( requestBuffer, &form ); // grab the data out of the form
00703   }
00704   
00705   strcat( buffer, "<form method=\"POST\">" );
00706   strcat( buffer, "App LED 0: <input type=\"checkbox\" name=\"appled0\"><br>" );
00707   strcat( buffer, "App LED 1: <input type=\"checkbox\" name=\"appled1\"><br>" );
00708   strcat( buffer, "App LED 2: <input type=\"checkbox\" name=\"appled2\"><br>" );
00709   strcat( buffer, "App LED 3: <input type=\"checkbox\" name=\"appled3\"><br>" );
00710   strcat( buffer, "<p></p>" ); 
00711   strcat( buffer, "<input type=\"submit\" value=\"Submit\">" );
00712   strcat( buffer, "</form>" );
00713   
00714   int i, j;
00715   for( j = 0; j < 4; j++ )
00716   {
00717     int value = 0;
00718     snprintf( temp, 100, "appled%d", j );
00719     for( i = 0; i < formElements; i++ )
00720     {
00721       if( strcmp( temp, form.elements[i].key ) == 0 )
00722         value = 1;
00723     }
00724     //AppLed_SetState( j, value );
00725   }
00726   
00727   // Write out the dynamically generated page.
00728   if( !SocketWrite( socket, buffer, strlen( buffer ) ) )
00729     return;
00730   
00731   WebServer_WriteBodyEnd( socket );
00732 }
00733 
00734 void WebServerTask( void *p )
00735 {
00736   (void)p;
00737 
00738   // Try to create a socket on the appropriate port
00739   WebServer_CreateServerSocket();
00740 
00741   while( 1 )
00742   {
00743     if(WebServer->changeListenPort == true)
00744     {
00745       WebServer_CreateServerSocket();
00746       WebServer->changeListenPort = false;
00747     }
00748     /* Wait for connection. */
00749     WebServer->requestSocket = ServerSocketAccept( WebServer->serverSocket );
00750     
00751     if ( WebServer->requestSocket != NULL )
00752     {
00753       WebServer->hits++;
00754       WebServer_ProcessRequest( WebServer->requestSocket );
00755       WebServer->requestSocket = NULL;
00756     }
00757     Sleep( 5 );
00758   }
00759 }
00760 
00761 /*
00762   Create a new ServerSocket on the appropriate listenPort
00763 */
00764 static void WebServer_CreateServerSocket( )
00765 {
00766   if(WebServer->serverSocket)
00767   {
00768     SocketClose(WebServer->serverSocket);
00769     WebServer->serverSocket = NULL;
00770   }
00771   while( WebServer->serverSocket == NULL )
00772   { 
00773     WebServer->serverSocket = ServerSocket( WebServer->listenPort );
00774     if ( WebServer->serverSocket == NULL )
00775       Sleep( 1000 );
00776   }
00777 }
00778 
00779 static int WebServer_WriteResponseOk_( char* contentType, void* socket )
00780 {
00781   int written = 0;
00782   written += SocketWrite( socket, HTTP_OK, strlen( HTTP_OK ) );
00783   written += SocketWrite( socket, contentType, strlen( contentType ) );
00784   return written;
00785 }
00786 
00787 char* WebServer_GetRequestAddress( char* request, int length, char** requestType  )
00788 {
00789   char *last = request + length;
00790   *requestType = NULL;
00791   char* address = NULL;
00792 
00793   // Skip any initial spaces
00794   while( *request == ' ' )
00795     request++;
00796 
00797   if ( request > last )
00798     return address;
00799 
00800   *requestType = request;
00801 
00802   // Skip the request type
00803   while ( *request != ' ' )
00804     request++;
00805 
00806   if ( request > last )
00807     return address;
00808 
00809   // Skip any subsequent spaces
00810   while( *request == ' ' )
00811     request++;
00812 
00813   if ( request > last )
00814     return address;
00815 
00816   address = request;
00817 
00818   while( !isspace( *request ) )
00819     request++;
00820   
00821   if ( request < last )
00822     *request = 0;
00823 
00824   return address;
00825 }
00826 
00827 #ifdef OSC // Webserver OSC interface
00828 
00829 /** \defgroup webserverosc Web Server - OSC
00830   Configure the Web Server  via OSC.
00831   \ingroup OSC
00832 
00833   \section devices Devices
00834     There is only one Web Server system, so a device index is not used.
00835    
00836   \section properties Properties
00837   The Web Server system has the following properties
00838   - active
00839   - listenport
00840 
00841   \section details Property Details
00842 
00843   \b Active
00844 
00845   The \b active property sets whether the web server on the Make Controller is running or not.
00846   The default web server does not really do anything too interesting, but provides a count of the
00847   number of requests it has served.  You can access the web server by typing the board's IP address
00848   into your favorite browser.  You can check the board's IP address in mchelper.
00849 
00850   To turn the web server on, send the message
00851   \code /webserver/active 1 \endcode
00852   then enter the board's IP address into the address bar of your favorite web browser.  Send the message
00853   \code /network/webserver 0 \endcode
00854   to turn the webserver off.
00855 
00856   <b> Listen Port </b>
00857 
00858   The \b listenport property sets which port the web server should listen on for incoming requests.  By default
00859   this is set to 80, the standard port for HTTP.
00860 
00861   To listen on port 8080, send the message
00862   \code /webserver/listenport 8080 \endcode
00863 
00864   Note that the server will most likely already be listening on the previous port, and it won't update its port
00865   until it serves that last request it's waiting for.
00866 */
00867 
00868 #include "osc.h"
00869 static char* WebServerOsc_Name = "webserver";
00870 static char* WebServerOsc_PropertyNames[] = { "active", "listenport", 0 }; // must have a trailing 0
00871 
00872 int WebServerOsc_PropertySet( int value, int property );
00873 int WebServerOsc_PropertyGet( int property );
00874 
00875 const char* WebServerOsc_GetName( void )
00876 {
00877   return WebServerOsc_Name;
00878 }
00879 
00880 int WebServerOsc_ReceiveMessage( int channel, char* message, int length )
00881 {
00882   int status = Osc_IntReceiverHelper( channel, message, length, 
00883                                       WebServerOsc_Name,
00884                                       WebServerOsc_PropertySet, WebServerOsc_PropertyGet, 
00885                                       WebServerOsc_PropertyNames );
00886 
00887   if ( status != CONTROLLER_OK )
00888     return Osc_SendError( channel, WebServerOsc_Name, status );
00889   return CONTROLLER_OK;
00890 }
00891 
00892 // Set the index LED, property with the value
00893 int WebServerOsc_PropertySet( int property, int value )
00894 {
00895   switch ( property )
00896   {
00897     case 0: // active
00898       WebServer_SetActive( value );
00899       break;
00900     case 1: // listenport
00901       if(value != WebServer_GetListenPort())
00902       {
00903         WebServer_SetListenPort( value );
00904         WebServer->changeListenPort = true;
00905       }
00906       break;     
00907   }
00908   return CONTROLLER_OK;
00909 }
00910 
00911 // Get the property
00912 int WebServerOsc_PropertyGet( int property )
00913 {
00914   int value = 0;
00915   switch ( property )
00916   {
00917     case 0: // active
00918       value = WebServer_GetActive( );
00919       break;
00920     case 1: // listenport
00921       value = WebServer_GetListenPort( );
00922       break;   
00923   }
00924   return value;
00925 }
00926 
00927 #endif // OSC
00928 
00929 #endif // MAKE_CTRL_NETWORK
00930 

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.