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
GainSpan Wi-Fi library
The GS1011/GS2100 is an ultra low power 802.11b wireless module from GainSpan.
mbed RTOS supported.
- about this library: http://mbed.org/users/gsfan/notebook/GSwifiInterface/
- about Wi-Fi module: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
ゲインスパン Wi-Fi モジュール ライブラリ
ゲインスパン社の低電力 Wi-Fiモジュール(無線LAN) GS1011/GS2100 シリーズ用のライブラリです。
mbed RTOS に対応しています。(mbed2.0)
- このライブラリについて: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
- Wi-FIモジュールについて: http://mbed.org/users/gsfan/notebook/gainspan_wifi/
- UARTコマンド、SPIデータインターフェースに対応しました。(2019/09)
Revision 12:057089026a20, committed 2013-11-22
- Comitter:
- gsfan
- Date:
- Fri Nov 22 14:03:07 2013 +0000
- Parent:
- 11:71d67fea5ace
- Child:
- 13:189e04ac70bd
- Commit message:
- add more function (smtp, http, httpd, websocket); fix some function;
Changed in this revision
--- a/GSwifi/CBuffer.h Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/CBuffer.h Fri Nov 22 14:03:07 2013 +0000 @@ -41,8 +41,9 @@ void queue(T k) { if (isFull()) { - read++; - read %= size; +// read++; +// read %= size; + return; } buf[write++] = k; write %= size;
--- a/GSwifi/GSwifi.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -63,6 +63,7 @@ strncpy(_state.name, CFG_DHCPNAME, sizeof(_state.name)); } clearFlags(); + _state.mode = MODE_COMMAND; sendCommand(NULL, RES_NULL, 0); if (cmdE(false)) return -1; if (_flow) { @@ -156,6 +157,7 @@ _state.wm = WM_ADHOCK; _state.initialized = true; clearFlags(); + _state.mode = MODE_COMMAND; sendCommand(NULL, RES_NULL, 0); if (cmdE(false)) return -1; if (_flow) { @@ -204,6 +206,7 @@ strncpy(_state.name, CFG_DNSNAME, sizeof(_state.name)); } clearFlags(); + _state.mode = MODE_COMMAND; sendCommand(NULL, RES_NULL, 0); if (cmdE(false)) return -1; if (_flow) { @@ -245,7 +248,7 @@ return r; } -int GSwifi::disconnect() +int GSwifi::dissociate() { int i; @@ -274,7 +277,7 @@ } -bool GSwifi::isConnected() +bool GSwifi::isAssociated() { return _state.associated; } @@ -283,7 +286,7 @@ #ifndef CFG_ENABLE_RTOS static int t = 0; - if (_state.wm == WM_INFRASTRUCTURE && (! isConnected()) && _state.ssid) { + if (_state.wm == WM_INFRASTRUCTURE && (! isAssociated()) && _state.ssid) { if (t && time(NULL) > t) { // Wi-Fi re-associate if (_state.initialized) { @@ -306,7 +309,7 @@ t = time(NULL) + CFG_RECONNECT; } #else - if (_state.wm == WM_INFRASTRUCTURE && (! isConnected()) && _state.ssid) { + if (_state.wm == WM_INFRASTRUCTURE && (! isAssociated()) && _state.ssid) { // Wi-Fi re-associate if (_state.initialized) { if (!cmdWA(_state.ssid)) { @@ -317,6 +320,20 @@ } } #endif + + for (int i = 0; i < 16; i ++) { + if (isConnected(i) && _con[i].received && _con[i].buf) + if (_con[i].func != NULL && !_con[i].buf->isEmpty()) { + _con[i].func(i); + if (_con[i].buf->isEmpty()) { + _con[i].received = false; + } + } + } + +#ifdef CFG_ENABLE_HTTPD + httpdPoll(); +#endif } #ifdef CFG_ENABLE_RTOS @@ -330,7 +347,7 @@ Thread::signal_wait(1); Thread::wait(1000); INFO("disassociated"); - while (!_wifi->isConnected()){ + while (!_wifi->isAssociated()){ _wifi->poll(); Thread::wait(CFG_TIMEOUT); } @@ -338,6 +355,22 @@ } #endif +GSwifi::Status GSwifi::getStatus () { + return _state.status; +} + +int GSwifi::setMacAddress (const char *mac) { + if (cmdNMAC(mac)) return -1; + strncpy(_state.mac, mac, sizeof(_state.mac)); + return 0; +} + +int GSwifi::getMacAddress (char *mac) { + if (cmdNMAC()) return -1; + strcpy(mac, _state.mac); + return 0; +} + int GSwifi::setAddress (const char *name) { _state.dhcp = true; strncpy(_state.name, name, sizeof(_state.name));
--- a/GSwifi/GSwifi.h Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi.h Fri Nov 22 14:03:07 2013 +0000 @@ -42,9 +42,6 @@ #include "rtos.h" #endif -#define MSG_TABLE_NUM 15 -#define RES_TABLE_NUM 10 - //Debug is disabled by default #if defined(DEBUG) and (!defined(TARGET_LPC11U24)) #define DBG(x, ...) std::printf("[DBG]" x "\r\n", ##__VA_ARGS__); @@ -146,10 +143,10 @@ * \param cts mbed pin to use for cts line of Serial interface * \param rts mbed pin to use for rts line of Serial interface * \param reset reset pin of the wifi module - * \param alarm alarm pin of the wifi module - * \param baud baud rate of Serial interface + * \param alarm alarm pin of the wifi module (default NULL) + * \param baud baud rate of Serial interface (default 9600) */ - GSwifi (PinName tx, PinName rx, PinName cts, PinName rts, PinName reset, PinName alarm, int baud); + GSwifi (PinName tx, PinName rx, PinName cts, PinName rts, PinName reset, PinName alarm = NC, int baud = 9600); /** Connect the wifi module to the ssid contained in the constructor. * @param sec Security type (NONE, WEP_128 or WPA) @@ -178,18 +175,51 @@ /** Disconnect the wifi module from the access point * @returns 0 if successful */ - int disconnect (); + int dissociate (); + int disconnect () { + return dissociate(); + } - /** Check if a tcp link is active + /** Check if a Wi-Fi link is active * @returns true if successful */ - bool isConnected(); + bool isAssociated(); + /** polling if not use rtos + */ void poll (); + /** get Wi-Fi modue status + * @return Status + */ + Status getStatus (); + + /** set MAC address + */ + int setMacAddress (const char *mac); + /** get MAC address + */ + int getMacAddress (char *mac); + + /** use DHCP + */ int setAddress (const char *name = NULL); + /** use static IP address + * @param ip my ip address (dhcp start address) + * @param netmask subnet mask + * @param gateway default gateway + * @param dns my host name (default NULL) + */ int setAddress (const char *ip, const char *netmask, const char *gateway, const char *name = NULL); + /** get IP address + */ int getAddress (char *ip, char *netmask, char *gateway); + + /** set Wi-Fi security parameter + * @param sec Security + * @param ssid SSID + * @param pass pass phrase + */ int setSsid (Security sec, const char *ssid, const char *phrase); static GSwifi * getInstance() { @@ -199,7 +229,7 @@ // ----- GSwifi_util.cpp ----- int setRegion (int reg); - /** RSSI + /** get RSSI * @return RSSI (dBm) */ int getRssi (); @@ -266,12 +296,12 @@ /** TCP/UDP client * @return CID, -1:failure */ - int open (Protocol proto, const char *ip, int port, int src = 0); + int open (Protocol proto, const char *ip, int port, int src = 0, void(*func)(int) = NULL); /** TCP/UDP server * @return CID, -1:failure */ - int listen (Protocol proto, int port); + int listen (Protocol proto, int port, void(*func)(int) = NULL); /** close client/server */ @@ -281,8 +311,7 @@ */ int send (int cid, const char *buf, int len); - /* - * send data udp(s) + /** send data udp(s) */ int sendto (int cid, const char *buf, int len, const char *ip, int port); @@ -308,12 +337,70 @@ int getRemote(int cid, char **ip, int *port); // ----- GSwifi_http.cpp ----- - int httpGet (const char *host, int port, const char *uri, bool ssl = false, const char *user = NULL, const char *pwd = NULL); - int httpPost (const char *host, int port, const char *uri, const char *body, bool ssl = false, const char *user = NULL, const char *pwd = NULL); + /** http request (GET method) + */ + int httpGet (const char *host, int port, const char *uri, bool ssl = false, const char *user = NULL, const char *pwd = NULL, void(*func)(int) = NULL); + int httpGet (const char *host, int port, const char *uri, void(*func)(int) = NULL) { + return httpGet(host, port, uri, false, NULL, NULL, func); + } + /** http request (POST method) + */ + int httpPost (const char *host, int port, const char *uri, const char *body, bool ssl = false, const char *user = NULL, const char *pwd = NULL, void(*func)(int) = NULL); + int httpPost (const char *host, int port, const char *uri, const char *body, void(*func)(int) = NULL) { + return httpPost(host, port, uri, body, false, NULL, NULL, func); + } + int base64encode (const char *input, int length, char *output, int len); int urlencode (const char *str, char *buf, int len); int urldecode (const char *str, char *buf, int len); +#ifdef CFG_ENABLE_HTTPD + // ----- GSwifi_httpd.cpp ----- + /** start http server + * @param port + */ + int httpd (int port = 80); + + // ----- GSwifi_httpd_util.cpp ----- + /** attach uri to dirctory handler + */ + void httpdError (int cid, int err); + /** attach uri to dirctory handler + */ + int httpdAttach (const char *uri, const char *dir); + /** attach uri to cgi handler + */ + int httpdAttach (const char *uri, void (*funcCgi)(int)); +#endif + +#ifdef CFG_ENABLE_WEBSOCKET + // ----- GSwifi_httpd_ws.cpp ----- + /** websocket request (Upgrade method) + * @return CID, -1:failure + */ + int wsOpen (const char *host, int port, const char *uri, const char *user = NULL, const char *pwd = NULL); + /** send websocket data + */ + int wsSend (int cid, const char *buf, int len, const char *mask = NULL); +#endif + +#ifdef CFG_ENABLE_SMTP + // ----- GSwifi_smtp.cpp ----- + /** send mail (smtp) + * @param host SMTP server + * @param port SMTP port (25 or 587 or etc.) + * @param to To address + * @param from From address + * @param subject Subject + * @param mesg Message + * @param user username (SMTP Auth) + * @param pwd password (SMTP Auth) + * @retval 0 success + * @retval -1 failure + */ + int mail (const char *host, int port, const char *to, const char *from, const char *subject, const char *mesg, const char *user = NULL, const char *pwd = NULL); +#endif + // ----- GSwifi_msg.cpp ----- // ----- GSwifi_at.cpp ----- @@ -353,6 +440,8 @@ LPC_UART1_TypeDef *_uart; #elif defined(TARGET_LPC11U24) LPC_USART_Type *_uart; +#elif defined(TARGET_LPC11XX) + LPC_UART_TypeDef *_uart; #endif DigitalInOut _reset; DigitalInOut *_alarm; @@ -395,20 +484,110 @@ volatile bool received; volatile int parent; volatile bool accept; + void(*func)(int); } _con[16]; +#ifdef CFG_ENABLE_HTTPD + enum HttpdMode { + HTTPDMODE_REQUEST, + HTTPDMODE_REQUEST_STR, + HTTPDMODE_HEADER, + HTTPDMODE_BODY, + HTTPDMODE_ENTER, + HTTPDMODE_ERROR, + HTTPDMODE_WEBSOCKET, + HTTPDMODE_WEBSOCKET_MASK, + HTTPDMODE_WEBSOCKET_BODY, + HTTPDMODE_WEBSOCKET_ENTER, + }; + + enum HttpdReq { + REQ_HTTPGET, + REQ_HTTPPOST, + }; + + struct HTTPD { + HttpdMode mode; + HttpdReq req; + CircBuffer <char>*buf; + char *uri; + char *filename; + char *querystring; + int enter; + int length; + int n; + int keepalive; +#ifdef CFG_ENABLE_WEBSOCKET + int websocket; + char *websocket_key; + int websocket_opcode; + int websocket_flg; + char websocket_mask[4]; + int websocket_payload; +#endif + } _httpd[16]; + + struct HTTPD_HANDLER { + char *uri; + char *dir; + void (*func)(int); + } _httpd_handler[CFG_HTTPD_HANDLER_NUM]; + + int _httpd_cid; + int _handler_count; +#endif // CFG_ENABLE_HTTPD + // ----- GSwifi.cpp ----- #ifdef CFG_ENABLE_RTOS static void threadPoll (void const *args); #endif + // ----- GSwifi_sock.cpp ----- + void initCon (int cid, bool connected); + // ----- GSwifi_util.cpp ----- int x2i (char c); char i2x (int i); int from_hex (int ch); int to_hex (int code); + // ----- GSwifi_http.cpp ----- + +#ifdef CFG_ENABLE_HTTPD + // ----- GSwifi_httpd.cpp ----- + void httpdRecvData (int cid, char c); + int httpdParseRequest (int cid); + void httpdPoll (); + int httpdParseHeader (int cid); + void reqContentLength (int cid, const char *buf); + void reqConnection (int cid, const char *buf); + void reqUpgrade (int cid, const char *buf); + void reqWebSocketVersion (int cid, const char *buf); + void reqWebSocketKey (int cid, const char *buf); + + // ----- GSwifi_httpd_util.cpp ----- + int httpdFile (int cid, char *dir); + int httpdGetHandler (const char *uri); + char *mimetype (char *file); + int strnicmp (const char *p1, const char *p2, int n); +#endif + +#ifdef CFG_ENABLE_WEBSOCKET + // ----- GSwifi_httpd_ws.cpp ----- + int wsWait (int cid, int code); +#ifdef CFG_ENABLE_HTTPD + void wsRecvData (int cid, char c); + int wsParseRequest (int cid); + int wsAccept (int cid); +#endif +#endif + +#ifdef CFG_ENABLE_SMTP + // ----- GSwifi_smtp.cpp ----- + int smtpWait (int cid, int code); +#endif + // ----- GSwifi_msg.cpp ----- void recvData (char c); int parseMessage (); @@ -430,6 +609,7 @@ void resTime (const char*); void resChannel (const char*); void resStatus (const char*); + void resHttp (const char *buf); // ----- GSwifi_at.cpp ----- void clearFlags ();
--- a/GSwifi/GSwifi_at.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_at.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -331,7 +331,7 @@ } else { sprintf(cmd, "AT+HTTPOPEN=%s,%d", s, n); } - return sendCommand(cmd, RES_CONNECT, CFG_TIMEOUT); + return sendCommand(cmd, RES_HTTP, CFG_TIMEOUT); } int GSwifi::cmdHTTPSEND (int n, bool m, const char *s, int t) { @@ -341,7 +341,7 @@ } else { sprintf(cmd, "AT+HTTPSEND=%d,1,%d,%s", n, CFG_TIMEOUT / 1000, s); } - return sendCommand(cmd, RES_CONNECT, CFG_TIMEOUT); + return sendCommand(cmd); } int GSwifi::cmdHTTPCLOSE (int n) {
--- a/GSwifi/GSwifi_conf.h Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_conf.h Fri Nov 22 14:03:07 2013 +0000 @@ -1,8 +1,13 @@ -#define DEBUG +//#define DEBUG +//#define DEBUG_DUMP #define CFG_ENABLE_RTOS +//#define CFG_ENABLE_HTTPD +//#define CFG_ENABLE_WEBSOCKET +//#define CFG_ENABLE_SMTP //#define CFG_UART_DIRECT + #define CFG_UART_BAUD 9600 #define CFG_WREGDOMAIN 2 // 0:FCC, 1:ETSI, 2:TELEC #define CFG_DHCPNAME "mbed-gswifi" @@ -13,11 +18,17 @@ #define DEFAULT_WAIT_RESP_TIMEOUT 500 #define CFG_TIMEOUT 30000 // ms -#define CFG_CMD_SIZE 100 -#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) +#define CFG_CMD_SIZE 128 + +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC176X) #define CFG_DATA_SIZE 1024 -#elif defined(TARGET_LPC11U24) -#define CFG_DATA_SIZE 128 -#elif defined(TARGET_LPC4088) +#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC1114) || defined(TARGET_LPC11XX) +#define CFG_DATA_SIZE 256 +#elif defined(TARGET_LPC4088) || defined(TARGET_LPC408X) #define CFG_DATA_SIZE 4096 +#elif defined(TARGET_KL25Z) +#define CFG_DATA_SIZE 512 #endif + +#define CFG_HTTPD_HANDLER_NUM 10 +#define CFG_HTTPD_KEEPALIVE 10
--- a/GSwifi/GSwifi_hal.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_hal.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -101,7 +101,7 @@ t.start(); while (_state.mode != MODE_COMMAND) { if (t.read_ms() >= ms) { - WARN("lock timeout\r\n"); + WARN("lock timeout (%d)\r\n", _state.mode); return -1; } } @@ -155,7 +155,6 @@ if (_baud) _gs.baud(_baud); _gs.attach(this, &GSwifi::isrUart, Serial::RxIrq); - _uart = NULL; _cts = NULL; _rts = NULL; _flow = 0;
--- a/GSwifi/GSwifi_http.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_http.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -18,11 +18,11 @@ #include "GSwifi.h" -int GSwifi::httpGet (const char *host, int port, const char *uri, bool ssl, const char *user, const char *pwd) { +int GSwifi::httpGet (const char *host, int port, const char *uri, bool ssl, const char *user, const char *pwd, void(*func)(int)) { char ip[17]; int cid; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; if (getHostByName(host, ip)) return -1; if (! port) { @@ -53,17 +53,18 @@ cid = _state.cid; _con[cid].protocol = PROTO_HTTPGET; _con[cid].type = TYPE_CLIENT; + _con[cid].func = func; cmdHTTPSEND(cid, false, uri); // GET return cid; } -int GSwifi::httpPost (const char *host, int port, const char *uri, const char *body, bool ssl, const char *user, const char *pwd) { +int GSwifi::httpPost (const char *host, int port, const char *uri, const char *body, bool ssl, const char *user, const char *pwd, void(*func)(int)) { char cmd[CFG_CMD_SIZE]; char ip[17]; int cid, len; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; if (getHostByName(host, ip)) return -1; if (! port) { @@ -96,6 +97,7 @@ cid = _state.cid; _con[cid].protocol = PROTO_HTTPPOST; _con[cid].type = TYPE_CLIENT; + _con[cid].func = func; cmdHTTPSEND(cid, true, uri, len); // POST sprintf(cmd, "\x1bH%X", cid); @@ -104,7 +106,6 @@ } - /* base64encode code from * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/GSwifi_httpd.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -0,0 +1,294 @@ +/* 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. + */ + +#include "GSwifi.h" + +#ifdef CFG_ENABLE_HTTPD + +int GSwifi::httpd (int port) { + int i; + + if (!isAssociated() || _state.status != STAT_READY) return -1; + + memset(&_httpd, 0, sizeof(_httpd)); + for (i = 0; i < 16; i ++) { + _httpd[i].mode = HTTPDMODE_REQUEST; + } + _handler_count = 0; + + _httpd_cid = listen(PROTO_TCP, port); + if (_httpd_cid < 0) return -1; + + _con[_httpd_cid].protocol = PROTO_HTTPD; + return _httpd_cid; +} + +void GSwifi::httpdRecvData (int cid, char c) { + + switch (_httpd[cid].mode) { + case HTTPDMODE_REQUEST: + if (_con[cid].buf == NULL) + _con[cid].buf = new CircBuffer<char>(CFG_DATA_SIZE); + _httpd[cid].buf = _con[cid].buf; + _httpd[cid].buf->flush(); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + _httpd[cid].buf->queue(c); + _httpd[cid].mode = HTTPDMODE_REQUEST_STR; + } + break; + case HTTPDMODE_REQUEST_STR: + switch (c) { + case 0: + case 0x0d: // CR + break; + case 0x0a: // LF + if (httpdParseRequest(cid)) { + _httpd[cid].mode = HTTPDMODE_REQUEST_STR; + } else { + _httpd[cid].mode = HTTPDMODE_HEADER; + } + _httpd[cid].enter = 0; + break; + default: + _httpd[cid].buf->queue(c); + break; + } + break; + case HTTPDMODE_HEADER: + switch (c) { + case 0: + case 0x0d: // CR + break; + case 0x0a: // LF + if (_httpd[cid].buf->available() == 0) { +// if ((_httpd[cid].enter == 0x0d && c == 0x0a) || (_httpd[cid].enter == 0x0a && c == 0x0a)) { + if (_httpd[cid].enter == 0x0a && c == 0x0a) { + _httpd[cid].buf->flush(); +#ifdef CFG_ENABLE_WEBSOCKET + if (_httpd[cid].websocket) { + INFO("MODE_WEBSOCKET"); + wsAccept(cid); + _httpd[cid].mode = HTTPDMODE_WEBSOCKET; + } else +#endif + if (_httpd[cid].length) { + INFO("MODE_BODY"); + _httpd[cid].mode = HTTPDMODE_BODY; + } else { + INFO("MODE_ENTER"); + _httpd[cid].mode = HTTPDMODE_ENTER; + _con[cid].received = true; + } + } + _httpd[cid].buf->flush(); + _httpd[cid].enter = c; + break; + } + + httpdParseHeader(cid); + _httpd[cid].enter = c; + break; + default: + _httpd[cid].buf->queue(c); + _httpd[cid].enter = 0; + break; + } + break; + case HTTPDMODE_BODY: + _httpd[cid].buf->queue(c); + if (_httpd[cid].buf->available() >= _httpd[cid].length) { + _httpd[cid].mode = HTTPDMODE_ENTER; + _con[cid].received = true; + } + break; +#ifdef CFG_ENABLE_WEBSOCKET + case HTTPDMODE_WEBSOCKET: + case HTTPDMODE_WEBSOCKET_MASK: + case HTTPDMODE_WEBSOCKET_BODY: + wsRecvData(cid, c); + break; +#endif + } +} + +void GSwifi::httpdPoll () { + for (int cid = 0; cid < 16; cid ++) { + if (isConnected(cid) && _con[cid].protocol == PROTO_HTTPD) { + + if (_httpd[cid].mode == HTTPDMODE_ENTER) { + int i = httpdGetHandler(_httpd[cid].uri); + if (i >= 0) { + if (_httpd_handler[i].dir) { + // file + httpdFile(cid, _httpd_handler[i].dir); + } else + if (_httpd_handler[i].func) { + // cgi + _httpd_handler[i].func(cid); +// _httpd[cid].keepalive = 0; + } else { + httpdError(cid, 403); + } + } else { + httpdError(cid, 404); + } + + if (_httpd[cid].keepalive) { + DBG("keepalive %d", _httpd[cid].keepalive); + _httpd[cid].keepalive --; + } else { + close(cid); + } + _httpd[cid].mode = HTTPDMODE_REQUEST; +#ifdef CFG_ENABLE_WEBSOCKET + } else + if (_httpd[cid].mode == HTTPDMODE_WEBSOCKET_ENTER) { + wsParseRequest(cid); + _httpd[cid].mode = HTTPDMODE_WEBSOCKET; +#endif + } + + } + } +} + +int GSwifi::httpdParseRequest (int cid) { + int i, j, len; + char buf[CFG_CMD_SIZE]; + + for (len = 0; len < sizeof(buf); len++) { + if (_httpd[cid].buf->dequeue(&buf[len]) == false) break; + } + buf[len] = 0; + + if (strnicmp(buf, "GET ", 4) == 0) { + _httpd[cid].req = REQ_HTTPGET; + j = 4; + } else + if (strnicmp(buf, "POST ", 5) == 0) { + _httpd[cid].req = REQ_HTTPPOST; + j = 5; + } else { + return -1; + } + + if (_httpd[cid].uri == NULL) + _httpd[cid].uri = (char*)malloc(CFG_CMD_SIZE); + + for (i = 0; i < len - j; i ++) { + _httpd[cid].uri[i] = buf[i + j]; + if (buf[i + j] == ' ' || i >= CFG_CMD_SIZE - 1) { + _httpd[cid].uri[i] = 0; + INFO("URI %d '%s'", _httpd[cid].req, _httpd[cid].uri); + _httpd[cid].mode = HTTPDMODE_HEADER; + _httpd[cid].buf->flush(); + _httpd[cid].length = 0; + _httpd[cid].n = 0; + _httpd[cid].filename = NULL; + _httpd[cid].querystring = NULL; +#ifdef CFG_ENABLE_WEBSOCKET + _httpd[cid].websocket = 0; +#endif + break; + } + } + + i = httpdGetHandler(_httpd[cid].uri); + if (i >= 0) { + _httpd[cid].filename = &_httpd[cid].uri[strlen(_httpd_handler[i].uri)]; + for (i = 0; i < strlen(_httpd[cid].filename); i ++) { + if (_httpd[cid].filename[i] == '?') { + _httpd[cid].filename[i] = 0; + _httpd[cid].querystring = _httpd[cid].filename + i + 1; + break; + } + } + INFO("FILE '%s' QUERY '%s'", _httpd[cid].filename, _httpd[cid].querystring); + } + return 0; +} + +#define HEADER_TABLE_NUM 5 +int GSwifi::httpdParseHeader (int cid) { + int i; + char buf[CFG_CMD_SIZE]; + static const struct HEADER_TABLE { + const char header[24]; + void (GSwifi::*func)(int id, const char*); + } header_table[HEADER_TABLE_NUM] = { + {"Content-Length:", &GSwifi::reqContentLength}, + {"Connection:", &GSwifi::reqConnection}, + {"Upgrade: websocket", &GSwifi::reqUpgrade}, + {"Sec-WebSocket-Version:", &GSwifi::reqWebSocketVersion}, + {"Sec-WebSocket-Key:", &GSwifi::reqWebSocketKey}, + }; + for (i = 0; i < sizeof(buf); i++) { + if (_httpd[cid].buf->dequeue(&buf[i]) == false) break; + } + buf[i] = 0; + + for (i = 0; i < HEADER_TABLE_NUM; i ++) { + if (strnicmp(buf, header_table[i].header, strlen(header_table[i].header)) == 0) { + DBG("parse header %d '%s'\r\n", i, buf); + if (header_table[i].func != NULL) { + (this->*(header_table[i].func))(cid, buf); + } + return 0; + } + } + + return -1; +} + +void GSwifi::reqContentLength (int cid, const char *buf) { + _httpd[cid].length = atoi(&buf[16]); +} + +void GSwifi::reqConnection (int cid, const char *buf) { + if (strnicmp(&buf[12], "Keep-Alive", 10) == 0 && _httpd[cid].keepalive == 0) { + _httpd[cid].keepalive = CFG_HTTPD_KEEPALIVE; + } else { + _httpd[cid].keepalive = 0; + } +} + +#ifdef CFG_ENABLE_WEBSOCKET +void GSwifi::reqUpgrade (int cid, const char *buf) { + if (! _httpd[cid].websocket) _httpd[cid].websocket = 1; +} + +void GSwifi::reqWebSocketVersion (int cid, const char *buf) { + _httpd[cid].websocket = atoi(&buf[23]); +} + +void GSwifi::reqWebSocketKey (int cid, const char *buf) { + if (_httpd[cid].websocket_key == NULL) { + _httpd[cid].websocket_key = (char*)malloc(30); + } + strncpy(_httpd[cid].websocket_key, &buf[19], 30); +} +#else +void GSwifi::reqUpgrade (int cid, const char *buf) { +} +void GSwifi::reqWebSocketVersion (int cid, const char *buf) { +} +void GSwifi::reqWebSocketKey (int cid, const char *buf) { +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/GSwifi_httpd_util.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -0,0 +1,196 @@ +/* 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. + */ + +#include "GSwifi.h" + +#ifdef CFG_ENABLE_HTTPD + +int GSwifi::httpdFile (int cid, char *dir) { + FILE *fp; + int i, len; + char buf[CFG_DATA_SIZE]; + char file[CFG_CMD_SIZE]; + + INFO("httpdFile %d %s", cid, dir); + + strcpy(file, dir); + strcat(file, _httpd[cid].filename); + if (file[strlen(file) - 1] == '/') { + strcat(file, "index.html"); + } + DBG("file: %s\r\n", file); + + fp = fopen(file, "r"); + if (fp) { + strcpy(buf, "HTTP/1.1 200 OK\r\n"); + send(cid, buf, strlen(buf)); + { + // file size + i = ftell(fp); + fseek(fp, 0, SEEK_END); + len = ftell(fp); + fseek(fp, i, SEEK_SET); + } + + strcpy(buf, "Server: GSwifi httpd\r\n"); + send(cid, buf, strlen(buf)); + if (_httpd[cid].keepalive) { + strcpy(buf, "Connection: Keep-Alive\r\n"); + } else { + strcpy(buf, "Connection: close\r\n"); + } + send(cid, buf, strlen(buf)); + sprintf(buf, "Content-Type: %s\r\n", mimetype(file)); + send(cid, buf, strlen(buf)); + sprintf(buf, "Content-Length: %d\r\n\r\n", len); + send(cid, buf, strlen(buf)); + + for (;;) { + i = fread(buf, sizeof(char), sizeof(buf), fp); + if (i <= 0) break; + send(cid, buf, i); +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) + if (feof(fp)) break; +#endif + } + fclose(fp); + return 0; + } + + httpdError(cid, 404); + return -1; +} + +void GSwifi::httpdError (int cid, int err) { + char buf[CFG_CMD_SIZE], 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\r\n"); + send(cid, buf, strlen(buf)); + + 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)); + wait_ms(100); + close(cid); +// WARN("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]); +// WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err); +} + +int GSwifi::httpdGetHandler (const char *uri) { + int i; + + for (i = 0; i < _handler_count; i ++) { + if (strncmp(uri, _httpd_handler[i].uri, strlen(_httpd_handler[i].uri)) == NULL) { + // found + return i; + } + } + return -1; +} + +int GSwifi::httpdAttach (const char *uri, const char *dir) { + if (_handler_count < CFG_HTTPD_HANDLER_NUM) { + _httpd_handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1); + strcpy(_httpd_handler[_handler_count].uri, uri); + _httpd_handler[_handler_count].dir = (char*)malloc(strlen(dir) + 1); + strcpy(_httpd_handler[_handler_count].dir, dir); + _httpd_handler[_handler_count].func = NULL; + DBG("httpdAttach %s %s\r\n", _httpd_handler[_handler_count].uri, _httpd_handler[_handler_count].dir); + _handler_count ++; + return 0; + } else { + return -1; + } +} + +int GSwifi::httpdAttach (const char *uri, void (*funcCgi)(int)) { + if (_handler_count < CFG_HTTPD_HANDLER_NUM) { + _httpd_handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1); + strcpy(_httpd_handler[_handler_count].uri, uri); + _httpd_handler[_handler_count].dir = NULL; + _httpd_handler[_handler_count].func = funcCgi; + DBG("httpdAttach %s %08x\r\n", _httpd_handler[_handler_count].uri, _httpd_handler[_handler_count].func); + _handler_count ++; + return 0; + } else { + return -1; + } +} + + +#define MIMETABLE_NUM 9 +char *GSwifi::mimetype (char *file) { + static const struct MIMETABLE { + const char ext[5]; + const 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 i, j; + + 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 (char*)mimetable[i].type; + } + } + return (char*)mimetable[0].type; +} + +int GSwifi::strnicmp (const char *p1, const 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; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/GSwifi_httpd_ws.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -0,0 +1,300 @@ +/* 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. + */ + +#include "GSwifi.h" + +#ifdef CFG_ENABLE_WEBSOCKET + +#include "sha1.h" + +int GSwifi::wsOpen (const char *host, int port, const char *uri, const char *user, const char *pwd) { + int cid; + char cmd[CFG_CMD_SIZE], tmp[CFG_CMD_SIZE]; + char ip[17]; + + if (!isAssociated() || _state.status != STAT_READY) return -1; + + if (getHostByName(host, ip)) return -1; + if (! port) { + port = 80; + } + + cid = open(PROTO_TCP, ip, port); + if (cid < 0) return -1; + DBG("ws cid %d\r\n", cid); + + // request + snprintf(cmd, sizeof(cmd), "GET %d HTTP/1.1\r\n", uri); + send(cid, cmd, strlen(cmd)); + if (host) { + snprintf(cmd, sizeof(cmd), "Host: %s\r\n", host); + send(cid, cmd, strlen(cmd)); + } + if (user && pwd) { + snprintf(cmd, sizeof(cmd), "%s:%s", user, pwd); + base64encode(cmd, strlen(cmd), tmp, sizeof(tmp)); + snprintf(cmd, sizeof(cmd), "Authorization: Basic %s\r\n", tmp); + send(cid, cmd, strlen(cmd)); + } + strcpy(cmd, "Upgrade: websocket\r\n"); + send(cid, cmd, strlen(cmd)); + strcpy(cmd, "Connection: Upgrade\r\n"); + send(cid, cmd, strlen(cmd)); + getMacAddress(tmp); + memcpy(&tmp[6], host, 10); + base64encode(tmp, 16, cmd, sizeof(cmd)); + snprintf(cmd, sizeof(cmd), "Sec-WebSocket-Key: %s\r\n", tmp); + send(cid, cmd, strlen(cmd)); + strcpy(cmd, "Sec-WebSocket-Version: 13\r\n\r\n"); + send(cid, cmd, strlen(cmd)); + + if (wsWait(cid, 101)) { + close(cid); + return -1; + } + wsWait(cid, 0); + return cid; +} + +int GSwifi::wsWait (int cid, int code) { + Timer timeout; + int i, n, len; + char buf[CFG_DATA_SIZE], data[CFG_CMD_SIZE]; + + if (code == 0) { + // dummy read + timeout.start(); + while (timeout.read_ms() < CFG_TIMEOUT) { + wait_ms(10); + if (!readable(cid)) break; + n = recv(cid, buf, sizeof(buf)); + if (n <= 0) break; + } + timeout.stop(); + return 0; + } + + // wait responce + len = 0; + timeout.start(); + while (timeout.read_ms() < CFG_TIMEOUT) { + wait_ms(10); + n = recv(cid, buf, sizeof(buf)); + for (i = 0; i < n; i ++) { + if (buf[i] == '\r') continue; + if (buf[i] == '\n') { + if (len == 0) continue; + goto next; + } else + if (len < sizeof(data) - 1) { + data[len] = buf[i]; + len ++; + } + } + } +next: + data[len] = 0; + timeout.stop(); + DBG("ws: %s\r\n", data); + + // check return code + if (strncmp(data, "HTTP/1.1 ", 9) != 0) return -1; + i = atoi(&data[9]); + DBG("ws status %d\r\n", i); + return i == code ? 0 : -1; +} + +int GSwifi::wsSend (int cid, const char *buf, int len, const char *mask) { + int i = 0, r; + char tmp[10]; + + tmp[i++] = 0x81; // single, text frame + if (len < 126) { + tmp[i++] = (mask == NULL ? 0 : 0x80) | len; + } else { + tmp[i++] = (mask == NULL ? 0 : 0x80) | 126; + tmp[i++] = (len >> 8) & 0xff; + tmp[i++] = len & 0xff; + } + if (mask) { + memcpy(&tmp[i], mask, 4); + i += 4; + } + r = send(cid, tmp, strlen(tmp)); + + if (r == 0) { + if (mask) { + char tmp2[len]; + for (i = 0; i < len; i ++) { + tmp2[i] = buf[i] ^ mask[i & 0x03]; + } + r = send(cid, tmp2, len); + } else { + r = send(cid, buf, len); + } + } + return r; +} + +#ifdef CFG_ENABLE_HTTPD + +void GSwifi::wsRecvData (int cid, char c) { + + switch (_httpd[cid].mode) { + case HTTPDMODE_WEBSOCKET: + if (_httpd[cid].n == 0) { + // flag + _httpd[cid].websocket_opcode = c & 0x0f; + _httpd[cid].websocket_flg = c << 8; + _httpd[cid].n ++; + } else + if (_httpd[cid].n == 1) { + // length 7bit + _httpd[cid].websocket_flg |= c; + _httpd[cid].length = c & 0x7f; + _httpd[cid].n ++; + if (_httpd[cid].length < 126) { + _httpd[cid].n = 0; + if (_httpd[cid].length) { + if (_httpd[cid].websocket_flg & 0x0080) { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK; + } else { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY; + } + } else { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER; + } + DBG("ws length %d\r\n", _httpd[cid].length); + } + } else { + // length 16bit,64bit + if (_httpd[cid].n == 2) { + _httpd[cid].length = c; + _httpd[cid].n ++; + } else + if (_httpd[cid].n < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) { + // 64bit + _httpd[cid].length = (_httpd[cid].length << 8) | c; + _httpd[cid].n ++; + } else { + // end + _httpd[cid].length = (_httpd[cid].length << 8) | c; + _httpd[cid].n = 0; + if (_httpd[cid].websocket_flg & 0x0080) { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_MASK; + } else { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY; + } + DBG("ws length2 %d\r\n", _httpd[cid].length); + } + } + break; + case HTTPDMODE_WEBSOCKET_MASK: + // masking key + _httpd[cid].websocket_mask[_httpd[cid].n] = c; + _httpd[cid].n ++; + if (_httpd[cid].n >= 4) { + _httpd[cid].n = 0; + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_BODY; + DBG("ws mask\r\n"); + } + break; + case HTTPDMODE_WEBSOCKET_BODY: + // payload + if (_httpd[cid].websocket_flg & 0x0080) { + // un-mask + _httpd[cid].buf->queue(c ^ _httpd[cid].websocket_mask[_httpd[cid].n & 0x03]); + } else { + _httpd[cid].buf->queue(c); + } + _httpd[cid].n ++; + if (_httpd[cid].n >= _httpd[cid].length) { + _httpd[cid].mode = HTTPDMODE_WEBSOCKET_ENTER; + _con[cid].received = true; + } + break; + } +} + +int GSwifi::wsParseRequest (int cid) { + int i; + + DBG("ws opcode %d\r\n", _httpd[cid].websocket_opcode); + switch (_httpd[cid].websocket_opcode) { + case 0x00: // continuation + break; + case 0x01: // text + case 0x02: // binary + i = httpdGetHandler(_httpd[cid].uri); + if (i >= 0) { + if (_httpd_handler[i].func) { + // cgi + _httpd_handler[i].func(cid); + } + } + break; + case 0x08: // close + close(cid); + break; + case 0x09: // ping + { + char pong[_httpd[cid].n + 2]; + pong[0] = 0x8a; + pong[1] = 0x04; + for (i = 0; i < _httpd[cid].length; i ++) { + if (_httpd[cid].buf->dequeue(&pong[i + 2]) == false) break; + } + send(cid, pong, _httpd[cid].length + 2); + } + break; + case 0x0a: // pong + break; + default: + break; + } + _httpd[cid].n = 0; + _httpd[cid].length = 0; + return 0; +} + +int GSwifi::wsAccept (int cid) { + char buf[CFG_CMD_SIZE], buf2[CFG_CMD_SIZE]; + + DBG("websocket accept: %d\r\n", cid); + + strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n"); + send(cid, buf, strlen(buf)); + strcpy(buf, "Upgrade: websocket\r\n"); + send(cid, buf, strlen(buf)); + strcpy(buf, "Connection: Upgrade\r\n"); + send(cid, buf, strlen(buf)); + + strcpy(buf, "Sec-WebSocket-Accept: "); + send(cid, buf, strlen(buf)); + 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)); + strcpy(buf, "\r\n\r\n"); + send(cid, buf, strlen(buf)); + return 0; +} + +#endif +#endif
--- a/GSwifi/GSwifi_msg.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_msg.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -162,6 +162,7 @@ if (_con[cid].buf->available() > CFG_DATA_SIZE - 16) { setRts(false); _con[cid].received = true; + WARN("buf full"); } } count ++; @@ -180,7 +181,7 @@ sub ++; len = 0; count = 0; - if (_state.mode == MODE_DATA_RX_BULK) { + if (_state.mode != MODE_DATA_RXUDP_BULK) { sub = 3; } break; @@ -215,11 +216,17 @@ break; default: // data +#ifdef CFG_ENABLE_HTTPD + if (_con[cid].protocol == PROTO_HTTPD) { + httpdRecvData(cid, c); + } else +#endif if (_con[cid].buf != NULL) { _con[cid].buf->queue(c); if (_con[cid].buf->available() > CFG_DATA_SIZE - 16) { setRts(false); _con[cid].received = true; + WARN("buf full"); } } count ++; @@ -234,6 +241,8 @@ } } +#define MSG_TABLE_NUM 15 +#define RES_TABLE_NUM 10 int GSwifi::parseMessage () { int i; char buf[256]; @@ -267,7 +276,7 @@ {RES_MACADDRESS, &GSwifi::resMacAddress}, {RES_DHCP, &GSwifi::resIp}, {RES_DNSLOOKUP, &GSwifi::resLookup}, - {RES_HTTP, &GSwifi::resConnect}, + {RES_HTTP, &GSwifi::resHttp}, {RES_RSSI, &GSwifi::resRssi}, {RES_TIME, &GSwifi::resTime}, {RES_STATUS, &GSwifi::resStatus}, @@ -344,15 +353,13 @@ } } - // initalize + // initialize + initCon(acid, true); _con[acid].protocol = _con[cid].protocol; _con[acid].type = _con[cid].type; _con[acid].parent = cid; + _con[acid].func = _con[cid].func; _con[acid].accept = true; - if (_con[acid].buf == NULL) - _con[acid].buf = new CircBuffer<char>(CFG_DATA_SIZE); - _con[acid].buf->flush(); - _con[acid].connected = true; } void GSwifi::msgDisconnect (const char *buf) { @@ -410,16 +417,10 @@ if (strncmp(buf, "CONNECT ", 8) == 0 && buf[9] == 0) { cid = x2i(buf[8]); DBG("connect %d\r\n", cid); - // initalize - _con[cid].parent = -1; - _con[cid].accept = false; - if (_con[cid].buf == NULL) - _con[cid].buf = new CircBuffer<char>(CFG_DATA_SIZE); - _con[cid].buf->flush(); - _con[cid].connected = true; + // initialize + initCon(cid, true); _state.cid = cid; _state.res = RES_NULL; - return; } } @@ -530,3 +531,17 @@ _state.res = RES_NULL; } } + +void GSwifi::resHttp (const char *buf) { + int cid; + + // http client socket + if (buf[0] >= '0' && buf[0] <= 'F' && buf[1] == 0) { + cid = x2i(buf[0]); + DBG("connect %d\r\n", cid); + // initialize + initCon(cid, true); + _state.cid = cid; + _state.res = RES_NULL; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/GSwifi_smtp.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -0,0 +1,145 @@ +/* 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. + */ + +#include "GSwifi.h" + +#ifdef CFG_ENABLE_SMTP + +int GSwifi::mail (const char *host, int port, const char *to, const char *from, const char *subject, const char *mesg, const char *user, const char *pwd) { + int ret = -1; + int cid; + char cmd[CFG_DATA_SIZE]; + char ip[17]; + + if (!isAssociated() || _state.status != STAT_READY) return -1; + + if (getHostByName(host, ip)) return -1; + if (! port) { + port = 25; + } + + cid = open(PROTO_TCP, ip, port); + if (cid < 0) return -1; + DBG("cid %d\r\n", cid); + + if (smtpWait(cid ,220)) goto exit; + + // send request + snprintf(cmd, sizeof(cmd), "EHLO %s\r\n", _state.name); + send(cid, cmd, strlen(cmd)); + wait_ms(100); + if (smtpWait(cid ,250)) goto quit; + smtpWait(cid ,0); + + if (user && pwd) { + // smtp auth + int len; + snprintf(cmd, sizeof(cmd), "%s%c%s%c%s", user, 0, user, 0, pwd); + len = strlen(user) * 2 + strlen(pwd) + 2; + char tmp[len + (len / 2)]; + base64encode(cmd, len, tmp, sizeof(tmp)); + snprintf(cmd, sizeof(cmd), "AUTH PLAIN %s\r\n", tmp); + send(cid, cmd, strlen(cmd)); + if (smtpWait(cid ,235)) goto quit; + } + + snprintf(cmd, sizeof(cmd), "MAIL FROM: %s\r\n", from); + send(cid, cmd, strlen(cmd)); + if (smtpWait(cid ,250)) goto quit; + + snprintf(cmd, sizeof(cmd), "RCPT TO: %s\r\n", to); + send(cid, cmd, strlen(cmd)); + if (smtpWait(cid ,250)) goto quit; + + strcpy(cmd, "DATA\r\n"); + send(cid, cmd, strlen(cmd)); + if (smtpWait(cid ,354)) goto quit; + + // mail data + snprintf(cmd, sizeof(cmd), "From: %s\r\n", from); + send(cid, cmd, strlen(cmd)); + snprintf(cmd, sizeof(cmd), "To: %s\r\n", to); + send(cid, cmd, strlen(cmd)); + snprintf(cmd, sizeof(cmd), "Subject: %s\r\n\r\n", subject); + send(cid, cmd, strlen(cmd)); + + send(cid, mesg, strlen(mesg)); + strcpy(cmd, "\r\n.\r\n"); + send(cid, cmd, strlen(cmd)); + if (smtpWait(cid ,250)) goto quit; + ret = 0; + + INFO("Mail, from: %s, to: %s %d\r\n", from, to, strlen(mesg)); + +quit: + strcpy(cmd, "QUIT\r\n"); + send(cid, cmd, strlen(cmd)); + smtpWait(cid ,221); +exit: + close(cid); + return ret; +} + +int GSwifi::smtpWait (int cid, int code) { + Timer timeout; + int i, n, len = 0; + char buf[CFG_CMD_SIZE], data[CFG_CMD_SIZE]; + + if (code == 0) { + // dummy read + timeout.start(); + while (timeout.read_ms() < CFG_TIMEOUT) { + wait_ms(10); + if (!readable(cid)) break; + n = recv(cid, buf, sizeof(buf)); + if (n <= 0) break; + } + timeout.stop(); + return 0; + } + + // wait responce + len = 0; + timeout.start(); + while (timeout.read_ms() < CFG_TIMEOUT) { + wait_ms(10); + n = recv(cid, buf, sizeof(buf)); + for (i = 0; i < n; i ++) { + if (buf[i] == '\r') continue; + if (buf[i] == '\n') { + if (len == 0) continue; + goto next; + } else + if (len < sizeof(data) - 1) { + data[len] = buf[i]; + len ++; + } + } + } +next: + data[len] = 0; + DBG("smtp: %s\r\n", data); + timeout.stop(); + + // check return code + i = atoi(data); + DBG("smtp status %d\r\n", i); + return i == code ? 0 : -1; +} + +#endif
--- a/GSwifi/GSwifi_sock.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_sock.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -22,7 +22,7 @@ { int i, flg = 0; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; for (i = 0; i < strlen(host); i ++) { if ((host[i] < '0' || host[i] > '9') && host[i] != '.') { @@ -44,10 +44,10 @@ return 0; } -int GSwifi::open (Protocol proto, const char *ip, int port, int src) { +int GSwifi::open (Protocol proto, const char *ip, int port, int src, void(*func)(int)) { int cid; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; _state.cid = -1; if (proto == PROTO_TCP) { @@ -59,13 +59,14 @@ cid = _state.cid; _con[cid].protocol = proto; _con[cid].type = TYPE_CLIENT; + _con[cid].func = func; return cid; } -int GSwifi::listen (Protocol proto, int port) { +int GSwifi::listen (Protocol proto, int port, void(*func)(int)) { int cid; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; _state.cid = -1; if (proto == PROTO_TCP) { @@ -77,6 +78,7 @@ cid = _state.cid; _con[cid].protocol = proto; _con[cid].type = TYPE_SERVER; + _con[cid].func = func; return cid; } @@ -185,3 +187,15 @@ *port = _con[cid].port; return 0; } + +void GSwifi::initCon (int cid, bool connected) { + _con[cid].parent = -1; + _con[cid].func = NULL; + _con[cid].accept = false; + if (_con[cid].buf == NULL) { + _con[cid].buf = new CircBuffer<char>(CFG_DATA_SIZE); + if (_con[cid].buf == NULL) error("Can't allocate memory"); + } + _con[cid].buf->flush(); + _con[cid].connected = connected; +}
--- a/GSwifi/GSwifi_util.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifi/GSwifi_util.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -87,7 +87,7 @@ int GSwifi::ntpdate (char *host, int sec) { char ip[17]; - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; if (getHostByName(host, ip)) return -1; return cmdNTIMESYNC(true, ip, sec); @@ -99,7 +99,7 @@ int GSwifi::provisioning (char *user, char *pass) { - if (!isConnected() && _state.status == STAT_READY) return -1; + if (!isAssociated() || _state.status != STAT_READY) return -1; return cmdWEBPROV(user, pass); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/sha1.cpp Fri Nov 22 14:03:07 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/GSwifi/sha1.h Fri Nov 22 14:03:07 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
--- a/GSwifiInterface.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/GSwifiInterface.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -35,7 +35,7 @@ int GSwifiInterface::disconnect() { - return GSwifi::disconnect(); + return GSwifi::dissociate(); } char * GSwifiInterface::getMACAddress()
--- a/Socket/UDPSocket.cpp Fri Nov 15 04:20:14 2013 +0000 +++ b/Socket/UDPSocket.cpp Fri Nov 22 14:03:07 2013 +0000 @@ -49,7 +49,7 @@ Timer tmr; int idx = 0; - if (_cid < 0 && _wifi->isConnected()) { + if (_cid < 0 && _wifi->isAssociated()) { // Socket open if (_server) { _cid = _wifi->listen(GSwifi::PROTO_UDP, _port); @@ -87,7 +87,7 @@ char ip[16]; int port; - if (_cid < 0 && _wifi->isConnected()) { + if (_cid < 0 && _wifi->isAssociated()) { // Socket open if (_server) { _cid = _wifi->listen(GSwifi::PROTO_UDP, _port);