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