Ethernet Interfaceを使用したWebSocketサーバー

Dependencies:   EthernetInterface TextLCD mbed-rtos mbed

main.cpp

Committer:
gtk2k
Date:
2013-03-30
Revision:
0:98ff551a3a1a

File content as of revision 0:98ff551a3a1a:

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

const int WS_HANDSHAKE = 1;
const int WS_CONNECT = 2;
int wsState = 0;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
TextLCD lcd(p24, p26, p27, p28, p29, p30);

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;
}

int main() {
    EthernetInterface eth;
    eth.init("192.168.0.2", "255.255.255.0", "192.168.0.2");
    eth.connect();
    lcd.cls();
    lcd.printf("%s", eth.getIPAddress());
    
    TCPSocketServer server;
    server.bind(8080);
    server.listen();
    printf("\nWait for new connection...\n");
    TCPSocketConnection sock;
    server.accept(sock);
    wsState = WS_HANDSHAKE;
    char buff[600];
    int len;
    while (true) {
        len = sock.receive(buff, sizeof(buff)-1);
        if (len <= 0){
            printf("close by 0 length\n");
            wsState = WS_HANDSHAKE;
            continue;
        }
        buff[len] = '\0';
        switch(wsState){
            case WS_HANDSHAKE:
                printf("Received %d chars from server:\n%s\n", len, 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", hsRes.c_str());
                                sock.send_all((char *)hsRes.c_str(), hsRes.size());
                                printf("change to WS_CONNECT state\n");
                                wsState = WS_CONNECT;
                                break;
                            }
                        }
                    }
                }
                break;
            case WS_CONNECT:
                bool fin = (buff[0] & 0x80) == 0x80;
                int opcode = buff[0] & 0x0f;
                if (opcode == 0x8) {
                    printf("close by close opcode\n");
                    wsState = WS_HANDSHAKE;
                    sock.close();
                    break;
                }
                if (opcode == 0x9) {
                    buff[0] += 1;
                    sock.send_all(buff, len);
                    break;
                }
                int dataLen = buff[1] & 0x7f;
                if (!fin || dataLen > 125) {
                    sock.close();
                    printf("close by illegal data length \n");
                    wsState = WS_HANDSHAKE;
                    break;
                }
                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;
                    sock.send_all(sendData, 2 + dataLen);
                } else if (opcode == 2) {
                    led1 = buff[6 + 0];
                    led2 = buff[6 + 1];
                    led3 = buff[6 + 2];
                    led4 = buff[6 + 3];
                }
                break;
        }
    }
      
    sock.close();
    eth.disconnect();
    while(1) {}
}