Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
Websocket.cpp
- Committer:
- uci1
- Date:
- 2012-06-30
- Revision:
- 0:664899e0b988
- Child:
- 1:e392595b4b76
File content as of revision 0:664899e0b988:
#include "Websocket.h" #include <string> //#define DEBUG #ifdef TARGET_LPC1768 Websocket::Websocket(char * url) { server_ip = NULL; netif = ETH; eth_writeable = false; eth_readable = false; eth_connected = false; response_server_eth = false; new_msg = false; fillFields(url); eth = new EthernetNetIf( IpAddr(128,195,204,148), //IP Address IpAddr(255,255,255,0), //Network Mask IpAddr(128,195,204,1), //Gateway IpAddr(128,200,1,201) //DNS ); sock = new TCPSocket(); EthernetErr ethErr = eth->setup(); #ifdef DEBUG if (ethErr) { printf("\r\nERROR %d in setup.\r\n", ethErr); } #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()); #ifdef DEBUG printf("\r\nserver with dns=%d.%d.%d.%d\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); } #endif //target void Websocket::fillFields(char * url) { printf("FILLFIELDS\r\n"); char *res = NULL; char *res1 = NULL; char buf[50]; strcpy(buf, url); printf("\r\nBuf is:"); for(int i=0;i<50;i++) { printf("%d", buf[i]); } printf("\r\n"); 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 #ifdef TARGET_LPC1768 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 } } #endif //target } } } bool Websocket::connect(Timer* stop, const uint32_t timeout) { // printf("CONNECT() Function\r\n"); char cmd[50]; #ifdef TARGET_LPC1768 //M: else if (netif == ETH) 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 myStop; if (stop==0) { stop = &myStop; } int i = 0; printf("I: %d\r\n", i); while (true) { Net::poll(); if (stop->read() > timeout) return false; if (tmr.read() > 0.05) { 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: null\r\n"); 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-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); sock->send(cmd, strlen(cmd)); i++; break; case 6: sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n"); sock->send(cmd, strlen(cmd)); i++; break; case 7: if (response_server_eth) i++; else break; default: break; } } 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::sendLength(uint32_t len) { //printf("SENDLENGTH(), Send Length: %d\r\n", len); if (len < 126) { sendChar(len | (1<<7)); } else if (len < 65535) { // use 2 bytes sendChar(126 | (1<<7)); //M: reverce these two lines sendChar((len >> 8) & 0xff); //2 sendChar(len & 0xff); //1 // sendChar((len >> 8) & 0xff); //2 } else { sendChar(127 | (1<<7)); for (int i = 0; i < 8; i++) { sendChar((len >> i*8) & 0xff); } } } int Websocket::sendChar(uint8_t c) { #ifdef TARGET_LPC1768 if (netif == ETH) { Net::poll(); return sock->send((const char *)&c, 1); // printf("SENDCHAR(), Sendchar %d \r\n", c); } #endif return 0; } void Websocket::sendOpcode(uint8_t opcode) { // printf("SENDOPCODE()\r\n"); sendChar(0x80 | (opcode & 0x0f)); // printf("SendOpcode: 0x%X\r\n", opcode); } /*Masking-key: 0 or 4 bytes All frames sent from the client to the server are masked by a 32- bit value that is contained within the frame. This field is present if the mask bit is set to 1, and is absent if the mask bit is set to 0. */ void Websocket::sendMask() { // printf("SENDMASK()\r\n"); for (int i = 0; i < 4; i++) { sendChar(0); //no frame masking } } void Websocket::send(char * str) { //printf("SEND()\r\n"); /* Opcode: 4 bits The opcode denotes the frame type of the WebSocket frame Defines the interpretation of the payload data. If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_. The following values are defined. * %x0 denotes a continuation frame * %x1 denotes a text frame * %x2 denotes a binary frame * %x3-7 are reserved for further non-control frames * %x8 denotes a connection close * %x9 denotes a pingg * %xA denotes a pong * %xB-F are reserved for further control frames */ sendOpcode(0x01); sendLength(strlen(str)); sendMask(); #ifdef TARGET_LPC1768 //M: else if (netif == ETH) { if (netif == ETH) { Net::poll(); sock->send(str, strlen(str)); } #endif //target } bool Websocket::sendBinary(char* str, const uint32_t len) { // CJR: add function for sending binary //printf("SEND()\r\n"); /* Opcode: 4 bits The opcode denotes the frame type of the WebSocket frame Defines the interpretation of the payload data. If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_. The following values are defined. * %x0 denotes a continuation frame * %x1 denotes a text frame * %x2 denotes a binary frame * %x3-7 are reserved for further non-control frames * %x8 denotes a connection close * %x9 denotes a pingg * %xA denotes a pong * %xB-F are reserved for further control frames */ sendOpcode(0x02); sendLength(len); sendMask(); #ifdef TARGET_LPC1768 //M: else if (netif == ETH) { if (netif == ETH) { Net::poll(); uint32_t nbytes=0; char* s = str; for (uint32_t i=0; i<len; i++, s++) { nbytes += sendChar(*s); } //const int32_t nbytes = sock->send(str, len); return nbytes==len; } #endif //target return false; } bool Websocket::sendBinary(FILE* f, const uint32_t nbytes) { // CJR: add function for sending binary // return false if EOF or file error before nbytes sent //printf("SEND()\r\n"); /* Opcode: 4 bits The opcode denotes the frame type of the WebSocket frame Defines the interpretation of the payload data. If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_. The following values are defined. * %x0 denotes a continuation frame * %x1 denotes a text frame * %x2 denotes a binary frame * %x3-7 are reserved for further non-control frames * %x8 denotes a connection close * %x9 denotes a pingg * %xA denotes a pong * %xB-F are reserved for further control frames */ sendOpcode(0x02); sendLength(nbytes); sendMask(); #ifdef TARGET_LPC1768 //M: else if (netif == ETH) { if (netif == ETH) { Net::poll(); uint8_t c; // conserve mbed memory by reading byte-by-byte for (uint32_t i=0; i<nbytes; i++) { fread(&c, 1, 1, f); if ((feof(f)==0) && (ferror(f)==0)) { sendChar(c); } else { return false; } } } #endif //target return true; } bool Websocket::read(char * message, Timer* timer, const uint32_t timeout) { //printf("READ()\r\n"); uint32_t len_msg; //32 bit size char opcode = 0; //continuation frame char mask[4] = {0, 0, 0, 0}; //no mask Timer myTimer; if (timer==0) { timer = &myTimer; } #ifdef TARGET_LPC1768 if (netif == ETH) { // printf("Current opcode in read() 0x%X\r\n", opcode); uint32_t index = 0; Net::poll(); if (new_msg) //from webserver { printf("There is new message from webserver\r\n"); // read the opcode while (true) { if (timer->read() > timeout) { return false; } opcode = eth_rx[index++]; printf("new opcode in read() func: 0x%X\r\n", opcode); //0x81 if (opcode == 0x81) { break; } }// end of while(true) #ifdef DEBUG // printf("opcode: 0x%X\r\n", opcode); #endif len_msg = eth_rx[index++] & 0x7f; printf("length_message2 : %d\r\n", len_msg); // if (len_msg == 126) { len_msg += eth_rx[index++] << 8; len_msg = eth_rx[index++]; printf("len message is greater than 126 %d\r\n", len_msg); } 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; } #ifdef DEBUG // printf("length: %d\r\n", len_msg); #endif if ((len_msg & 0x80)) { printf("print mask bit %d\r\n", len_msg & 0x80); for (int j = 0; j < 4; j++){ mask[j] = eth_rx[index++]; printf(" mask index %i is %i, ", j, mask[j]); } } // for (int i = 0; i < 4; i++) //{ // mask[i] = 0; //} /* for (int i = 0; i < 4; i++) { printf(" mask index %i is %i, ", i, mask[i]); }*/ printf("\r\n"); for (int i = 0; i < len_msg; i++) { // printf("%c", eth_rx[i]); // message[i-8] = eth_rx[i]; // message[i] = eth_rx[index++] ^ mask[i % 4]; if (len_msg < 126) message[i] = eth_rx[i+2]; else message[i] = eth_rx[i+4]; // printf("message is %s\r\n", message); } message[len_msg] = 0; //M: add : // if (new_msg) // {new_msg = true;} //else new_msg = false; return true; }//if new message printf("no new message!\r\n"); return false; }//end of if(eth) #endif //target //the program shouldn't be here return false; } // end of read func bool Websocket::close() { // printf("COSE()\r\n"); #ifdef TARGET_LPC1768 if (netif == ETH) { if (sock->close()) return false; return true; } #endif //target //the program shouldn't be here return false; } bool Websocket::connected() { // printf("CONNECTED()\r\n"); #ifdef TARGET_LPC1768 if (netif == ETH) { return eth_connected; } #endif //target //the program shouldn't be here return false; } std::string Websocket::getPath() { return path; } #ifdef TARGET_LPC1768 void Websocket::onTCPSocketEvent(TCPSocketEvent e) { // printf("TCPSocketEvent is "); if (e == TCPSOCKET_CONNECTED) { eth_connected = true; #ifdef DEBUG // printf("TCP Socket Connected\r\n"); #endif } else if (e == TCPSOCKET_WRITEABLE) { // printf("TCPSOCKET_WRITEABLE\r\n"); } else if (e == TCPSOCKET_READABLE) { // printf("TCPSOCKET_READABLE\r\n"); 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("DdLWT/1JcX+nQFHebYP+rqEx5xI="); if (found != string::npos) response_server_eth = true; } } else { #ifdef DEBUG printf("TCP Socket Fail\r\n"); #endif eth_connected = false; } } #endif //target