websocket client
Fork of WebSocketClient by
Websocket.cpp@9:6275000e9224, 2016-02-04 (annotated)
- Committer:
- kanehara
- Date:
- Thu Feb 04 15:49:27 2016 +0000
- Revision:
- 9:6275000e9224
- Parent:
- 8:a909ee26be2d
fix the newline character.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kanehara | 9:6275000e9224 | 1 | #include "Websocket.h" |
kanehara | 9:6275000e9224 | 2 | |
kanehara | 9:6275000e9224 | 3 | #define MAX_TRY_WRITE 20 |
kanehara | 9:6275000e9224 | 4 | #define MAX_TRY_READ 10 |
kanehara | 9:6275000e9224 | 5 | |
kanehara | 9:6275000e9224 | 6 | //Debug is disabled by default |
kanehara | 9:6275000e9224 | 7 | #ifdef DEBUG |
kanehara | 9:6275000e9224 | 8 | #define DBG(x, ...) std::printf("[WebSocket : DBG]"x"\r\n", ##__VA_ARGS__); |
kanehara | 9:6275000e9224 | 9 | #define WARN(x, ...) std::printf("[WebSocket : WARN]"x"\r\n", ##__VA_ARGS__); |
kanehara | 9:6275000e9224 | 10 | #define ERR(x, ...) std::printf("[WebSocket : ERR]"x"\r\n", ##__VA_ARGS__); |
kanehara | 9:6275000e9224 | 11 | #define INFO(x, ...) printf("[WebSocket : INFO]"x"\r\n", ##__VA_ARGS__); |
kanehara | 9:6275000e9224 | 12 | #else |
kanehara | 9:6275000e9224 | 13 | #define DBG(x, ...) |
kanehara | 9:6275000e9224 | 14 | #define WARN(x, ...) |
kanehara | 9:6275000e9224 | 15 | #define ERR(x, ...) |
kanehara | 9:6275000e9224 | 16 | #define INFO(x, ...) |
kanehara | 9:6275000e9224 | 17 | #endif |
kanehara | 9:6275000e9224 | 18 | |
kanehara | 9:6275000e9224 | 19 | Websocket::Websocket(const char * url) { |
kanehara | 9:6275000e9224 | 20 | fillFields(url); |
kanehara | 9:6275000e9224 | 21 | socket.set_blocking(false, 400); |
kanehara | 9:6275000e9224 | 22 | } |
kanehara | 9:6275000e9224 | 23 | |
kanehara | 9:6275000e9224 | 24 | Websocket::~Websocket () { |
kanehara | 9:6275000e9224 | 25 | close (); |
kanehara | 9:6275000e9224 | 26 | } |
kanehara | 9:6275000e9224 | 27 | |
kanehara | 9:6275000e9224 | 28 | void Websocket::setFnPing (void (*fn)()) { |
kanehara | 9:6275000e9224 | 29 | fnPing = fn; |
kanehara | 9:6275000e9224 | 30 | } |
kanehara | 9:6275000e9224 | 31 | |
kanehara | 9:6275000e9224 | 32 | void Websocket::fillFields(const char * url) { |
kanehara | 9:6275000e9224 | 33 | int ret = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); |
kanehara | 9:6275000e9224 | 34 | if(ret) |
kanehara | 9:6275000e9224 | 35 | { |
kanehara | 9:6275000e9224 | 36 | ERR("URL parsing failed; please use: \"ws://ip-or-domain[:port]/path\""); |
kanehara | 9:6275000e9224 | 37 | return; |
kanehara | 9:6275000e9224 | 38 | } |
kanehara | 9:6275000e9224 | 39 | |
kanehara | 9:6275000e9224 | 40 | if(port == 0) //TODO do handle WSS->443 |
kanehara | 9:6275000e9224 | 41 | { |
kanehara | 9:6275000e9224 | 42 | port = 80; |
kanehara | 9:6275000e9224 | 43 | } |
kanehara | 9:6275000e9224 | 44 | |
kanehara | 9:6275000e9224 | 45 | if(strcmp(scheme, "ws")) |
kanehara | 9:6275000e9224 | 46 | { |
kanehara | 9:6275000e9224 | 47 | ERR("Wrong scheme, please use \"ws\" instead"); |
kanehara | 9:6275000e9224 | 48 | } |
kanehara | 9:6275000e9224 | 49 | } |
kanehara | 9:6275000e9224 | 50 | |
kanehara | 9:6275000e9224 | 51 | 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 |
kanehara | 9:6275000e9224 | 52 | { |
kanehara | 9:6275000e9224 | 53 | char* schemePtr = (char*) url; |
kanehara | 9:6275000e9224 | 54 | char* hostPtr = (char*) strstr(url, "://"); |
kanehara | 9:6275000e9224 | 55 | if(hostPtr == NULL) |
kanehara | 9:6275000e9224 | 56 | { |
kanehara | 9:6275000e9224 | 57 | WARN("Could not find host"); |
kanehara | 9:6275000e9224 | 58 | return -1; //URL is invalid |
kanehara | 9:6275000e9224 | 59 | } |
kanehara | 9:6275000e9224 | 60 | |
kanehara | 9:6275000e9224 | 61 | if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char |
kanehara | 9:6275000e9224 | 62 | { |
kanehara | 9:6275000e9224 | 63 | WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); |
kanehara | 9:6275000e9224 | 64 | return -1; |
kanehara | 9:6275000e9224 | 65 | } |
kanehara | 9:6275000e9224 | 66 | memcpy(scheme, schemePtr, hostPtr - schemePtr); |
kanehara | 9:6275000e9224 | 67 | scheme[hostPtr - schemePtr] = '\0'; |
kanehara | 9:6275000e9224 | 68 | |
kanehara | 9:6275000e9224 | 69 | hostPtr+=3; |
kanehara | 9:6275000e9224 | 70 | |
kanehara | 9:6275000e9224 | 71 | size_t hostLen = 0; |
kanehara | 9:6275000e9224 | 72 | |
kanehara | 9:6275000e9224 | 73 | char* portPtr = strchr(hostPtr, ':'); |
kanehara | 9:6275000e9224 | 74 | if( portPtr != NULL ) |
kanehara | 9:6275000e9224 | 75 | { |
kanehara | 9:6275000e9224 | 76 | hostLen = portPtr - hostPtr; |
kanehara | 9:6275000e9224 | 77 | portPtr++; |
kanehara | 9:6275000e9224 | 78 | if( sscanf(portPtr, "%hu", port) != 1) |
kanehara | 9:6275000e9224 | 79 | { |
kanehara | 9:6275000e9224 | 80 | WARN("Could not find port"); |
kanehara | 9:6275000e9224 | 81 | return -1; |
kanehara | 9:6275000e9224 | 82 | } |
kanehara | 9:6275000e9224 | 83 | } |
kanehara | 9:6275000e9224 | 84 | else |
kanehara | 9:6275000e9224 | 85 | { |
kanehara | 9:6275000e9224 | 86 | *port=0; |
kanehara | 9:6275000e9224 | 87 | } |
kanehara | 9:6275000e9224 | 88 | char* pathPtr = strchr(hostPtr, '/'); |
kanehara | 9:6275000e9224 | 89 | if( hostLen == 0 ) |
kanehara | 9:6275000e9224 | 90 | { |
kanehara | 9:6275000e9224 | 91 | hostLen = pathPtr - hostPtr; |
kanehara | 9:6275000e9224 | 92 | } |
kanehara | 9:6275000e9224 | 93 | |
kanehara | 9:6275000e9224 | 94 | if( maxHostLen < hostLen + 1 ) //including NULL-terminating char |
kanehara | 9:6275000e9224 | 95 | { |
kanehara | 9:6275000e9224 | 96 | WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); |
kanehara | 9:6275000e9224 | 97 | return -1; |
kanehara | 9:6275000e9224 | 98 | } |
kanehara | 9:6275000e9224 | 99 | memcpy(host, hostPtr, hostLen); |
kanehara | 9:6275000e9224 | 100 | host[hostLen] = '\0'; |
kanehara | 9:6275000e9224 | 101 | |
kanehara | 9:6275000e9224 | 102 | size_t pathLen; |
kanehara | 9:6275000e9224 | 103 | char* fragmentPtr = strchr(hostPtr, '#'); |
kanehara | 9:6275000e9224 | 104 | if(fragmentPtr != NULL) |
kanehara | 9:6275000e9224 | 105 | { |
kanehara | 9:6275000e9224 | 106 | pathLen = fragmentPtr - pathPtr; |
kanehara | 9:6275000e9224 | 107 | } |
kanehara | 9:6275000e9224 | 108 | else |
kanehara | 9:6275000e9224 | 109 | { |
kanehara | 9:6275000e9224 | 110 | pathLen = strlen(pathPtr); |
kanehara | 9:6275000e9224 | 111 | } |
kanehara | 9:6275000e9224 | 112 | |
kanehara | 9:6275000e9224 | 113 | if( maxPathLen < pathLen + 1 ) //including NULL-terminating char |
kanehara | 9:6275000e9224 | 114 | { |
kanehara | 9:6275000e9224 | 115 | WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); |
kanehara | 9:6275000e9224 | 116 | return -1; |
kanehara | 9:6275000e9224 | 117 | } |
kanehara | 9:6275000e9224 | 118 | memcpy(path, pathPtr, pathLen); |
kanehara | 9:6275000e9224 | 119 | path[pathLen] = '\0'; |
kanehara | 9:6275000e9224 | 120 | |
kanehara | 9:6275000e9224 | 121 | return 0; |
kanehara | 9:6275000e9224 | 122 | } |
kanehara | 9:6275000e9224 | 123 | |
kanehara | 9:6275000e9224 | 124 | |
kanehara | 9:6275000e9224 | 125 | bool Websocket::connect() { |
kanehara | 9:6275000e9224 | 126 | // char cmd[200]; |
kanehara | 9:6275000e9224 | 127 | |
kanehara | 9:6275000e9224 | 128 | while (socket.connect(host, port) < 0) { |
kanehara | 9:6275000e9224 | 129 | ERR("Unable to connect to (%s) on port (%d)", host, port); |
kanehara | 9:6275000e9224 | 130 | wait(0.2); |
kanehara | 9:6275000e9224 | 131 | return false; |
kanehara | 9:6275000e9224 | 132 | } |
kanehara | 9:6275000e9224 | 133 | |
kanehara | 9:6275000e9224 | 134 | // sent http header to upgrade to the ws protocol |
kanehara | 9:6275000e9224 | 135 | membuf.size = sprintf(membuf.ptr, "GET %s HTTP/1.1\r\n", path); |
kanehara | 9:6275000e9224 | 136 | write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 137 | |
kanehara | 9:6275000e9224 | 138 | membuf.size = sprintf(membuf.ptr, "Host: %s:%d\r\n", host, port); |
kanehara | 9:6275000e9224 | 139 | write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 140 | |
kanehara | 9:6275000e9224 | 141 | membuf.size = sprintf(membuf.ptr, "Upgrade: WebSocket\r\n"); |
kanehara | 9:6275000e9224 | 142 | write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 143 | |
kanehara | 9:6275000e9224 | 144 | membuf.size = sprintf(membuf.ptr, "Connection: Upgrade\r\n"); |
kanehara | 9:6275000e9224 | 145 | write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 146 | |
kanehara | 9:6275000e9224 | 147 | membuf.size = sprintf(membuf.ptr, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); |
kanehara | 9:6275000e9224 | 148 | write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 149 | |
kanehara | 9:6275000e9224 | 150 | membuf.size = sprintf(membuf.ptr, "Sec-WebSocket-Version: 13\r\n\r\n"); |
kanehara | 9:6275000e9224 | 151 | int ret = write(membuf.ptr, membuf.size); |
kanehara | 9:6275000e9224 | 152 | if (ret != membuf.size) { |
kanehara | 9:6275000e9224 | 153 | close(); |
kanehara | 9:6275000e9224 | 154 | ERR("Could not send request"); |
kanehara | 9:6275000e9224 | 155 | return false; |
kanehara | 9:6275000e9224 | 156 | } |
kanehara | 9:6275000e9224 | 157 | |
kanehara | 9:6275000e9224 | 158 | membuf.size = read(membuf.ptr, 200, 100); |
kanehara | 9:6275000e9224 | 159 | if (membuf.size < 0) { |
kanehara | 9:6275000e9224 | 160 | close(); |
kanehara | 9:6275000e9224 | 161 | ERR("Could not receive answer\r\n"); |
kanehara | 9:6275000e9224 | 162 | return false; |
kanehara | 9:6275000e9224 | 163 | } |
kanehara | 9:6275000e9224 | 164 | |
kanehara | 9:6275000e9224 | 165 | membuf.ptr[membuf.size] = '\0'; |
kanehara | 9:6275000e9224 | 166 | DBG("recv: %s\r\n", membuf.ptr); |
kanehara | 9:6275000e9224 | 167 | |
kanehara | 9:6275000e9224 | 168 | char* p = strstr (membuf.ptr, "DdLWT/1JcX+nQFHebYP+rqEx5xI="); |
kanehara | 9:6275000e9224 | 169 | if (p == NULL) { |
kanehara | 9:6275000e9224 | 170 | ERR("Wrong answer from server, got \"%s\" instead\r\n", membuf.ptr); |
kanehara | 9:6275000e9224 | 171 | do { |
kanehara | 9:6275000e9224 | 172 | membuf.size = read(membuf.ptr, 200, 100); |
kanehara | 9:6275000e9224 | 173 | if (membuf.size < 0) { |
kanehara | 9:6275000e9224 | 174 | ERR("Could not receive answer\r\n"); |
kanehara | 9:6275000e9224 | 175 | return false; |
kanehara | 9:6275000e9224 | 176 | } |
kanehara | 9:6275000e9224 | 177 | membuf.ptr[membuf.size] = '\0'; |
kanehara | 9:6275000e9224 | 178 | } while (membuf.size > 0); |
kanehara | 9:6275000e9224 | 179 | close(); |
kanehara | 9:6275000e9224 | 180 | return false; |
kanehara | 9:6275000e9224 | 181 | } |
kanehara | 9:6275000e9224 | 182 | |
kanehara | 9:6275000e9224 | 183 | INFO("\r\nhost: %s\r\npath: %s\r\nport: %d\r\n\r\n", host, path, port); |
kanehara | 9:6275000e9224 | 184 | p = strstr (p, "\r\n\r\n"); |
kanehara | 9:6275000e9224 | 185 | if (p) { |
kanehara | 9:6275000e9224 | 186 | membuf.skipTo (p + 4); |
kanehara | 9:6275000e9224 | 187 | } |
kanehara | 9:6275000e9224 | 188 | return true; |
kanehara | 9:6275000e9224 | 189 | } |
kanehara | 9:6275000e9224 | 190 | |
kanehara | 9:6275000e9224 | 191 | int Websocket::sendLength(uint32_t len, char * msg) { |
kanehara | 9:6275000e9224 | 192 | |
kanehara | 9:6275000e9224 | 193 | if (len < 126) { |
kanehara | 9:6275000e9224 | 194 | msg[0] = len | (1<<7); |
kanehara | 9:6275000e9224 | 195 | return 1; |
kanehara | 9:6275000e9224 | 196 | } else if (len < 65535) { |
kanehara | 9:6275000e9224 | 197 | msg[0] = 126 | (1<<7); |
kanehara | 9:6275000e9224 | 198 | msg[1] = (len >> 8) & 0xff; |
kanehara | 9:6275000e9224 | 199 | msg[2] = len & 0xff; |
kanehara | 9:6275000e9224 | 200 | return 3; |
kanehara | 9:6275000e9224 | 201 | } else { |
kanehara | 9:6275000e9224 | 202 | msg[0] = 127 | (1<<7); |
kanehara | 9:6275000e9224 | 203 | for (int i = 0; i < 8; i++) { |
kanehara | 9:6275000e9224 | 204 | msg[i+1] = (len >> i*8) & 0xff; |
kanehara | 9:6275000e9224 | 205 | } |
kanehara | 9:6275000e9224 | 206 | return 9; |
kanehara | 9:6275000e9224 | 207 | } |
kanehara | 9:6275000e9224 | 208 | } |
kanehara | 9:6275000e9224 | 209 | |
kanehara | 9:6275000e9224 | 210 | int Websocket::readChar(char * pC, bool block) { |
kanehara | 9:6275000e9224 | 211 | return read(pC, 1, 1); |
kanehara | 9:6275000e9224 | 212 | } |
kanehara | 9:6275000e9224 | 213 | |
kanehara | 9:6275000e9224 | 214 | int Websocket::sendOpcode(uint8_t opcode, char * msg) { |
kanehara | 9:6275000e9224 | 215 | msg[0] = 0x80 | (opcode & 0x0f); |
kanehara | 9:6275000e9224 | 216 | return 1; |
kanehara | 9:6275000e9224 | 217 | } |
kanehara | 9:6275000e9224 | 218 | |
kanehara | 9:6275000e9224 | 219 | int Websocket::sendMask(char * msg) { |
kanehara | 9:6275000e9224 | 220 | for (int i = 0; i < 4; i++) { |
kanehara | 9:6275000e9224 | 221 | msg[i] = 0; |
kanehara | 9:6275000e9224 | 222 | } |
kanehara | 9:6275000e9224 | 223 | return 4; |
kanehara | 9:6275000e9224 | 224 | } |
kanehara | 9:6275000e9224 | 225 | |
kanehara | 9:6275000e9224 | 226 | int Websocket::sendOp(uint8_t opcode, size_t len, char* str) { |
kanehara | 9:6275000e9224 | 227 | char msg[strlen(str) + 15]; |
kanehara | 9:6275000e9224 | 228 | int idx = 0; |
kanehara | 9:6275000e9224 | 229 | idx = sendOpcode(opcode, msg); |
kanehara | 9:6275000e9224 | 230 | idx += sendLength(len, msg + idx); |
kanehara | 9:6275000e9224 | 231 | idx += sendMask(msg + idx); |
kanehara | 9:6275000e9224 | 232 | memcpy(msg + idx, str, len); |
kanehara | 9:6275000e9224 | 233 | int res = write(msg, idx + len); |
kanehara | 9:6275000e9224 | 234 | return res; |
kanehara | 9:6275000e9224 | 235 | } |
kanehara | 9:6275000e9224 | 236 | |
kanehara | 9:6275000e9224 | 237 | int Websocket::send(char * str) { |
kanehara | 9:6275000e9224 | 238 | return sendOp(0x01, strlen(str), str); |
kanehara | 9:6275000e9224 | 239 | } |
kanehara | 9:6275000e9224 | 240 | |
kanehara | 9:6275000e9224 | 241 | int Websocket::sendBin(size_t len, char* str) { |
kanehara | 9:6275000e9224 | 242 | return sendOp(0x02, len, str); |
kanehara | 9:6275000e9224 | 243 | } |
kanehara | 9:6275000e9224 | 244 | |
kanehara | 9:6275000e9224 | 245 | bool Websocket::read(char * message, size_t& size) { |
kanehara | 9:6275000e9224 | 246 | uint8_t opcode = 0; |
kanehara | 9:6275000e9224 | 247 | Timer tmr; |
kanehara | 9:6275000e9224 | 248 | |
kanehara | 9:6275000e9224 | 249 | // read the opcode |
kanehara | 9:6275000e9224 | 250 | tmr.start(); |
kanehara | 9:6275000e9224 | 251 | while (true) { |
kanehara | 9:6275000e9224 | 252 | if (tmr.read() > 3) { |
kanehara | 9:6275000e9224 | 253 | DBG("timeout ws\r\n"); |
kanehara | 9:6275000e9224 | 254 | return false; |
kanehara | 9:6275000e9224 | 255 | } |
kanehara | 9:6275000e9224 | 256 | |
kanehara | 9:6275000e9224 | 257 | if(!socket.is_connected()) |
kanehara | 9:6275000e9224 | 258 | { |
kanehara | 9:6275000e9224 | 259 | WARN("Connection was closed by server"); |
kanehara | 9:6275000e9224 | 260 | return false; |
kanehara | 9:6275000e9224 | 261 | } |
kanehara | 9:6275000e9224 | 262 | |
kanehara | 9:6275000e9224 | 263 | if (membuf.size > 0) { |
kanehara | 9:6275000e9224 | 264 | opcode = (uint8_t)*membuf.ptr; |
kanehara | 9:6275000e9224 | 265 | membuf.skip (1); |
kanehara | 9:6275000e9224 | 266 | } else { |
kanehara | 9:6275000e9224 | 267 | socket.set_blocking(false, 1); |
kanehara | 9:6275000e9224 | 268 | if (socket.receive((char*)&opcode, 1) != 1) { |
kanehara | 9:6275000e9224 | 269 | socket.set_blocking(false, 2000); |
kanehara | 9:6275000e9224 | 270 | return false; |
kanehara | 9:6275000e9224 | 271 | } |
kanehara | 9:6275000e9224 | 272 | } |
kanehara | 9:6275000e9224 | 273 | |
kanehara | 9:6275000e9224 | 274 | socket.set_blocking(false, 2000); |
kanehara | 9:6275000e9224 | 275 | |
kanehara | 9:6275000e9224 | 276 | DBG("opcode: 0x%X", opcode); |
kanehara | 9:6275000e9224 | 277 | |
kanehara | 9:6275000e9224 | 278 | switch (opcode) { |
kanehara | 9:6275000e9224 | 279 | case 0x81: |
kanehara | 9:6275000e9224 | 280 | case 0x82: |
kanehara | 9:6275000e9224 | 281 | DBG ("readBinFrame ()"); |
kanehara | 9:6275000e9224 | 282 | return readBinFrame (message, size); |
kanehara | 9:6275000e9224 | 283 | case 0x89: |
kanehara | 9:6275000e9224 | 284 | DBG ("readPing ()"); |
kanehara | 9:6275000e9224 | 285 | return readPing (); |
kanehara | 9:6275000e9224 | 286 | default:; |
kanehara | 9:6275000e9224 | 287 | } |
kanehara | 9:6275000e9224 | 288 | } |
kanehara | 9:6275000e9224 | 289 | |
kanehara | 9:6275000e9224 | 290 | return false; |
kanehara | 9:6275000e9224 | 291 | } |
kanehara | 9:6275000e9224 | 292 | |
kanehara | 9:6275000e9224 | 293 | bool Websocket::close() { |
kanehara | 9:6275000e9224 | 294 | if (!is_connected()) |
kanehara | 9:6275000e9224 | 295 | return false; |
kanehara | 9:6275000e9224 | 296 | |
kanehara | 9:6275000e9224 | 297 | int ret = socket.close(); |
kanehara | 9:6275000e9224 | 298 | if (ret < 0) { |
kanehara | 9:6275000e9224 | 299 | ERR("Could not disconnect"); |
kanehara | 9:6275000e9224 | 300 | return false; |
kanehara | 9:6275000e9224 | 301 | } |
kanehara | 9:6275000e9224 | 302 | return true; |
kanehara | 9:6275000e9224 | 303 | } |
kanehara | 9:6275000e9224 | 304 | |
kanehara | 9:6275000e9224 | 305 | bool Websocket::is_connected() { |
kanehara | 9:6275000e9224 | 306 | return socket.is_connected(); |
kanehara | 9:6275000e9224 | 307 | } |
kanehara | 9:6275000e9224 | 308 | |
kanehara | 9:6275000e9224 | 309 | char* Websocket::getPath() { |
kanehara | 9:6275000e9224 | 310 | return path; |
kanehara | 9:6275000e9224 | 311 | } |
kanehara | 9:6275000e9224 | 312 | |
kanehara | 9:6275000e9224 | 313 | int Websocket::write(char * str, int len) { |
kanehara | 9:6275000e9224 | 314 | int res = 0, idx = 0; |
kanehara | 9:6275000e9224 | 315 | |
kanehara | 9:6275000e9224 | 316 | for (int j = 0; j < MAX_TRY_WRITE; j++) { |
kanehara | 9:6275000e9224 | 317 | |
kanehara | 9:6275000e9224 | 318 | if(!socket.is_connected()) |
kanehara | 9:6275000e9224 | 319 | { |
kanehara | 9:6275000e9224 | 320 | WARN("Connection was closed by server"); |
kanehara | 9:6275000e9224 | 321 | break; |
kanehara | 9:6275000e9224 | 322 | } |
kanehara | 9:6275000e9224 | 323 | |
kanehara | 9:6275000e9224 | 324 | if ((res = socket.send_all(str + idx, len - idx)) == -1) |
kanehara | 9:6275000e9224 | 325 | continue; |
kanehara | 9:6275000e9224 | 326 | |
kanehara | 9:6275000e9224 | 327 | idx += res; |
kanehara | 9:6275000e9224 | 328 | |
kanehara | 9:6275000e9224 | 329 | if (idx == len) |
kanehara | 9:6275000e9224 | 330 | return len; |
kanehara | 9:6275000e9224 | 331 | } |
kanehara | 9:6275000e9224 | 332 | |
kanehara | 9:6275000e9224 | 333 | return (idx == 0) ? -1 : idx; |
kanehara | 9:6275000e9224 | 334 | } |
kanehara | 9:6275000e9224 | 335 | |
kanehara | 9:6275000e9224 | 336 | int Websocket::read(char * str, int len, int min_len) { |
kanehara | 9:6275000e9224 | 337 | if (len == 0) |
kanehara | 9:6275000e9224 | 338 | return 0; |
kanehara | 9:6275000e9224 | 339 | if (membuf.size > 0) { |
kanehara | 9:6275000e9224 | 340 | int s; |
kanehara | 9:6275000e9224 | 341 | s = len < membuf.size ? len : membuf.size; |
kanehara | 9:6275000e9224 | 342 | memcpy (str, membuf.ptr, s); |
kanehara | 9:6275000e9224 | 343 | membuf.skip (s); |
kanehara | 9:6275000e9224 | 344 | if (min_len != -1 && s >= min_len) |
kanehara | 9:6275000e9224 | 345 | return s; |
kanehara | 9:6275000e9224 | 346 | str += s; |
kanehara | 9:6275000e9224 | 347 | len -= s; |
kanehara | 9:6275000e9224 | 348 | min_len -= s; |
kanehara | 9:6275000e9224 | 349 | } |
kanehara | 9:6275000e9224 | 350 | int res = 0, idx = 0; |
kanehara | 9:6275000e9224 | 351 | |
kanehara | 9:6275000e9224 | 352 | for (int j = 0; j < MAX_TRY_WRITE; j++) { |
kanehara | 9:6275000e9224 | 353 | |
kanehara | 9:6275000e9224 | 354 | if ((res = socket.receive_all(str + idx, len - idx)) == -1) |
kanehara | 9:6275000e9224 | 355 | continue; |
kanehara | 9:6275000e9224 | 356 | |
kanehara | 9:6275000e9224 | 357 | idx += res; |
kanehara | 9:6275000e9224 | 358 | |
kanehara | 9:6275000e9224 | 359 | if (idx == len || (min_len != -1 && idx > min_len)) |
kanehara | 9:6275000e9224 | 360 | return idx; |
kanehara | 9:6275000e9224 | 361 | } |
kanehara | 9:6275000e9224 | 362 | |
kanehara | 9:6275000e9224 | 363 | return (idx == 0) ? -1 : idx; |
kanehara | 9:6275000e9224 | 364 | } |
kanehara | 9:6275000e9224 | 365 | |
kanehara | 9:6275000e9224 | 366 | uint32_t Websocket::readLenFrame (char* mask) { |
kanehara | 9:6275000e9224 | 367 | uint32_t len_msg; |
kanehara | 9:6275000e9224 | 368 | char c; |
kanehara | 9:6275000e9224 | 369 | bool is_masked; |
kanehara | 9:6275000e9224 | 370 | int i; |
kanehara | 9:6275000e9224 | 371 | size_t s; |
kanehara | 9:6275000e9224 | 372 | |
kanehara | 9:6275000e9224 | 373 | s = read (&c, 1, 1); |
kanehara | 9:6275000e9224 | 374 | if (s < 1) return 0; |
kanehara | 9:6275000e9224 | 375 | len_msg = c & 0x7f; |
kanehara | 9:6275000e9224 | 376 | is_masked = c & 0x80; |
kanehara | 9:6275000e9224 | 377 | if (len_msg == 126) { |
kanehara | 9:6275000e9224 | 378 | s = read (&c, 1, 1); |
kanehara | 9:6275000e9224 | 379 | if (s < 1) return 0; |
kanehara | 9:6275000e9224 | 380 | len_msg = c << 8; |
kanehara | 9:6275000e9224 | 381 | s = read (&c, 1, 1); |
kanehara | 9:6275000e9224 | 382 | if (s < 1) return 0; |
kanehara | 9:6275000e9224 | 383 | len_msg += c; |
kanehara | 9:6275000e9224 | 384 | } else if (len_msg == 127) { |
kanehara | 9:6275000e9224 | 385 | len_msg = 0; |
kanehara | 9:6275000e9224 | 386 | for (int i = 0; i < 8; i++) { |
kanehara | 9:6275000e9224 | 387 | s = read (&c, 1, 1); |
kanehara | 9:6275000e9224 | 388 | len_msg += (c << (7 - i) * 8); |
kanehara | 9:6275000e9224 | 389 | } |
kanehara | 9:6275000e9224 | 390 | } |
kanehara | 9:6275000e9224 | 391 | if (is_masked) { |
kanehara | 9:6275000e9224 | 392 | DBG ("is_masked"); |
kanehara | 9:6275000e9224 | 393 | for (i = 0; i < 4; i++) { |
kanehara | 9:6275000e9224 | 394 | s = read (&c, 1, 1); |
kanehara | 9:6275000e9224 | 395 | if (s < 1) return 0; |
kanehara | 9:6275000e9224 | 396 | if (mask) |
kanehara | 9:6275000e9224 | 397 | mask[i] = c; |
kanehara | 9:6275000e9224 | 398 | } |
kanehara | 9:6275000e9224 | 399 | } |
kanehara | 9:6275000e9224 | 400 | |
kanehara | 9:6275000e9224 | 401 | return len_msg; |
kanehara | 9:6275000e9224 | 402 | } |
kanehara | 9:6275000e9224 | 403 | |
kanehara | 9:6275000e9224 | 404 | bool Websocket::readBinFrame (char* message, size_t& size) { |
kanehara | 9:6275000e9224 | 405 | int i; |
kanehara | 9:6275000e9224 | 406 | uint32_t len_msg; |
kanehara | 9:6275000e9224 | 407 | char mask[4] = {0, 0, 0, 0}; |
kanehara | 9:6275000e9224 | 408 | |
kanehara | 9:6275000e9224 | 409 | len_msg = readLenFrame (mask); |
kanehara | 9:6275000e9224 | 410 | DBG("length: %d", len_msg); |
kanehara | 9:6275000e9224 | 411 | if (len_msg == 0) { |
kanehara | 9:6275000e9224 | 412 | return false; |
kanehara | 9:6275000e9224 | 413 | } |
kanehara | 9:6275000e9224 | 414 | if (size < len_msg) |
kanehara | 9:6275000e9224 | 415 | len_msg = size; |
kanehara | 9:6275000e9224 | 416 | |
kanehara | 9:6275000e9224 | 417 | int nb = read(message, len_msg, len_msg); |
kanehara | 9:6275000e9224 | 418 | if (nb != len_msg) |
kanehara | 9:6275000e9224 | 419 | return false; |
kanehara | 9:6275000e9224 | 420 | |
kanehara | 9:6275000e9224 | 421 | for (i = 0; i < len_msg; i++) { |
kanehara | 9:6275000e9224 | 422 | message[i] = message[i] ^ mask[i % 4]; |
kanehara | 9:6275000e9224 | 423 | } |
kanehara | 9:6275000e9224 | 424 | size = len_msg; |
kanehara | 9:6275000e9224 | 425 | |
kanehara | 9:6275000e9224 | 426 | return true; |
kanehara | 9:6275000e9224 | 427 | } |
kanehara | 9:6275000e9224 | 428 | |
kanehara | 9:6275000e9224 | 429 | bool Websocket::readPing () { |
kanehara | 9:6275000e9224 | 430 | uint32_t len_msg = readLenFrame (NULL); |
kanehara | 9:6275000e9224 | 431 | char data[len_msg]; |
kanehara | 9:6275000e9224 | 432 | int nb = read(data, len_msg, len_msg); |
kanehara | 9:6275000e9224 | 433 | DBG ("ping"); |
kanehara | 9:6275000e9224 | 434 | sendOp (0x0A, 0, NULL); |
kanehara | 9:6275000e9224 | 435 | if (fnPing) { |
kanehara | 9:6275000e9224 | 436 | fnPing (); |
kanehara | 9:6275000e9224 | 437 | } |
kanehara | 9:6275000e9224 | 438 | return false; |
kanehara | 9:6275000e9224 | 439 | } |