Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of WebSocketClient by
Websocket.cpp
00001 #include "Websocket.h" 00002 #include "DNSClient.h" 00003 00004 #define MAX_TRY_WRITE 20 00005 #define MAX_TRY_READ 10 00006 00007 //Debug is disabled by default 00008 #if 1 00009 #define DBG(x, ...) std::printf("[WebSocket : DBG]"x"\r\n", ##__VA_ARGS__); 00010 #define WARN(x, ...) std::printf("[WebSocket : WARN]"x"\r\n", ##__VA_ARGS__); 00011 #define ERR(x, ...) std::printf("[WebSocket : ERR]"x"\r\n", ##__VA_ARGS__); 00012 #else 00013 #define DBG(x, ...) 00014 #define WARN(x, ...) 00015 #define ERR(x, ...) 00016 #endif 00017 00018 #define INFO(x, ...) printf("[WebSocket : INFO]"x"\r\n", ##__VA_ARGS__); 00019 00020 Websocket::Websocket(NetworkStack *ns, char * url) { 00021 m_ns = ns; 00022 fillFields(url); 00023 socket.open(ns); 00024 socket.set_blocking(false); 00025 socket.set_timeout(400); 00026 } 00027 00028 void Websocket::fillFields(char * url) { 00029 int ret = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); 00030 if(ret) 00031 { 00032 ERR("URL parsing failed; please use: \"ws://ip-or-domain[:port]/path\""); 00033 return; 00034 } 00035 00036 if(port == 0) //TODO do handle WSS->443 00037 { 00038 port = 80; 00039 } 00040 00041 if(strcmp(scheme, "ws")) 00042 { 00043 ERR("Wrong scheme, please use \"ws\" instead"); 00044 } 00045 } 00046 00047 int Websocket::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL 00048 { 00049 char* schemePtr = (char*) url; 00050 char* hostPtr = (char*) strstr(url, "://"); 00051 if(hostPtr == NULL) 00052 { 00053 WARN("Could not find host"); 00054 return -1; //URL is invalid 00055 } 00056 00057 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char 00058 { 00059 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); 00060 return -1; 00061 } 00062 memcpy(scheme, schemePtr, hostPtr - schemePtr); 00063 scheme[hostPtr - schemePtr] = '\0'; 00064 00065 hostPtr+=3; 00066 00067 size_t hostLen = 0; 00068 00069 char* portPtr = strchr(hostPtr, ':'); 00070 if( portPtr != NULL ) 00071 { 00072 hostLen = portPtr - hostPtr; 00073 portPtr++; 00074 if( sscanf(portPtr, "%hu", port) != 1) 00075 { 00076 WARN("Could not find port"); 00077 return -1; 00078 } 00079 } 00080 else 00081 { 00082 *port=0; 00083 } 00084 char* pathPtr = strchr(hostPtr, '/'); 00085 if( hostLen == 0 ) 00086 { 00087 hostLen = pathPtr - hostPtr; 00088 } 00089 00090 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char 00091 { 00092 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); 00093 return -1; 00094 } 00095 memcpy(host, hostPtr, hostLen); 00096 host[hostLen] = '\0'; 00097 00098 size_t pathLen; 00099 char* fragmentPtr = strchr(hostPtr, '#'); 00100 if(fragmentPtr != NULL) 00101 { 00102 pathLen = fragmentPtr - pathPtr; 00103 } 00104 else 00105 { 00106 pathLen = strlen(pathPtr); 00107 } 00108 00109 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char 00110 { 00111 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); 00112 return -1; 00113 } 00114 memcpy(path, pathPtr, pathLen); 00115 path[pathLen] = '\0'; 00116 00117 return 0; 00118 } 00119 00120 00121 bool Websocket::connect() { 00122 DNSClient dns(m_ns); 00123 char cmd[200]; 00124 00125 if (!dns.lookup(host)) { 00126 ERR("Websocket: Unable to resolve hostname (%s)", host); 00127 wait(0.2); 00128 connected = false; 00129 return false; 00130 } 00131 00132 while (socket.connect(dns.get_ip_address(), port) < 0) { 00133 ERR("Websocket: Unable to connect to (%s) on port (%d)", host, port); 00134 wait(0.2); 00135 connected = false; 00136 return false; 00137 } 00138 00139 connected = true; 00140 00141 // sent http header to upgrade to the ws protocol 00142 sprintf(cmd, "GET %s HTTP/1.1\r\n", path); 00143 write(cmd, strlen(cmd)); 00144 00145 sprintf(cmd, "Host: %s:%d\r\n", host, port); 00146 write(cmd, strlen(cmd)); 00147 00148 sprintf(cmd, "Upgrade: WebSocket\r\n"); 00149 write(cmd, strlen(cmd)); 00150 00151 sprintf(cmd, "Connection: Upgrade\r\n"); 00152 write(cmd, strlen(cmd)); 00153 00154 sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); 00155 write(cmd, strlen(cmd)); 00156 00157 sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n"); 00158 int ret = write(cmd, strlen(cmd)); 00159 if (ret != strlen(cmd)) { 00160 close(); 00161 ERR("Could not send request"); 00162 return false; 00163 } 00164 00165 ret = read(cmd, 200, 100); 00166 if (ret < 0) { 00167 close(); 00168 ERR("Could not receive answer\r\n"); 00169 return false; 00170 } 00171 00172 cmd[ret] = '\0'; 00173 DBG("recv: %s\r\n", cmd); 00174 00175 if ( strstr(cmd, "DdLWT/1JcX+nQFHebYP+rqEx5xI=") == NULL ) { 00176 ERR("Wrong answer from server, got \"%s\" instead\r\n", cmd); 00177 do { 00178 ret = read(cmd, 200, 100); 00179 if (ret < 0) { 00180 ERR("Could not receive answer\r\n"); 00181 return false; 00182 } 00183 cmd[ret] = '\0'; 00184 printf("%s",cmd); 00185 } while (ret > 0); 00186 close(); 00187 return false; 00188 } 00189 00190 INFO("\r\nhost: %s\r\npath: %s\r\nport: %d\r\n\r\n", host, path, port); 00191 return true; 00192 } 00193 00194 int Websocket::sendLength(uint32_t len, char * msg) { 00195 00196 if (len < 126) { 00197 msg[0] = len | (1<<7); 00198 return 1; 00199 } else if (len < 65535) { 00200 msg[0] = 126 | (1<<7); 00201 msg[1] = (len >> 8) & 0xff; 00202 msg[2] = len & 0xff; 00203 return 3; 00204 } else { 00205 msg[0] = 127 | (1<<7); 00206 for (int i = 0; i < 8; i++) { 00207 msg[i+1] = (len >> i*8) & 0xff; 00208 } 00209 return 9; 00210 } 00211 } 00212 00213 int Websocket::readChar(char * pC, bool block) { 00214 return read(pC, 1, 1); 00215 } 00216 00217 int Websocket::sendOpcode(uint8_t opcode, char * msg) { 00218 msg[0] = 0x80 | (opcode & 0x0f); 00219 return 1; 00220 } 00221 00222 int Websocket::sendMask(char * msg) { 00223 for (int i = 0; i < 4; i++) { 00224 msg[i] = 0; 00225 } 00226 return 4; 00227 } 00228 00229 int Websocket::send(char * str) { 00230 char msg[strlen(str) + 15]; 00231 int idx = 0; 00232 idx = sendOpcode(0x01, msg); 00233 idx += sendLength(strlen(str), msg + idx); 00234 idx += sendMask(msg + idx); 00235 memcpy(msg+idx, str, strlen(str)); 00236 int res = write(msg, idx + strlen(str)); 00237 return res; 00238 } 00239 00240 00241 bool Websocket::read(char * message) { 00242 int i = 0; 00243 uint32_t len_msg; 00244 char opcode = 0; 00245 char c; 00246 char mask[4] = {0, 0, 0, 0}; 00247 bool is_masked = false; 00248 Timer tmr; 00249 00250 // read the opcode 00251 tmr.start(); 00252 while (true) { 00253 if (tmr.read() > 3) { 00254 DBG("timeout ws\r\n"); 00255 return false; 00256 } 00257 00258 if(!connected) 00259 { 00260 WARN("Connection was closed by server"); 00261 return false; 00262 } 00263 00264 socket.set_blocking(false); 00265 socket.set_timeout(1); 00266 if (socket.recv(&opcode, 1) != 1) { 00267 socket.set_blocking(false); 00268 socket.set_timeout(2000); 00269 return false; 00270 } 00271 00272 socket.set_blocking(false); 00273 socket.set_timeout(2000); 00274 00275 if (opcode == 0x81) 00276 break; 00277 } 00278 DBG("opcode: 0x%X\r\n", opcode); 00279 00280 readChar(&c); 00281 len_msg = c & 0x7f; 00282 is_masked = c & 0x80; 00283 if (len_msg == 126) { 00284 readChar(&c); 00285 len_msg = c << 8; 00286 readChar(&c); 00287 len_msg += c; 00288 } else if (len_msg == 127) { 00289 len_msg = 0; 00290 for (int i = 0; i < 8; i++) { 00291 readChar(&c); 00292 len_msg += (c << (7-i)*8); 00293 } 00294 } 00295 00296 if (len_msg == 0) { 00297 return false; 00298 } 00299 DBG("length: %d\r\n", len_msg); 00300 00301 if (is_masked) { 00302 for (i = 0; i < 4; i++) 00303 readChar(&c); 00304 mask[i] = c; 00305 } 00306 00307 int nb = read(message, len_msg, len_msg); 00308 if (nb != len_msg) 00309 return false; 00310 00311 for (i = 0; i < len_msg; i++) { 00312 message[i] = message[i] ^ mask[i % 4]; 00313 } 00314 00315 message[len_msg] = '\0'; 00316 00317 return true; 00318 } 00319 00320 bool Websocket::close() { 00321 if (!is_connected()) 00322 return false; 00323 00324 int ret = socket.close(); 00325 if (ret < 0) { 00326 ERR("Could not disconnect"); 00327 return false; 00328 } 00329 return true; 00330 } 00331 00332 bool Websocket::is_connected() { 00333 return connected; 00334 } 00335 00336 char* Websocket::getPath() { 00337 return path; 00338 } 00339 00340 int Websocket::write(char * str, int len) { 00341 int res = 0, idx = 0; 00342 00343 for (int j = 0; j < MAX_TRY_WRITE; j++) { 00344 00345 if(!connected) 00346 { 00347 WARN("Connection was closed by server"); 00348 break; 00349 } 00350 00351 if ((res = socket.send(str + idx, len - idx)) == -1) 00352 continue; 00353 00354 idx += res; 00355 00356 if (idx == len) 00357 return len; 00358 } 00359 00360 return (idx == 0) ? -1 : idx; 00361 } 00362 00363 int Websocket::read(char * str, int len, int min_len) { 00364 int res = 0, idx = 0; 00365 00366 for (int j = 0; j < MAX_TRY_WRITE; j++) { 00367 00368 if ((res = socket.recv(str + idx, len - idx)) == -1) 00369 continue; 00370 00371 idx += res; 00372 00373 if (idx == len || (min_len != -1 && idx > min_len)) 00374 return idx; 00375 } 00376 00377 return (idx == 0) ? -1 : idx; 00378 }
Generated on Sun Jul 17 2022 09:02:19 by
1.7.2
