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.
Dependencies: SNICInterface_mod WebSocketServer mbed-rtos mbed PowerControl C12832
WebSocketConnection.cpp@10:578778037efb, 2015-03-16 (annotated)
- Committer:
- flatbird
- Date:
- Mon Mar 16 18:48:50 2015 +0900
- Revision:
- 10:578778037efb
added WebSocketConnection.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| flatbird |
10:578778037efb | 1 | #include "WebSocketConnection.h" |
| flatbird |
10:578778037efb | 2 | #include "WebSocketServer.h" |
| flatbird |
10:578778037efb | 3 | #include "sha1.h" |
| flatbird |
10:578778037efb | 4 | |
| flatbird |
10:578778037efb | 5 | #define UPGRADE_WEBSOCKET "Upgrade: websocket" |
| flatbird |
10:578778037efb | 6 | #define SEC_WEBSOCKET_KEY "Sec-WebSocket-Key:" |
| flatbird |
10:578778037efb | 7 | #define MAGIC_NUMBER "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" |
| flatbird |
10:578778037efb | 8 | #define OP_CONT 0x0 |
| flatbird |
10:578778037efb | 9 | #define OP_TEXT 0x1 |
| flatbird |
10:578778037efb | 10 | #define OP_BINARY 0x2 |
| flatbird |
10:578778037efb | 11 | #define OP_CLOSE 0x8 |
| flatbird |
10:578778037efb | 12 | #define OP_PING 0x9 |
| flatbird |
10:578778037efb | 13 | #define OP_PONG 0xA |
| flatbird |
10:578778037efb | 14 | |
| flatbird |
10:578778037efb | 15 | WebSocketConnection::WebSocketConnection(WebSocketServer* server) |
| flatbird |
10:578778037efb | 16 | { |
| flatbird |
10:578778037efb | 17 | mServer = server; |
| flatbird |
10:578778037efb | 18 | } |
| flatbird |
10:578778037efb | 19 | |
| flatbird |
10:578778037efb | 20 | WebSocketConnection::~WebSocketConnection() |
| flatbird |
10:578778037efb | 21 | { |
| flatbird |
10:578778037efb | 22 | } |
| flatbird |
10:578778037efb | 23 | |
| flatbird |
10:578778037efb | 24 | void WebSocketConnection::run() |
| flatbird |
10:578778037efb | 25 | { |
| flatbird |
10:578778037efb | 26 | char buf[1024]; |
| flatbird |
10:578778037efb | 27 | bool isWebSocket = false; |
| flatbird |
10:578778037efb | 28 | |
| flatbird |
10:578778037efb | 29 | // it doesn't work... |
| flatbird |
10:578778037efb | 30 | // mConnection.set_blocking(true); |
| flatbird |
10:578778037efb | 31 | |
| flatbird |
10:578778037efb | 32 | while (mConnection.is_connected()) { |
| flatbird |
10:578778037efb | 33 | int ret = mConnection.receive(buf, sizeof(buf) - 1); |
| flatbird |
10:578778037efb | 34 | if (ret == 0) { |
| flatbird |
10:578778037efb | 35 | // printf("No data to receive\r\n"); |
| flatbird |
10:578778037efb | 36 | continue; |
| flatbird |
10:578778037efb | 37 | } |
| flatbird |
10:578778037efb | 38 | if (ret < 0) { |
| flatbird |
10:578778037efb | 39 | printf("ERROR: Failed to receive %d\r\n", ret); |
| flatbird |
10:578778037efb | 40 | break; |
| flatbird |
10:578778037efb | 41 | } |
| flatbird |
10:578778037efb | 42 | if (!isWebSocket) { |
| flatbird |
10:578778037efb | 43 | if (this->handleHTTP(buf, ret)) { |
| flatbird |
10:578778037efb | 44 | isWebSocket = true; |
| flatbird |
10:578778037efb | 45 | } else { |
| flatbird |
10:578778037efb | 46 | printf("ERROR: Non websocket\r\n"); |
| flatbird |
10:578778037efb | 47 | break; |
| flatbird |
10:578778037efb | 48 | } |
| flatbird |
10:578778037efb | 49 | } else { |
| flatbird |
10:578778037efb | 50 | if (!this->handleWebSocket(buf, ret)) { |
| flatbird |
10:578778037efb | 51 | break; |
| flatbird |
10:578778037efb | 52 | } |
| flatbird |
10:578778037efb | 53 | } |
| flatbird |
10:578778037efb | 54 | } |
| flatbird |
10:578778037efb | 55 | // printf("Closed\r\n"); |
| flatbird |
10:578778037efb | 56 | mConnection.close(); |
| flatbird |
10:578778037efb | 57 | } |
| flatbird |
10:578778037efb | 58 | |
| flatbird |
10:578778037efb | 59 | bool WebSocketConnection::handleHTTP(char* buf, int size) |
| flatbird |
10:578778037efb | 60 | { |
| flatbird |
10:578778037efb | 61 | char* line = &buf[0]; |
| flatbird |
10:578778037efb | 62 | char key[128]; |
| flatbird |
10:578778037efb | 63 | bool isUpgradeWebSocket = false; |
| flatbird |
10:578778037efb | 64 | bool isSecWebSocketKeyFound = false; |
| flatbird |
10:578778037efb | 65 | |
| flatbird |
10:578778037efb | 66 | for (int i = 0; i < size; i++) { |
| flatbird |
10:578778037efb | 67 | if (buf[i] == '\r' && i+1 < size && buf[i+1] == '\n') { |
| flatbird |
10:578778037efb | 68 | buf[i] = '\0'; |
| flatbird |
10:578778037efb | 69 | if (strlen(buf) <= 0) { |
| flatbird |
10:578778037efb | 70 | break; |
| flatbird |
10:578778037efb | 71 | } |
| flatbird |
10:578778037efb | 72 | printf("[%s]\r\n", line); |
| flatbird |
10:578778037efb | 73 | if (line == &buf[0]) { |
| flatbird |
10:578778037efb | 74 | char* method = strtok(buf, " "); |
| flatbird |
10:578778037efb | 75 | char* path = strtok(NULL, " "); |
| flatbird |
10:578778037efb | 76 | char* version = strtok(NULL, " "); |
| flatbird |
10:578778037efb | 77 | // printf("[%s] [%s] [%s]\r\n", method, path, version); |
| flatbird |
10:578778037efb | 78 | mHandler = mServer->getHandler(path); |
| flatbird |
10:578778037efb | 79 | if (!mHandler) { |
| flatbird |
10:578778037efb | 80 | printf("ERROR: Handler not found for %s\r\n", path); |
| flatbird |
10:578778037efb | 81 | return false; |
| flatbird |
10:578778037efb | 82 | } |
| flatbird |
10:578778037efb | 83 | } else if (strncmp(line, UPGRADE_WEBSOCKET, strlen(UPGRADE_WEBSOCKET)) == 0) { |
| flatbird |
10:578778037efb | 84 | isUpgradeWebSocket = true; |
| flatbird |
10:578778037efb | 85 | } else if (strncmp(line, SEC_WEBSOCKET_KEY, strlen(SEC_WEBSOCKET_KEY)) == 0) { |
| flatbird |
10:578778037efb | 86 | isSecWebSocketKeyFound = true; |
| flatbird |
10:578778037efb | 87 | char* ptr = line + strlen(SEC_WEBSOCKET_KEY); |
| flatbird |
10:578778037efb | 88 | while (*ptr == ' ') ++ptr; |
| flatbird |
10:578778037efb | 89 | strcpy(key, ptr); |
| flatbird |
10:578778037efb | 90 | } |
| flatbird |
10:578778037efb | 91 | i += 2; |
| flatbird |
10:578778037efb | 92 | line = &buf[i]; |
| flatbird |
10:578778037efb | 93 | } |
| flatbird |
10:578778037efb | 94 | } |
| flatbird |
10:578778037efb | 95 | |
| flatbird |
10:578778037efb | 96 | if (isUpgradeWebSocket && isSecWebSocketKeyFound) { |
| flatbird |
10:578778037efb | 97 | this->sendUpgradeResponse(key); |
| flatbird |
10:578778037efb | 98 | if (mHandler) { |
| flatbird |
10:578778037efb | 99 | mHandler->onOpen(); |
| flatbird |
10:578778037efb | 100 | } |
| flatbird |
10:578778037efb | 101 | mPrevFin = true; |
| flatbird |
10:578778037efb | 102 | return true; |
| flatbird |
10:578778037efb | 103 | } |
| flatbird |
10:578778037efb | 104 | |
| flatbird |
10:578778037efb | 105 | return false; |
| flatbird |
10:578778037efb | 106 | } |
| flatbird |
10:578778037efb | 107 | |
| flatbird |
10:578778037efb | 108 | bool WebSocketConnection::handleWebSocket(char* buf, int size) |
| flatbird |
10:578778037efb | 109 | { |
| flatbird |
10:578778037efb | 110 | uint8_t* ptr = (uint8_t*)buf; |
| flatbird |
10:578778037efb | 111 | |
| flatbird |
10:578778037efb | 112 | bool fin = (*ptr & 0x80) == 0x80; |
| flatbird |
10:578778037efb | 113 | uint8_t opcode = *ptr & 0xF; |
| flatbird |
10:578778037efb | 114 | |
| flatbird |
10:578778037efb | 115 | if (opcode == OP_PING) { |
| flatbird |
10:578778037efb | 116 | *ptr = ((*ptr & 0xF0) | OP_PONG); |
| flatbird |
10:578778037efb | 117 | mConnection.send_all(buf, size); |
| flatbird |
10:578778037efb | 118 | return true; |
| flatbird |
10:578778037efb | 119 | } |
| flatbird |
10:578778037efb | 120 | if (opcode == OP_CLOSE) { |
| flatbird |
10:578778037efb | 121 | if (mHandler) { |
| flatbird |
10:578778037efb | 122 | mHandler->onClose(); |
| flatbird |
10:578778037efb | 123 | } |
| flatbird |
10:578778037efb | 124 | return false; |
| flatbird |
10:578778037efb | 125 | } |
| flatbird |
10:578778037efb | 126 | ptr++; |
| flatbird |
10:578778037efb | 127 | |
| flatbird |
10:578778037efb | 128 | if (!fin || !mPrevFin) { |
| flatbird |
10:578778037efb | 129 | printf("WARN: Data consists of multiple frame not supported\r\n"); |
| flatbird |
10:578778037efb | 130 | mPrevFin = fin; |
| flatbird |
10:578778037efb | 131 | return true; // not an error, just discard it |
| flatbird |
10:578778037efb | 132 | } |
| flatbird |
10:578778037efb | 133 | mPrevFin = fin; |
| flatbird |
10:578778037efb | 134 | |
| flatbird |
10:578778037efb | 135 | bool mask = (*ptr & 0x80) == 0x80; |
| flatbird |
10:578778037efb | 136 | uint8_t len = *ptr & 0x7F; |
| flatbird |
10:578778037efb | 137 | ptr++; |
| flatbird |
10:578778037efb | 138 | |
| flatbird |
10:578778037efb | 139 | if (len > 125) { |
| flatbird |
10:578778037efb | 140 | printf("WARN: Extended payload length not supported\r\n"); |
| flatbird |
10:578778037efb | 141 | return true; // not an error, just discard it |
| flatbird |
10:578778037efb | 142 | } |
| flatbird |
10:578778037efb | 143 | |
| flatbird |
10:578778037efb | 144 | char* data; |
| flatbird |
10:578778037efb | 145 | if (mask) { |
| flatbird |
10:578778037efb | 146 | char* maskingKey = (char*)ptr; |
| flatbird |
10:578778037efb | 147 | data = (char*)(ptr + 4); |
| flatbird |
10:578778037efb | 148 | for (int i = 0; i < len; i++) { |
| flatbird |
10:578778037efb | 149 | data[i] = data[i] ^ maskingKey[(i % 4)]; |
| flatbird |
10:578778037efb | 150 | } |
| flatbird |
10:578778037efb | 151 | } else { |
| flatbird |
10:578778037efb | 152 | data = (char*)ptr; |
| flatbird |
10:578778037efb | 153 | } |
| flatbird |
10:578778037efb | 154 | if (mHandler) { |
| flatbird |
10:578778037efb | 155 | if (opcode == OP_TEXT) { |
| flatbird |
10:578778037efb | 156 | data[len] = '\0'; |
| flatbird |
10:578778037efb | 157 | mHandler->onMessage(data); |
| flatbird |
10:578778037efb | 158 | } else if (opcode == OP_BINARY) { |
| flatbird |
10:578778037efb | 159 | mHandler->onMessage(data, len); |
| flatbird |
10:578778037efb | 160 | } |
| flatbird |
10:578778037efb | 161 | } |
| flatbird |
10:578778037efb | 162 | return true; |
| flatbird |
10:578778037efb | 163 | } |
| flatbird |
10:578778037efb | 164 | |
| flatbird |
10:578778037efb | 165 | char* base64Encode(const uint8_t* data, size_t size, |
| flatbird |
10:578778037efb | 166 | char* outputBuffer, size_t outputBufferSize) |
| flatbird |
10:578778037efb | 167 | { |
| flatbird |
10:578778037efb | 168 | static char encodingTable[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |
| flatbird |
10:578778037efb | 169 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |
| flatbird |
10:578778037efb | 170 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
| flatbird |
10:578778037efb | 171 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |
| flatbird |
10:578778037efb | 172 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |
| flatbird |
10:578778037efb | 173 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
| flatbird |
10:578778037efb | 174 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
| flatbird |
10:578778037efb | 175 | '4', '5', '6', '7', '8', '9', '+', '/'}; |
| flatbird |
10:578778037efb | 176 | size_t outputLength = 4 * ((size + 2) / 3); |
| flatbird |
10:578778037efb | 177 | if (outputBufferSize - 1 < outputLength) { // -1 for NUL |
| flatbird |
10:578778037efb | 178 | return NULL; |
| flatbird |
10:578778037efb | 179 | } |
| flatbird |
10:578778037efb | 180 | |
| flatbird |
10:578778037efb | 181 | for (size_t i = 0, j = 0; i < size; /* nothing */) { |
| flatbird |
10:578778037efb | 182 | uint32_t octet1 = i < size ? (unsigned char)data[i++] : 0; |
| flatbird |
10:578778037efb | 183 | uint32_t octet2 = i < size ? (unsigned char)data[i++] : 0; |
| flatbird |
10:578778037efb | 184 | uint32_t octet3 = i < size ? (unsigned char)data[i++] : 0; |
| flatbird |
10:578778037efb | 185 | |
| flatbird |
10:578778037efb | 186 | uint32_t triple = (octet1 << 0x10) + (octet2 << 0x08) + octet3; |
| flatbird |
10:578778037efb | 187 | |
| flatbird |
10:578778037efb | 188 | outputBuffer[j++] = encodingTable[(triple >> 3 * 6) & 0x3F]; |
| flatbird |
10:578778037efb | 189 | outputBuffer[j++] = encodingTable[(triple >> 2 * 6) & 0x3F]; |
| flatbird |
10:578778037efb | 190 | outputBuffer[j++] = encodingTable[(triple >> 1 * 6) & 0x3F]; |
| flatbird |
10:578778037efb | 191 | outputBuffer[j++] = encodingTable[(triple >> 0 * 6) & 0x3F]; |
| flatbird |
10:578778037efb | 192 | } |
| flatbird |
10:578778037efb | 193 | |
| flatbird |
10:578778037efb | 194 | static int padTable[] = { 0, 2, 1 }; |
| flatbird |
10:578778037efb | 195 | int paddingCount = padTable[size % 3]; |
| flatbird |
10:578778037efb | 196 | |
| flatbird |
10:578778037efb | 197 | for (int i = 0; i < paddingCount; i++) { |
| flatbird |
10:578778037efb | 198 | outputBuffer[outputLength - 1 - i] = '='; |
| flatbird |
10:578778037efb | 199 | } |
| flatbird |
10:578778037efb | 200 | outputBuffer[outputLength] = '\0'; // NUL |
| flatbird |
10:578778037efb | 201 | |
| flatbird |
10:578778037efb | 202 | return outputBuffer; |
| flatbird |
10:578778037efb | 203 | } |
| flatbird |
10:578778037efb | 204 | |
| flatbird |
10:578778037efb | 205 | bool WebSocketConnection::sendUpgradeResponse(char* key) |
| flatbird |
10:578778037efb | 206 | { |
| flatbird |
10:578778037efb | 207 | char buf[128]; |
| flatbird |
10:578778037efb | 208 | |
| flatbird |
10:578778037efb | 209 | if (strlen(key) + sizeof(MAGIC_NUMBER) > sizeof(buf)) { |
| flatbird |
10:578778037efb | 210 | return false; |
| flatbird |
10:578778037efb | 211 | } |
| flatbird |
10:578778037efb | 212 | strcpy(buf, key); |
| flatbird |
10:578778037efb | 213 | strcat(buf, MAGIC_NUMBER); |
| flatbird |
10:578778037efb | 214 | |
| flatbird |
10:578778037efb | 215 | unsigned char hash[20]; |
| flatbird |
10:578778037efb | 216 | char encoded[30]; |
| flatbird |
10:578778037efb | 217 | sha1(buf, strlen(buf), (char*)hash); |
| flatbird |
10:578778037efb | 218 | base64Encode(hash, 20, encoded, sizeof(encoded)); |
| flatbird |
10:578778037efb | 219 | |
| flatbird |
10:578778037efb | 220 | char resp[] = "HTTP/1.1 101 Switching Protocols\r\n" \ |
| flatbird |
10:578778037efb | 221 | "Upgrade: websocket\r\n" \ |
| flatbird |
10:578778037efb | 222 | "Connection: Upgrade\r\n" \ |
| flatbird |
10:578778037efb | 223 | "Sec-WebSocket-Accept: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n\r\n"; |
| flatbird |
10:578778037efb | 224 | char* ptr = strstr(resp, "XXXXX"); |
| flatbird |
10:578778037efb | 225 | strcpy(ptr, encoded); |
| flatbird |
10:578778037efb | 226 | strcpy(ptr+strlen(encoded), "\r\n\r\n"); |
| flatbird |
10:578778037efb | 227 | |
| flatbird |
10:578778037efb | 228 | int ret = mConnection.send_all(resp, strlen(resp)); |
| flatbird |
10:578778037efb | 229 | if (ret < 0) { |
| flatbird |
10:578778037efb | 230 | printf("ERROR: Failed to send response\r\n"); |
| flatbird |
10:578778037efb | 231 | return false; |
| flatbird |
10:578778037efb | 232 | } |
| flatbird |
10:578778037efb | 233 | |
| flatbird |
10:578778037efb | 234 | return true; |
| flatbird |
10:578778037efb | 235 | } |