Embedded WebSockets Experiment

Dependencies:   mbed MD5

Committer:
nandgate
Date:
Tue Jul 26 05:30:53 2011 +0000
Revision:
0:6dee052a3fa4

        

Who changed what in which revision?

UserRevisionLine numberNew 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