WebSocket client library
Diff: Websocket.cpp
- Revision:
- 22:f4aac491ea26
- Parent:
- 21:2c4462ca74fa
- Child:
- 23:80bffaf28bef
--- a/Websocket.cpp Tue Nov 15 19:37:40 2011 +0000 +++ b/Websocket.cpp Wed Feb 01 17:23:40 2012 +0000 @@ -1,6 +1,7 @@ #include "Websocket.h" #include <string> +//#define DEBUG Websocket::Websocket(char * url, Wifly * wifi) { this->wifi = wifi; @@ -9,6 +10,7 @@ } +#ifdef TARGET_LPC1768 Websocket::Websocket(char * url) { server_ip = NULL; netif = ETH; @@ -35,7 +37,7 @@ server_ip = new IpAddr(); *server_ip = dr.resolveName(ip_domain.c_str()); #ifdef DEBUG - printf("\r\nserver with dns=%i.%i.%i.%i\r\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]); + printf("\r\nserver with dns=%d.%d.%d.%d\r\n", (*server_ip)[0], (*server_ip)[1], (*server_ip)[2], (*server_ip)[3]); #endif } @@ -47,6 +49,7 @@ sock->setOnEvent(this, &Websocket::onTCPSocketEvent); } +#endif //target void Websocket::fillFields(char * url) { @@ -87,6 +90,7 @@ ip_domain = res; //if we use ethernet, we must decode ip address or use dnsresolver +#ifdef TARGET_LPC1768 if (netif == ETH) { strcpy(buf, res); @@ -106,6 +110,7 @@ #endif } } +#endif //target } } } @@ -114,49 +119,75 @@ bool Websocket::connect() { char cmd[50]; if (netif == WIF) { - wifi->send("exit\r", "NO"); //enter in cmd mode - while (!wifi->send("$$$", "CMD")) { + wifi->exit(); + while (!wifi->cmdMode()) { #ifdef DEBUG printf("cannot enter in CMD mode\r\n"); #endif + wifi->send("a\r\n"); + wait(0.2); wifi->exit(); + if (!wifi->cmdMode()) + return false; + } + + if (!wifi->send("set comm remote 0\r\n", "AOK")) { +#ifdef DEBUG + printf("Websocket::connect(): cannot set empty remote string\r\n"); +#endif + return false; } //open the connection + char recv[30]; + string str; sprintf(cmd, "open %s %s\r\n", ip_domain.c_str(), port.c_str()); - if (!wifi->send(cmd, "OPEN*")) { + wifi->send(cmd, "NO", recv); + str = recv; + +#ifdef DEBUG + printf("Websocket::connect recv: %s\r\n", recv); +#endif + + if (str.find("Connected") == string::npos && str.find("OPEN") == string::npos) { #ifdef DEBUG printf("Websocket::connect cannot open\r\n"); #endif return false; } + if (str.find("Connected") != string::npos) { +#ifdef DEBUG + printf("will try to close the conn\r\n"); +#endif + if (!wifi->send("close\r\n", "CLOS")) { + return false; + } + if (!wifi->send(cmd, "OPEN")) + return false; + } //send websocket HTTP header sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str()); - wifi->send(cmd, "NO"); - + wifi->send(cmd); + wifi->send("Upgrade: websocket\r\n"); + wifi->send("Connection: Upgrade\r\n"); sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str()); - wifi->send(cmd, "NO"); - - wifi->send("Upgrade: WebSocket\r\n", "NO"); - - sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str()); - wifi->send(cmd, "NO"); - + wifi->send(cmd); + wifi->send("Origin: null\r\n"); + wifi->send("Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); + if (!wifi->send("Sec-WebSocket-Version: 13\r\n\r\n", "DdLWT/1JcX+nQFHebYP+rqEx5xI=")) + return false; - wifi->send("Connection: Upgrade\r\n", "NO"); - wifi->send("Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n", "NO"); - wifi->send("Sec-WebSocket-key2: 12998 5 Y3 1 .P00\r\n\r\n", "NO"); - if (!wifi->send("^n:ds[4U", "8jKS'y:G*Co,Wxa-")) - return false; -#ifdef DEBUG - printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str()); -#endif + wifi->flush(); + + //printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str()); return true; - } else if (netif == ETH) { + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { Host server (*server_ip, atoi(port.c_str())); sock->close(); TCPSocketErr bindErr = sock->connect(server); @@ -178,7 +209,7 @@ Net::poll(); if (stop.read() > 3) return false; - if (tmr.read() > 0.01) { + if (tmr.read() > 0.05) { tmr.reset(); if (eth_connected) { switch (i) { @@ -198,7 +229,7 @@ i++; break; case 3: - sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str()); + sprintf(cmd, "Origin: null\r\n"); sock->send(cmd, strlen(cmd)); i++; break; @@ -208,20 +239,16 @@ i++; break; case 5: - sprintf(cmd, "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"); + sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); sock->send(cmd, strlen(cmd)); i++; break; case 6: - sprintf(cmd, "Sec-WebSocket-key2: 12998 5 Y3 1 .P00\r\n\r\n"); + sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n"); sock->send(cmd, strlen(cmd)); i++; break; case 7: - sock->send("^n:ds[4U", 8); - i++; - break; - case 8: if (response_server_eth) i++; else @@ -231,75 +258,188 @@ break; } } - if (i==9) { + if (i==8) { +#ifdef DEBUG printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str()); +#endif return true; } } } } +#endif //target //the program shouldn't be here return false; } -void Websocket::send(char * str) { - if (netif == WIF) { - wifi->putc('\x00'); - wifi->send(str, "NO"); - wifi->putc('\xff'); - } else if (netif == ETH) { - char c = '\x00'; - Net::poll(); - sock->send(&c, 1); - sock->send(str, strlen(str)); - c = '\xff'; - sock->send(&c, 1); +void Websocket::sendLength(uint32_t len) { + if (len < 126) { + sendChar(len | (1<<7)); + } else if (len < 65535) { + sendChar(126 | (1<<7)); + sendChar(len & 0xff); + sendChar((len >> 8) & 0xff); + } else { + sendChar(127 | (1<<7)); + for (int i = 0; i < 8; i++) { + sendChar((len >> i*8) & 0xff); + } } } +void Websocket::sendChar(uint8_t c) { + if (netif == WIF) { + wifi->putc(c); + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { + Net::poll(); + sock->send((const char *)&c, 1); + } +#endif +} + +void Websocket::sendOpcode(uint8_t opcode) { + sendChar(0x80 | (opcode & 0x0f)); +} + +void Websocket::sendMask() { + for (int i = 0; i < 4; i++) { + sendChar(0); + } +} + +void Websocket::send(char * str) { + sendOpcode(0x01); + sendLength(strlen(str)); + sendMask(); + if (netif == WIF) { + wifi->send(str, "NO"); + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { + Net::poll(); + sock->send(str, strlen(str)); + } +#endif //target +} + + + bool Websocket::read(char * message) { int i = 0; + int length_buffer = 0; + uint32_t len_msg; + char opcode = 0; + char mask[4] = {0, 0, 0, 0}; + Timer tmr; if (netif == WIF) { - if (!wifi->read(message)) + length_buffer = wifi->readable(); + + if (length_buffer > 1) { + // read the opcode + tmr.start(); + while (true) { + if (tmr.read() > 3) { + return false; + } + if (wifi->readable()) { + opcode = wifi->getc(); + } + if (opcode == 0x81) { + break; + } + } +#ifdef DEBUG + printf("opcode: 0x%X\r\n", opcode); +#endif + len_msg = wifi->getc() & 0x7f; + if (len_msg == 126) { + len_msg = wifi->getc(); + len_msg += wifi->getc() << 8; + } else if (len_msg == 127) { + len_msg = 0; + for (int i = 0; i < 8; i++) { + len_msg += wifi->getc() << i*8; + } + } + if(len_msg == 0) { + return false; + } +#ifdef DEBUG + printf("length: %d\r\n", len_msg); +#endif + if ((len_msg & 0x80)) { + for (int i = 0; i < 4; i++) + mask[i] = wifi->getc(); + } + } else return false; - //we check if the first byte is 0x00 - if (message == NULL || message[0] != 0x00) { - message = NULL; - return false; + + for (i = 0; i < len_msg; i++) { + message[i] = wifi->getc() ^ mask[i % 4]; } - while (message[i + 1] != 0xff && i < strlen(message + 1)) - i++; + message[len_msg] = 0; + return true; + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { - if (message[i+1] == 0xff) { - message[i+1] = 0; - memcpy(message, message + 1, strlen(message + 1) + 1); - return true; - } else { - message = NULL; - return false; - } - } else if (netif == ETH) { + uint32_t index = 0; Net::poll(); if (new_msg) { - if (eth_rx[0] != 0x00) { - message = NULL; + tmr.start(); + // read the opcode + while (true) { + if (tmr.read() > 3) { + return false; + } + opcode = eth_rx[index++]; + if (opcode == 0x81) { + break; + } + } +#ifdef DEBUG + printf("opcode: 0x%X\r\n", opcode); +#endif + + len_msg = eth_rx[index++] & 0x7f; + if (len_msg == 126) { + len_msg = eth_rx[index++]; + len_msg += eth_rx[index++] << 8; + } else if (len_msg == 127) { + len_msg = 0; + for (int i = 0; i < 8; i++) { + len_msg += eth_rx[index++] << i*8; + } + } + if(len_msg == 0) { return false; } - while (eth_rx[i + 1] != 0xff) { - message[i] = eth_rx[i + 1]; - i++; +#ifdef DEBUG + printf("length: %d\r\n", len_msg); +#endif + if ((len_msg & 0x80)) { + for (int i = 0; i < 4; i++) + mask[i] = eth_rx[index++]; } - message[i] = 0; + + for (i = 0; i < len_msg; i++) { + message[i] = eth_rx[index++] ^ mask[i % 4]; + } + + message[len_msg] = 0; new_msg = false; return true; } return false; } - //the program shouldn't be here +#endif //target +//the program shouldn't be here return false; } @@ -316,12 +456,15 @@ if (!wifi->exit()) return false; - } else if (netif == ETH) { + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { if (sock->close()) return false; return true; } +#endif //target //the program shouldn't be here return false; } @@ -332,6 +475,7 @@ if (netif == WIF) { char str[10]; + // we have to wait at least 0.25s to enter in cmd mode whan we was sending tcp packets wait(0.25); if (!wifi->cmdMode()) { #ifdef DEBUG @@ -342,6 +486,9 @@ wait(0.25); wifi->send("show c\r\n", "NO", str); +#ifdef DEBUG + printf("Websocket::connected: str: %s\r\n", str); +#endif if (str[3] == '1') { if (!wifi->exit()) { @@ -358,22 +505,24 @@ #endif } return false; - } else if (netif == ETH) { - + } +#ifdef TARGET_LPC1768 + else if (netif == ETH) { return eth_connected; } +#endif //target //the program shouldn't be here return false; } -std::string Websocket::getPath() -{ +std::string Websocket::getPath() { return path; } +#ifdef TARGET_LPC1768 void Websocket::onTCPSocketEvent(TCPSocketEvent e) { if (e == TCPSOCKET_CONNECTED) { eth_connected = true; @@ -389,7 +538,7 @@ string checking; size_t found = string::npos; checking = eth_rx; - found = checking.find("HTTP"); + found = checking.find("DdLWT/1JcX+nQFHebYP+rqEx5xI="); if (found != string::npos) response_server_eth = true; } @@ -400,5 +549,6 @@ eth_connected = false; } } +#endif //target