WebSocketServer test

Dependencies:   mbed

main.cpp

Committer:
gtk2k
Date:
2012-04-29
Revision:
0:74be48b504a5

File content as of revision 0:74be48b504a5:

#include <string>
#include <sstream>
#include "mbed.h"
#include "TextLCD.h"
#include "EthernetNetIf.h"
#include "TCPSocket.h"
#include "sha1config.h"
#include "sha1.h"

//EthernetNetIf eth;
EthernetNetIf  eth(
    IpAddr(192,168,0,2), //IP Address
    IpAddr(255,255,255,0), //Network Mask
    IpAddr(192,168,0,1), //Gateway
    IpAddr(192,168,0,1)  //DNS
);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
TCPSocket tcp;  //The listening port where requests are queued
TCPSocket* link; //The port where accepted requests can communicate
IpAddr localIp = IpAddr(192, 168, 0, 2);
int localPort = 80;
Host local(localIp, localPort); //mbed IP
Host client;

TextLCD lcd(p24, p26, p27, p28, p29, p30);

TCPSocketErr accErr;
int wsState = 0;

// encode64 from http://uinu.org/archives/105
string encode64(char *Buf,int Length) {
    char *Codes64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    int Byte3=0;
    string Result="";
    for (int i=0; i<Length; i++) {
        Byte3=(Byte3<<8)+(int)Buf[i];
        if ((i+1)%3==0) {
            Result=Result+Codes64[(Byte3>>18)&0x3F];
            Result=Result+Codes64[(Byte3>>12)&0x3F];
            Result=Result+Codes64[(Byte3>>6)&0x3F];
            Result=Result+Codes64[(Byte3)&0x3F];
            Byte3=0;
        }
    }

    int Rest=Length%3;
    switch (Rest) {
        case 1:
            Byte3=Byte3<<4;
            Result=Result+Codes64[(Byte3>>6)&0x3F];
            Result=Result+Codes64[(Byte3)&0x3F];
            Result=Result+"==";
            break;
        case 2:
            Byte3=Byte3<<2;
            Result=Result+Codes64[(Byte3>>12)&0x3F];
            Result=Result+Codes64[(Byte3>>6 )&0x3F];
            Result=Result+Codes64[(Byte3)&0x3F];
            Result=Result+"=";
            break;
    }
    return Result;
}

void onLinkSocketEvent(TCPSocketEvent e) {
    switch (e) {
        case TCPSOCKET_CONNECTED:
            printf("TCP Socket Connected\n");
            break;
        case TCPSOCKET_WRITEABLE:
            //Can now write some data...
            printf("TCP Socket Writable\n");
            break;
        case TCPSOCKET_READABLE:
            //Can now read dome data...
            printf("TCP Socket Readable\n");
            // Read in any available data into the buffer
            char buff[256];
            while ( int len = link->recv(buff, 256) ) {
                // And send straight back out again
                //link->send(buff, len);
                printf("len = %d\n", len);
                if (wsState == 0) {
                    buff[len]=0; // make terminater
                    printf("%s\n", (char*)buff);
                    for (int i = 0; i < len; i++) {
                        if (buff[i] == 'K' && buff[i + 1] == 'e' && buff[i + 2] == 'y') {
                            for (int j = i + 1; j < len; j++) {
                                if (buff[j] == '\r') {
                                    i += 5;
                                    int keyLen = j - i;
                                    char strKey[keyLen + 1];
                                    strKey[keyLen] = 0;
                                    strncpy(strKey, buff + i, keyLen);
                                    char guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                                    strcat(strKey, guid);
                                    unsigned char hash[20];
                                    sha1((unsigned char*)strKey,strlen((char*)strKey),hash);
                                    string accept = encode64((char*)hash, 20);
                                    string hsRes = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
                                    hsRes += accept;
                                    hsRes += "\r\n\r\n";
                                    printf("%s\n", hsRes.c_str());
                                    link->send(hsRes.c_str(), hsRes.size());
                                    wsState = 1;
                                    return;
                                }
                            }
                        }
                    }
                } else {
                    if (len == 0) {
                        link->close();
                        return;
                    }
                    bool fin = (buff[0] & 0x80) == 0x80;
                    int opcode = buff[0] & 0x0f;
                    if (opcode == 0x9) {
                        buff[0] += 1;
                        link->send(buff, len);
                        return;
                    }
                    int dataLen = buff[1] & 0x7f;
                    if (!fin || dataLen > 125) {
                        link->close();
                        return;
                    }
                    int i = 0;
                    for (i = 0; i < dataLen; i++) {
                        buff[6 + i] = buff[6 + i] ^ buff[2 + (i % 4)];
                    }
                    printf("data length:%d\n", dataLen);
                    buff[6 + dataLen] = 0;
                    if (opcode == 1) {
                        printf("received data:%s\n", buff + 6);
                        char sendData[2 + dataLen + 1];
                        sendData[0] = buff[0];
                        sendData[1] = buff[1] & 0x7f;
                        for (i = 0; i < dataLen; i++) {
                            sendData[2 + i] = buff[6 + i];
                        }
                        sendData[2 + dataLen] = 0;
                        link->send(sendData, 2 + dataLen);
                    } else if (opcode == 2) {
                        led1 = buff[6 + 0];
                        led2 = buff[6 + 1];
                        led3 = buff[6 + 2];
                        led4 = buff[6 + 3];
                    }
                }
            };
            break;
        case TCPSOCKET_CONTIMEOUT:
            printf("TCP Socket Timeout\n");
            break;
        case TCPSOCKET_CONRST:
            printf("TCP Socket CONRST\n");
            break;
        case TCPSOCKET_CONABRT:
            printf("TCP Socket CONABRT\n");
            break;
        case TCPSOCKET_ERROR:
            printf("TCP Socket Error\n");
            link->close();
            break;
        case TCPSOCKET_DISCONNECTED:
            printf("TCP Socket Disconnected\n");
            wsState = 0;
            link->close();
            break;
        default:
            printf("DEFAULT\n");
    }
}

