Web Socket connection (MBED is client side)
Dependencies: EthernetNetIf MbedJSONValue mbed
Fork of WebSocket_test by
Diff: Websocket/Websocket.cpp
- Revision:
- 0:236a084b1d6b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Websocket/Websocket.cpp Wed Nov 02 02:56:07 2011 +0000 @@ -0,0 +1,456 @@ +/* + * modify by Suga + */ +#include "Websocket.h" +#include <string> + +#ifdef WIFLY +Websocket::Websocket(char * url, Wifly * wifi) { + this->wifi = wifi; + netif = WIF; + fillFields(url); +} +#endif + +void Websocket::isr_dns (DNSReply r) { + if (DNS_FOUND) { + dns_status = 1; + } else { + dns_status = -1; + } +} + +Websocket::Websocket(char * url, EthernetNetIf *e) { + server_ip = NULL; + netif = ETH; + eth_writeable = false; + eth_readable = false; + eth_connected = false; + response_server_eth = false; + new_msg = false; + fillFields(url); + +#ifdef ETH_SETUP + eth = new EthernetNetIf(); +#else + eth = e; +#endif + sock = new TCPSocket(); + +#ifdef ETH_SETUP + EthernetErr ethErr = eth->setup(); +#ifdef DEBUG + if (ethErr) { + printf("\r\nERROR %d in setup.\r\n", ethErr); + } +#endif +#endif + + //we must use dnsresolver to find the ip address + if (server_ip == NULL) { +/* + DNSResolver dr; + server_ip = new IpAddr(); + *server_ip = dr.resolveName(ip_domain.c_str()); +*/ + DNSRequest dns; + Timer timeout; + server_ip = new IpAddr(); + dns_status = 0; + dns.setOnReply(this, &Websocket::isr_dns); + if (dns.resolve(ip_domain.c_str()) != DNS_OK) return; + timeout.reset(); + timeout.start(); + while (timeout.read_ms() < 15000) { + if (dns_status) break; + Net::poll(); + } + timeout.stop(); + if (dns_status <= 0) return; + dns.getResult(server_ip); + dns.close(); +#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]); +#endif + + } + + IpAddr ipt = eth->getIp(); +#ifdef DEBUG + printf("\r\nmbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]); +#endif + + sock->setOnEvent(this, &Websocket::onTCPSocketEvent); +} + + +void Websocket::fillFields(char * url) { + char *res = NULL; + char *res1 = NULL; + + char buf[50]; + strcpy(buf, url); + + res = strtok(buf, ":"); + if (strcmp(res, "ws")) { +#ifdef DEBUG + printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n"); +#endif + } else { + //ip_domain and port + res = strtok(NULL, "/"); + + //path + res1 = strtok(NULL, " "); + if (res1 != NULL) { + path = res1; + } + + //ip_domain + res = strtok(res, ":"); + + //port + res1 = strtok(NULL, " "); + //port + if (res1 != NULL) { + port = res1; + } else { + port = "80"; + } + + if (res != NULL) { + ip_domain = res; + + //if we use ethernet, we must decode ip address or use dnsresolver + if (netif == ETH) { + strcpy(buf, res); + + //we try to decode the ip address + if (buf[0] >= '0' && buf[0] <= '9') { + res = strtok(buf, "."); + int i = 0; + int ip[4]; + while (res != NULL) { + ip[i] = atoi(res); + res = strtok(NULL, "."); + i++; + } + server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]); +#ifdef DEBUG + printf("server without dns=%i.%i.%i.%i\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]); +#endif + } + } + } + } +} + + +bool Websocket::connect() { + char cmd[50]; +#ifdef WIFLY + if (netif == WIF) { + wifi->send("exit\r", "NO"); + //enter in cmd mode + while (!wifi->send("$$$", "CMD")) { +#ifdef DEBUG + printf("cannot enter in CMD mode\r\n"); +#endif + wifi->exit(); + } + + + //open the connection + sprintf(cmd, "open %s %s\r\n", ip_domain.c_str(), port.c_str()); + if (!wifi->send(cmd, "OPEN*")) { +#ifdef DEBUG + printf("Websocket::connect cannot open\r\n"); +#endif + return false; + } + + + //send websocket HTTP header + sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str()); + wifi->send(cmd, "NO"); + + 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("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 + return true; + } else +#endif + if (netif == ETH) { + Host server (*server_ip, atoi(port.c_str())); + sock->close(); + TCPSocketErr bindErr = sock->connect(server); + if (bindErr) { +#ifdef DEBUG + printf("\r\nERROR binderr: %d\r\n", bindErr); +#endif + return false; + } + + Timer tmr; + tmr.start(); + + Timer stop; + stop.start(); + + int i = 0; + while (true) { + Net::poll(); + if (stop.read() > 3) + return false; + if (tmr.read() > 0.01) { + tmr.reset(); + if (eth_connected) { + switch (i) { + case 0: + sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str()); + sock->send(cmd, strlen(cmd)); + i++; + break; + case 1: + sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str()); + sock->send(cmd, strlen(cmd)); + i++; + break; + case 2: + sprintf(cmd, "Upgrade: WebSocket\r\n"); + sock->send(cmd, strlen(cmd)); + i++; + break; + case 3: + sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str()); + sock->send(cmd, strlen(cmd)); + i++; + break; + case 4: + sprintf(cmd, "Connection: Upgrade\r\n"); + sock->send(cmd, strlen(cmd)); + i++; + break; + case 5: + sprintf(cmd, "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\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"); + 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 + break; + + default: + break; + } + } + if (i==9) { +#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; + } + } + } + } + //the program shouldn't be here + return false; +} + +void Websocket::send(char * str) { +#ifdef WIFLY + if (netif == WIF) { + wifi->putc('\x00'); + wifi->send(str, "NO"); + wifi->putc('\xff'); + } else +#endif + if (netif == ETH) { + char c = '\x00'; + Net::poll(); + sock->send(&c, 1); + sock->send(str, strlen(str)); + c = '\xff'; + sock->send(&c, 1); + } +} + +bool Websocket::read(char * message) { + int i = 0; + +#ifdef WIFLY + if (netif == WIF) { + if (!wifi->read(message)) + return false; + + //we check if the first byte is 0x00 + if (message == NULL || message[0] != 0x00) { + message = NULL; + return false; + } + + while (message[i + 1] != 0xff && i < strlen(message + 1)) + i++; + + 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 +#endif + if (netif == ETH) { + Net::poll(); + + if (new_msg) { + if (eth_rx[0] != 0x00) { + message = NULL; + return false; + } + while (eth_rx[i + 1] != 0xff) { + message[i] = eth_rx[i + 1]; + i++; + } + message[i] = 0; + new_msg = false; + return true; + } + return false; + } + //the program shouldn't be here + return false; +} + +bool Websocket::close() { +#ifdef WIFLY + if (netif == WIF) { + if (!wifi->cmdMode()) { +#ifdef DEBUG + printf("Websocket::close: cannot enter in cmd mode\r\n"); +#endif + return false; + } + + wifi->send("close\r", "NO"); + + if (!wifi->exit()) + return false; + } else +#endif + if (netif == ETH) { + + if (sock->close()) + return false; + return true; + } + //the program shouldn't be here + return false; +} + + + +bool Websocket::connected() { +#ifdef WIFLY + if (netif == WIF) { + char str[10]; + + wait(0.25); + if (!wifi->cmdMode()) { +#ifdef DEBUG + printf("Websocket::connected: cannot enter in cmd mode\r\n"); +#endif + return false; + } + wait(0.25); + + wifi->send("show c\r\n", "NO", str); + + if (str[3] == '1') { + if (!wifi->exit()) { +#ifdef DEBUG + printf("Websocket::connected: cannot exit\r\n"); +#endif + return false; + } + return true; + } + if (!wifi->exit()) { +#ifdef DEBUG + printf("Websocket::connected: cannot exit\r\n"); +#endif + } + return false; + } else +#endif + if (netif == ETH) { + + return eth_connected; + } + //the program shouldn't be here + return false; +} + +std::string Websocket::getPath() +{ + return path; +} + + + + +void Websocket::onTCPSocketEvent(TCPSocketEvent e) { + if (e == TCPSOCKET_CONNECTED) { + eth_connected = true; +#ifdef DEBUG + printf("TCP Socket Connected\r\n"); +#endif + } else if (e == TCPSOCKET_WRITEABLE) { + } else if (e == TCPSOCKET_READABLE) { + int len = sock->recv(eth_rx, 512); + eth_rx[len] = 0; + new_msg = true; + if (!response_server_eth) { + string checking; + size_t found = string::npos; + checking = eth_rx; + found = checking.find("HTTP"); + if (found != string::npos) + response_server_eth = true; + } + } else { +#ifdef DEBUG + printf("TCP Socket Fail\r\n"); +#endif + eth_connected = false; + } +} + +