GainSpan Wi-Fi library see: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
Dependents: GSwifi_httpd GSwifi_websocket GSwifi_tcpclient GSwifi_tcpserver ... more
Fork of GSwifi by
GainSpan Wi-Fi library
The GS1011 is an ultra low power 802.11b wireless module from GainSpan.
see: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
ゲインスパン Wi-Fi モジュール ライブラリ
ゲインスパン社の低電力 Wi-Fiモジュール(無線LAN) GS1011 シリーズ用のライブラリです。
解説: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
Revision 23:a783c62c36d0, committed 2013-01-21
- Comitter:
- gsfan
- Date:
- Mon Jan 21 05:58:28 2013 +0000
- Parent:
- 22:9b077e2823ce
- Child:
- 24:5c350ae2e703
- Commit message:
- support websocket
Changed in this revision
--- a/GSwifi.cpp Wed Dec 26 08:41:43 2012 +0000 +++ b/GSwifi.cpp Mon Jan 21 05:58:28 2013 +0000 @@ -15,24 +15,12 @@ #include "GSwifi.h" #include <ctype.h> -#ifdef GS_UART_DIRECT -#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) -#define _gs_getc() LPC_UART1->RBR -#define _gs_putc(c) while(!(LPC_UART1->LSR & (1<<5))); LPC_UART1->THR = c -#elif defined(TARGET_LPC11U24) -#define _gs_getc() LPC_USART->RBR -#define _gs_putc(c) while(!(LPC_USART->LSR & (1<<5))); LPC_USART->THR = c -#endif -#else -#define _gs_getc() _gs.getc() -#define _gs_putc(c) _gs.putc(c) -#endif GSwifi::GSwifi (PinName p_tx, PinName p_rx, int baud) : _gs(p_tx, p_rx), _buf_cmd(GS_CMD_SIZE) { _connect = false; _status = GSSTAT_READY; _escape = 0; - _response = 1; + _response = GSRES_NONE; _gs_mode = GSMODE_COMMAND; _gs.baud(baud); @@ -44,7 +32,7 @@ _connect = false; _status = GSSTAT_READY; _escape = 0; - _response = 1; + _response = GSRES_NONE; _gs_mode = GSMODE_COMMAND; _gs.baud(baud); @@ -95,8 +83,16 @@ dat = _gs_getc(); if (flg & ((1 << 7)|(1 << 3)|(1 << 4))) return; +#ifdef DEBUG_VIEW // DBG("%02x_", dat); - +#endif +/* + if (dat >= 0x20 && dat < 0x7f) { + DBG("_%c", dat); + } else { + DBG("_%02x", dat); + } +*/ switch (_gs_mode) { case GSMODE_COMMAND: // command responce if (_escape) { @@ -145,7 +141,11 @@ _buf_cmd.put(dat); if (dat == '\n') { _gs_enter ++; - if (!_response && _connect) poll_cmd(); + DBG("* %d %d *", _response, _connect); + if (_response == GSRES_NONE && _connect) { + DBG("poll_cmd\r\n"); + poll_cmd(); + } } } } @@ -317,7 +317,7 @@ return 0; } - _response = 1; + _response = res; _buf_cmd.clear(); _gs_ok = 0; _gs_failure = 0; @@ -329,11 +329,11 @@ _gs_putc('\n'); DBG("command: %s\r\n", cmd); if (strlen(cmd) == 0) return 0; - wait_ms(10); +// wait_ms(10); if (timeout) { r = cmdResponse(res, timeout); } - _response = 0; + _response = GSRES_NONE; return r; } @@ -883,7 +883,7 @@ // received "\n" char buf[GS_CMD_SIZE]; - wait_ms(10); +// wait_ms(10); _gs_enter --; i = 0; while (_buf_cmd.use() && i < sizeof(buf)) { @@ -894,7 +894,7 @@ i ++; } buf[i] = 0; - DBG("poll: %s\r\n", buf); + DBG("poll: %d %s\r\n", _gs_enter, buf); if (i == 0) { } else @@ -1049,8 +1049,8 @@ if (! _gs_sock[cid].connect) return -1; _gs_sock[cid].connect = false; - delete _gs_sock[cid].data; - _gs_sock[cid].data = NULL; +// delete _gs_sock[cid].data; +// _gs_sock[cid].data = NULL; sprintf(cmd, "AT+NCLOSE=%X", cid); return command(cmd, GSRES_NORMAL); } @@ -1071,14 +1071,18 @@ _gs.printf("\x1bZ%X%04d", cid, len); for (i = 0; i < len; i ++) { _gs_putc(buf[i]); -// DBG("%c", buf[i]); +#ifdef DEBUG_VIEW + DBG("%c", buf[i]); +#endif } #else _gs.printf("\x1bS%X", cid); for (i = 0; i < len; i ++) { if (buf[i] >= 0x20 && buf[i] < 0x7f) { _gs_putc(buf[i]); -// DBG("%c", buf[i]); +#ifdef DEBUG_VIEW + DBG("%c", buf[i]); +#endif } } _gs_putc(0x1b); @@ -1108,7 +1112,9 @@ _gs.printf("%04d", len); for (i = 0; i < len; i ++) { _gs_putc(buf[i]); -// DBG("%c", buf[i]); +#ifdef DEBUG_VIEW + DBG("%c", buf[i]); +#endif } #else _gs.printf("\x1bU%X", cid); @@ -1116,7 +1122,9 @@ for (i = 0; i < len; i ++) { if (buf[i] >= 0x20 && buf[i] < 0x7f) { _gs_putc(buf[i]); -// DBG("%c", buf[i]); +#ifdef DEBUG_VIEW + DBG("%c", buf[i]); +#endif } } _gs_putc(0x1b); @@ -1303,7 +1311,6 @@ } int GSwifi::setBaud (int baud) { - char cmd[GS_CMD_SIZE]; if (_status != GSSTAT_READY) return -1; @@ -1418,9 +1425,19 @@ return 0; } - #ifdef DEBUG // for test +void GSwifi::dump () { + int i; + + DBG("GS mode=%d, escape=%d, cid=%d\r\n", _gs_mode, _escape, _cid); + for (i = 0; i < 16; i ++) { + DBG("%d: connect=%d, type=%d, protocol=%d, len=%d\r\n", i, _gs_sock[i].connect, _gs_sock[i].type, _gs_sock[i].protocol, _gs_sock[i].data->use()); + if (_gs_sock[i].protocol == GSPROT_HTTPD) { + DBG(" mode=%d, type=%d, len=%d\r\n", i, _httpd[i].mode, _httpd[i].type, _httpd[i].len); + } + } +} void GSwifi::test () { /*
--- a/GSwifi.h Wed Dec 26 08:41:43 2012 +0000 +++ b/GSwifi.h Mon Jan 21 05:58:28 2013 +0000 @@ -37,6 +37,19 @@ #define GS_DATA_SIZE 500 #endif +#ifdef GS_UART_DIRECT +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) +#define _gs_getc() LPC_UART1->RBR +#define _gs_putc(c) while(!(LPC_UART1->LSR & (1<<5))); LPC_UART1->THR = c +#elif defined(TARGET_LPC11U24) +#define _gs_getc() LPC_USART->RBR +#define _gs_putc(c) while(!(LPC_USART->LSR & (1<<5))); LPC_USART->THR = c +#endif +#else +#define _gs_getc() _gs.getc() +#define _gs_putc(c) _gs.putc(c) +#endif + /** * Wi-Fi security */ @@ -72,6 +85,7 @@ }; enum GSRESPONCE { + GSRES_NONE, GSRES_NORMAL, GSRES_CONNECT, GSRES_WPS, @@ -361,6 +375,9 @@ * attach uri to cgi handler */ int attach_httpd (const char *uri, onHttpdCgiFunc ponHttpCgi); +#ifdef GS_USE_WEBSOCKET + int send_websocket (int cid, const char *buf, int len); +#endif #endif /** @@ -385,6 +402,7 @@ int urldecode (char *str, char *buf, int len); #ifdef DEBUG + void dump (); void test (); int getc(); void putc(char c); @@ -405,8 +423,10 @@ #endif #ifdef GS_USE_HTTPD + int get_handler (char *uri); int httpd_request (int cid, GS_httpd *gshttpd, char *dir); char *mimetype (char *file); + int strnicmp (char *p1, char *p2, int n); #endif private: @@ -415,7 +435,7 @@ volatile bool _connect; volatile GSSTATUS _status; volatile int _gs_ok, _gs_failure, _gs_enter; - volatile int _response; + volatile GSRESPONCE _response; GSMODE _gs_mode; int _escape; int _cid, _rssi; @@ -432,6 +452,10 @@ int _handler_count; void poll_httpd (int cid, int len); +#ifdef GS_USE_WEBSOCKET + void poll_websocket (int cid, int len); + void send_websocket_accept (int cid); +#endif #endif };
--- a/GSwifi_httpd.cpp Wed Dec 26 08:41:43 2012 +0000 +++ b/GSwifi_httpd.cpp Mon Jan 21 05:58:28 2013 +0000 @@ -1,15 +1,11 @@ #include "dbg.h" #include "mbed.h" #include "GSwifi.h" +#include "sha1.h" +#include <string.h> #ifdef GS_USE_HTTPD -#define HTTPD_REQUEST 0 -#define HTTPD_HEAD 1 -#define HTTPD_SPACE 2 -#define HTTPD_BODY 3 -#define HTTPD_ERROR 4 - #define MIMETABLE_NUM 8 struct { char ext[6]; @@ -31,10 +27,9 @@ if (! _connect || _status != GSSTAT_READY) return -1; + memset(&_httpd, 0, sizeof(_httpd)); for (i = 0; i < 16; i ++) { - _httpd[i].mode = HTTPD_REQUEST; - _httpd[i].buf = NULL; - _httpd[i].uri = NULL; + _httpd[i].mode = GSHTTPDMODE_REQUEST; } _handler_count = 0; @@ -57,48 +52,62 @@ char c; if (len == 0) { - _httpd[cid].mode = HTTPD_REQUEST; + // start request + _httpd[cid].mode = GSHTTPDMODE_REQUEST; _httpd[cid].len = 0; _httpd[cid].keepalive = 0; +#ifdef GS_USE_WEBSOCKET + _httpd[cid].websocket = 0; +#endif return; } +#ifdef GS_USE_WEBSOCKET + if (_httpd[cid].mode >= GSHTTPDMODE_WEBSOCKET) { + poll_websocket(cid, len); + return; + } +#endif + while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) { flg = 0; if (_httpd[cid].buf == NULL) { _httpd[cid].buf = new char[HTTPD_BUF_SIZE]; } + // get 1 line for (j = 0; j < len; j ++) { _gs_sock[cid].data->get(&c); if (c == '\r') continue; - if (c == '\n' && _httpd[cid].mode != HTTPD_BODY) break; + if (c == '\n' && _httpd[cid].mode != GSHTTPDMODE_BODY) break; if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) { _httpd[cid].buf[_httpd[cid].len] = c; } _httpd[cid].len ++; - if (_httpd[cid].len >= _httpd[cid].length && _httpd[cid].mode == HTTPD_BODY) break; + if (_httpd[cid].mode == GSHTTPDMODE_BODY && _httpd[cid].len >= _httpd[cid].length) break; // end of body } - if (j >= len) return; + if (j >= len) return; // continue if (_httpd[cid].len < HTTPD_BUF_SIZE) { _httpd[cid].buf[_httpd[cid].len] = 0; DBG("httpd %d: %d %s (%d)\r\n", cid, _httpd[cid].mode, _httpd[cid].buf, _httpd[cid].len); } + // parse switch (_httpd[cid].mode) { - case HTTPD_REQUEST: - if (strncmp(_httpd[cid].buf, "GET ", 4) == 0) { + case GSHTTPDMODE_REQUEST: + if (strnicmp(_httpd[cid].buf, "GET ", 4) == 0) { _httpd[cid].type = GSPROT_HTTPGET; j = 4; } else - if (strncmp(_httpd[cid].buf, "POST ", 5) == 0) { + if (strnicmp(_httpd[cid].buf, "POST ", 5) == 0) { _httpd[cid].type = GSPROT_HTTPPOST; j = 5; } else { - _httpd[cid].mode = HTTPD_ERROR; + _httpd[cid].mode = GSHTTPDMODE_ERROR; break; } + // get uri for (i = j; i < _httpd[cid].len; i ++) { if (_httpd[cid].buf[i] == ' ') break; } @@ -110,79 +119,105 @@ strncpy(_httpd[cid].uri, &_httpd[cid].buf[j], i); _httpd[cid].uri[i] = 0; } - _httpd[cid].mode = HTTPD_HEAD; + _httpd[cid].mode = GSHTTPDMODE_HEAD; _httpd[cid].length = 0; DBG("uri: %s\r\n", _httpd[cid].uri); break; - case HTTPD_HEAD: + case GSHTTPDMODE_HEAD: if (_httpd[cid].len == 0) { - _httpd[cid].mode = HTTPD_BODY; + // blank line (end of header) + _httpd[cid].mode = GSHTTPDMODE_BODY; if (_httpd[cid].length == 0) flg = 1; // no body +#ifdef GS_USE_WEBSOCKET + if (_httpd[cid].websocket && _httpd[cid].websocket_key) { + // enter websocket + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET; + _httpd[cid].len = 0; + flg = 1; + } +#endif } else - if (strncmp(_httpd[cid].buf, "Content-Length: ", 16) == 0) { + if (strnicmp(_httpd[cid].buf, "Content-Length: ", 16) == 0) { _httpd[cid].length = atoi(&_httpd[cid].buf[16]); } else - if (strncmp(_httpd[cid].buf, "Connection: Keep-Alive", 22) == 0 || - strncmp(_httpd[cid].buf, "Connection: keep-alive", 22) == 0) { + if (strnicmp(_httpd[cid].buf, "Connection: Keep-Alive", 22) == 0) { if (! _httpd[cid].keepalive) { _httpd[cid].keepalive = HTTPD_KEEPALIVE; } +#ifdef GS_USE_WEBSOCKET + } else + if (strnicmp(_httpd[cid].buf, "Upgrade: websocket", 18) == 0) { + if (! _httpd[cid].websocket) _httpd[cid].websocket = 1; + } else + if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Version: ", 23) == 0) { + _httpd[cid].websocket = atoi(&_httpd[cid].buf[23]); + } else + if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Key: ", 19) == 0) { + if (_httpd[cid].websocket_key == NULL) { + _httpd[cid].websocket_key = new char[30]; + } + strncpy(_httpd[cid].websocket_key, &_httpd[cid].buf[19], 30); +#endif } break; - case HTTPD_BODY: + case GSHTTPDMODE_BODY: if (_httpd[cid].len >= _httpd[cid].length) { DBG("body: %s\r\n", _httpd[cid].buf); flg = 1; } break; + } +#ifdef GS_USE_WEBSOCKET + if (flg && _httpd[cid].mode == GSHTTPDMODE_WEBSOCKET) { + // websocket + send_websocket_accept(cid); + break; // break while + + } else +#endif if (flg) { // http request _httpd[cid].buf[_httpd[cid].len] = 0; - // scan handler - flg = 0; - for (i = 0; i < _handler_count; i ++) { - j = strlen(_handler[i].uri); - if (strncmp(_httpd[cid].uri, _handler[i].uri, j) == NULL) { - // found - _httpd[cid].host = _gs_sock[cid].host; - _httpd[cid].file = &_httpd[cid].uri[j]; - _httpd[cid].query = NULL; - for (; j < strlen(_httpd[cid].uri); j ++) { - if (_httpd[cid].uri[j] == '?') { - // query string - _httpd[cid].uri[j] = 0; - _httpd[cid].query = &_httpd[cid].uri[j + 1]; - break; - } - } - if (_handler[i].dir) { - // file - httpd_request(cid, &_httpd[cid], _handler[i].dir); - flg = 1; - } else - if (_handler[i].onHttpCgi) { - // cgi - _handler[i].onHttpCgi(cid, &_httpd[cid]); - _httpd[cid].keepalive = 0; - LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]); - LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length); - flg = 1; + i = get_handler(_httpd[cid].uri); + if (i >= 0) { + _httpd[cid].host = _gs_sock[cid].host; + j = strlen(_handler[i].uri); + _httpd[cid].file = &_httpd[cid].uri[j]; + _httpd[cid].query = NULL; + for (; j < strlen(_httpd[cid].uri); j ++) { + if (_httpd[cid].uri[j] == '?') { + // query string + _httpd[cid].uri[j] = 0; + _httpd[cid].query = &_httpd[cid].uri[j + 1]; + break; } - break; } - } - if (! flg) { + + if (_handler[i].dir) { + // file + httpd_request(cid, &_httpd[cid], _handler[i].dir); + flg = 1; + } else + if (_handler[i].onHttpCgi) { + // cgi + _handler[i].onHttpCgi(cid, &_httpd[cid]); + _httpd[cid].keepalive = 0; + LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]); + LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length); + flg = 1; + } + } else { // not found send_httpd_error(cid, 403); } if (_httpd[cid].keepalive) { - _httpd[cid].mode = HTTPD_REQUEST; + _httpd[cid].mode = GSHTTPDMODE_REQUEST; _httpd[cid].len = 0; _httpd[cid].length = 0; _httpd[cid].keepalive --; @@ -191,12 +226,25 @@ } } - if (_httpd[cid].mode == HTTPD_ERROR) { + if (_httpd[cid].mode == GSHTTPDMODE_ERROR) { send_httpd_error(cid, 400); } _httpd[cid].len = 0; - } + } // while +} + +int GSwifi::get_handler (char *uri) { + int i, j; + + for (i = 0; i < _handler_count; i ++) { + j = strlen(_handler[i].uri); + if (strncmp(uri, _handler[i].uri, j) == NULL) { + // found + return i; + } + } + return -1; } int GSwifi::httpd_request (int cid, GS_httpd *gshttpd, char *dir) { @@ -261,13 +309,26 @@ DBG("<%s>\r\n", file); for (i = 0; i < MIMETABLE_NUM; i ++) { j = strlen(mimetable[i].ext); - if (strncmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) { + if (strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) { return mimetable[i].type; } } return mimetable[0].type; } +int GSwifi::strnicmp (char *p1, char *p2, int n) { + int i, r; + char c1, c2; + + for (i = 0; i < n; i ++) { + c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i]; + c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i]; + r = c1 - c2; + if (r) break; + } + return r; +} + void GSwifi::send_httpd_error (int cid, int err) { char buf[100], msg[30]; @@ -330,4 +391,182 @@ } } +#ifdef GS_USE_WEBSOCKET +void GSwifi::poll_websocket (int cid, int len) { + int i, j, flg; + unsigned char c; + + while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) { + flg = 0; + // get 1 line + for (j = 0; j < len; j ++) { + _gs_sock[cid].data->get((char*)&c); +// DBG("_%c", c); + + switch (_httpd[cid].mode) { + case GSHTTPDMODE_WEBSOCKET: + if (_httpd[cid].len == 0) { + _httpd[cid].type = c & 0x0f; + _httpd[cid].websocket_flg = c << 8; + _httpd[cid].len ++; + } else + if (_httpd[cid].len == 1) { + _httpd[cid].websocket_flg |= c; + _httpd[cid].length = c & 0x7f; + _httpd[cid].len ++; + if (_httpd[cid].length < 126) { + _httpd[cid].len = 0; + if (_httpd[cid].websocket_flg & 0x0080) { + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK; + } else { + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY; + } + DBG("ws length %d\r\n", _httpd[cid].length); + } + } else { + // length 16bit,64bit + if (_httpd[cid].len == 2) { + _httpd[cid].length = c; + _httpd[cid].len ++; + } else + if (_httpd[cid].len < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) { + // 64bit + _httpd[cid].length = (_httpd[cid].length << 8) | c; + _httpd[cid].len ++; + } else { + _httpd[cid].length = (_httpd[cid].length << 8) | c; + _httpd[cid].len = 0; + if (_httpd[cid].websocket_flg & 0x0080) { + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK; + } else { + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY; + } + DBG("ws length2 %d\r\n", _httpd[cid].length); + } + } + break; + + case GSHTTPDMODE_WEBSOCKET_MASK: + _httpd[cid].websocket_mask[_httpd[cid].len] = c; + _httpd[cid].len ++; + if (_httpd[cid].len >= 4) { + _httpd[cid].len = 0; + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY; + DBG("ws mask\r\n"); + } + break; + + case GSHTTPDMODE_WEBSOCKET_BODY: + if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) { + if (_httpd[cid].websocket_flg & 0x0080) { + _httpd[cid].buf[_httpd[cid].len] = c ^ _httpd[cid].websocket_mask[_httpd[cid].len & 0x03]; + } else { + _httpd[cid].buf[_httpd[cid].len] = c; + } + _httpd[cid].len ++; + } + break; + } + + if (_httpd[cid].mode == GSHTTPDMODE_WEBSOCKET_BODY && _httpd[cid].len >= _httpd[cid].length) { + flg = 1; + break; + } + } + if (j >= len) return; // continue + if (_httpd[cid].len < HTTPD_BUF_SIZE) { + _httpd[cid].buf[_httpd[cid].len] = 0; + DBG("websocket %d: (%d)\r\n", cid, _httpd[cid].len); + } + + if (flg) { + // websocket request + DBG("ws type %d\r\n", _httpd[cid].type); + switch (_httpd[cid].type) { + case 0x00: // continuation + case 0x01: // text + case 0x02: // binary + i = get_handler(_httpd[cid].uri); + if (i >= 0) { + _httpd[cid].host = _gs_sock[cid].host; + j = strlen(_handler[i].uri); + _httpd[cid].file = &_httpd[cid].uri[j]; + _httpd[cid].query = NULL; + + if (_handler[i].onHttpCgi) { + // cgi + _handler[i].onHttpCgi(cid, &_httpd[cid]); + LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]); + LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length); + flg = 1; + } + } + break; + + case 0x08: // close + close(cid); + break; + + case 0x09: // ping + _gs_putc(0x8a); // pong + _gs_putc(0x04); + for (i = 0; i < _httpd[cid].len; i ++) { + _gs_putc(_httpd[cid].buf[i]); + } + break; + + case 0x0a: // pong + break; + } + _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET; + _httpd[cid].len = 0; + _httpd[cid].length = 0; + } + } // while +} + +int GSwifi::send_websocket (int cid, const char *buf, int len) { + int r; + char tmp[10]; + + tmp[0] = 0x81; // single, text frame + if (len < 126) { + tmp[1] = len; + r = send(cid, tmp, 2); + } else { + tmp[1] = 126; + tmp[2] = (len >> 8) & 0xff; + tmp[3] = len & 0xff; + r = send(cid, tmp, 4); + } + if (r == 0) { + r = send(cid, buf, len); + } + return r; +} + +void GSwifi::send_websocket_accept (int cid) { + char buf[100], buf2[20]; + + DBG("websocket accept: %d\r\n", cid); + + send(cid, "HTTP/1.1 101 Switching Protocols\r\n", 34); + send(cid, "Upgrade: websocket\r\n", 20); + send(cid, "Connection: Upgrade\r\n", 21); + + send(cid, "Sec-WebSocket-Accept: ", 22); + strcpy(buf, _httpd[cid].websocket_key); + strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + sha1(buf, strlen(buf), buf2); + base64encode(buf2, 20, buf, sizeof(buf)); + send(cid, buf, strlen(buf)); + send(cid, "\r\n", 2); + +// send(cid, "Sec-WebSocket-Protocol: chat\r\n", 30); + send(cid, "\r\n", 2); + LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]); + LOG("%s %s %d 101 - %s\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, buf); +} #endif + +#endif
--- a/GSwifi_net.h Wed Dec 26 08:41:43 2012 +0000 +++ b/GSwifi_net.h Mon Jan 21 05:58:28 2013 +0000 @@ -17,6 +17,7 @@ #include "host.h" #define GS_USE_HTTPD // comment out if not use httpd +#define GS_USE_WEBSOCKET #define GS_USE_SMTP // comment out if not use smtp #define GS_SYSLOG // log for stdout @@ -46,8 +47,19 @@ #define HTTPD_KEEPALIVE 10 // request count +enum GSHTTPDMODE { + GSHTTPDMODE_REQUEST, + GSHTTPDMODE_HEAD, + GSHTTPDMODE_SPACE, + GSHTTPDMODE_BODY, + GSHTTPDMODE_ERROR, + GSHTTPDMODE_WEBSOCKET, + GSHTTPDMODE_WEBSOCKET_MASK, + GSHTTPDMODE_WEBSOCKET_BODY, +}; + struct GS_httpd { - int mode; + GSHTTPDMODE mode; int type; char *buf; // body int len; // length of buf @@ -57,6 +69,13 @@ int length; // content-length int keepalive; Host host; +#ifdef GS_USE_WEBSOCKET + int websocket; + char *websocket_key; + int websocket_flg; + char websocket_mask[4]; + int websocket_payload; +#endif }; typedef void (*onHttpdCgiFunc)(int cid, GS_httpd *gshttpd);
--- a/dbg.h Wed Dec 26 08:41:43 2012 +0000 +++ b/dbg.h Mon Jan 21 05:58:28 2013 +0000 @@ -1,4 +1,5 @@ //#define DEBUG +//#define DEBUG_VIEW #ifdef DEBUG #define DBG(...) printf("" __VA_ARGS__)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sha1.cpp Mon Jan 21 05:58:28 2013 +0000 @@ -0,0 +1,364 @@ +/* + * source from http://www.ipa.go.jp/security/rfc/RFC3174JA.html + */ +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const uint8_t *message_array, + unsigned length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} + +void sha1 (const char *input, int len, char *output) { + SHA1Context sha; + + SHA1Reset(&sha); + SHA1Input(&sha, (unsigned char*)input, len); + SHA1Result(&sha, (uint8_t*)output); + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sha1.h Mon Jan 21 05:58:28 2013 +0000 @@ -0,0 +1,78 @@ +/* + * source from http://www.ipa.go.jp/security/rfc/RFC3174JA.html + */ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include "mbed.h" +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typdef the following: + * name meaning + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + + +void sha1 (const char *input, int len, char *output); +#endif