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/
GSwifi_httpd.cpp
- Committer:
- gsfan
- Date:
- 2013-02-11
- Revision:
- 25:f6e5622d2930
- Parent:
- 24:5c350ae2e703
- Child:
- 26:b347ee3a1087
File content as of revision 25:f6e5622d2930:
/* Copyright (C) 2013 gsfan, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** @file * @brief Gainspan wi-fi module library for mbed * GS1011MIC, GS1011MIP, GainSpan WiFi Breakout, etc. */ #include "dbg.h" #include "mbed.h" #include "GSwifi.h" #include "sha1.h" #include <string.h> #ifdef GS_USE_HTTPD #define MIMETABLE_NUM 9 struct { char ext[5]; char type[24]; } mimetable[MIMETABLE_NUM] = { {"txt", "text/plain"}, // default {"html", "text/html"}, {"htm", "text/html"}, {"css", "text/css"}, {"js", "application/javascript"}, {"jpg", "image/jpeg"}, {"png", "image/png"}, {"gif", "image/gif"}, {"ico", "image/x-icon"}, }; int GSwifi::httpd (int port) { int i; char cmd[GS_CMD_SIZE]; if (! _connect || _status != GSSTAT_READY) return -1; memset(&_httpd, 0, sizeof(_httpd)); for (i = 0; i < 16; i ++) { _httpd[i].mode = GSHTTPDMODE_REQUEST; } _handler_count = 0; sprintf(cmd, "AT+NSTCP=%d", port); if (command(cmd, GSRES_CONNECT)) return -1; newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, NULL); /* // newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, &GSwifi::poll_httpd); // newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, reinterpret_cast<onGsReceiveFunc>(&GSwifi::poll_httpd)); void (GSwifi::*f1)(int,int) = &GSwifi::poll_httpd; onGsReceiveFunc f2 = reinterpret_cast<onGsReceiveFunc>(f1); newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, f2); */ return _cid; } void GSwifi::poll_httpd (int cid, int len) { int i, j, flg = 0; char c; if (len == 0) { // 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->dequeue(&c); if (c == '\r') continue; 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].mode == GSHTTPDMODE_BODY && _httpd[cid].len >= _httpd[cid].length) break; // end of body } 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 GSHTTPDMODE_REQUEST: if (strnicmp(_httpd[cid].buf, "GET ", 4) == 0) { _httpd[cid].type = GSPROT_HTTPGET; j = 4; } else if (strnicmp(_httpd[cid].buf, "POST ", 5) == 0) { _httpd[cid].type = GSPROT_HTTPPOST; j = 5; } else { _httpd[cid].mode = GSHTTPDMODE_ERROR; break; } // get uri for (i = j; i < _httpd[cid].len; i ++) { if (_httpd[cid].buf[i] == ' ') break; } i = i - j; if (i) { if (_httpd[cid].uri == NULL) { _httpd[cid].uri = new char[HTTPD_URI_SIZE]; } strncpy(_httpd[cid].uri, &_httpd[cid].buf[j], i); _httpd[cid].uri[i] = 0; } _httpd[cid].mode = GSHTTPDMODE_HEAD; _httpd[cid].length = 0; DBG("uri: %s\r\n", _httpd[cid].uri); break; case GSHTTPDMODE_HEAD: if (_httpd[cid].len == 0) { // 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 (strnicmp(_httpd[cid].buf, "Content-Length: ", 16) == 0) { _httpd[cid].length = atoi(&_httpd[cid].buf[16]); } else 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 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 _httpd[cid].host = _gs_sock[cid].host; j = strlen(_handler[i].uri); _httpd[cid].file = &_httpd[cid].uri[j]; _httpd[cid].query = NULL; send_websocket_accept(cid); break; // exit while } else #endif if (flg) { // http request _httpd[cid].buf[_httpd[cid].len] = 0; 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; } } 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 = GSHTTPDMODE_REQUEST; _httpd[cid].len = 0; _httpd[cid].length = 0; _httpd[cid].keepalive --; } else { close(cid); } } 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) { FILE *fp; int i, len; char buf[HTTPD_BUF_SIZE]; char file[HTTPD_URI_SIZE]; strcpy(file, dir); strcat(file, gshttpd->file); if (file[strlen(file) - 1] == '/') { strcat(file, "index.html"); } DBG("file: %s\r\n", file); fp = fopen(file, "r"); if (fp) { send(cid, "HTTP/1.1 200 OK\r\n", 17); { // file size i = ftell(fp); fseek(fp, 0, SEEK_END); len = ftell(fp); fseek(fp, i, SEEK_SET); } sprintf(buf, "Content-Length: %d\r\n", len); send(cid, buf, strlen(buf)); sprintf(buf, "Content-Type: %s\r\n", mimetype(file)); send(cid, buf, strlen(buf)); if (gshttpd->keepalive) { strcpy(buf, "Connection: Keep-Alive\r\n"); } else { strcpy(buf, "Connection: close\r\n"); } send(cid, buf, strlen(buf)); strcpy(buf, "Server: GSwifi httpd\r\n"); send(cid, buf, strlen(buf)); send(cid, "\r\n", 2); for (;;) { i = fread(buf, sizeof(char), sizeof(buf), fp); if (i <= 0) break; if (! _gs_sock[cid].connect) break; send(cid, buf, i); #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) if (feof(fp)) break; #endif } fclose(fp); 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 %d\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, len); return 0; } send_httpd_error(cid, 404); return -1; } char *GSwifi::mimetype (char *file) { int i, j; DBG("<%s>\r\n", file); for (i = 0; i < MIMETABLE_NUM; i ++) { j = strlen(mimetable[i].ext); if (file[strlen(file) - j - 1] == '.' && 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 = -1; 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]; switch (err) { case 400: strcpy(msg, "Bad Request"); break; case 403: strcpy(msg, "Forbidden"); break; case 404: strcpy(msg, "Not Found"); break; case 500: default: strcpy(msg, "Internal Server Error"); break; } DBG("httpd error: %d %d %s\r\n", cid, err, msg); sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg); send(cid, buf, strlen(buf)); strcpy(buf, "Content-Type: text/html\r\n"); send(cid, buf, strlen(buf)); send(cid, "\r\n", 2); sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg); send(cid, buf, strlen(buf)); sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg); send(cid, buf, strlen(buf)); close(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 %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err); } int GSwifi::attach_httpd (const char *uri, const char *dir) { if (_handler_count < HTTPD_HANDLE) { _handler[_handler_count].uri = new char[strlen(uri) + 1]; strcpy(_handler[_handler_count].uri, uri); _handler[_handler_count].dir = new char[strlen(dir) + 1]; strcpy(_handler[_handler_count].dir, dir); _handler[_handler_count].onHttpCgi = NULL; _handler_count ++; return 0; } else { return -1; } } int GSwifi::attach_httpd (const char *uri, onHttpdCgiFunc ponHttpCgi) { if (_handler_count < HTTPD_HANDLE) { _handler[_handler_count].uri = new char[strlen(uri) + 1]; strcpy(_handler[_handler_count].uri, uri); _handler[_handler_count].dir = NULL; _handler[_handler_count].onHttpCgi = ponHttpCgi; _handler_count ++; return 0; } else { return -1; } } #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->dequeue((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) { 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", "WEBSOCKET", _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