WebSocket client library
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Fri Jul 15 2022 13:24:59 by 1.7.2