Ethernetwebsoc

Dependencies:   C12832_lcd LM75B WebSocketClient mbed-rtos mbed Socket lwip-eth lwip-sys lwip

Committer:
GordonSin
Date:
Fri May 31 04:09:54 2013 +0000
Revision:
0:0ed2a7c7190c
31/5/2013;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
GordonSin 0:0ed2a7c7190c 1 #include "Websocket.h"
GordonSin 0:0ed2a7c7190c 2 #include <string>
GordonSin 0:0ed2a7c7190c 3
GordonSin 0:0ed2a7c7190c 4 #define MAX_TRY_WRITE 50
GordonSin 0:0ed2a7c7190c 5 #define MAX_TRY_READ 30
GordonSin 0:0ed2a7c7190c 6
GordonSin 0:0ed2a7c7190c 7 //Debug is disabled by default
GordonSin 0:0ed2a7c7190c 8 #if 0
GordonSin 0:0ed2a7c7190c 9 #define DBG(x, ...) std::printf("[WebSocket : DBG]"x"\r\n", ##__VA_ARGS__);
GordonSin 0:0ed2a7c7190c 10 #define WARN(x, ...) std::printf("[WebSocket : WARN]"x"\r\n", ##__VA_ARGS__);
GordonSin 0:0ed2a7c7190c 11 #define ERR(x, ...) std::printf("[WebSocket : ERR]"x"\r\n", ##__VA_ARGS__);
GordonSin 0:0ed2a7c7190c 12 #else
GordonSin 0:0ed2a7c7190c 13 #define DBG(x, ...)
GordonSin 0:0ed2a7c7190c 14 #define WARN(x, ...)
GordonSin 0:0ed2a7c7190c 15 #define ERR(x, ...)
GordonSin 0:0ed2a7c7190c 16 #endif
GordonSin 0:0ed2a7c7190c 17
GordonSin 0:0ed2a7c7190c 18 #define INFO(x, ...) printf("[WebSocket : INFO]"x"\r\n", ##__VA_ARGS__);
GordonSin 0:0ed2a7c7190c 19
GordonSin 0:0ed2a7c7190c 20 Websocket::Websocket(char * url) {
GordonSin 0:0ed2a7c7190c 21 fillFields(url);
GordonSin 0:0ed2a7c7190c 22 socket.set_blocking(false, 400);
GordonSin 0:0ed2a7c7190c 23 }
GordonSin 0:0ed2a7c7190c 24
GordonSin 0:0ed2a7c7190c 25 void Websocket::fillFields(char * url) {
GordonSin 0:0ed2a7c7190c 26 char *res = NULL;
GordonSin 0:0ed2a7c7190c 27 char *res1 = NULL;
GordonSin 0:0ed2a7c7190c 28
GordonSin 0:0ed2a7c7190c 29 char buf[50];
GordonSin 0:0ed2a7c7190c 30 strcpy(buf, url);
GordonSin 0:0ed2a7c7190c 31
GordonSin 0:0ed2a7c7190c 32 res = strtok(buf, ":");
GordonSin 0:0ed2a7c7190c 33 if (strcmp(res, "ws")) {
GordonSin 0:0ed2a7c7190c 34 DBG("\r\nFormat printfor: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
GordonSin 0:0ed2a7c7190c 35 } else {
GordonSin 0:0ed2a7c7190c 36 //ip_domain and port
GordonSin 0:0ed2a7c7190c 37 res = strtok(NULL, "/");
GordonSin 0:0ed2a7c7190c 38
GordonSin 0:0ed2a7c7190c 39 //path
GordonSin 0:0ed2a7c7190c 40 res1 = strtok(NULL, " ");
GordonSin 0:0ed2a7c7190c 41 if (res1 != NULL) {
GordonSin 0:0ed2a7c7190c 42 path = res1;
GordonSin 0:0ed2a7c7190c 43 }
GordonSin 0:0ed2a7c7190c 44
GordonSin 0:0ed2a7c7190c 45 //ip_domain
GordonSin 0:0ed2a7c7190c 46 res = strtok(res, ":");
GordonSin 0:0ed2a7c7190c 47
GordonSin 0:0ed2a7c7190c 48 //port
GordonSin 0:0ed2a7c7190c 49 res1 = strtok(NULL, " ");
GordonSin 0:0ed2a7c7190c 50 if (res1 != NULL) {
GordonSin 0:0ed2a7c7190c 51 port = res1;
GordonSin 0:0ed2a7c7190c 52 } else {
GordonSin 0:0ed2a7c7190c 53 port = "80";
GordonSin 0:0ed2a7c7190c 54 }
GordonSin 0:0ed2a7c7190c 55
GordonSin 0:0ed2a7c7190c 56 if (res != NULL) {
GordonSin 0:0ed2a7c7190c 57 ip_domain = res;
GordonSin 0:0ed2a7c7190c 58 }
GordonSin 0:0ed2a7c7190c 59 }
GordonSin 0:0ed2a7c7190c 60 }
GordonSin 0:0ed2a7c7190c 61
GordonSin 0:0ed2a7c7190c 62
GordonSin 0:0ed2a7c7190c 63 bool Websocket::connect() {
GordonSin 0:0ed2a7c7190c 64 char cmd[200];
GordonSin 0:0ed2a7c7190c 65
GordonSin 0:0ed2a7c7190c 66 while (socket.connect(ip_domain.c_str(), atoi(port.c_str())) < 0) {
GordonSin 0:0ed2a7c7190c 67 ERR("Unable to connect to (%s) on port (%d)\r\n", ip_domain.c_str(), atoi(port.c_str()));
GordonSin 0:0ed2a7c7190c 68 wait(0.2);
GordonSin 0:0ed2a7c7190c 69 }
GordonSin 0:0ed2a7c7190c 70
GordonSin 0:0ed2a7c7190c 71 // sent http header to upgrade to the ws protocol
GordonSin 0:0ed2a7c7190c 72 sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
GordonSin 0:0ed2a7c7190c 73 write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 74
GordonSin 0:0ed2a7c7190c 75 sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
GordonSin 0:0ed2a7c7190c 76 write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 77
GordonSin 0:0ed2a7c7190c 78 sprintf(cmd, "Upgrade: WebSocket\r\n");
GordonSin 0:0ed2a7c7190c 79 write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 80
GordonSin 0:0ed2a7c7190c 81 sprintf(cmd, "Connection: Upgrade\r\n");
GordonSin 0:0ed2a7c7190c 82 write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 83
GordonSin 0:0ed2a7c7190c 84 sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n");
GordonSin 0:0ed2a7c7190c 85 write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 86
GordonSin 0:0ed2a7c7190c 87 sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
GordonSin 0:0ed2a7c7190c 88 int ret = write(cmd, strlen(cmd));
GordonSin 0:0ed2a7c7190c 89 if (ret != strlen(cmd)) {
GordonSin 0:0ed2a7c7190c 90 close();
GordonSin 0:0ed2a7c7190c 91 ERR("Could not send request");
GordonSin 0:0ed2a7c7190c 92 return false;
GordonSin 0:0ed2a7c7190c 93 }
GordonSin 0:0ed2a7c7190c 94
GordonSin 0:0ed2a7c7190c 95 ret = read(cmd, 200, 100);
GordonSin 0:0ed2a7c7190c 96 if (ret < 0) {
GordonSin 0:0ed2a7c7190c 97 close();
GordonSin 0:0ed2a7c7190c 98 ERR("Could not receive answer\r\n");
GordonSin 0:0ed2a7c7190c 99 return false;
GordonSin 0:0ed2a7c7190c 100 }
GordonSin 0:0ed2a7c7190c 101
GordonSin 0:0ed2a7c7190c 102 cmd[ret] = '\0';
GordonSin 0:0ed2a7c7190c 103 DBG("recv: %s\r\n", cmd);
GordonSin 0:0ed2a7c7190c 104
GordonSin 0:0ed2a7c7190c 105 if ( strstr(cmd, "DdLWT/1JcX+nQFHebYP+rqEx5xI=") == NULL ) {
GordonSin 0:0ed2a7c7190c 106 ERR("Wrong answer from server, got \"%s\" instead\r\n", cmd);
GordonSin 0:0ed2a7c7190c 107 do {
GordonSin 0:0ed2a7c7190c 108 ret = read(cmd, 200, 100);
GordonSin 0:0ed2a7c7190c 109 if (ret < 0) {
GordonSin 0:0ed2a7c7190c 110 ERR("Could not receive answer\r\n");
GordonSin 0:0ed2a7c7190c 111 return false;
GordonSin 0:0ed2a7c7190c 112 }
GordonSin 0:0ed2a7c7190c 113 cmd[ret] = '\0';
GordonSin 0:0ed2a7c7190c 114 printf("%s",cmd);
GordonSin 0:0ed2a7c7190c 115 } while (ret > 0);
GordonSin 0:0ed2a7c7190c 116 close();
GordonSin 0:0ed2a7c7190c 117 return false;
GordonSin 0:0ed2a7c7190c 118 }
GordonSin 0:0ed2a7c7190c 119
GordonSin 0:0ed2a7c7190c 120 INFO("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n", ip_domain.c_str(), path.c_str(), port.c_str());
GordonSin 0:0ed2a7c7190c 121 return true;
GordonSin 0:0ed2a7c7190c 122 }
GordonSin 0:0ed2a7c7190c 123
GordonSin 0:0ed2a7c7190c 124 int Websocket::sendLength(uint32_t len, char * msg) {
GordonSin 0:0ed2a7c7190c 125
GordonSin 0:0ed2a7c7190c 126 if (len < 126) {
GordonSin 0:0ed2a7c7190c 127 msg[0] = len | (1<<7);
GordonSin 0:0ed2a7c7190c 128 return 1;
GordonSin 0:0ed2a7c7190c 129 } else if (len < 65535) {
GordonSin 0:0ed2a7c7190c 130 msg[0] = 126 | (1<<7);
GordonSin 0:0ed2a7c7190c 131 msg[1] = (len >> 8) & 0xff;
GordonSin 0:0ed2a7c7190c 132 msg[2] = len & 0xff;
GordonSin 0:0ed2a7c7190c 133 return 3;
GordonSin 0:0ed2a7c7190c 134 } else {
GordonSin 0:0ed2a7c7190c 135 msg[0] = 127 | (1<<7);
GordonSin 0:0ed2a7c7190c 136 for (int i = 0; i < 8; i++) {
GordonSin 0:0ed2a7c7190c 137 msg[i+1] = (len >> i*8) & 0xff;
GordonSin 0:0ed2a7c7190c 138 }
GordonSin 0:0ed2a7c7190c 139 return 9;
GordonSin 0:0ed2a7c7190c 140 }
GordonSin 0:0ed2a7c7190c 141 }
GordonSin 0:0ed2a7c7190c 142
GordonSin 0:0ed2a7c7190c 143 int Websocket::readChar(char * pC, bool block) {
GordonSin 0:0ed2a7c7190c 144 return read(pC, 1, 1);
GordonSin 0:0ed2a7c7190c 145 }
GordonSin 0:0ed2a7c7190c 146
GordonSin 0:0ed2a7c7190c 147 int Websocket::sendOpcode(uint8_t opcode, char * msg) {
GordonSin 0:0ed2a7c7190c 148 msg[0] = 0x80 | (opcode & 0x0f);
GordonSin 0:0ed2a7c7190c 149 return 1;
GordonSin 0:0ed2a7c7190c 150 }
GordonSin 0:0ed2a7c7190c 151
GordonSin 0:0ed2a7c7190c 152 int Websocket::sendMask(char * msg) {
GordonSin 0:0ed2a7c7190c 153 for (int i = 0; i < 4; i++) {
GordonSin 0:0ed2a7c7190c 154 msg[i] = 0;
GordonSin 0:0ed2a7c7190c 155 }
GordonSin 0:0ed2a7c7190c 156 return 4;
GordonSin 0:0ed2a7c7190c 157 }
GordonSin 0:0ed2a7c7190c 158
GordonSin 0:0ed2a7c7190c 159 int Websocket::send(char * str) {
GordonSin 0:0ed2a7c7190c 160 char msg[strlen(str) + 15];
GordonSin 0:0ed2a7c7190c 161 int idx = 0;
GordonSin 0:0ed2a7c7190c 162 idx = sendOpcode(0x01, msg);
GordonSin 0:0ed2a7c7190c 163 idx += sendLength(strlen(str), msg + idx);
GordonSin 0:0ed2a7c7190c 164 idx += sendMask(msg + idx);
GordonSin 0:0ed2a7c7190c 165 memcpy(msg+idx, str, strlen(str));
GordonSin 0:0ed2a7c7190c 166 int res = write(msg, idx + strlen(str));
GordonSin 0:0ed2a7c7190c 167 return res;
GordonSin 0:0ed2a7c7190c 168 }
GordonSin 0:0ed2a7c7190c 169
GordonSin 0:0ed2a7c7190c 170
GordonSin 0:0ed2a7c7190c 171 bool Websocket::read(char * message) {
GordonSin 0:0ed2a7c7190c 172 int i = 0;
GordonSin 0:0ed2a7c7190c 173 uint32_t len_msg;
GordonSin 0:0ed2a7c7190c 174 char opcode = 0;
GordonSin 0:0ed2a7c7190c 175 char c;
GordonSin 0:0ed2a7c7190c 176 char mask[4] = {0, 0, 0, 0};
GordonSin 0:0ed2a7c7190c 177 bool is_masked = false;
GordonSin 0:0ed2a7c7190c 178 Timer tmr;
GordonSin 0:0ed2a7c7190c 179
GordonSin 0:0ed2a7c7190c 180 // read the opcode
GordonSin 0:0ed2a7c7190c 181 tmr.start();
GordonSin 0:0ed2a7c7190c 182 while (true) {
GordonSin 0:0ed2a7c7190c 183 if (tmr.read() > 3) {
GordonSin 0:0ed2a7c7190c 184 DBG("timeout ws\r\n");
GordonSin 0:0ed2a7c7190c 185 return false;
GordonSin 0:0ed2a7c7190c 186 }
GordonSin 0:0ed2a7c7190c 187
GordonSin 0:0ed2a7c7190c 188 socket.set_blocking(false, 1);
GordonSin 0:0ed2a7c7190c 189 if (socket.receive(&opcode, 1) != 1) {
GordonSin 0:0ed2a7c7190c 190 socket.set_blocking(false, 2000);
GordonSin 0:0ed2a7c7190c 191 return false;
GordonSin 0:0ed2a7c7190c 192 }
GordonSin 0:0ed2a7c7190c 193
GordonSin 0:0ed2a7c7190c 194 socket.set_blocking(false, 2000);
GordonSin 0:0ed2a7c7190c 195
GordonSin 0:0ed2a7c7190c 196 if (opcode == 0x81)
GordonSin 0:0ed2a7c7190c 197 break;
GordonSin 0:0ed2a7c7190c 198 }
GordonSin 0:0ed2a7c7190c 199 DBG("opcode: 0x%X\r\n", opcode);
GordonSin 0:0ed2a7c7190c 200
GordonSin 0:0ed2a7c7190c 201 readChar(&c);
GordonSin 0:0ed2a7c7190c 202 len_msg = c & 0x7f;
GordonSin 0:0ed2a7c7190c 203 is_masked = c & 0x80;
GordonSin 0:0ed2a7c7190c 204 if (len_msg == 126) {
GordonSin 0:0ed2a7c7190c 205 readChar(&c);
GordonSin 0:0ed2a7c7190c 206 len_msg = c << 8;
GordonSin 0:0ed2a7c7190c 207 readChar(&c);
GordonSin 0:0ed2a7c7190c 208 len_msg += c;
GordonSin 0:0ed2a7c7190c 209 } else if (len_msg == 127) {
GordonSin 0:0ed2a7c7190c 210 len_msg = 0;
GordonSin 0:0ed2a7c7190c 211 for (int i = 0; i < 8; i++) {
GordonSin 0:0ed2a7c7190c 212 readChar(&c);
GordonSin 0:0ed2a7c7190c 213 len_msg += (c << (7-i)*8);
GordonSin 0:0ed2a7c7190c 214 }
GordonSin 0:0ed2a7c7190c 215 }
GordonSin 0:0ed2a7c7190c 216
GordonSin 0:0ed2a7c7190c 217 if (len_msg == 0) {
GordonSin 0:0ed2a7c7190c 218 return false;
GordonSin 0:0ed2a7c7190c 219 }
GordonSin 0:0ed2a7c7190c 220 DBG("length: %d\r\n", len_msg);
GordonSin 0:0ed2a7c7190c 221
GordonSin 0:0ed2a7c7190c 222 if (is_masked) {
GordonSin 0:0ed2a7c7190c 223 for (i = 0; i < 4; i++)
GordonSin 0:0ed2a7c7190c 224 readChar(&c);
GordonSin 0:0ed2a7c7190c 225 mask[i] = c;
GordonSin 0:0ed2a7c7190c 226 }
GordonSin 0:0ed2a7c7190c 227
GordonSin 0:0ed2a7c7190c 228 int nb = read(message, len_msg, len_msg);
GordonSin 0:0ed2a7c7190c 229 if (nb != len_msg)
GordonSin 0:0ed2a7c7190c 230 return false;
GordonSin 0:0ed2a7c7190c 231
GordonSin 0:0ed2a7c7190c 232 for (i = 0; i < len_msg; i++) {
GordonSin 0:0ed2a7c7190c 233 message[i] = message[i] ^ mask[i % 4];
GordonSin 0:0ed2a7c7190c 234 }
GordonSin 0:0ed2a7c7190c 235
GordonSin 0:0ed2a7c7190c 236 message[len_msg] = '\0';
GordonSin 0:0ed2a7c7190c 237
GordonSin 0:0ed2a7c7190c 238 return true;
GordonSin 0:0ed2a7c7190c 239 }
GordonSin 0:0ed2a7c7190c 240
GordonSin 0:0ed2a7c7190c 241 bool Websocket::close() {
GordonSin 0:0ed2a7c7190c 242 if (!is_connected())
GordonSin 0:0ed2a7c7190c 243 return false;
GordonSin 0:0ed2a7c7190c 244
GordonSin 0:0ed2a7c7190c 245 int ret = socket.close();
GordonSin 0:0ed2a7c7190c 246 if (ret < 0) {
GordonSin 0:0ed2a7c7190c 247 ERR("Could not disconnect");
GordonSin 0:0ed2a7c7190c 248 return false;
GordonSin 0:0ed2a7c7190c 249 }
GordonSin 0:0ed2a7c7190c 250 return true;
GordonSin 0:0ed2a7c7190c 251 }
GordonSin 0:0ed2a7c7190c 252
GordonSin 0:0ed2a7c7190c 253 bool Websocket::is_connected() {
GordonSin 0:0ed2a7c7190c 254 return socket.is_connected();
GordonSin 0:0ed2a7c7190c 255 }
GordonSin 0:0ed2a7c7190c 256
GordonSin 0:0ed2a7c7190c 257 std::string Websocket::getPath() {
GordonSin 0:0ed2a7c7190c 258 return path;
GordonSin 0:0ed2a7c7190c 259 }
GordonSin 0:0ed2a7c7190c 260
GordonSin 0:0ed2a7c7190c 261 int Websocket::write(char * str, int len) {
GordonSin 0:0ed2a7c7190c 262 int res = 0, idx = 0;
GordonSin 0:0ed2a7c7190c 263
GordonSin 0:0ed2a7c7190c 264 for (int j = 0; j < MAX_TRY_WRITE; j++) {
GordonSin 0:0ed2a7c7190c 265
GordonSin 0:0ed2a7c7190c 266 if ((res = socket.send_all(str + idx, len - idx)) == -1)
GordonSin 0:0ed2a7c7190c 267 continue;
GordonSin 0:0ed2a7c7190c 268
GordonSin 0:0ed2a7c7190c 269 idx += res;
GordonSin 0:0ed2a7c7190c 270
GordonSin 0:0ed2a7c7190c 271 if (idx == len)
GordonSin 0:0ed2a7c7190c 272 return len;
GordonSin 0:0ed2a7c7190c 273 }
GordonSin 0:0ed2a7c7190c 274
GordonSin 0:0ed2a7c7190c 275 return (idx == 0) ? -1 : idx;
GordonSin 0:0ed2a7c7190c 276 }
GordonSin 0:0ed2a7c7190c 277
GordonSin 0:0ed2a7c7190c 278 int Websocket::read(char * str, int len, int min_len) {
GordonSin 0:0ed2a7c7190c 279 int res = 0, idx = 0;
GordonSin 0:0ed2a7c7190c 280
GordonSin 0:0ed2a7c7190c 281 for (int j = 0; j < MAX_TRY_WRITE; j++) {
GordonSin 0:0ed2a7c7190c 282
GordonSin 0:0ed2a7c7190c 283 if ((res = socket.receive_all(str + idx, len - idx)) == -1)
GordonSin 0:0ed2a7c7190c 284 continue;
GordonSin 0:0ed2a7c7190c 285
GordonSin 0:0ed2a7c7190c 286 idx += res;
GordonSin 0:0ed2a7c7190c 287
GordonSin 0:0ed2a7c7190c 288 if (idx == len || (min_len != -1 && idx > min_len))
GordonSin 0:0ed2a7c7190c 289 return idx;
GordonSin 0:0ed2a7c7190c 290 }
GordonSin 0:0ed2a7c7190c 291
GordonSin 0:0ed2a7c7190c 292 return (idx == 0) ? -1 : idx;
GordonSin 0:0ed2a7c7190c 293 }