Guest User

WiServer.cpp

a guest
Oct 19th, 2014
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.54 KB | None | 0 0
  1. /******************************************************************************
  2.  
  3.   Filename:        WiSever.cpp
  4.   Description: Main library code for the WiServer library
  5.  
  6.  ******************************************************************************
  7.  
  8.   Copyright(c) 2009 Mark A. Patel  All rights reserved.
  9.  
  10.   This program is free software; you can redistribute it and/or modify it
  11.   under the terms of version 2 of the GNU General Public License as
  12.   published by the Free Software Foundation.
  13.  
  14.   This program is distributed in the hope that it will be useful, but WITHOUT
  15.   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16.   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  17.   more details.
  18.  
  19.   You should have received a copy of the GNU General Public License along with
  20.   this program; if not, write to the Free Software Foundation, Inc., 59
  21.   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  22.  
  23.   Contact Information:
  24.  
  25.    Author               Date        Comment
  26.   ---------------------------------------------------------------
  27.    Mark A. Patel       05/27/2009  Initial version
  28.  
  29.    Mark A. Patel       06/05/2009  Revised to work with stack version 1.1,
  30.                                     plus added various enhancements such as
  31.                                     multi-pass transmission, local client
  32.                                     checks, activity LED support, etc.
  33.  
  34.  
  35.  *****************************************************************************/
  36.  
  37.  
  38.  
  39. #include "WiServer.h"
  40. #include <Arduino.h>
  41.  
  42.  
  43. extern "C" {
  44.     #include "g2100.h"
  45.     #include "spi.h"
  46.     #include "uip.h"
  47.     #include "server.h"
  48.     #include "global-conf.h"
  49.     void stack_init(void);
  50.     void stack_process(void);
  51. }
  52.  
  53. #ifdef APP_WISERVER
  54.  
  55. #define CR 13
  56. #define LF 10
  57.  
  58. // Strings stored in program memory (defined in strings.c)
  59. extern const char PROGMEM httpOK[];
  60. extern const char PROGMEM httpNotFound[];
  61. extern const char PROGMEM http10[];
  62. extern const char PROGMEM post[];
  63. extern const char PROGMEM get[];
  64. extern const char PROGMEM authBasic[];
  65. extern const char PROGMEM host[];
  66. extern const char PROGMEM userAgent[];
  67. extern const char PROGMEM contentTypeForm[];
  68. extern const char PROGMEM contentLength[];
  69. extern const char PROGMEM status[];
  70. extern const char PROGMEM base64Chars[];
  71.  
  72.  
  73.  
  74. /* Application's callback function for serving pages */
  75. pageServingFunction callbackFunc;
  76.  
  77. /* Digital output pin to indicate TX activity */
  78. char txPin = -1;
  79.  
  80. /* Digital output pin to indicate RX activity */
  81. char rxPin = -1;
  82.  
  83. /* Enables basic log messages via Serial */
  84. boolean verbose = false;
  85.  
  86. void Server::init(pageServingFunction function) {
  87.  
  88.     // WiShield init
  89.     zg_init();
  90.  
  91. #ifdef USE_DIG0_INTR
  92.     attachInterrupt(0, zg_isr, LOW);
  93. #endif
  94.  
  95. #ifdef USE_DIG8_INTR
  96.     // set digital pin 8 on Arduino
  97.     // as ZG interrupt pin
  98.     PCICR |= (1<<PCIE0);
  99.     PCMSK0 |= (1<<PCINT0);
  100. #endif
  101.  
  102.     while(zg_get_conn_state() != 1) {
  103.         zg_drv_process();
  104.     }
  105.  
  106.     // Start the stack
  107.     stack_init();
  108.  
  109.     // Store the callback function for serving pages
  110.     // and start listening for connections on port 80 if
  111.     // the function is non-null
  112.     callbackFunc = function;
  113.     if (callbackFunc) {
  114.         // Listen for server requests on port 80
  115.         uip_listen(HTONS(80));
  116.     }
  117.  
  118. #ifdef DEBUG
  119.     verbose = true;
  120.     Serial.println("WiServer init called");
  121. #endif // DEBUG
  122. }
  123.  
  124. #ifdef USE_DIG8_INTR
  125. // PCINT0 interrupt vector
  126. ISR(PCINT0_vect)
  127. {
  128.     zg_isr();
  129. }
  130. #endif
  131.  
  132. void Server::setIndicatorPins(int tx, int rx) {
  133.     // Store the pin numbers
  134.     txPin = tx;
  135.     rxPin = rx;
  136.     // Set pin modes as needed
  137.     if (tx != -1) pinMode(tx, OUTPUT);
  138.     if (rx != -1) pinMode(rx, OUTPUT);
  139. }
  140.  
  141. /*
  142.  * Sets the TX pin (if enabled) to the specified value (HIGH or LOW)
  143.  */
  144. void setTXPin(byte value) {
  145.     if (txPin != -1) digitalWrite(txPin, value);
  146. }
  147.  
  148. /*
  149.  * Sets the RX pin (if enabled) to the specified value (HIGH or LOW)
  150.  */
  151. void setRXPin(byte value) {
  152.     if (rxPin != -1) digitalWrite(rxPin, value);
  153. }
  154.  
  155.  
  156. void Server::enableVerboseMode(boolean enable) {
  157.     verbose = enable;
  158. }
  159.  
  160.  
  161.  
  162. /******* Generic printing and sending functions ********/
  163.  
  164.  
  165. void Server::write_P(const char data[], int len) {
  166.     while (len-- > 0) {
  167.         this->write(pgm_read_byte(data++));
  168.     }
  169. }
  170.  
  171.  
  172. void Server::print_P(const char s[]) {
  173.     char c = pgm_read_byte(s);
  174.     while (c) {
  175.         this->print(c);
  176.         c = pgm_read_byte(++s);
  177.     }
  178. }
  179.  
  180.  
  181. void Server::println_P(const char c[]) {
  182.     this->print_P(c);
  183.     this->println();
  184. }
  185.  
  186.  
  187.  
  188. void Server::printTime(long t) {
  189.  
  190.     long secs = t / 1000;
  191.     int mins = (int)(secs / 60);
  192.     int hours = mins / 60;
  193.  
  194.     hours %= 24;
  195.     this->print(hours / 10);
  196.     this->print(hours % 10);
  197.     this->print(':');
  198.  
  199.     mins %= 60;
  200.     this->print(mins / 10);
  201.     this->print(mins % 10);
  202.     this->print(':');
  203.  
  204.     secs %= 60;
  205.     this->print(secs / 10);
  206.     this->print(secs % 10);
  207. }
  208.  
  209.  
  210. /*
  211.  * Writes a byte to the virtual buffer for the current connection
  212.  */
  213. size_t Server::write(uint8_t b) {
  214.  
  215.     // Make sure there's a current connection
  216.     if (uip_conn) {
  217.         // Check if the cursor is within the range that maps to the uip_appdata buffer
  218.         // (and we'll increment the cursor while we're at it)
  219.         int offset = (int)(uip_conn->appstate.cursor++) - uip_conn->appstate.ackedCount;
  220.         if ((offset >= 0) && (offset < (int)uip_conn->mss)) {
  221.             // Write the byte to the corresponding location in the buffer
  222.             *((char*)uip_appdata + offset) = b;
  223.         }
  224.     }
  225. }
  226.  
  227.  
  228. /*
  229.  * Sends the real data in the current connection's virtual buffer
  230.  */
  231. void send() {
  232.  
  233.     uip_tcp_appstate_t *app = &(uip_conn->appstate);
  234.  
  235.     // Find the intersection of the virtual buffer and the real uip buffer
  236.     int len = (int)app->cursor - app->ackedCount;
  237.     len = len < 0 ? 0 : len;
  238.     len = len > (int)uip_conn->mss ? (int)uip_conn->mss : len;
  239.  
  240.     if (verbose) {
  241.         Serial.print("TX ");
  242.         Serial.print(len);
  243.         Serial.println(" bytes");
  244.     }
  245.  
  246. #ifdef DEBUG
  247.     Serial.print(app->ackedCount);
  248.     Serial.print(" - ");
  249.     Serial.print(app->ackedCount + len - 1);
  250.     Serial.print(" of ");
  251.     Serial.println((int)app->cursor);
  252. #endif // DEBUG
  253.  
  254.     // Send the real bytes from the virtual buffer and record how many were sent
  255.     uip_send(uip_appdata, len);
  256.     app->sentCount = len;
  257.     setTXPin(HIGH);
  258. }
  259.  
  260.  
  261. /******* Server mode functions ********/
  262.  
  263.  
  264. /*
  265.  * Processes a line of data in an HTTP request.  This function looks
  266.  * for GET and saves a copy of the URL in the current connection's
  267.  * server request.  It also sets the request's isValid flag if the
  268.  * URL has been saved and an empty line is found.
  269.  */
  270. boolean processLine(char* data, int len) {
  271.  
  272.     // Check for a valid GET line
  273.     if ((uip_conn->appstate.request == NULL) && (strncmp(data, "GET /", 4) == 0)) {
  274.         // URL starts at the '/'
  275.         char* start = data + 4;
  276.         // Find trailing space after the URL
  277.         data = start;
  278.         char* end = data + len;
  279.         while (++data < end) {
  280.             if (*data == ' ') {
  281.                 // Replace the space with a NULL to terminate it
  282.                 *(data++) = 0;
  283.                 // Compute length of the URL including the NULL
  284.                 int len = data - start;
  285.                 // Allocate space for the URL and copy the contents
  286.                 uip_conn->appstate.request = malloc(len);
  287.                 memcpy(uip_conn->appstate.request, start, len);
  288.                 return false;
  289.             }
  290.         }
  291.         // No space, not valid
  292.     }
  293.  
  294.     return (len == 0);
  295. }
  296.  
  297.  
  298. /*
  299.  * Processes a packet of data that supposedly contains an HTTP request
  300.  * This function looks for CR/LF (or just LF) and calls processLine
  301.  * with each line of data found.
  302.  */
  303. boolean processPacket(char* data, int len) {
  304.  
  305.     // Address after the last byte of data
  306.     char* end = data + len;
  307.     // Start of current line
  308.     char* start = data;
  309.  
  310.     // Scan through the bytes in the packet looking for a Line Feed character
  311.     while (data < end) {
  312.         if (*data == LF) {
  313.             // Determine the length of the line excluding the Line Feed
  314.             int lineLength = data - start;
  315.  
  316.             if (*(data - 1) == CR) {
  317.                 lineLength--;
  318.             }
  319.  
  320.             *(start + lineLength) = 0;
  321.             // Process the line
  322.             if (processLine(start, lineLength)) {
  323.                 return true;
  324.             }
  325.             // Set up for the start of the next line
  326.             start = ++data;
  327.         } else {
  328.             // Go to the next byte
  329.             data++;
  330.         }
  331.     }
  332.     return false;
  333. }
  334.  
  335.  
  336. /*
  337.  * Attempts to send the requested page for the current connection
  338.  */
  339. void sendPage() {
  340.  
  341.     // Reset the virtual buffer cursor
  342.     uip_conn->appstate.cursor = 0;
  343.  
  344.     // Start off with an HTTP OK response header and a blank line
  345.     WiServer.println_P(httpOK);
  346.     WiServer.println();
  347.  
  348.     // Call the application's 'sendPage' function and ask it to
  349.     // generate the requested page content.
  350.     if (!callbackFunc((char*)uip_conn->appstate.request)) {
  351.         // The URL is not recognized by the sketch
  352.         // Reset the cursor and overwrite the HTTP OK header with a 404 message
  353.         uip_conn->appstate.cursor = 0;
  354.         WiServer.println_P(httpNotFound);
  355.         WiServer.println();
  356. #ifdef DEBUG
  357.         Serial.println("URL Not Found");
  358. #endif // DEBUG
  359.     }
  360.     // Send the 'real' bytes in the buffer
  361.     send();
  362. }
  363.  
  364.  
  365. boolean Server::sendInProgress() {
  366.     return false; // FIX ME
  367. }
  368.  
  369.  
  370. boolean Server::clientIsLocal() {
  371.     // Check if there is a current connection
  372.     if (uip_conn != NULL) {
  373.         // Check if the remote host is local to the server
  374.         uip_ipaddr_t hostaddr, mask;
  375.         // Get the server's address
  376.         uip_gethostaddr(&hostaddr);
  377.         // Get the subnet mask
  378.         uip_getnetmask(&mask);
  379.         // Compare with the client's address
  380.         return uip_ipaddr_maskcmp(&hostaddr, uip_conn->ripaddr, &mask);
  381.     }
  382.     return false;
  383. }
  384.  
  385. /*
  386.  * Handles high-level server communications
  387.  */
  388. void server_task_impl() {
  389.  
  390.     // Get the connection's app state
  391.     uip_tcp_appstate_t *app = &(uip_conn->appstate);
  392.  
  393.     if (uip_connected()) {
  394.  
  395.         if (verbose) {
  396.             Serial.println("Server connected");
  397.         }
  398.  
  399.         // Initialize the server request data
  400.         app->ackedCount = 0;
  401.         app->request = NULL;
  402.     }
  403.  
  404.     if (uip_newdata()) {
  405.         setRXPin(HIGH);
  406.         // Process the received packet and check if a valid GET request had been received
  407.         if (processPacket((char*)uip_appdata, uip_datalen()) && app->request) {
  408.             if (verbose) {
  409.                 Serial.print("Processing request for ");
  410.                 Serial.println((char*)app->request);
  411.             }
  412.             sendPage();
  413.         }
  414.     }
  415.  
  416.  
  417.     // Did we get an ack for the last packet?
  418.     if (uip_acked()) {
  419.         // Record the bytes that were successfully sent
  420.         app->ackedCount += app->sentCount;
  421.         app->sentCount = 0;
  422.  
  423.         // Check if we're done or need to send more content for this
  424.         // request
  425.         if (app->ackedCount == (int)app->cursor) {
  426.             // Done with the current request and connection
  427.             uip_close();
  428.         } else {
  429.             // Generate the content again to send the next packet of data
  430.             sendPage();
  431.         }
  432.     }
  433.  
  434.     // Check if we need to retransmit
  435.     if (uip_rexmit()) {
  436.         // Send the same data again (same ackedCount value)
  437.         sendPage();
  438.     }
  439.  
  440.     if (uip_aborted() || uip_closed() || uip_timedout()) {
  441.  
  442.         // Check if a URL was stored for this connection
  443.         if (app->request != NULL) {
  444.             if (verbose) {
  445.                 Serial.println("Server connection closed");
  446.             }
  447.  
  448.             // Free RAM and clear the pointer
  449.             free(app->request);
  450.             app->request = NULL;
  451.         }
  452.     }
  453. }
  454.  
  455.  
  456.  
  457. /******* Client mode functions ********/
  458. #ifdef ENABLE_CLIENT_MODE
  459.  
  460. /* Linked list of queued client requests */
  461. GETrequest* queue = NULL;
  462.  
  463. void Server::submitRequest(GETrequest *req) {
  464.      // Check for an empty queue
  465.     if (queue == NULL) {
  466.         // Point to the new request
  467.         queue = req;
  468.     } else {
  469.         // Find the tail of the queue
  470.         GETrequest* r = queue;
  471.         while (r->next != NULL) {
  472.             r = r->next;
  473.         }
  474.         // Append the new request
  475.         r->next = req;
  476.     }
  477.     // Set the request as being active
  478.     req->active = true;
  479. }
  480.  
  481.  
  482. /**
  483.  * Sends the request for the current connection
  484.  */
  485. void sendRequest() {
  486.  
  487.     uip_tcp_appstate_t *app = &(uip_conn->appstate);
  488.     GETrequest *req = (GETrequest*)app->request;
  489.  
  490.     // Reset the virtual buffer
  491.     app->cursor = 0;
  492.  
  493.     // Indicates if this is a POST request (instead of a GET)
  494.     // Main difference is that POST requests have a body and a
  495.     // callback function to generate said body
  496.     bool isPost = req->body != NULL;
  497.  
  498.     // Write out the request header
  499.     WiServer.print_P(isPost ? post : get);
  500.     WiServer.print(req->URL);
  501.     WiServer.println_P(http10);
  502.  
  503.     // Host name
  504.     WiServer.print_P(host);
  505.     WiServer.println(req->hostName);
  506.  
  507.     // Auth data (if applicable)
  508.     if (req->auth) {
  509.         WiServer.print_P(authBasic);
  510.         WiServer.println(req->auth);
  511.     }
  512.  
  513.     // User agent (WiServer, of course!)
  514.     WiServer.println_P(userAgent);
  515.  
  516.     if (isPost) {
  517.         // Since a post has a body after the blank header line, it has to include
  518.         // an accurate content length so that the server knows when it has received
  519.         // all of the body data.
  520.         char* lengthFieldPos; // Cursor position where the content length place holder starts
  521.         char* contentStart; // Start of the body
  522.         char* contentEnd; // End of the body
  523.  
  524.         // Just form data for now
  525.         WiServer.println_P(contentTypeForm);
  526.  
  527.         // Content length line (with 4-space placeholder for the value)
  528.         WiServer.println_P(contentLength);
  529.         // Make a note of where the place holder is so we can fill it in later
  530.         lengthFieldPos = app->cursor - 6; // 6 bytes for CR, LF, and 4 spaces
  531.  
  532.         // Blank line to indicate end of header
  533.         WiServer.println();
  534.  
  535.         // Body starts here
  536.         contentStart = app->cursor;
  537.  
  538.         // Print the body preamble if the request has one
  539.         if (req->bodyPreamble) {
  540.             WiServer.print(req->bodyPreamble);
  541.         }
  542.  
  543.         // Have the sketch provide the body for the POST
  544.         req->body();
  545.  
  546.         // Body ends here
  547.         contentEnd = app->cursor;
  548.  
  549.         // Move the cursor back to the content length value and write in the real length
  550.         app->cursor = lengthFieldPos;
  551.         WiServer.print((int)(contentEnd - contentStart));
  552.  
  553.         // Put the cursor back at the end of the body so that all of the data gets sent
  554.         app->cursor = contentEnd;
  555.  
  556.     } else {
  557.         // Blank line to indicate end of GET header
  558.         WiServer.println();
  559.     }
  560.  
  561.     // Send the 'real' bytes in the buffer
  562.     send();
  563. }
  564.  
  565. /**
  566.  * Handle client communications
  567.  */
  568. void client_task_impl() {
  569.  
  570.     uip_tcp_appstate_t *app = &(uip_conn->appstate);
  571.     GETrequest *req = (GETrequest*)app->request;
  572.  
  573.     if (uip_connected()) {
  574.  
  575.         if (verbose) {
  576.             Serial.print("Connected to ");
  577.             Serial.println(req->hostName);
  578.         }
  579.         app->ackedCount = 0;
  580.         sendRequest();
  581.     }
  582.  
  583.     // Did we get an ack for the last packet?
  584.     if (uip_acked()) {
  585.         // Record the bytes that were successfully sent
  586.         app->ackedCount += app->sentCount;
  587.         app->sentCount = 0;
  588.  
  589.         // Check if we're done or need to send more content for this
  590.         // request
  591.         if (app->ackedCount != (int)app->cursor) {
  592.             // Generate the post again to send the next packet of data
  593.             sendRequest();
  594.         }
  595.     }
  596.  
  597.     if (uip_rexmit()) {
  598.         sendRequest();
  599.     }
  600.  
  601.     if (uip_newdata())  {
  602.         setRXPin(HIGH);
  603.  
  604.         if (verbose) {
  605.             Serial.print("RX ");
  606.             Serial.print(uip_datalen());
  607.             Serial.print(" bytes from ");
  608.             Serial.println(req->hostName);
  609.         }
  610.  
  611.         // Check if the sketch cares about the returned data
  612.         if ((req->returnFunc) && (uip_datalen() > 0)){
  613.             // Call the sketch's callback function
  614.             req->returnFunc((char*)uip_appdata, uip_datalen());
  615.         }
  616.     }
  617.  
  618.     if (uip_aborted() || uip_timedout() || uip_closed()) {
  619.         if (req != NULL) {
  620.             if (verbose) {
  621.                 Serial.print("Ended connection with ");
  622.                 Serial.println(req->hostName);
  623.             }
  624.  
  625.             if (req->returnFunc) {
  626.                 // Call the sketch's callback function with 0 bytes to indicate End Of Data
  627.                 req->returnFunc((char*)uip_appdata, 0);
  628.             }
  629.             // Remove the request from the connection
  630.             app->request = NULL;
  631.             // Request is no longer active
  632.             req->active = false;
  633.         }
  634.     }
  635. }
  636.  
  637.  
  638. char getChar(int nibble) {
  639.     return pgm_read_byte(base64Chars + nibble);
  640. }
  641.  
  642. void storeBlock(char* src, char* dest, int len) {
  643.    
  644.     dest[0] = getChar(src[0] >> 2);
  645.     dest[1] = getChar(((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4));
  646.     dest[2] = len > 1 ? getChar(((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)) : '=';
  647.     dest[3] = len > 2 ? getChar(src[2] & 0x3f ) : '=';
  648. }
  649.  
  650. char* Server::base64encode(char* data) {
  651.    
  652.     int len = strlen(data);
  653.     int outLenPadded = ((len + 2) / 3) << 2;
  654.     char* out = (char*)malloc(outLenPadded + 1);
  655.    
  656.     char* outP = out;
  657.     while (len > 0) {
  658.        
  659.         storeBlock(data, outP, min(len,3));
  660.         outP += 4;
  661.         data += 3;
  662.         len -= 3;
  663.     }
  664.     *(out + outLenPadded) = 0;
  665.     return out;
  666. }
  667.  
  668.  
  669.  
  670. #endif // ENABLE_CLIENT_MODE
  671.  
  672.  
  673.  
  674. /********* High-level WiServer functions ***********/
  675.  
  676. /*
  677.  * This function is called by uip whenever a stack event occurs
  678.  */
  679. void server_app_task() {
  680.  
  681.     // Clear the activity pins
  682.     setTXPin(LOW);
  683.     setRXPin(LOW);
  684.  
  685.     // Check for an active connection
  686.     if (uip_conn) {
  687.         // Is the connection for local port 80?
  688.         if (uip_conn->lport == HTONS(80)) {
  689.             // Server mode
  690.             server_task_impl();
  691.         } else {
  692. #ifdef ENABLE_CLIENT_MODE
  693.             // Client mode
  694.             client_task_impl();
  695. #endif // ENABLE_CLIENT_MODE
  696.         }
  697.     }
  698. }
  699.  
  700.  
  701. /*
  702.  * Called by the sketch's main loop
  703.  */
  704. void Server::server_task() {
  705.  
  706.     // Run the stack state machine
  707.     stack_process();
  708.  
  709.     // Run the driver
  710.     zg_drv_process();
  711.  
  712. #ifdef ENABLE_CLIENT_MODE
  713.     // Check if there is a pending client request
  714.     if (queue) {
  715.         // Attempt to connect to the server
  716.         struct uip_conn *conn = uip_connect(&(queue->ipAddr), queue->port);
  717.  
  718.         if (conn != NULL) {
  719. #ifdef DEBUG
  720.             Serial.print("Got connection for ");
  721.             Serial.println(queue->hostName);
  722. #endif // DEBUG
  723.  
  724.             // Attach the request object to its connection
  725.             conn->appstate.request = queue;
  726.             // Move the head of the queue to the next request in the queue
  727.             queue = queue->next;
  728.             // Clear the next pointer of the connected request
  729.             ((GETrequest*)conn->appstate.request)->next = NULL;
  730.         }
  731.     }
  732. #endif // ENABLE_CLIENT_MODE
  733. }
  734.  
  735. // Single instance of the server
  736. Server WiServer;
  737.  
  738. #endif  /* APP_WISERVER */
Add Comment
Please, Sign In to add comment