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