GSwifiInterface library (interface for GainSpan Wi-Fi GS1011 modules) Please see https://mbed.org/users/gsfan/notebook/GSwifiInterface/

Dependents:   GSwifiInterface_HelloWorld GSwifiInterface_HelloServo GSwifiInterface_UDPEchoServer GSwifiInterface_UDPEchoClient ... more

Fork of WiflyInterface by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GSwifi_httpd_ws.cpp Source File

GSwifi_httpd_ws.cpp

00001 /* Copyright (C) 2013 gsfan, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "GSwifi.h"
00020 
00021 #ifdef CFG_ENABLE_WEBSOCKET
00022 
00023 #include "sha1.h"
00024 
00025 int GSwifi::wsOpen (const char *host, int port, const char *uri, const char *user, const char *pwd) {
00026     int cid;
00027     char cmd[CFG_CMD_SIZE], tmp[CFG_CMD_SIZE];
00028     char ip[17];
00029 
00030     if (!isAssociated() || _state.status != STAT_READY) return -1;
00031 
00032     if (getHostByName(host, ip)) return -1;
00033     if (! port) {
00034         port = 80;
00035     }
00036 
00037     cid = open(PROTO_TCP, ip, port);
00038     if (cid < 0) return -1;
00039     DBG("ws cid %d\r\n", cid);
00040 
00041     // request
00042     snprintf(cmd, sizeof(cmd), "GET %s HTTP/1.1\r\n", uri);
00043     send(cid, cmd, strlen(cmd));
00044     if (host) {
00045         snprintf(cmd, sizeof(cmd), "Host: %s\r\n", host);
00046         send(cid, cmd, strlen(cmd));
00047     }
00048     if (user && pwd) {
00049         snprintf(cmd, sizeof(cmd), "%s:%s", user, pwd);
00050         base64encode(cmd, strlen(cmd), tmp, sizeof(tmp));
00051         snprintf(cmd, sizeof(cmd), "Authorization: Basic %s\r\n", tmp);
00052         send(cid, cmd, strlen(cmd));
00053     }
00054     strcpy(cmd, "Upgrade: websocket\r\n");
00055     send(cid, cmd, strlen(cmd));
00056     strcpy(cmd, "Connection: Upgrade\r\n");
00057     send(cid, cmd, strlen(cmd));
00058     getMacAddress(cmd);
00059     memcpy(&cmd[6], host, 10);
00060     base64encode(cmd, 16, tmp, sizeof(tmp));
00061     snprintf(cmd, sizeof(cmd), "Sec-WebSocket-Key: %s\r\n", tmp);
00062     send(cid, cmd, strlen(cmd));
00063 //    strcpy(cmd, "Sec-WebSocket-Protocol: chat\r\n");
00064 //    send(cid, cmd, strlen(cmd));
00065     strcpy(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
00066     send(cid, cmd, strlen(cmd));
00067 
00068     if (wsWait(cid, 101)) {
00069         close(cid);
00070         return -1;
00071     }
00072     wsWait(cid, 0);
00073     return cid;
00074 }
00075 
00076 int GSwifi::wsWait (int cid, int code) {
00077     Timer timeout;
00078     int i, n, len;
00079     char buf[CFG_DATA_SIZE], data[CFG_CMD_SIZE];
00080 
00081     if (code == 0) {
00082         // dummy read
00083         timeout.start();
00084         while (timeout.read_ms() < CFG_TIMEOUT) {
00085             wait_ms(10);
00086             if (!readable(cid)) break;
00087             n = recv(cid, buf, sizeof(buf));
00088             if (n <= 0) break;
00089         }
00090         timeout.stop();
00091         return 0;
00092     }
00093 
00094     // wait responce
00095     len = 0;
00096     timeout.start();
00097     while (timeout.read_ms() < CFG_TIMEOUT) {
00098         wait_ms(10);
00099         n = recv(cid, buf, sizeof(buf));
00100         for (i = 0; i < n; i ++) {
00101             if (buf[i] == '\r') continue;
00102             if (buf[i] == '\n') {
00103                 if (len == 0) continue;
00104                 goto next;
00105             } else
00106             if (len < sizeof(data) - 1) {
00107                 data[len] = buf[i];
00108                 len ++;
00109             }
00110         }
00111     }
00112 next:
00113     data[len] = 0;
00114     timeout.stop();
00115     DBG("ws: %s\r\n", data);
00116  
00117     // check return code
00118     if (strncmp(data, "HTTP/1.1 ", 9) != 0) return -1;
00119     i = atoi(&data[9]);
00120     DBG("ws status %d\r\n", i);
00121     return i == code ? 0 : -1;
00122 }
00123 
00124 int GSwifi::wsSend (int cid, const char *buf, int len, const char *mask) {
00125     int i = 0, r;
00126     char tmp[10];
00127  
00128     tmp[i++] = 0x81; // single, text frame
00129     if (len < 126) {
00130         tmp[i++] = (mask == NULL ? 0 : 0x80) | len;
00131     } else {
00132         tmp[i++] = (mask == NULL ? 0 : 0x80) | 126;
00133         tmp[i++] = (len >> 8) & 0xff;
00134         tmp[i++] = len & 0xff;
00135     }
00136     if (mask) {
00137         memcpy(&tmp[i], mask, 4);
00138         i += 4;
00139     }
00140     r = send(cid, tmp, i);
00141  
00142     if (r > 0) {
00143         if (mask) {
00144             char tmp2[len];
00145             for (i = 0; i < len; i ++) {
00146                 tmp2[i] = buf[i] ^ mask[i & 0x03];
00147             }
00148             r = send(cid, tmp2, len);
00149         } else {
00150             r = send(cid, buf, len);
00151         }
00152     }
00153     return r;
00154 }
00155 
00156 #ifdef CFG_ENABLE_HTTPD
00157 
00158 void GSwifi::wsRecvData (int cid, char c) {
00159 
00160     switch (_httpd[cid].mode) {
00161     case HTTPDMODE_WEBSOCKET:
00162         if (_httpd[cid].n == 0) {
00163             // flag
00164             _httpd[cid].websocket_opcode = c & 0x0f;
00165             _httpd[cid].websocket_flg = c << 8;
00166             _httpd[cid].n ++;
00167         } else
00168         if (_httpd[cid].n == 1) {
00169             // length 7bit
00170             _httpd[cid].websocket_flg |= c;
00171             _httpd[cid].length = c & 0x7f;
00172             _httpd[cid].n ++;
00173             if (_httpd[cid].length < 126) {
00174                 _httpd[cid].n = 0;
00175                 if (_httpd[cid].length) {
00176                     if (_httpd[cid].websocket_flg & 0x0080) {
00177                         _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK;
00178                     } else {
00179                         _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
00180                     }
00181                 } else {
00182                     _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER;
00183                 }
00184                 DBG("ws length %d\r\n", _httpd[cid].length);
00185             }
00186         } else {
00187             // length 16bit,64bit
00188             if (_httpd[cid].n == 2) {
00189                 _httpd[cid].length = c;
00190                 _httpd[cid].n ++;
00191             } else
00192             if (_httpd[cid].n < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) {
00193                 // 64bit
00194                 _httpd[cid].length = (_httpd[cid].length << 8) | c;
00195                 _httpd[cid].n ++;
00196             } else {
00197                 // end
00198                 _httpd[cid].length = (_httpd[cid].length << 8) | c;
00199                 _httpd[cid].n = 0;
00200                 if (_httpd[cid].websocket_flg & 0x0080) {
00201                     _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK;
00202                 } else {
00203                     _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
00204                 }
00205                 DBG("ws length2 %d\r\n", _httpd[cid].length);
00206             }
00207         }
00208         break;
00209     case HTTPDMODE_WEBSOCKET_MASK:
00210         // masking key
00211         _httpd[cid].websocket_mask[_httpd[cid].n] = c;
00212         _httpd[cid].n ++;
00213         if (_httpd[cid].n >= 4) {
00214             _httpd[cid].n = 0;
00215             _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
00216             DBG("ws mask\r\n");
00217         }
00218         break;
00219     case HTTPDMODE_WEBSOCKET_BODY:
00220         // payload
00221         if (_httpd[cid].websocket_flg & 0x0080) {
00222             // un-mask
00223             _httpd[cid].buf->queue(c ^ _httpd[cid].websocket_mask[_httpd[cid].n & 0x03]); 
00224         } else {
00225             _httpd[cid].buf->queue(c); 
00226         }
00227         _httpd[cid].n ++;
00228         if (_httpd[cid].n >= _httpd[cid].length) {
00229             _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER;
00230             _con[cid].received = true;
00231         }
00232         break;
00233     }
00234 }
00235 
00236 int GSwifi::wsParseRequest (int cid) {
00237     int i;
00238 
00239     DBG("ws opcode %d\r\n", _httpd[cid].websocket_opcode);
00240     switch (_httpd[cid].websocket_opcode) {
00241     case 0x00: // continuation
00242         break;
00243     case 0x01: // text
00244     case 0x02: // binary
00245         i = httpdGetHandler(_httpd[cid].uri);
00246         if (i >= 0) {
00247             if (_httpd_handler[i].func && _httpd_handler[i].ws) {
00248                 // cgi
00249                 _httpd_handler[i].func(cid);
00250             }
00251         }
00252         break;
00253     case 0x08: // close
00254         close(cid);
00255         break;
00256     case 0x09: // ping
00257         {
00258         char pong[_httpd[cid].n + 2];
00259         pong[0] = 0x8a;
00260         pong[1] = 0x04;
00261         for (i = 0; i < _httpd[cid].length; i ++) {
00262             if (_httpd[cid].buf->dequeue(&pong[i + 2]) == false) break;
00263         }
00264         send(cid, pong, _httpd[cid].length + 2);
00265         }
00266         break;
00267     case 0x0a: // pong
00268         break;
00269     default:
00270         break;
00271     }
00272     _httpd[cid].n = 0;
00273     _httpd[cid].length = 0;
00274     return 0;
00275 }
00276 
00277 int GSwifi::wsAccept (int cid) {
00278     char buf[CFG_CMD_SIZE], buf2[CFG_CMD_SIZE];
00279     
00280     DBG("websocket accept: %d\r\n", cid);
00281 
00282     strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
00283     send(cid, buf, strlen(buf));
00284     strcpy(buf, "Upgrade: websocket\r\n");
00285     send(cid, buf, strlen(buf));
00286     strcpy(buf, "Connection: Upgrade\r\n");
00287     send(cid, buf, strlen(buf));
00288 
00289     strcpy(buf, "Sec-WebSocket-Accept: ");
00290     send(cid, buf, strlen(buf));
00291     strcpy(buf, _httpd[cid].websocket_key);
00292     strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
00293     sha1(buf, strlen(buf), buf2);
00294     base64encode(buf2, 20, buf, sizeof(buf));
00295     send(cid, buf, strlen(buf));
00296     strcpy(buf, "\r\n\r\n");
00297     send(cid, buf, strlen(buf));
00298     return 0;
00299 }
00300 
00301 #endif
00302 #endif