Integrating the ublox LISA C200 modem

Fork of SprintUSBModemHTTPClientTest by Donatien Garnier

Committer:
sam_grove
Date:
Tue Oct 08 00:08:22 2013 +0000
Revision:
21:3f45e53afe4f
Parent:
15:48374c26e004
Added http client test. Return from post seems to be a bit wonky but haven't looked closely at this

Who changed what in which revision?

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