see http://mbed.org/users/okini3939/notebook/wattmeter-shield-on-mbed/

Dependencies:   mbed

Fork of GSwifi_xively by gs fan

Committer:
okini3939
Date:
Wed Nov 27 08:18:45 2013 +0000
Revision:
4:9a2415f2ab07
update GSwifiInterface library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 4:9a2415f2ab07 1 /* Copyright (C) 2013 gsfan, MIT License
okini3939 4:9a2415f2ab07 2 *
okini3939 4:9a2415f2ab07 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
okini3939 4:9a2415f2ab07 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
okini3939 4:9a2415f2ab07 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
okini3939 4:9a2415f2ab07 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
okini3939 4:9a2415f2ab07 7 * furnished to do so, subject to the following conditions:
okini3939 4:9a2415f2ab07 8 *
okini3939 4:9a2415f2ab07 9 * The above copyright notice and this permission notice shall be included in all copies or
okini3939 4:9a2415f2ab07 10 * substantial portions of the Software.
okini3939 4:9a2415f2ab07 11 *
okini3939 4:9a2415f2ab07 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
okini3939 4:9a2415f2ab07 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
okini3939 4:9a2415f2ab07 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
okini3939 4:9a2415f2ab07 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
okini3939 4:9a2415f2ab07 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
okini3939 4:9a2415f2ab07 17 */
okini3939 4:9a2415f2ab07 18
okini3939 4:9a2415f2ab07 19 #include "GSwifi.h"
okini3939 4:9a2415f2ab07 20
okini3939 4:9a2415f2ab07 21 #ifdef CFG_ENABLE_WEBSOCKET
okini3939 4:9a2415f2ab07 22
okini3939 4:9a2415f2ab07 23 #include "sha1.h"
okini3939 4:9a2415f2ab07 24
okini3939 4:9a2415f2ab07 25 int GSwifi::wsOpen (const char *host, int port, const char *uri, const char *user, const char *pwd) {
okini3939 4:9a2415f2ab07 26 int cid;
okini3939 4:9a2415f2ab07 27 char cmd[CFG_CMD_SIZE], tmp[CFG_CMD_SIZE];
okini3939 4:9a2415f2ab07 28 char ip[17];
okini3939 4:9a2415f2ab07 29
okini3939 4:9a2415f2ab07 30 if (!isAssociated() || _state.status != STAT_READY) return -1;
okini3939 4:9a2415f2ab07 31
okini3939 4:9a2415f2ab07 32 if (getHostByName(host, ip)) return -1;
okini3939 4:9a2415f2ab07 33 if (! port) {
okini3939 4:9a2415f2ab07 34 port = 80;
okini3939 4:9a2415f2ab07 35 }
okini3939 4:9a2415f2ab07 36
okini3939 4:9a2415f2ab07 37 cid = open(PROTO_TCP, ip, port);
okini3939 4:9a2415f2ab07 38 if (cid < 0) return -1;
okini3939 4:9a2415f2ab07 39 DBG("ws cid %d\r\n", cid);
okini3939 4:9a2415f2ab07 40
okini3939 4:9a2415f2ab07 41 // request
okini3939 4:9a2415f2ab07 42 snprintf(cmd, sizeof(cmd), "GET %d HTTP/1.1\r\n", uri);
okini3939 4:9a2415f2ab07 43 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 44 if (host) {
okini3939 4:9a2415f2ab07 45 snprintf(cmd, sizeof(cmd), "Host: %s\r\n", host);
okini3939 4:9a2415f2ab07 46 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 47 }
okini3939 4:9a2415f2ab07 48 if (user && pwd) {
okini3939 4:9a2415f2ab07 49 snprintf(cmd, sizeof(cmd), "%s:%s", user, pwd);
okini3939 4:9a2415f2ab07 50 base64encode(cmd, strlen(cmd), tmp, sizeof(tmp));
okini3939 4:9a2415f2ab07 51 snprintf(cmd, sizeof(cmd), "Authorization: Basic %s\r\n", tmp);
okini3939 4:9a2415f2ab07 52 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 53 }
okini3939 4:9a2415f2ab07 54 strcpy(cmd, "Upgrade: websocket\r\n");
okini3939 4:9a2415f2ab07 55 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 56 strcpy(cmd, "Connection: Upgrade\r\n");
okini3939 4:9a2415f2ab07 57 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 58 getMacAddress(tmp);
okini3939 4:9a2415f2ab07 59 memcpy(&tmp[6], host, 10);
okini3939 4:9a2415f2ab07 60 base64encode(tmp, 16, cmd, sizeof(cmd));
okini3939 4:9a2415f2ab07 61 snprintf(cmd, sizeof(cmd), "Sec-WebSocket-Key: %s\r\n", tmp);
okini3939 4:9a2415f2ab07 62 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 63 strcpy(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
okini3939 4:9a2415f2ab07 64 send(cid, cmd, strlen(cmd));
okini3939 4:9a2415f2ab07 65
okini3939 4:9a2415f2ab07 66 if (wsWait(cid, 101)) {
okini3939 4:9a2415f2ab07 67 close(cid);
okini3939 4:9a2415f2ab07 68 return -1;
okini3939 4:9a2415f2ab07 69 }
okini3939 4:9a2415f2ab07 70 wsWait(cid, 0);
okini3939 4:9a2415f2ab07 71 return cid;
okini3939 4:9a2415f2ab07 72 }
okini3939 4:9a2415f2ab07 73
okini3939 4:9a2415f2ab07 74 int GSwifi::wsWait (int cid, int code) {
okini3939 4:9a2415f2ab07 75 Timer timeout;
okini3939 4:9a2415f2ab07 76 int i, n, len;
okini3939 4:9a2415f2ab07 77 char buf[CFG_DATA_SIZE], data[CFG_CMD_SIZE];
okini3939 4:9a2415f2ab07 78
okini3939 4:9a2415f2ab07 79 if (code == 0) {
okini3939 4:9a2415f2ab07 80 // dummy read
okini3939 4:9a2415f2ab07 81 timeout.start();
okini3939 4:9a2415f2ab07 82 while (timeout.read_ms() < CFG_TIMEOUT) {
okini3939 4:9a2415f2ab07 83 wait_ms(10);
okini3939 4:9a2415f2ab07 84 if (!readable(cid)) break;
okini3939 4:9a2415f2ab07 85 n = recv(cid, buf, sizeof(buf));
okini3939 4:9a2415f2ab07 86 if (n <= 0) break;
okini3939 4:9a2415f2ab07 87 }
okini3939 4:9a2415f2ab07 88 timeout.stop();
okini3939 4:9a2415f2ab07 89 return 0;
okini3939 4:9a2415f2ab07 90 }
okini3939 4:9a2415f2ab07 91
okini3939 4:9a2415f2ab07 92 // wait responce
okini3939 4:9a2415f2ab07 93 len = 0;
okini3939 4:9a2415f2ab07 94 timeout.start();
okini3939 4:9a2415f2ab07 95 while (timeout.read_ms() < CFG_TIMEOUT) {
okini3939 4:9a2415f2ab07 96 wait_ms(10);
okini3939 4:9a2415f2ab07 97 n = recv(cid, buf, sizeof(buf));
okini3939 4:9a2415f2ab07 98 for (i = 0; i < n; i ++) {
okini3939 4:9a2415f2ab07 99 if (buf[i] == '\r') continue;
okini3939 4:9a2415f2ab07 100 if (buf[i] == '\n') {
okini3939 4:9a2415f2ab07 101 if (len == 0) continue;
okini3939 4:9a2415f2ab07 102 goto next;
okini3939 4:9a2415f2ab07 103 } else
okini3939 4:9a2415f2ab07 104 if (len < sizeof(data) - 1) {
okini3939 4:9a2415f2ab07 105 data[len] = buf[i];
okini3939 4:9a2415f2ab07 106 len ++;
okini3939 4:9a2415f2ab07 107 }
okini3939 4:9a2415f2ab07 108 }
okini3939 4:9a2415f2ab07 109 }
okini3939 4:9a2415f2ab07 110 next:
okini3939 4:9a2415f2ab07 111 data[len] = 0;
okini3939 4:9a2415f2ab07 112 timeout.stop();
okini3939 4:9a2415f2ab07 113 DBG("ws: %s\r\n", data);
okini3939 4:9a2415f2ab07 114
okini3939 4:9a2415f2ab07 115 // check return code
okini3939 4:9a2415f2ab07 116 if (strncmp(data, "HTTP/1.1 ", 9) != 0) return -1;
okini3939 4:9a2415f2ab07 117 i = atoi(&data[9]);
okini3939 4:9a2415f2ab07 118 DBG("ws status %d\r\n", i);
okini3939 4:9a2415f2ab07 119 return i == code ? 0 : -1;
okini3939 4:9a2415f2ab07 120 }
okini3939 4:9a2415f2ab07 121
okini3939 4:9a2415f2ab07 122 int GSwifi::wsSend (int cid, const char *buf, int len, const char *mask) {
okini3939 4:9a2415f2ab07 123 int i = 0, r;
okini3939 4:9a2415f2ab07 124 char tmp[10];
okini3939 4:9a2415f2ab07 125
okini3939 4:9a2415f2ab07 126 tmp[i++] = 0x81; // single, text frame
okini3939 4:9a2415f2ab07 127 if (len < 126) {
okini3939 4:9a2415f2ab07 128 tmp[i++] = (mask == NULL ? 0 : 0x80) | len;
okini3939 4:9a2415f2ab07 129 } else {
okini3939 4:9a2415f2ab07 130 tmp[i++] = (mask == NULL ? 0 : 0x80) | 126;
okini3939 4:9a2415f2ab07 131 tmp[i++] = (len >> 8) & 0xff;
okini3939 4:9a2415f2ab07 132 tmp[i++] = len & 0xff;
okini3939 4:9a2415f2ab07 133 }
okini3939 4:9a2415f2ab07 134 if (mask) {
okini3939 4:9a2415f2ab07 135 memcpy(&tmp[i], mask, 4);
okini3939 4:9a2415f2ab07 136 i += 4;
okini3939 4:9a2415f2ab07 137 }
okini3939 4:9a2415f2ab07 138 r = send(cid, tmp, strlen(tmp));
okini3939 4:9a2415f2ab07 139
okini3939 4:9a2415f2ab07 140 if (r == 0) {
okini3939 4:9a2415f2ab07 141 if (mask) {
okini3939 4:9a2415f2ab07 142 char tmp2[len];
okini3939 4:9a2415f2ab07 143 for (i = 0; i < len; i ++) {
okini3939 4:9a2415f2ab07 144 tmp2[i] = buf[i] ^ mask[i & 0x03];
okini3939 4:9a2415f2ab07 145 }
okini3939 4:9a2415f2ab07 146 r = send(cid, tmp2, len);
okini3939 4:9a2415f2ab07 147 } else {
okini3939 4:9a2415f2ab07 148 r = send(cid, buf, len);
okini3939 4:9a2415f2ab07 149 }
okini3939 4:9a2415f2ab07 150 }
okini3939 4:9a2415f2ab07 151 return r;
okini3939 4:9a2415f2ab07 152 }
okini3939 4:9a2415f2ab07 153
okini3939 4:9a2415f2ab07 154 #ifdef CFG_ENABLE_HTTPD
okini3939 4:9a2415f2ab07 155
okini3939 4:9a2415f2ab07 156 void GSwifi::wsRecvData (int cid, char c) {
okini3939 4:9a2415f2ab07 157
okini3939 4:9a2415f2ab07 158 switch (_httpd[cid].mode) {
okini3939 4:9a2415f2ab07 159 case HTTPDMODE_WEBSOCKET:
okini3939 4:9a2415f2ab07 160 if (_httpd[cid].n == 0) {
okini3939 4:9a2415f2ab07 161 // flag
okini3939 4:9a2415f2ab07 162 _httpd[cid].websocket_opcode = c & 0x0f;
okini3939 4:9a2415f2ab07 163 _httpd[cid].websocket_flg = c << 8;
okini3939 4:9a2415f2ab07 164 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 165 } else
okini3939 4:9a2415f2ab07 166 if (_httpd[cid].n == 1) {
okini3939 4:9a2415f2ab07 167 // length 7bit
okini3939 4:9a2415f2ab07 168 _httpd[cid].websocket_flg |= c;
okini3939 4:9a2415f2ab07 169 _httpd[cid].length = c & 0x7f;
okini3939 4:9a2415f2ab07 170 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 171 if (_httpd[cid].length < 126) {
okini3939 4:9a2415f2ab07 172 _httpd[cid].n = 0;
okini3939 4:9a2415f2ab07 173 if (_httpd[cid].length) {
okini3939 4:9a2415f2ab07 174 if (_httpd[cid].websocket_flg & 0x0080) {
okini3939 4:9a2415f2ab07 175 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK;
okini3939 4:9a2415f2ab07 176 } else {
okini3939 4:9a2415f2ab07 177 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
okini3939 4:9a2415f2ab07 178 }
okini3939 4:9a2415f2ab07 179 } else {
okini3939 4:9a2415f2ab07 180 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER;
okini3939 4:9a2415f2ab07 181 }
okini3939 4:9a2415f2ab07 182 DBG("ws length %d\r\n", _httpd[cid].length);
okini3939 4:9a2415f2ab07 183 }
okini3939 4:9a2415f2ab07 184 } else {
okini3939 4:9a2415f2ab07 185 // length 16bit,64bit
okini3939 4:9a2415f2ab07 186 if (_httpd[cid].n == 2) {
okini3939 4:9a2415f2ab07 187 _httpd[cid].length = c;
okini3939 4:9a2415f2ab07 188 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 189 } else
okini3939 4:9a2415f2ab07 190 if (_httpd[cid].n < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) {
okini3939 4:9a2415f2ab07 191 // 64bit
okini3939 4:9a2415f2ab07 192 _httpd[cid].length = (_httpd[cid].length << 8) | c;
okini3939 4:9a2415f2ab07 193 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 194 } else {
okini3939 4:9a2415f2ab07 195 // end
okini3939 4:9a2415f2ab07 196 _httpd[cid].length = (_httpd[cid].length << 8) | c;
okini3939 4:9a2415f2ab07 197 _httpd[cid].n = 0;
okini3939 4:9a2415f2ab07 198 if (_httpd[cid].websocket_flg & 0x0080) {
okini3939 4:9a2415f2ab07 199 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK;
okini3939 4:9a2415f2ab07 200 } else {
okini3939 4:9a2415f2ab07 201 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
okini3939 4:9a2415f2ab07 202 }
okini3939 4:9a2415f2ab07 203 DBG("ws length2 %d\r\n", _httpd[cid].length);
okini3939 4:9a2415f2ab07 204 }
okini3939 4:9a2415f2ab07 205 }
okini3939 4:9a2415f2ab07 206 break;
okini3939 4:9a2415f2ab07 207 case HTTPDMODE_WEBSOCKET_MASK:
okini3939 4:9a2415f2ab07 208 // masking key
okini3939 4:9a2415f2ab07 209 _httpd[cid].websocket_mask[_httpd[cid].n] = c;
okini3939 4:9a2415f2ab07 210 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 211 if (_httpd[cid].n >= 4) {
okini3939 4:9a2415f2ab07 212 _httpd[cid].n = 0;
okini3939 4:9a2415f2ab07 213 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY;
okini3939 4:9a2415f2ab07 214 DBG("ws mask\r\n");
okini3939 4:9a2415f2ab07 215 }
okini3939 4:9a2415f2ab07 216 break;
okini3939 4:9a2415f2ab07 217 case HTTPDMODE_WEBSOCKET_BODY:
okini3939 4:9a2415f2ab07 218 // payload
okini3939 4:9a2415f2ab07 219 if (_httpd[cid].websocket_flg & 0x0080) {
okini3939 4:9a2415f2ab07 220 // un-mask
okini3939 4:9a2415f2ab07 221 _httpd[cid].buf->queue(c ^ _httpd[cid].websocket_mask[_httpd[cid].n & 0x03]);
okini3939 4:9a2415f2ab07 222 } else {
okini3939 4:9a2415f2ab07 223 _httpd[cid].buf->queue(c);
okini3939 4:9a2415f2ab07 224 }
okini3939 4:9a2415f2ab07 225 _httpd[cid].n ++;
okini3939 4:9a2415f2ab07 226 if (_httpd[cid].n >= _httpd[cid].length) {
okini3939 4:9a2415f2ab07 227 _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER;
okini3939 4:9a2415f2ab07 228 _con[cid].received = true;
okini3939 4:9a2415f2ab07 229 }
okini3939 4:9a2415f2ab07 230 break;
okini3939 4:9a2415f2ab07 231 }
okini3939 4:9a2415f2ab07 232 }
okini3939 4:9a2415f2ab07 233
okini3939 4:9a2415f2ab07 234 int GSwifi::wsParseRequest (int cid) {
okini3939 4:9a2415f2ab07 235 int i;
okini3939 4:9a2415f2ab07 236
okini3939 4:9a2415f2ab07 237 DBG("ws opcode %d\r\n", _httpd[cid].websocket_opcode);
okini3939 4:9a2415f2ab07 238 switch (_httpd[cid].websocket_opcode) {
okini3939 4:9a2415f2ab07 239 case 0x00: // continuation
okini3939 4:9a2415f2ab07 240 break;
okini3939 4:9a2415f2ab07 241 case 0x01: // text
okini3939 4:9a2415f2ab07 242 case 0x02: // binary
okini3939 4:9a2415f2ab07 243 i = httpdGetHandler(_httpd[cid].uri);
okini3939 4:9a2415f2ab07 244 if (i >= 0) {
okini3939 4:9a2415f2ab07 245 if (_httpd_handler[i].func) {
okini3939 4:9a2415f2ab07 246 // cgi
okini3939 4:9a2415f2ab07 247 _httpd_handler[i].func(cid);
okini3939 4:9a2415f2ab07 248 }
okini3939 4:9a2415f2ab07 249 }
okini3939 4:9a2415f2ab07 250 break;
okini3939 4:9a2415f2ab07 251 case 0x08: // close
okini3939 4:9a2415f2ab07 252 close(cid);
okini3939 4:9a2415f2ab07 253 break;
okini3939 4:9a2415f2ab07 254 case 0x09: // ping
okini3939 4:9a2415f2ab07 255 {
okini3939 4:9a2415f2ab07 256 char pong[_httpd[cid].n + 2];
okini3939 4:9a2415f2ab07 257 pong[0] = 0x8a;
okini3939 4:9a2415f2ab07 258 pong[1] = 0x04;
okini3939 4:9a2415f2ab07 259 for (i = 0; i < _httpd[cid].length; i ++) {
okini3939 4:9a2415f2ab07 260 if (_httpd[cid].buf->dequeue(&pong[i + 2]) == false) break;
okini3939 4:9a2415f2ab07 261 }
okini3939 4:9a2415f2ab07 262 send(cid, pong, _httpd[cid].length + 2);
okini3939 4:9a2415f2ab07 263 }
okini3939 4:9a2415f2ab07 264 break;
okini3939 4:9a2415f2ab07 265 case 0x0a: // pong
okini3939 4:9a2415f2ab07 266 break;
okini3939 4:9a2415f2ab07 267 default:
okini3939 4:9a2415f2ab07 268 break;
okini3939 4:9a2415f2ab07 269 }
okini3939 4:9a2415f2ab07 270 _httpd[cid].n = 0;
okini3939 4:9a2415f2ab07 271 _httpd[cid].length = 0;
okini3939 4:9a2415f2ab07 272 return 0;
okini3939 4:9a2415f2ab07 273 }
okini3939 4:9a2415f2ab07 274
okini3939 4:9a2415f2ab07 275 int GSwifi::wsAccept (int cid) {
okini3939 4:9a2415f2ab07 276 char buf[CFG_CMD_SIZE], buf2[CFG_CMD_SIZE];
okini3939 4:9a2415f2ab07 277
okini3939 4:9a2415f2ab07 278 DBG("websocket accept: %d\r\n", cid);
okini3939 4:9a2415f2ab07 279
okini3939 4:9a2415f2ab07 280 strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
okini3939 4:9a2415f2ab07 281 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 282 strcpy(buf, "Upgrade: websocket\r\n");
okini3939 4:9a2415f2ab07 283 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 284 strcpy(buf, "Connection: Upgrade\r\n");
okini3939 4:9a2415f2ab07 285 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 286
okini3939 4:9a2415f2ab07 287 strcpy(buf, "Sec-WebSocket-Accept: ");
okini3939 4:9a2415f2ab07 288 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 289 strcpy(buf, _httpd[cid].websocket_key);
okini3939 4:9a2415f2ab07 290 strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
okini3939 4:9a2415f2ab07 291 sha1(buf, strlen(buf), buf2);
okini3939 4:9a2415f2ab07 292 base64encode(buf2, 20, buf, sizeof(buf));
okini3939 4:9a2415f2ab07 293 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 294 strcpy(buf, "\r\n\r\n");
okini3939 4:9a2415f2ab07 295 send(cid, buf, strlen(buf));
okini3939 4:9a2415f2ab07 296 return 0;
okini3939 4:9a2415f2ab07 297 }
okini3939 4:9a2415f2ab07 298
okini3939 4:9a2415f2ab07 299 #endif
okini3939 4:9a2415f2ab07 300 #endif