WebSocketServer test

Dependencies:   mbed

Committer:
gtk2k
Date:
Sun Apr 29 03:58:08 2012 +0000
Revision:
0:74be48b504a5
WebSocketServer

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gtk2k 0:74be48b504a5 1 #include <string>
gtk2k 0:74be48b504a5 2 #include <sstream>
gtk2k 0:74be48b504a5 3 #include "mbed.h"
gtk2k 0:74be48b504a5 4 #include "TextLCD.h"
gtk2k 0:74be48b504a5 5 #include "EthernetNetIf.h"
gtk2k 0:74be48b504a5 6 #include "TCPSocket.h"
gtk2k 0:74be48b504a5 7 #include "sha1config.h"
gtk2k 0:74be48b504a5 8 #include "sha1.h"
gtk2k 0:74be48b504a5 9
gtk2k 0:74be48b504a5 10 //EthernetNetIf eth;
gtk2k 0:74be48b504a5 11 EthernetNetIf eth(
gtk2k 0:74be48b504a5 12 IpAddr(192,168,0,2), //IP Address
gtk2k 0:74be48b504a5 13 IpAddr(255,255,255,0), //Network Mask
gtk2k 0:74be48b504a5 14 IpAddr(192,168,0,1), //Gateway
gtk2k 0:74be48b504a5 15 IpAddr(192,168,0,1) //DNS
gtk2k 0:74be48b504a5 16 );
gtk2k 0:74be48b504a5 17
gtk2k 0:74be48b504a5 18 DigitalOut led1(LED1);
gtk2k 0:74be48b504a5 19 DigitalOut led2(LED2);
gtk2k 0:74be48b504a5 20 DigitalOut led3(LED3);
gtk2k 0:74be48b504a5 21 DigitalOut led4(LED4);
gtk2k 0:74be48b504a5 22 TCPSocket tcp; //The listening port where requests are queued
gtk2k 0:74be48b504a5 23 TCPSocket* link; //The port where accepted requests can communicate
gtk2k 0:74be48b504a5 24 IpAddr localIp = IpAddr(192, 168, 0, 2);
gtk2k 0:74be48b504a5 25 int localPort = 80;
gtk2k 0:74be48b504a5 26 Host local(localIp, localPort); //mbed IP
gtk2k 0:74be48b504a5 27 Host client;
gtk2k 0:74be48b504a5 28
gtk2k 0:74be48b504a5 29 TextLCD lcd(p24, p26, p27, p28, p29, p30);
gtk2k 0:74be48b504a5 30
gtk2k 0:74be48b504a5 31 TCPSocketErr accErr;
gtk2k 0:74be48b504a5 32 int wsState = 0;
gtk2k 0:74be48b504a5 33
gtk2k 0:74be48b504a5 34 // encode64 from http://uinu.org/archives/105
gtk2k 0:74be48b504a5 35 string encode64(char *Buf,int Length) {
gtk2k 0:74be48b504a5 36 char *Codes64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
gtk2k 0:74be48b504a5 37 int Byte3=0;
gtk2k 0:74be48b504a5 38 string Result="";
gtk2k 0:74be48b504a5 39 for (int i=0; i<Length; i++) {
gtk2k 0:74be48b504a5 40 Byte3=(Byte3<<8)+(int)Buf[i];
gtk2k 0:74be48b504a5 41 if ((i+1)%3==0) {
gtk2k 0:74be48b504a5 42 Result=Result+Codes64[(Byte3>>18)&0x3F];
gtk2k 0:74be48b504a5 43 Result=Result+Codes64[(Byte3>>12)&0x3F];
gtk2k 0:74be48b504a5 44 Result=Result+Codes64[(Byte3>>6)&0x3F];
gtk2k 0:74be48b504a5 45 Result=Result+Codes64[(Byte3)&0x3F];
gtk2k 0:74be48b504a5 46 Byte3=0;
gtk2k 0:74be48b504a5 47 }
gtk2k 0:74be48b504a5 48 }
gtk2k 0:74be48b504a5 49
gtk2k 0:74be48b504a5 50 int Rest=Length%3;
gtk2k 0:74be48b504a5 51 switch (Rest) {
gtk2k 0:74be48b504a5 52 case 1:
gtk2k 0:74be48b504a5 53 Byte3=Byte3<<4;
gtk2k 0:74be48b504a5 54 Result=Result+Codes64[(Byte3>>6)&0x3F];
gtk2k 0:74be48b504a5 55 Result=Result+Codes64[(Byte3)&0x3F];
gtk2k 0:74be48b504a5 56 Result=Result+"==";
gtk2k 0:74be48b504a5 57 break;
gtk2k 0:74be48b504a5 58 case 2:
gtk2k 0:74be48b504a5 59 Byte3=Byte3<<2;
gtk2k 0:74be48b504a5 60 Result=Result+Codes64[(Byte3>>12)&0x3F];
gtk2k 0:74be48b504a5 61 Result=Result+Codes64[(Byte3>>6 )&0x3F];
gtk2k 0:74be48b504a5 62 Result=Result+Codes64[(Byte3)&0x3F];
gtk2k 0:74be48b504a5 63 Result=Result+"=";
gtk2k 0:74be48b504a5 64 break;
gtk2k 0:74be48b504a5 65 }
gtk2k 0:74be48b504a5 66 return Result;
gtk2k 0:74be48b504a5 67 }
gtk2k 0:74be48b504a5 68
gtk2k 0:74be48b504a5 69 void onLinkSocketEvent(TCPSocketEvent e) {
gtk2k 0:74be48b504a5 70 switch (e) {
gtk2k 0:74be48b504a5 71 case TCPSOCKET_CONNECTED:
gtk2k 0:74be48b504a5 72 printf("TCP Socket Connected\n");
gtk2k 0:74be48b504a5 73 break;
gtk2k 0:74be48b504a5 74 case TCPSOCKET_WRITEABLE:
gtk2k 0:74be48b504a5 75 //Can now write some data...
gtk2k 0:74be48b504a5 76 printf("TCP Socket Writable\n");
gtk2k 0:74be48b504a5 77 break;
gtk2k 0:74be48b504a5 78 case TCPSOCKET_READABLE:
gtk2k 0:74be48b504a5 79 //Can now read dome data...
gtk2k 0:74be48b504a5 80 printf("TCP Socket Readable\n");
gtk2k 0:74be48b504a5 81 // Read in any available data into the buffer
gtk2k 0:74be48b504a5 82 char buff[256];
gtk2k 0:74be48b504a5 83 while ( int len = link->recv(buff, 256) ) {
gtk2k 0:74be48b504a5 84 // And send straight back out again
gtk2k 0:74be48b504a5 85 //link->send(buff, len);
gtk2k 0:74be48b504a5 86 printf("len = %d\n", len);
gtk2k 0:74be48b504a5 87 if (wsState == 0) {
gtk2k 0:74be48b504a5 88 buff[len]=0; // make terminater
gtk2k 0:74be48b504a5 89 printf("%s\n", (char*)buff);
gtk2k 0:74be48b504a5 90 for (int i = 0; i < len; i++) {
gtk2k 0:74be48b504a5 91 if (buff[i] == 'K' && buff[i + 1] == 'e' && buff[i + 2] == 'y') {
gtk2k 0:74be48b504a5 92 for (int j = i + 1; j < len; j++) {
gtk2k 0:74be48b504a5 93 if (buff[j] == '\r') {
gtk2k 0:74be48b504a5 94 i += 5;
gtk2k 0:74be48b504a5 95 int keyLen = j - i;
gtk2k 0:74be48b504a5 96 char strKey[keyLen + 1];
gtk2k 0:74be48b504a5 97 strKey[keyLen] = 0;
gtk2k 0:74be48b504a5 98 strncpy(strKey, buff + i, keyLen);
gtk2k 0:74be48b504a5 99 char guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
gtk2k 0:74be48b504a5 100 strcat(strKey, guid);
gtk2k 0:74be48b504a5 101 unsigned char hash[20];
gtk2k 0:74be48b504a5 102 sha1((unsigned char*)strKey,strlen((char*)strKey),hash);
gtk2k 0:74be48b504a5 103 string accept = encode64((char*)hash, 20);
gtk2k 0:74be48b504a5 104 string hsRes = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
gtk2k 0:74be48b504a5 105 hsRes += accept;
gtk2k 0:74be48b504a5 106 hsRes += "\r\n\r\n";
gtk2k 0:74be48b504a5 107 printf("%s\n", hsRes.c_str());
gtk2k 0:74be48b504a5 108 link->send(hsRes.c_str(), hsRes.size());
gtk2k 0:74be48b504a5 109 wsState = 1;
gtk2k 0:74be48b504a5 110 return;
gtk2k 0:74be48b504a5 111 }
gtk2k 0:74be48b504a5 112 }
gtk2k 0:74be48b504a5 113 }
gtk2k 0:74be48b504a5 114 }
gtk2k 0:74be48b504a5 115 } else {
gtk2k 0:74be48b504a5 116 if (len == 0) {
gtk2k 0:74be48b504a5 117 link->close();
gtk2k 0:74be48b504a5 118 return;
gtk2k 0:74be48b504a5 119 }
gtk2k 0:74be48b504a5 120 bool fin = (buff[0] & 0x80) == 0x80;
gtk2k 0:74be48b504a5 121 int opcode = buff[0] & 0x0f;
gtk2k 0:74be48b504a5 122 if (opcode == 0x9) {
gtk2k 0:74be48b504a5 123 buff[0] += 1;
gtk2k 0:74be48b504a5 124 link->send(buff, len);
gtk2k 0:74be48b504a5 125 return;
gtk2k 0:74be48b504a5 126 }
gtk2k 0:74be48b504a5 127 int dataLen = buff[1] & 0x7f;
gtk2k 0:74be48b504a5 128 if (!fin || dataLen > 125) {
gtk2k 0:74be48b504a5 129 link->close();
gtk2k 0:74be48b504a5 130 return;
gtk2k 0:74be48b504a5 131 }
gtk2k 0:74be48b504a5 132 int i = 0;
gtk2k 0:74be48b504a5 133 for (i = 0; i < dataLen; i++) {
gtk2k 0:74be48b504a5 134 buff[6 + i] = buff[6 + i] ^ buff[2 + (i % 4)];
gtk2k 0:74be48b504a5 135 }
gtk2k 0:74be48b504a5 136 printf("data length:%d\n", dataLen);
gtk2k 0:74be48b504a5 137 buff[6 + dataLen] = 0;
gtk2k 0:74be48b504a5 138 if (opcode == 1) {
gtk2k 0:74be48b504a5 139 printf("received data:%s\n", buff + 6);
gtk2k 0:74be48b504a5 140 char sendData[2 + dataLen + 1];
gtk2k 0:74be48b504a5 141 sendData[0] = buff[0];
gtk2k 0:74be48b504a5 142 sendData[1] = buff[1] & 0x7f;
gtk2k 0:74be48b504a5 143 for (i = 0; i < dataLen; i++) {
gtk2k 0:74be48b504a5 144 sendData[2 + i] = buff[6 + i];
gtk2k 0:74be48b504a5 145 }
gtk2k 0:74be48b504a5 146 sendData[2 + dataLen] = 0;
gtk2k 0:74be48b504a5 147 link->send(sendData, 2 + dataLen);
gtk2k 0:74be48b504a5 148 } else if (opcode == 2) {
gtk2k 0:74be48b504a5 149 led1 = buff[6 + 0];
gtk2k 0:74be48b504a5 150 led2 = buff[6 + 1];
gtk2k 0:74be48b504a5 151 led3 = buff[6 + 2];
gtk2k 0:74be48b504a5 152 led4 = buff[6 + 3];
gtk2k 0:74be48b504a5 153 }
gtk2k 0:74be48b504a5 154 }
gtk2k 0:74be48b504a5 155 };
gtk2k 0:74be48b504a5 156 break;
gtk2k 0:74be48b504a5 157 case TCPSOCKET_CONTIMEOUT:
gtk2k 0:74be48b504a5 158 printf("TCP Socket Timeout\n");
gtk2k 0:74be48b504a5 159 break;
gtk2k 0:74be48b504a5 160 case TCPSOCKET_CONRST:
gtk2k 0:74be48b504a5 161 printf("TCP Socket CONRST\n");
gtk2k 0:74be48b504a5 162 break;
gtk2k 0:74be48b504a5 163 case TCPSOCKET_CONABRT:
gtk2k 0:74be48b504a5 164 printf("TCP Socket CONABRT\n");
gtk2k 0:74be48b504a5 165 break;
gtk2k 0:74be48b504a5 166 case TCPSOCKET_ERROR:
gtk2k 0:74be48b504a5 167 printf("TCP Socket Error\n");
gtk2k 0:74be48b504a5 168 link->close();
gtk2k 0:74be48b504a5 169 break;
gtk2k 0:74be48b504a5 170 case TCPSOCKET_DISCONNECTED:
gtk2k 0:74be48b504a5 171 printf("TCP Socket Disconnected\n");
gtk2k 0:74be48b504a5 172 wsState = 0;
gtk2k 0:74be48b504a5 173 link->close();
gtk2k 0:74be48b504a5 174 break;
gtk2k 0:74be48b504a5 175 default:
gtk2k 0:74be48b504a5 176 printf("DEFAULT\n");
gtk2k 0:74be48b504a5 177 }
gtk2k 0:74be48b504a5 178 }
gtk2k 0:74be48b504a5 179
gtk2k 0:74be48b504a5 180 void onTCPSocketEvent(TCPSocketEvent e) {
gtk2k 0:74be48b504a5 181 switch (e) {
gtk2k 0:74be48b504a5 182 case TCPSOCKET_CONNECTED:
gtk2k 0:74be48b504a5 183 printf("Connected\n");
gtk2k 0:74be48b504a5 184 break;
gtk2k 0:74be48b504a5 185
gtk2k 0:74be48b504a5 186 case TCPSOCKET_ACCEPT: {
gtk2k 0:74be48b504a5 187 accErr = tcp.accept(&client,&link);
gtk2k 0:74be48b504a5 188 switch (accErr) {
gtk2k 0:74be48b504a5 189 case TCPSOCKET_SETUP:
gtk2k 0:74be48b504a5 190 printf("Err:Setup\n");
gtk2k 0:74be48b504a5 191 break; //TCPSocket not properly configured.
gtk2k 0:74be48b504a5 192 case TCPSOCKET_TIMEOUT:
gtk2k 0:74be48b504a5 193 printf("Err:Timeout\n");
gtk2k 0:74be48b504a5 194 break; //Connection timed out.
gtk2k 0:74be48b504a5 195 case TCPSOCKET_IF:
gtk2k 0:74be48b504a5 196 printf("Err:Interface\n");
gtk2k 0:74be48b504a5 197 break; //Interface has problems, does not exist or is not initialized.
gtk2k 0:74be48b504a5 198 case TCPSOCKET_MEM:
gtk2k 0:74be48b504a5 199 printf("Err:Memory\n");
gtk2k 0:74be48b504a5 200 break; //Not enough mem.
gtk2k 0:74be48b504a5 201 case TCPSOCKET_INUSE:
gtk2k 0:74be48b504a5 202 printf("Err:In use\n");
gtk2k 0:74be48b504a5 203 break; //Interface / Port is in use.
gtk2k 0:74be48b504a5 204 case TCPSOCKET_EMPTY:
gtk2k 0:74be48b504a5 205 printf("Err:Empty\n");
gtk2k 0:74be48b504a5 206 break; //Connections queue is empty.
gtk2k 0:74be48b504a5 207 case TCPSOCKET_RST:
gtk2k 0:74be48b504a5 208 printf("Err:Reset\n");
gtk2k 0:74be48b504a5 209 break; //Connection was reset by remote host.
gtk2k 0:74be48b504a5 210 case TCPSOCKET_OK:
gtk2k 0:74be48b504a5 211 printf("Accepted: ");
gtk2k 0:74be48b504a5 212 break; //Success.
gtk2k 0:74be48b504a5 213 }
gtk2k 0:74be48b504a5 214 link->setOnEvent(&onLinkSocketEvent);
gtk2k 0:74be48b504a5 215 IpAddr clientIp = client.getIp();
gtk2k 0:74be48b504a5 216 printf("Incoming TCP connection from %d.%d.%d.%d\n",
gtk2k 0:74be48b504a5 217 clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
gtk2k 0:74be48b504a5 218 }
gtk2k 0:74be48b504a5 219 break;
gtk2k 0:74be48b504a5 220
gtk2k 0:74be48b504a5 221 case TCPSOCKET_READABLE:
gtk2k 0:74be48b504a5 222 printf("Readable\n");
gtk2k 0:74be48b504a5 223 break;
gtk2k 0:74be48b504a5 224
gtk2k 0:74be48b504a5 225 case TCPSOCKET_WRITEABLE:
gtk2k 0:74be48b504a5 226 printf("Writeable\n");
gtk2k 0:74be48b504a5 227 break;
gtk2k 0:74be48b504a5 228
gtk2k 0:74be48b504a5 229 case TCPSOCKET_CONTIMEOUT:
gtk2k 0:74be48b504a5 230 printf("Timeout\n");
gtk2k 0:74be48b504a5 231 break;
gtk2k 0:74be48b504a5 232
gtk2k 0:74be48b504a5 233 case TCPSOCKET_CONRST:
gtk2k 0:74be48b504a5 234 printf("Reset\n");
gtk2k 0:74be48b504a5 235 break;
gtk2k 0:74be48b504a5 236 case TCPSOCKET_CONABRT:
gtk2k 0:74be48b504a5 237 printf("Aborted\n");
gtk2k 0:74be48b504a5 238 break;
gtk2k 0:74be48b504a5 239
gtk2k 0:74be48b504a5 240 case TCPSOCKET_ERROR:
gtk2k 0:74be48b504a5 241 printf("Error\n");
gtk2k 0:74be48b504a5 242 break;
gtk2k 0:74be48b504a5 243
gtk2k 0:74be48b504a5 244 case TCPSOCKET_DISCONNECTED:
gtk2k 0:74be48b504a5 245 printf("Disconnected\n");
gtk2k 0:74be48b504a5 246 tcp.close();
gtk2k 0:74be48b504a5 247 break;
gtk2k 0:74be48b504a5 248 }
gtk2k 0:74be48b504a5 249 }
gtk2k 0:74be48b504a5 250
gtk2k 0:74be48b504a5 251 int main() {
gtk2k 0:74be48b504a5 252 printf("Setting up...\n");
gtk2k 0:74be48b504a5 253 EthernetErr ethErr = eth.setup();
gtk2k 0:74be48b504a5 254 if (ethErr) {
gtk2k 0:74be48b504a5 255 printf("Error %d in setup.\n", ethErr);
gtk2k 0:74be48b504a5 256 return -1;
gtk2k 0:74be48b504a5 257 }
gtk2k 0:74be48b504a5 258
gtk2k 0:74be48b504a5 259 printf("Setup OK\n");
gtk2k 0:74be48b504a5 260 //****End of basic setup*****
gtk2k 0:74be48b504a5 261
gtk2k 0:74be48b504a5 262 tcp.setOnEvent(&onTCPSocketEvent); //Generate method to deal with requests
gtk2k 0:74be48b504a5 263
gtk2k 0:74be48b504a5 264 //Bind to local port
gtk2k 0:74be48b504a5 265 printf("Init bind..\n");
gtk2k 0:74be48b504a5 266 TCPSocketErr bindErr = tcp.bind(local);
gtk2k 0:74be48b504a5 267 switch (bindErr) {
gtk2k 0:74be48b504a5 268 case TCPSOCKET_SETUP:
gtk2k 0:74be48b504a5 269 printf("Err:Setup\n");
gtk2k 0:74be48b504a5 270 return -1; //TCPSocket not properly configured.
gtk2k 0:74be48b504a5 271 case TCPSOCKET_TIMEOUT:
gtk2k 0:74be48b504a5 272 printf("Err:Timeout\n");
gtk2k 0:74be48b504a5 273 return -1; //Connection timed out.
gtk2k 0:74be48b504a5 274 case TCPSOCKET_IF:
gtk2k 0:74be48b504a5 275 printf("Err:Interface\n");
gtk2k 0:74be48b504a5 276 return -1; //Interface has problems, does not exist or is not initialized.
gtk2k 0:74be48b504a5 277 case TCPSOCKET_MEM:
gtk2k 0:74be48b504a5 278 printf("Err:Memory\n");
gtk2k 0:74be48b504a5 279 return -1; //Not enough mem.
gtk2k 0:74be48b504a5 280 case TCPSOCKET_INUSE:
gtk2k 0:74be48b504a5 281 printf("Err:In use\n");
gtk2k 0:74be48b504a5 282 return -1; //Interface / Port is in use.
gtk2k 0:74be48b504a5 283 case TCPSOCKET_EMPTY:
gtk2k 0:74be48b504a5 284 printf("Err:Empty\n");
gtk2k 0:74be48b504a5 285 return -1; //Connections queue is empty.
gtk2k 0:74be48b504a5 286 case TCPSOCKET_RST:
gtk2k 0:74be48b504a5 287 printf("Err:Reset\n");
gtk2k 0:74be48b504a5 288 return -1; //Connection was reset by remote host.
gtk2k 0:74be48b504a5 289 case TCPSOCKET_OK:
gtk2k 0:74be48b504a5 290 printf("Bound to port\n");
gtk2k 0:74be48b504a5 291 break; //Success.
gtk2k 0:74be48b504a5 292 }
gtk2k 0:74be48b504a5 293
gtk2k 0:74be48b504a5 294 //Listen to local port
gtk2k 0:74be48b504a5 295 printf("Init listen..\n");
gtk2k 0:74be48b504a5 296 TCPSocketErr listenErr = tcp.listen();
gtk2k 0:74be48b504a5 297 switch (listenErr) {
gtk2k 0:74be48b504a5 298 case TCPSOCKET_SETUP:
gtk2k 0:74be48b504a5 299 printf("Err:Setup\n");
gtk2k 0:74be48b504a5 300 return -1; //TCPSocket not properly configured.
gtk2k 0:74be48b504a5 301 case TCPSOCKET_TIMEOUT:
gtk2k 0:74be48b504a5 302 printf("Err:Timeout\n");
gtk2k 0:74be48b504a5 303 return -1; //Connection timed out.
gtk2k 0:74be48b504a5 304 case TCPSOCKET_IF:
gtk2k 0:74be48b504a5 305 printf("Err:Interface\n");
gtk2k 0:74be48b504a5 306 return -1; //Interface has problems, does not exist or is not initialized.
gtk2k 0:74be48b504a5 307 case TCPSOCKET_MEM:
gtk2k 0:74be48b504a5 308 printf("Err:Memory\n");
gtk2k 0:74be48b504a5 309 return -1; //Not enough mem.
gtk2k 0:74be48b504a5 310 case TCPSOCKET_INUSE:
gtk2k 0:74be48b504a5 311 printf("Err:In use\n");
gtk2k 0:74be48b504a5 312 return -1; //Interface / Port is in use.
gtk2k 0:74be48b504a5 313 case TCPSOCKET_EMPTY:
gtk2k 0:74be48b504a5 314 printf("Err:Empty\n");
gtk2k 0:74be48b504a5 315 return -1; //Connections queue is empty.
gtk2k 0:74be48b504a5 316 case TCPSOCKET_RST:
gtk2k 0:74be48b504a5 317 printf("Err:Reset\n");
gtk2k 0:74be48b504a5 318 return -1; //Connection was reset by remote host.
gtk2k 0:74be48b504a5 319 case TCPSOCKET_OK:
gtk2k 0:74be48b504a5 320 printf("Listening\n");
gtk2k 0:74be48b504a5 321 break; //Success.
gtk2k 0:74be48b504a5 322 }
gtk2k 0:74be48b504a5 323
gtk2k 0:74be48b504a5 324 Timer tmr;
gtk2k 0:74be48b504a5 325 tmr.start();
gtk2k 0:74be48b504a5 326 while (1) {
gtk2k 0:74be48b504a5 327 Net::poll();
gtk2k 0:74be48b504a5 328 if (tmr.read() > 2) {
gtk2k 0:74be48b504a5 329 tmr.reset();
gtk2k 0:74be48b504a5 330 //led1=!led1; //Show that we are alive
gtk2k 0:74be48b504a5 331 }
gtk2k 0:74be48b504a5 332 }
gtk2k 0:74be48b504a5 333 }