John Lowe
/
WebSockets2
Embedded WebSockets Experiment
HTTPWebSocketHandler.cpp@0:6dee052a3fa4, 2011-07-26 (annotated)
- Committer:
- nandgate
- Date:
- Tue Jul 26 05:30:53 2011 +0000
- Revision:
- 0:6dee052a3fa4
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
nandgate | 0:6dee052a3fa4 | 1 | #include "HTTPWebSocketHandler.h" |
nandgate | 0:6dee052a3fa4 | 2 | #include "md5.h" |
nandgate | 0:6dee052a3fa4 | 3 | #include "TemperatureSensor.h" |
nandgate | 0:6dee052a3fa4 | 4 | #include "RGBLed.h" |
nandgate | 0:6dee052a3fa4 | 5 | |
nandgate | 0:6dee052a3fa4 | 6 | extern TemperatureSensor sensor; |
nandgate | 0:6dee052a3fa4 | 7 | extern RGBLed rgb; |
nandgate | 0:6dee052a3fa4 | 8 | |
nandgate | 0:6dee052a3fa4 | 9 | HTTPWebSocketConnectingState::HTTPWebSocketConnectingState() { |
nandgate | 0:6dee052a3fa4 | 10 | memset(challange, 0, 16); |
nandgate | 0:6dee052a3fa4 | 11 | } |
nandgate | 0:6dee052a3fa4 | 12 | |
nandgate | 0:6dee052a3fa4 | 13 | HTTPStatus HTTPWebSocketConnectingState::init(HTTPConnection *conn) { |
nandgate | 0:6dee052a3fa4 | 14 | uint32_t key1Part= computeKeyPart(conn->getField("Sec-WebSocket-Key1")); |
nandgate | 0:6dee052a3fa4 | 15 | uint32_t key2Part= computeKeyPart(conn->getField("Sec-WebSocket-Key2")); |
nandgate | 0:6dee052a3fa4 | 16 | |
nandgate | 0:6dee052a3fa4 | 17 | challange[0]= (key1Part >> 24) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 18 | challange[1]= (key1Part >> 16) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 19 | challange[2]= (key1Part >> 8) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 20 | challange[3]= (key1Part >> 0) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 21 | challange[4]= (key2Part >> 24) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 22 | challange[5]= (key2Part >> 16) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 23 | challange[6]= (key2Part >> 8) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 24 | challange[7]= (key2Part >> 0) & 0xFF; |
nandgate | 0:6dee052a3fa4 | 25 | |
nandgate | 0:6dee052a3fa4 | 26 | char headers[1024]; |
nandgate | 0:6dee052a3fa4 | 27 | char *str; |
nandgate | 0:6dee052a3fa4 | 28 | |
nandgate | 0:6dee052a3fa4 | 29 | memset(headers, 0, 1024); |
nandgate | 0:6dee052a3fa4 | 30 | strcat(headers, "Upgrade: WebSocket\r\n"); |
nandgate | 0:6dee052a3fa4 | 31 | strcat(headers, "Connection: Upgrade\r\n"); |
nandgate | 0:6dee052a3fa4 | 32 | |
nandgate | 0:6dee052a3fa4 | 33 | // The host field string can have junk at the end... |
nandgate | 0:6dee052a3fa4 | 34 | str= (char*) conn->getField("Host"); |
nandgate | 0:6dee052a3fa4 | 35 | for (char *p= str; *p != 0; p++) { |
nandgate | 0:6dee052a3fa4 | 36 | if(!isprint(*p)) { |
nandgate | 0:6dee052a3fa4 | 37 | *p= 0; |
nandgate | 0:6dee052a3fa4 | 38 | } |
nandgate | 0:6dee052a3fa4 | 39 | } |
nandgate | 0:6dee052a3fa4 | 40 | strcat(headers, "Sec-WebSocket-Location: ws://"); |
nandgate | 0:6dee052a3fa4 | 41 | strcat(headers, str); |
nandgate | 0:6dee052a3fa4 | 42 | strcat(headers, conn->getURL()); |
nandgate | 0:6dee052a3fa4 | 43 | strcat(headers, "\r\n"); |
nandgate | 0:6dee052a3fa4 | 44 | |
nandgate | 0:6dee052a3fa4 | 45 | // The host field string can have junk at the end... |
nandgate | 0:6dee052a3fa4 | 46 | str= (char*) conn->getField("Origin"); |
nandgate | 0:6dee052a3fa4 | 47 | for (char *p= str; *p != 0; p++) { |
nandgate | 0:6dee052a3fa4 | 48 | if(!isprint(*p)) { |
nandgate | 0:6dee052a3fa4 | 49 | *p= 0; |
nandgate | 0:6dee052a3fa4 | 50 | } |
nandgate | 0:6dee052a3fa4 | 51 | } |
nandgate | 0:6dee052a3fa4 | 52 | strcat(headers, "Sec-WebSocket-Origin: "); |
nandgate | 0:6dee052a3fa4 | 53 | strcat(headers, str); |
nandgate | 0:6dee052a3fa4 | 54 | strcat(headers, "\r\n"); |
nandgate | 0:6dee052a3fa4 | 55 | conn->setLength(16); |
nandgate | 0:6dee052a3fa4 | 56 | conn->setHeaderFields(headers); |
nandgate | 0:6dee052a3fa4 | 57 | |
nandgate | 0:6dee052a3fa4 | 58 | printf("\n%s\n", headers); |
nandgate | 0:6dee052a3fa4 | 59 | |
nandgate | 0:6dee052a3fa4 | 60 | return HTTP_SwitchProtocols; |
nandgate | 0:6dee052a3fa4 | 61 | } |
nandgate | 0:6dee052a3fa4 | 62 | |
nandgate | 0:6dee052a3fa4 | 63 | HTTPHandle HTTPWebSocketConnectingState::data(HTTPConnection *conn, void *data, int len) { |
nandgate | 0:6dee052a3fa4 | 64 | // The body needs to hold key3, and only key3 |
nandgate | 0:6dee052a3fa4 | 65 | if (len != 8) { |
nandgate | 0:6dee052a3fa4 | 66 | printf("key3 length error\n"); |
nandgate | 0:6dee052a3fa4 | 67 | return HTTP_Failed; |
nandgate | 0:6dee052a3fa4 | 68 | } |
nandgate | 0:6dee052a3fa4 | 69 | |
nandgate | 0:6dee052a3fa4 | 70 | // Copy key3 into the challange |
nandgate | 0:6dee052a3fa4 | 71 | memcpy(challange+8, data, 8); |
nandgate | 0:6dee052a3fa4 | 72 | |
nandgate | 0:6dee052a3fa4 | 73 | printf("Challange: "); |
nandgate | 0:6dee052a3fa4 | 74 | for (int i= 0; i<16; i++) { |
nandgate | 0:6dee052a3fa4 | 75 | printf("%02x ", challange[i]); |
nandgate | 0:6dee052a3fa4 | 76 | } |
nandgate | 0:6dee052a3fa4 | 77 | printf("\n"); |
nandgate | 0:6dee052a3fa4 | 78 | |
nandgate | 0:6dee052a3fa4 | 79 | return HTTP_Success; |
nandgate | 0:6dee052a3fa4 | 80 | } |
nandgate | 0:6dee052a3fa4 | 81 | |
nandgate | 0:6dee052a3fa4 | 82 | HTTPHandle HTTPWebSocketConnectingState::send(HTTPConnection *conn, int maxData) { |
nandgate | 0:6dee052a3fa4 | 83 | MD5 md5; |
nandgate | 0:6dee052a3fa4 | 84 | md5.update(challange, 16); |
nandgate | 0:6dee052a3fa4 | 85 | const char *hex= md5.finalize().hexdigest().c_str(); |
nandgate | 0:6dee052a3fa4 | 86 | char binary[16]; |
nandgate | 0:6dee052a3fa4 | 87 | hexStringToBinary(hex, binary); |
nandgate | 0:6dee052a3fa4 | 88 | conn->write(binary, 16, (TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE)); |
nandgate | 0:6dee052a3fa4 | 89 | |
nandgate | 0:6dee052a3fa4 | 90 | printf("MD5 bin: "); |
nandgate | 0:6dee052a3fa4 | 91 | for (int i= 0; i<16; i++) { |
nandgate | 0:6dee052a3fa4 | 92 | printf("%02x ", binary[i]); |
nandgate | 0:6dee052a3fa4 | 93 | } |
nandgate | 0:6dee052a3fa4 | 94 | printf("\n"); |
nandgate | 0:6dee052a3fa4 | 95 | |
nandgate | 0:6dee052a3fa4 | 96 | delete conn->data; |
nandgate | 0:6dee052a3fa4 | 97 | conn->data= new HTTPWebSocketStreamingState(); |
nandgate | 0:6dee052a3fa4 | 98 | return HTTP_Success; |
nandgate | 0:6dee052a3fa4 | 99 | } |
nandgate | 0:6dee052a3fa4 | 100 | |
nandgate | 0:6dee052a3fa4 | 101 | uint32_t HTTPWebSocketConnectingState::extractNumber(const char *keyValue) { |
nandgate | 0:6dee052a3fa4 | 102 | uint32_t value= 0; |
nandgate | 0:6dee052a3fa4 | 103 | while (*keyValue) { |
nandgate | 0:6dee052a3fa4 | 104 | if (isdigit(*keyValue)) { |
nandgate | 0:6dee052a3fa4 | 105 | value= value*10 + (*keyValue-'0'); |
nandgate | 0:6dee052a3fa4 | 106 | }; |
nandgate | 0:6dee052a3fa4 | 107 | keyValue++; |
nandgate | 0:6dee052a3fa4 | 108 | }; |
nandgate | 0:6dee052a3fa4 | 109 | return value; |
nandgate | 0:6dee052a3fa4 | 110 | } |
nandgate | 0:6dee052a3fa4 | 111 | |
nandgate | 0:6dee052a3fa4 | 112 | uint32_t HTTPWebSocketConnectingState::countSpaces(const char *keyValue) { |
nandgate | 0:6dee052a3fa4 | 113 | uint32_t count= 0; |
nandgate | 0:6dee052a3fa4 | 114 | while (*keyValue) { |
nandgate | 0:6dee052a3fa4 | 115 | if (*keyValue == 0x20) { |
nandgate | 0:6dee052a3fa4 | 116 | count++; |
nandgate | 0:6dee052a3fa4 | 117 | } |
nandgate | 0:6dee052a3fa4 | 118 | keyValue++; |
nandgate | 0:6dee052a3fa4 | 119 | } |
nandgate | 0:6dee052a3fa4 | 120 | return count; |
nandgate | 0:6dee052a3fa4 | 121 | } |
nandgate | 0:6dee052a3fa4 | 122 | |
nandgate | 0:6dee052a3fa4 | 123 | uint32_t HTTPWebSocketConnectingState::computeKeyPart(const char *keyValue) { |
nandgate | 0:6dee052a3fa4 | 124 | if (keyValue != NULL) { |
nandgate | 0:6dee052a3fa4 | 125 | printf("key:%s:\n", keyValue); |
nandgate | 0:6dee052a3fa4 | 126 | uint32_t keyPart= extractNumber(keyValue) / countSpaces(keyValue); |
nandgate | 0:6dee052a3fa4 | 127 | printf("keyPart: %08x\n", keyPart); |
nandgate | 0:6dee052a3fa4 | 128 | return keyPart; |
nandgate | 0:6dee052a3fa4 | 129 | } |
nandgate | 0:6dee052a3fa4 | 130 | // No key value |
nandgate | 0:6dee052a3fa4 | 131 | return 0; |
nandgate | 0:6dee052a3fa4 | 132 | } |
nandgate | 0:6dee052a3fa4 | 133 | |
nandgate | 0:6dee052a3fa4 | 134 | void HTTPWebSocketConnectingState::hexStringToBinary(const char *hex, char *binary) { |
nandgate | 0:6dee052a3fa4 | 135 | while (*hex) { |
nandgate | 0:6dee052a3fa4 | 136 | char c; |
nandgate | 0:6dee052a3fa4 | 137 | |
nandgate | 0:6dee052a3fa4 | 138 | c= *hex++; |
nandgate | 0:6dee052a3fa4 | 139 | *binary= (c < '@' ? c-'0' : c-'a'+10) << 4; |
nandgate | 0:6dee052a3fa4 | 140 | c= *hex++; |
nandgate | 0:6dee052a3fa4 | 141 | *binary |= (c < '@' ? c-'0' : c-'a'+10); |
nandgate | 0:6dee052a3fa4 | 142 | binary++; |
nandgate | 0:6dee052a3fa4 | 143 | } |
nandgate | 0:6dee052a3fa4 | 144 | } |
nandgate | 0:6dee052a3fa4 | 145 | |
nandgate | 0:6dee052a3fa4 | 146 | //----- |
nandgate | 0:6dee052a3fa4 | 147 | |
nandgate | 0:6dee052a3fa4 | 148 | HTTPWebSocketStreamingState::HTTPWebSocketStreamingState() : led(LED2) { |
nandgate | 0:6dee052a3fa4 | 149 | sendCnt= 0; |
nandgate | 0:6dee052a3fa4 | 150 | } |
nandgate | 0:6dee052a3fa4 | 151 | |
nandgate | 0:6dee052a3fa4 | 152 | HTTPStatus HTTPWebSocketStreamingState::init(HTTPConnection *conn) { |
nandgate | 0:6dee052a3fa4 | 153 | return HTTP_InternalServerError; // ignored |
nandgate | 0:6dee052a3fa4 | 154 | } |
nandgate | 0:6dee052a3fa4 | 155 | |
nandgate | 0:6dee052a3fa4 | 156 | HTTPHandle HTTPWebSocketStreamingState::data(HTTPConnection *conn, void *data, int len) { |
nandgate | 0:6dee052a3fa4 | 157 | char *str= ((char*)data)+1; // skip leading 0x00 |
nandgate | 0:6dee052a3fa4 | 158 | str[len]= 0; // stop on trailing 0xFF |
nandgate | 0:6dee052a3fa4 | 159 | //printf("IN:%d:%s\n", len, str); |
nandgate | 0:6dee052a3fa4 | 160 | rgb.setRgb(str); |
nandgate | 0:6dee052a3fa4 | 161 | return HTTP_Success; |
nandgate | 0:6dee052a3fa4 | 162 | } |
nandgate | 0:6dee052a3fa4 | 163 | |
nandgate | 0:6dee052a3fa4 | 164 | HTTPHandle HTTPWebSocketStreamingState::send(HTTPConnection *conn, int maxData) { |
nandgate | 0:6dee052a3fa4 | 165 | char buffer[80]; |
nandgate | 0:6dee052a3fa4 | 166 | int len; |
nandgate | 0:6dee052a3fa4 | 167 | |
nandgate | 0:6dee052a3fa4 | 168 | if (sendCnt > 1000) { |
nandgate | 0:6dee052a3fa4 | 169 | sprintf(buffer, "%c%f,%f,%f\n%c", 0x00, sensor.getPercentOfScale(), sensor.getResistance(), sensor.getKelvin(), 0xFF); |
nandgate | 0:6dee052a3fa4 | 170 | len= strlen(buffer+1); |
nandgate | 0:6dee052a3fa4 | 171 | conn->write(buffer, len+1); |
nandgate | 0:6dee052a3fa4 | 172 | sendCnt= 0; |
nandgate | 0:6dee052a3fa4 | 173 | //led= !led; |
nandgate | 0:6dee052a3fa4 | 174 | } else { |
nandgate | 0:6dee052a3fa4 | 175 | sensor.measure(); |
nandgate | 0:6dee052a3fa4 | 176 | sendCnt++; |
nandgate | 0:6dee052a3fa4 | 177 | } |
nandgate | 0:6dee052a3fa4 | 178 | |
nandgate | 0:6dee052a3fa4 | 179 | return HTTP_Success; |
nandgate | 0:6dee052a3fa4 | 180 | } |
nandgate | 0:6dee052a3fa4 | 181 | |
nandgate | 0:6dee052a3fa4 | 182 | //----- |
nandgate | 0:6dee052a3fa4 | 183 | |
nandgate | 0:6dee052a3fa4 | 184 | // Register headers required by this handler. Headers that are not registered will |
nandgate | 0:6dee052a3fa4 | 185 | // be stripped by the server. |
nandgate | 0:6dee052a3fa4 | 186 | void HTTPWebSocketHandler::reg(HTTPServer *server) { |
nandgate | 0:6dee052a3fa4 | 187 | server->registerField("Sec-WebSocket-Key1"); |
nandgate | 0:6dee052a3fa4 | 188 | server->registerField("Sec-WebSocket-Key2"); |
nandgate | 0:6dee052a3fa4 | 189 | server->registerField("Host"); |
nandgate | 0:6dee052a3fa4 | 190 | server->registerField("Origin"); |
nandgate | 0:6dee052a3fa4 | 191 | } |
nandgate | 0:6dee052a3fa4 | 192 | |
nandgate | 0:6dee052a3fa4 | 193 | HTTPStatus HTTPWebSocketHandler::init(HTTPConnection *conn) const { |
nandgate | 0:6dee052a3fa4 | 194 | // Todo: validate headers |
nandgate | 0:6dee052a3fa4 | 195 | HTTPWebSocketState *state= new HTTPWebSocketConnectingState(); |
nandgate | 0:6dee052a3fa4 | 196 | conn->data= state; |
nandgate | 0:6dee052a3fa4 | 197 | HTTPStatus status= state->init(conn); |
nandgate | 0:6dee052a3fa4 | 198 | printf("init: %d\n", status); |
nandgate | 0:6dee052a3fa4 | 199 | return status; |
nandgate | 0:6dee052a3fa4 | 200 | } |
nandgate | 0:6dee052a3fa4 | 201 | |
nandgate | 0:6dee052a3fa4 | 202 | HTTPHandle HTTPWebSocketHandler::data(HTTPConnection *conn, void *data, int len) const { |
nandgate | 0:6dee052a3fa4 | 203 | HTTPWebSocketState *state= (HTTPWebSocketState *) conn->data; |
nandgate | 0:6dee052a3fa4 | 204 | HTTPHandle result= state->data(conn, data, len); |
nandgate | 0:6dee052a3fa4 | 205 | //printf("data: %d\n", result); |
nandgate | 0:6dee052a3fa4 | 206 | return result; |
nandgate | 0:6dee052a3fa4 | 207 | } |
nandgate | 0:6dee052a3fa4 | 208 | |
nandgate | 0:6dee052a3fa4 | 209 | HTTPHandle HTTPWebSocketHandler::send(HTTPConnection *conn, int maxData) const { |
nandgate | 0:6dee052a3fa4 | 210 | HTTPWebSocketState *state= (HTTPWebSocketState *) conn->data; |
nandgate | 0:6dee052a3fa4 | 211 | HTTPHandle result= state->send(conn, maxData); |
nandgate | 0:6dee052a3fa4 | 212 | //printf("send: %d\n", result); |
nandgate | 0:6dee052a3fa4 | 213 | return result; |
nandgate | 0:6dee052a3fa4 | 214 | } |
nandgate | 0:6dee052a3fa4 | 215 |