void onTCPSocketEvent(TCPSocketEvent e) {
    switch (e) {
        case TCPSOCKET_CONNECTED:
            printf("Connected\n");
            break;

        case TCPSOCKET_ACCEPT: {
            accErr = tcp.accept(&client,&link);
            switch (accErr) {
                case TCPSOCKET_SETUP:
                    printf("Err:Setup\n");
                    break;  //TCPSocket not properly configured.
                case TCPSOCKET_TIMEOUT:
                    printf("Err:Timeout\n");
                    break;  //Connection timed out.
                case TCPSOCKET_IF:
                    printf("Err:Interface\n");
                    break;  //Interface has problems, does not exist or is not initialized.
                case TCPSOCKET_MEM:
                    printf("Err:Memory\n");
                    break;  //Not enough mem.
                case TCPSOCKET_INUSE:
                    printf("Err:In use\n");
                    break;  //Interface / Port is in use.
                case TCPSOCKET_EMPTY:
                    printf("Err:Empty\n");
                    break;  //Connections queue is empty.
                case TCPSOCKET_RST:
                    printf("Err:Reset\n");
                    break;  //Connection was reset by remote host.
                case TCPSOCKET_OK:
                    printf("Accepted: ");
                    break;  //Success.
            }
            link->setOnEvent(&onLinkSocketEvent);
            IpAddr clientIp = client.getIp();
            printf("Incoming TCP connection from %d.%d.%d.%d\n",
                   clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
        }
        break;

        case TCPSOCKET_READABLE:
            printf("Readable\n");
            break;

        case TCPSOCKET_WRITEABLE:
            printf("Writeable\n");
            break;

        case TCPSOCKET_CONTIMEOUT:
            printf("Timeout\n");
            break;

        case TCPSOCKET_CONRST:
            printf("Reset\n");
            break;
        case TCPSOCKET_CONABRT:
            printf("Aborted\n");
            break;

        case TCPSOCKET_ERROR:
            printf("Error\n");
            break;

        case TCPSOCKET_DISCONNECTED:
            printf("Disconnected\n");
            tcp.close();
            break;
    }
}

int main() {
    printf("Setting up...\n");
    EthernetErr ethErr = eth.setup();
    if (ethErr) {
        printf("Error %d in setup.\n", ethErr);
        return -1;
    }

    printf("Setup OK\n");
    //****End of basic setup*****

    tcp.setOnEvent(&onTCPSocketEvent); //Generate method to deal with requests

    //Bind to local port
    printf("Init bind..\n");
    TCPSocketErr bindErr = tcp.bind(local);
    switch (bindErr) {
        case TCPSOCKET_SETUP:
            printf("Err:Setup\n");
            return -1;  //TCPSocket not properly configured.
        case TCPSOCKET_TIMEOUT:
            printf("Err:Timeout\n");
            return -1;  //Connection timed out.
        case TCPSOCKET_IF:
            printf("Err:Interface\n");
            return -1;  //Interface has problems, does not exist or is not initialized.
        case TCPSOCKET_MEM:
            printf("Err:Memory\n");
            return -1;  //Not enough mem.
        case TCPSOCKET_INUSE:
            printf("Err:In use\n");
            return -1;  //Interface / Port is in use.
        case TCPSOCKET_EMPTY:
            printf("Err:Empty\n");
            return -1;  //Connections queue is empty.
        case TCPSOCKET_RST:
            printf("Err:Reset\n");
            return -1;  //Connection was reset by remote host.
        case TCPSOCKET_OK:
            printf("Bound to port\n");
            break;  //Success.
    }

    //Listen to local port
    printf("Init listen..\n");
    TCPSocketErr listenErr = tcp.listen();
    switch (listenErr) {
        case TCPSOCKET_SETUP:
            printf("Err:Setup\n");
            return -1;  //TCPSocket not properly configured.
        case TCPSOCKET_TIMEOUT:
            printf("Err:Timeout\n");
            return -1;  //Connection timed out.
        case TCPSOCKET_IF:
            printf("Err:Interface\n");
            return -1;  //Interface has problems, does not exist or is not initialized.
        case TCPSOCKET_MEM:
            printf("Err:Memory\n");
            return -1;  //Not enough mem.
        case TCPSOCKET_INUSE:
            printf("Err:In use\n");
            return -1;  //Interface / Port is in use.
        case TCPSOCKET_EMPTY:
            printf("Err:Empty\n");
            return -1;  //Connections queue is empty.
        case TCPSOCKET_RST:
            printf("Err:Reset\n");
            return -1;  //Connection was reset by remote host.
        case TCPSOCKET_OK:
            printf("Listening\n");
            break;  //Success.
    }

    Timer tmr;
    tmr.start();
    while (1) {
        Net::poll();
        if (tmr.read() > 2) {
            tmr.reset();
            //led1=!led1; //Show that we are alive
        }
    }
}