WebSocket client library

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Websocket.cpp Source File

Websocket.cpp

00001 #include "Websocket.h"
00002 #include <string>
00003 
00004 //#define DEBUG
00005 
00006 Websocket::Websocket(char * url, Wifly * wifi) {
00007     this->wifi = wifi;
00008     netif = WIF;
00009     fillFields(url);
00010 }
00011 
00012 
00013 #ifdef TARGET_LPC1768
00014 Websocket::Websocket(char * url) {
00015     server_ip = NULL;
00016     netif = ETH;
00017     eth_writeable = false;
00018     eth_readable = false;
00019     eth_connected = false;
00020     response_server_eth = false;
00021     new_msg = false;
00022     fillFields(url);
00023 
00024     eth = new EthernetNetIf();
00025     sock = new TCPSocket();
00026 
00027     EthernetErr ethErr = eth->setup();
00028 #ifdef DEBUG
00029     if (ethErr) {
00030         printf("\r\nERROR %d in setup.\r\n", ethErr);
00031     }
00032 #endif
00033 
00034     //we must use dnsresolver to find the ip address
00035     if (server_ip == NULL) {
00036         DNSResolver dr;
00037         server_ip = new IpAddr();
00038         *server_ip = dr.resolveName(ip_domain.c_str());
00039 #ifdef DEBUG
00040         printf("\r\nserver with dns=%d.%d.%d.%d\r\n", (*server_ip)[0], (*server_ip)[1], (*server_ip)[2], (*server_ip)[3]);
00041 #endif
00042 
00043     }
00044 
00045     IpAddr ipt = eth->getIp();
00046 #ifdef DEBUG
00047     printf("\r\nmbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]);
00048 #endif
00049 
00050     sock->setOnEvent(this, &Websocket::onTCPSocketEvent);
00051 }
00052 #endif //target
00053 
00054 
00055 void Websocket::fillFields(char * url) {
00056     char *res = NULL;
00057     char *res1 = NULL;
00058 
00059     char buf[50];
00060     strcpy(buf, url);
00061 
00062     res = strtok(buf, ":");
00063     if (strcmp(res, "ws")) {
00064 #ifdef DEBUG
00065         printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
00066 #endif
00067     } else {
00068         //ip_domain and port
00069         res = strtok(NULL, "/");
00070 
00071         //path
00072         res1 = strtok(NULL, " ");
00073         if (res1 != NULL) {
00074             path = res1;
00075         }
00076 
00077         //ip_domain
00078         res = strtok(res, ":");
00079 
00080         //port
00081         res1 = strtok(NULL, " ");
00082         //port
00083         if (res1 != NULL) {
00084             port = res1;
00085         } else {
00086             port = "80";
00087         }
00088 
00089         if (res != NULL) {
00090             ip_domain = res;
00091 
00092             //if we use ethernet, we must decode ip address or use dnsresolver
00093 #ifdef TARGET_LPC1768
00094             if (netif == ETH) {
00095                 strcpy(buf, res);
00096 
00097                 //we try to decode the ip address
00098                 if (buf[0] >= '0' && buf[0] <= '9') {
00099                     res = strtok(buf, ".");
00100                     int i = 0;
00101                     int ip[4];
00102                     while (res != NULL) {
00103                         ip[i] = atoi(res);
00104                         res = strtok(NULL, ".");
00105                         i++;
00106                     }
00107                     server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]);
00108 #ifdef DEBUG
00109                     printf("server without dns=%i.%i.%i.%i\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]);
00110 #endif
00111                 }
00112             }
00113 #endif //target
00114         }
00115     }
00116 }
00117 
00118 
00119 bool Websocket::connect() {
00120     char cmd[50];
00121     if (netif == WIF) {
00122         //enter in cmd mode
00123         wifi->exit();
00124         while (!wifi->cmdMode()) {
00125 #ifdef DEBUG
00126             printf("cannot enter in CMD mode\r\n");
00127 #endif
00128             wifi->send("a\r\n");
00129             wait(0.2);
00130             wifi->exit();
00131             if (!wifi->cmdMode())
00132                 return false;
00133         }
00134 
00135         if (!wifi->send("set comm remote 0\r\n", "AOK")) {
00136 #ifdef DEBUG
00137             printf("Websocket::connect(): cannot set empty remote string\r\n");
00138 #endif
00139             return false;
00140         }
00141 
00142         //open the connection
00143         sprintf(cmd, "open %s %s\r\n", ip_domain.c_str(), port.c_str());
00144         if (!wifi->send(cmd, "OPEN")) {
00145             if (wifi->send(cmd, "nected")) {
00146 #ifdef DEBUG
00147                 printf("will try to close the conn\r\n");
00148 #endif
00149                 if (!wifi->send("close\r", "CLOS")) {
00150                     return false;
00151                 }
00152                 if (!wifi->send(cmd, "OPEN"))
00153                     return false;
00154             } else {
00155                 return false;
00156             }
00157         }
00158 
00159         //send websocket HTTP header
00160         sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
00161         wifi->send(cmd);
00162         wifi->send("Upgrade: websocket\r\n");
00163         wifi->send("Connection: Upgrade\r\n");
00164         sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
00165         wifi->send(cmd);
00166         wifi->send("Origin: null\r\n");
00167         wifi->send("Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n");
00168         if (!wifi->send("Sec-WebSocket-Version: 13\r\n\r\n", "DdLWT/1JcX+nQFHebYP+rqEx5xI="))
00169             return false;
00170 
00171         wifi->flush();
00172 
00173         //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());
00174         return true;
00175     }
00176 #ifdef TARGET_LPC1768
00177     else if (netif == ETH) {
00178         Host server (*server_ip, atoi(port.c_str()));
00179         sock->close();
00180         TCPSocketErr bindErr = sock->connect(server);
00181         if (bindErr) {
00182 #ifdef DEBUG
00183             printf("\r\nERROR binderr: %d\r\n", bindErr);
00184 #endif
00185             return false;
00186         }
00187 
00188         Timer tmr;
00189         tmr.start();
00190 
00191         Timer stop;
00192         stop.start();
00193 
00194         int i = 0;
00195         while (true) {
00196             Net::poll();
00197             if (stop.read() > 3)
00198                 return false;
00199             if (tmr.read() > 0.05) {
00200                 tmr.reset();
00201                 if (eth_connected) {
00202                     switch (i) {
00203                         case 0:
00204                             sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
00205                             sock->send(cmd, strlen(cmd));
00206                             i++;
00207                             break;
00208                         case 1:
00209                             sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
00210                             sock->send(cmd, strlen(cmd));
00211                             i++;
00212                             break;
00213                         case 2:
00214                             sprintf(cmd, "Upgrade: WebSocket\r\n");
00215                             sock->send(cmd, strlen(cmd));
00216                             i++;
00217                             break;
00218                         case 3:
00219                             sprintf(cmd, "Origin: null\r\n");
00220                             sock->send(cmd, strlen(cmd));
00221                             i++;
00222                             break;
00223                         case 4:
00224                             sprintf(cmd, "Connection: Upgrade\r\n");
00225                             sock->send(cmd, strlen(cmd));
00226                             i++;
00227                             break;
00228                         case 5:
00229                             sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n");
00230                             sock->send(cmd, strlen(cmd));
00231                             i++;
00232                             break;
00233                         case 6:
00234                             sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
00235                             sock->send(cmd, strlen(cmd));
00236                             i++;
00237                             break;
00238                         case 7:
00239                             if (response_server_eth)
00240                                 i++;
00241                             else
00242                                 break;
00243 
00244                         default:
00245                             break;
00246                     }
00247                 }
00248                 if (i==8) {
00249 #ifdef DEBUG
00250                     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());
00251 #endif
00252                     return true;
00253                 }
00254             }
00255         }
00256     }
00257 #endif //target
00258     //the program shouldn't be here
00259     return false;
00260 }
00261 
00262 void Websocket::sendLength(uint32_t len) {
00263     if (len < 126) {
00264         sendChar(len | (1<<7));
00265     } else if (len < 65535) {
00266         sendChar(126 | (1<<7));
00267         sendChar((len >> 8) & 0xff);
00268         sendChar(len & 0xff);
00269     } else {
00270         sendChar(127 | (1<<7));
00271         for (int i = 0; i < 8; i++) {
00272             sendChar((len >> i*8) & 0xff);
00273         }
00274     }
00275 }
00276 
00277 void Websocket::sendChar(uint8_t c) {
00278     if (netif == WIF) {
00279         wifi->putc(c);
00280     }
00281 #ifdef TARGET_LPC1768
00282     else if (netif == ETH) {
00283         Net::poll();
00284         sock->send((const char *)&c, 1);
00285     }
00286 #endif
00287 }
00288 
00289 void Websocket::sendOpcode(uint8_t opcode) {
00290     sendChar(0x80 | (opcode & 0x0f));
00291 }
00292 
00293 void Websocket::sendMask() {
00294     for (int i = 0; i < 4; i++) {
00295         sendChar(0);
00296     }
00297 }
00298 
00299 void Websocket::send(char * str) {
00300     sendOpcode(0x01);
00301     sendLength(strlen(str));
00302     sendMask();
00303     if (netif == WIF) {
00304         wifi->send(str, NULL);
00305     }
00306 #ifdef TARGET_LPC1768
00307     else if (netif == ETH) {
00308         Net::poll();
00309         sock->send(str, strlen(str));
00310     }
00311 #endif //target
00312 }
00313 
00314 
00315 
00316 bool Websocket::read(char * message) {
00317     int i = 0;
00318     int length_buffer = 0;
00319     uint64_t len_msg;
00320     char opcode = 0;
00321     char mask[4] = {0, 0, 0, 0};
00322     Timer tmr;
00323 
00324     if (netif == WIF) {
00325         length_buffer = wifi->readable();
00326 
00327         if (length_buffer > 1) {
00328             // read the opcode
00329             tmr.start();
00330             while (true) {
00331                 if (tmr.read() > 3) {
00332                     return false;
00333                 }
00334                 if (wifi->readable()) {
00335                     opcode = wifi->getc();
00336                 }
00337                 if (opcode == 0x81) {
00338                     break;
00339                 }
00340             }
00341 #ifdef DEBUG
00342             printf("opcode: 0x%X\r\n", opcode);
00343 #endif
00344             len_msg = wifi->getc() & 0x7f;
00345             if (len_msg == 126) {
00346                 len_msg = (wifi->getc() << 8);
00347                 len_msg += wifi->getc();
00348             } else if (len_msg == 127) {
00349                 len_msg = 0;
00350                 for (int i = 0; i < 8; i++) {
00351                     len_msg += (wifi->getc() << (7-i)*8);
00352                 }
00353             }
00354             if (len_msg == 0) {
00355                 return false;
00356             }
00357 #ifdef DEBUG
00358             printf("length: %lld\r\n", len_msg);
00359 #endif
00360             if ((len_msg & 0x80)) {
00361 #ifdef DEBUG
00362                 printf("will read mask\r\n");
00363 #endif
00364                 for (int i = 0; i < 4; i++) {
00365                     mask[i] = wifi->getc();
00366 #ifdef DEBUG
00367                     printf("mask[%d]: %d\r\n", i, mask[i]);
00368 #endif
00369                 }
00370             } else {
00371 #ifdef DEBUG
00372                 printf("len not 0x80\r\n");
00373 #endif
00374             }
00375         } else {
00376             return false;
00377         }
00378 
00379 
00380         for (i = 0; i < len_msg; i++) {
00381             message[i] = wifi->getc() ^ mask[i % 4];
00382         }
00383 
00384         message[len_msg] = 0;
00385         return true;
00386     }
00387 #ifdef TARGET_LPC1768
00388     else if (netif == ETH) {
00389 
00390         uint32_t index = 0;
00391         Net::poll();
00392 
00393         if (new_msg) {
00394             tmr.start();
00395             // read the opcode
00396             while (true) {
00397                 if (tmr.read() > 3) {
00398                     return false;
00399                 }
00400                 opcode = eth_rx[index++];
00401                 if (opcode == 0x81) {
00402                     break;
00403                 }
00404             }
00405 #ifdef DEBUG
00406             printf("opcode: 0x%X\r\n", opcode);
00407 #endif
00408 
00409             len_msg = eth_rx[index++] & 0x7f;
00410             if (len_msg == 126) {
00411                 len_msg = (eth_rx[index++] << 8);
00412                 len_msg += eth_rx[index++];
00413             } else if (len_msg == 127) {
00414                 len_msg = 0;
00415                 for (int i = 0; i < 8; i++) {
00416                     len_msg += eth_rx[index++] << (7-i)*8;
00417                 }
00418             }
00419             if (len_msg == 0) {
00420                 return false;
00421             }
00422 #ifdef DEBUG
00423             printf("length: %lld\r\n", len_msg);
00424 #endif
00425             if ((len_msg & 0x80)) {
00426                 for (int i = 0; i < 4; i++)
00427                     mask[i] = eth_rx[index++];
00428             }
00429 
00430             for (i = 0; i < len_msg; i++) {
00431                 message[i] = eth_rx[index++] ^ mask[i % 4];
00432             }
00433 
00434             message[len_msg] = 0;
00435             new_msg = false;
00436             return true;
00437         }
00438         return false;
00439     }
00440 #endif //target
00441 //the program shouldn't be here
00442     return false;
00443 }
00444 
00445 bool Websocket::close() {
00446     sendOpcode(0x08);
00447     sendLength(0);
00448     sendMask();
00449     if (netif == WIF) {
00450 
00451         wait(0.25);
00452         if (!wifi->cmdMode()) {
00453 #ifdef DEBUG
00454             printf("Websocket::close: cannot enter in cmd mode\r\n");
00455 #endif
00456             return false;
00457         }
00458         wait(0.25);
00459 
00460         wifi->send("close\r", NULL);
00461 
00462         if (!wifi->exit())
00463             return false;
00464     }
00465 #ifdef TARGET_LPC1768
00466     else if (netif == ETH) {
00467 #ifdef TARGET_LPC1768
00468         Net::poll();
00469 #endif //target
00470 
00471         if (sock->close())
00472             return false;
00473         return true;
00474     }
00475 #endif //target
00476     //the program shouldn't be here
00477     return false;
00478 }
00479 
00480 
00481 
00482 bool Websocket::connected() {
00483     if (netif == WIF) {
00484         char str[10];
00485 
00486         // we have to wait at least 0.25s to enter in cmd mode whan we was sending tcp packets
00487         wait(0.25);
00488         if (!wifi->cmdMode()) {
00489 #ifdef DEBUG
00490             printf("Websocket::connected: cannot enter in cmd mode\r\n");
00491 #endif
00492             return false;
00493         }
00494         wait(0.25);
00495 
00496         wifi->send("show c\r\n", NULL, str);
00497 #ifdef DEBUG
00498         printf("Websocket::connected: str: %s\r\n", str);
00499 #endif
00500 
00501         if (str[3] == '1') {
00502             if (!wifi->exit()) {
00503 #ifdef DEBUG
00504                 printf("Websocket::connected: cannot exit\r\n");
00505 #endif
00506                 return false;
00507             }
00508             return true;
00509         }
00510         if (!wifi->exit()) {
00511 #ifdef DEBUG
00512             printf("Websocket::connected: cannot exit\r\n");
00513 #endif
00514         }
00515         return false;
00516     }
00517 #ifdef TARGET_LPC1768
00518     else if (netif == ETH) {
00519         return eth_connected;
00520     }
00521 #endif //target
00522     //the program shouldn't be here
00523     return false;
00524 }
00525 
00526 
00527 std::string Websocket::getPath() {
00528     return path;
00529 }
00530 
00531 
00532 
00533 
00534 #ifdef TARGET_LPC1768
00535 void Websocket::onTCPSocketEvent(TCPSocketEvent e) {
00536     if (e == TCPSOCKET_CONNECTED) {
00537         eth_connected = true;
00538 #ifdef DEBUG
00539         printf("TCP Socket Connected\r\n");
00540 #endif
00541     } else if (e == TCPSOCKET_WRITEABLE) {
00542     } else if (e == TCPSOCKET_READABLE) {
00543         int len = sock->recv(eth_rx, 512);
00544         eth_rx[len] = 0;
00545         new_msg = true;
00546         if (!response_server_eth) {
00547             string checking;
00548             size_t found = string::npos;
00549             checking = eth_rx;
00550             found = checking.find("DdLWT/1JcX+nQFHebYP+rqEx5xI=");
00551             if (found != string::npos)
00552                 response_server_eth = true;
00553         }
00554     } else {
00555 #ifdef DEBUG
00556         printf("TCP Socket Fail\r\n");
00557 #endif
00558         eth_connected = false;
00559     }
00560 }
00561 #endif //target
00562 
00563