http://mbed.org/users/okini3939/notebook/node_websocket/

Dependencies:   EthernetNetIf mbed MbedJSONValue

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Websocket.cpp Source File

Websocket.cpp

00001 /*
00002  * modify by Suga
00003  */
00004 #include "Websocket.h"
00005 #include <string>
00006 
00007 #ifdef WIFLY
00008 Websocket::Websocket(char * url, Wifly * wifi) {
00009     this->wifi = wifi;
00010     netif = WIF;
00011     fillFields(url);
00012 }
00013 #endif
00014 
00015 void Websocket::isr_dns (DNSReply r) {
00016     if (DNS_FOUND) {
00017         dns_status = 1;
00018     } else {
00019         dns_status = -1;
00020     }
00021 }
00022 
00023 Websocket::Websocket(char * url, EthernetNetIf *e) {
00024     server_ip = NULL;
00025     netif = ETH;
00026     eth_writeable = false;
00027     eth_readable = false;
00028     eth_connected = false;
00029     response_server_eth = false;
00030     new_msg = false;
00031     fillFields(url);
00032 
00033 #ifdef ETH_SETUP
00034     eth = new EthernetNetIf();
00035 #else
00036     eth = e;
00037 #endif
00038     sock = new TCPSocket();
00039 
00040 #ifdef ETH_SETUP
00041     EthernetErr ethErr = eth->setup();
00042 #ifdef DEBUG
00043     if (ethErr) {
00044         printf("\r\nERROR %d in setup.\r\n", ethErr);
00045     }
00046 #endif
00047 #endif
00048 
00049     //we must use dnsresolver to find the ip address
00050     if (server_ip == NULL) {
00051 /*
00052         DNSResolver dr;
00053         server_ip = new IpAddr();
00054         *server_ip = dr.resolveName(ip_domain.c_str());
00055 */
00056         DNSRequest dns;
00057         Timer timeout;
00058         server_ip = new IpAddr();
00059         dns_status = 0;
00060         dns.setOnReply(this, &Websocket::isr_dns);
00061         if (dns.resolve(ip_domain.c_str()) != DNS_OK) return;
00062         timeout.reset();
00063         timeout.start();
00064         while (timeout.read_ms() < 15000) {
00065             if (dns_status) break;
00066             Net::poll();
00067         }
00068         timeout.stop();
00069         if (dns_status <= 0) return;
00070         dns.getResult(server_ip);
00071         dns.close();
00072 #ifdef DEBUG
00073         printf("\r\nserver with dns=%i.%i.%i.%i\r\n",server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
00074 #endif
00075 
00076     }
00077 
00078     IpAddr ipt = eth->getIp();
00079 #ifdef DEBUG
00080     printf("\r\nmbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]);
00081 #endif
00082 
00083     sock->setOnEvent(this, &Websocket::onTCPSocketEvent);
00084 }
00085 
00086 
00087 void Websocket::fillFields(char * url) {
00088     char *res = NULL;
00089     char *res1 = NULL;
00090 
00091     char buf[50];
00092     strcpy(buf, url);
00093 
00094     res = strtok(buf, ":");
00095     if (strcmp(res, "ws")) {
00096 #ifdef DEBUG
00097         printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
00098 #endif
00099     } else {
00100         //ip_domain and port
00101         res = strtok(NULL, "/");
00102 
00103         //path
00104         res1 = strtok(NULL, " ");
00105         if (res1 != NULL) {
00106             path = res1;
00107         }
00108 
00109         //ip_domain
00110         res = strtok(res, ":");
00111 
00112         //port
00113         res1 = strtok(NULL, " ");
00114         //port
00115         if (res1 != NULL) {
00116             port = res1;
00117         } else {
00118             port = "80";
00119         }
00120 
00121         if (res != NULL) {
00122             ip_domain = res;
00123 
00124             //if we use ethernet, we must decode ip address or use dnsresolver
00125             if (netif == ETH) {
00126                 strcpy(buf, res);
00127 
00128                 //we try to decode the ip address
00129                 if (buf[0] >= '0' && buf[0] <= '9') {
00130                     res = strtok(buf, ".");
00131                     int i = 0;
00132                     int ip[4];
00133                     while (res != NULL) {
00134                         ip[i] = atoi(res);
00135                         res = strtok(NULL, ".");
00136                         i++;
00137                     }
00138                     server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]);
00139 #ifdef DEBUG
00140                     printf("server without dns=%i.%i.%i.%i\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]);
00141 #endif
00142                 }
00143             }
00144         }
00145     }
00146 }
00147 
00148 
00149 bool Websocket::connect() {
00150     char cmd[50];
00151 #ifdef WIFLY
00152     if (netif == WIF) {
00153         wifi->send("exit\r", "NO");
00154         //enter in cmd mode
00155         while (!wifi->send("$$$", "CMD")) {
00156 #ifdef DEBUG
00157             printf("cannot enter in CMD mode\r\n");
00158 #endif
00159             wifi->exit();
00160         }
00161 
00162 
00163         //open the connection
00164         sprintf(cmd, "open %s %s\r\n", ip_domain.c_str(), port.c_str());
00165         if (!wifi->send(cmd, "OPEN*")) {
00166 #ifdef DEBUG
00167             printf("Websocket::connect cannot open\r\n");
00168 #endif
00169             return false;
00170         }
00171 
00172 
00173         //send websocket HTTP header
00174         sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
00175         wifi->send(cmd, "NO");
00176 
00177         sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
00178         wifi->send(cmd, "NO");
00179 
00180         wifi->send("Upgrade: WebSocket\r\n", "NO");
00181 
00182         sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str());
00183         wifi->send(cmd, "NO");
00184 
00185 
00186         wifi->send("Connection: Upgrade\r\n", "NO");
00187         wifi->send("Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n", "NO");
00188         wifi->send("Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n", "NO");
00189         if (!wifi->send("^n:ds[4U", "8jKS'y:G*Co,Wxa-"))
00190             return false;
00191 #ifdef DEBUG
00192         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());
00193 #endif
00194         return true;
00195     } else
00196 #endif
00197     if (netif == ETH) {
00198         Host server (*server_ip, atoi(port.c_str()));
00199         sock->close();
00200         TCPSocketErr bindErr = sock->connect(server);
00201         if (bindErr) {
00202 #ifdef DEBUG
00203             printf("\r\nERROR binderr: %d\r\n", bindErr);
00204 #endif
00205             return false;
00206         }
00207 
00208         Timer tmr;
00209         tmr.start();
00210 
00211         Timer stop;
00212         stop.start();
00213 
00214         int i = 0;
00215         while (true) {
00216             Net::poll();
00217             if (stop.read() > 3)
00218                 return false;
00219             if (tmr.read() > 0.01) {
00220                 tmr.reset();
00221                 if (eth_connected) {
00222                     switch (i) {
00223                         case 0:
00224                             sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
00225                             sock->send(cmd, strlen(cmd));
00226                             i++;
00227                             break;
00228                         case 1:
00229                             sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
00230                             sock->send(cmd, strlen(cmd));
00231                             i++;
00232                             break;
00233                         case 2:
00234                             sprintf(cmd, "Upgrade: WebSocket\r\n");
00235                             sock->send(cmd, strlen(cmd));
00236                             i++;
00237                             break;
00238                         case 3:
00239                             sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str());
00240                             sock->send(cmd, strlen(cmd));
00241                             i++;
00242                             break;
00243                         case 4:
00244                             sprintf(cmd, "Connection: Upgrade\r\n");
00245                             sock->send(cmd, strlen(cmd));
00246                             i++;
00247                             break;
00248                         case 5:
00249                             sprintf(cmd, "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n");
00250                             sock->send(cmd, strlen(cmd));
00251                             i++;
00252                             break;
00253                         case 6:
00254                             sprintf(cmd, "Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n");
00255                             sock->send(cmd, strlen(cmd));
00256                             i++;
00257                             break;
00258                         case 7:
00259                             sock->send("^n:ds[4U", 8);
00260                             i++;
00261                             break;
00262                         case 8:
00263                             if (response_server_eth)
00264                                 i++;
00265                             else
00266                                 break;
00267 
00268                         default:
00269                             break;
00270                     }
00271                 }
00272                 if (i==9) {
00273 #ifdef DEBUG
00274                     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());
00275 #endif
00276                     return true;
00277                 }
00278             }
00279         }
00280     }
00281     //the program shouldn't be here
00282     return false;
00283 }
00284 
00285 void Websocket::send(char * str) {
00286 #ifdef WIFLY
00287     if (netif == WIF) {
00288         wifi->putc('\x00');
00289         wifi->send(str, "NO");
00290         wifi->putc('\xff');
00291     } else
00292 #endif
00293     if (netif == ETH) {
00294         char c = '\x00';
00295         Net::poll();
00296         sock->send(&c, 1);
00297         sock->send(str, strlen(str));
00298         c = '\xff';
00299         sock->send(&c, 1);
00300     }
00301 }
00302 
00303 bool Websocket::read(char * message) {
00304     int i = 0;
00305 
00306 #ifdef WIFLY
00307     if (netif == WIF) {
00308         if (!wifi->read(message))
00309             return false;
00310 
00311         //we check if the first byte is 0x00
00312         if (message == NULL || message[0] != 0x00) {
00313             message = NULL;
00314             return false;
00315         }
00316 
00317         while (message[i + 1] != 0xff && i < strlen(message + 1))
00318             i++;
00319 
00320         if (message[i+1] == 0xff) {
00321             message[i+1] = 0;
00322             memcpy(message, message + 1, strlen(message + 1) + 1);
00323             return true;
00324         } else {
00325             message = NULL;
00326             return false;
00327         }
00328     } else
00329 #endif
00330     if (netif == ETH) {
00331         Net::poll();
00332 
00333         if (new_msg) {
00334             if (eth_rx[0] != 0x00) {
00335                 message = NULL;
00336                 return false;
00337             }
00338             while (eth_rx[i + 1] != 0xff) {
00339                 message[i] = eth_rx[i + 1];
00340                 i++;
00341             }
00342             message[i] = 0;
00343             new_msg = false;
00344             return true;
00345         }
00346         return false;
00347     }
00348     //the program shouldn't be here
00349     return false;
00350 }
00351 
00352 bool Websocket::close() {
00353 #ifdef WIFLY
00354     if (netif == WIF) {
00355         if (!wifi->cmdMode()) {
00356 #ifdef DEBUG
00357             printf("Websocket::close: cannot enter in cmd mode\r\n");
00358 #endif
00359             return false;
00360         }
00361 
00362         wifi->send("close\r", "NO");
00363 
00364         if (!wifi->exit())
00365             return false;
00366     } else
00367 #endif
00368     if (netif == ETH) {
00369 
00370         if (sock->close())
00371             return false;
00372         return true;
00373     }
00374     //the program shouldn't be here
00375     return false;
00376 }
00377 
00378 
00379 
00380 bool Websocket::connected() {
00381 #ifdef WIFLY
00382     if (netif == WIF) {
00383         char str[10];
00384 
00385         wait(0.25);
00386         if (!wifi->cmdMode()) {
00387 #ifdef DEBUG
00388             printf("Websocket::connected: cannot enter in cmd mode\r\n");
00389 #endif
00390             return false;
00391         }
00392         wait(0.25);
00393 
00394         wifi->send("show c\r\n", "NO", str);
00395 
00396         if (str[3] == '1') {
00397             if (!wifi->exit()) {
00398 #ifdef DEBUG
00399                 printf("Websocket::connected: cannot exit\r\n");
00400 #endif
00401                 return false;
00402             }
00403             return true;
00404         }
00405         if (!wifi->exit()) {
00406 #ifdef DEBUG
00407             printf("Websocket::connected: cannot exit\r\n");
00408 #endif
00409         }
00410         return false;
00411     } else
00412 #endif
00413     if (netif == ETH) {
00414 
00415         return eth_connected;
00416     }
00417     //the program shouldn't be here
00418     return false;
00419 }
00420 
00421 std::string Websocket::getPath()
00422 {
00423     return path;
00424 }
00425 
00426 
00427 
00428 
00429 void Websocket::onTCPSocketEvent(TCPSocketEvent e) {
00430     if (e == TCPSOCKET_CONNECTED) {
00431         eth_connected = true;
00432 #ifdef DEBUG
00433         printf("TCP Socket Connected\r\n");
00434 #endif
00435     } else if (e == TCPSOCKET_WRITEABLE) {
00436     } else if (e == TCPSOCKET_READABLE) {
00437         int len = sock->recv(eth_rx, 512);
00438         eth_rx[len] = 0;
00439         new_msg = true;
00440         if (!response_server_eth) {
00441             string checking;
00442             size_t found = string::npos;
00443             checking = eth_rx;
00444             found = checking.find("HTTP");
00445             if (found != string::npos)
00446                 response_server_eth = true;
00447         }
00448     } else {
00449 #ifdef DEBUG
00450         printf("TCP Socket Fail\r\n");
00451 #endif
00452         eth_connected = false;
00453     }
00454 }
00455 
00456