WebSocket client library

Websocket.cpp

Committer:
samux
Date:
2011-08-24
Revision:
6:01a1eb7c0145
Parent:
4:1d3e630b8f9c
Child:
7:b15978708360

File content as of revision 6:01a1eb7c0145:

#include "Websocket.h"
#include <string>

Websocket::Websocket(char * url, Wifly * wifi) {
        this->wifi = wifi;
        wifi_use = true;
        eth_use = false;
        fillFields(wifi_use, url);
}

void Websocket::fillFields(bool wifi, char * url) {
    char *res = NULL;
    char *res1 = NULL;

    char buf[30];
    strcpy(buf, url);

    res = strtok(buf, ":");
    if (strcmp(res, "ws")) 
    {
        this->ip_domain = NULL;
        this->path = NULL;
        printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
    } 
    else 
    {
        //ip_domain and port
        res = strtok(NULL, "/");

        //path
        res1 = strtok(NULL, " ");
        if (res1 != NULL) {
            path = (char *) malloc (sizeof(char) * strlen(res1));
            strcpy(this->path, res1);
        }

        //ip_domain
        res = strtok(res, ":");
        if (res != NULL) {
            ip_domain = (char *) malloc (sizeof(char) * strlen(res));
            strcpy(this->ip_domain, res);
            //if we use ethernet, we must decode ip address or use dnsresolver
            if (!wifi) {
                printf("ethernet use\r\n");
                strcpy(buf, res);
                //we try to decode the ip address
                if (buf[0] >= '0' && buf[0] <= '9') {
                    res = strtok(buf, ".");
                    int i = 0;
                    int ip[4];
                    while (res != NULL) {
                        ip[i] = atoi(res);
                        res = strtok(NULL, ".");
                        i++;
                    }
                    server_ip = IpAddr(ip[0], ip[1], ip[2], ip[3]);
                    printf("server=%i.%i.%i.%i\n",server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
                }
                //we must use dnsresolver to find the ip address
                else {
                    DNSResolver dr;
                    server_ip = dr.resolveName(buf);
                    printf("server=%i.%i.%i.%i\n",server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
                }
            }
        }

        //port
        res = strtok(NULL, ":");
        if (res != NULL) {
            port = (char *) malloc (sizeof(char) * strlen(res));
            strcpy(this->port, res);
        } else {
            port = (char *) malloc (sizeof(char) * 3);
            strcpy(this->port, "80");
        }
    }
}


Websocket::Websocket(char * url) {
        wifi_use = false;
        eth_use = true;
        eth_writeable = false;
        eth_readable = false;
        eth_connected = false;
        fillFields(wifi_use, url);
}




bool Websocket::connect() {
    char cmd[50];
    if ( wifi_use ) {
        wifi->Send("exit\r", "NO");
        //enter in cmd mode
        while (!wifi->Send("$$$", "CMD")) {
            printf("cannot enter in CMD mode\r\n");
            wifi->exit();
        }


        //open the connection
        sprintf(cmd, "open %s %s\r\n", ip_domain, port);
        if (!wifi->Send(cmd, "OPEN")) {
            printf("Websocket::connect cannot open\r\n");
            return false;
        }


        //send websocket HTTP header
        sprintf(cmd, "GET /%s HTTP/1.1\r\n", path);
        wifi->Send(cmd, "NO");

        sprintf(cmd, "Host: %s:%s\r\n", ip_domain, port);
        wifi->Send(cmd, "NO");

        wifi->Send("Upgrade: WebSocket\r\n", "NO");

        sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain, port);
        wifi->Send(cmd, "NO");


        wifi->Send("Connection: Upgrade\r\n", "NO");
        wifi->Send("Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n", "NO");
        wifi->Send("Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n", "NO");
        if (!wifi->Send("^n:ds[4U", "8jKS'y:G*Co,Wxa-"))
            return false;

        printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain, this->path, this->port);
        return true;
    } else if ( eth_use ) {
        int i = 0;

        EthernetErr ethErr = eth.setup();
        if (ethErr) {
            printf("Error %d in setup.\r\n", ethErr);
            return false;
        }

        printf("setup OK\r\n");

        IpAddr ipt = eth.getIp();
        printf("mbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]);

        sock.setOnEvent(this, &Websocket::onTCPSocketEvent);
        Host server (server_ip, atoi(port));
        TCPSocketErr bindErr = sock.connect(server);
        if (bindErr) {
            printf("binderr: %d", bindErr);
            return false;
        }


        Timer tmr;
        tmr.start();
        char msg[10];

        while (true) {
            Net::poll();
            if (tmr.read() > 0.1) {
                tmr.reset();
                if (eth_connected) {
                    switch (i) {
                        case 0:
                            sprintf(cmd, "GET /%s HTTP/1.1\r\n", path);
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 1:
                            sprintf(cmd, "Host: %s:%s\r\n", ip_domain, port);
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 2:
                            sprintf(cmd, "Upgrade: WebSocket\r\n");
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 3:
                            sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain, port);
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 4:
                            sprintf(cmd, "Connection: Upgrade\r\n");
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 5:
                            sprintf(cmd, "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n");
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 6:
                            sprintf(cmd, "Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n");
                            sock.send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 7:
                            sock.send("^n:ds[4U", 8);
                            i++;
                            break;
                        case 8:
                            if(eth_readable)
                            {
                                string checking;
                                size_t found = string::npos;
                                sock.recv(msg, 10);
                                Net::poll();
                                checking = msg;
                                found = checking.find("HTTP");
                                if(found != string::npos)
                                {
                                    //printf("checking: %s\r\n", checking);
                                    i++;
                                    break;
                                }
                                else
                                    return false;
                            }
                            break;
                            
                        default:
                            break;
                    }
                }
                if (i==9)
                {
                    printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain, this->path, this->port);
                    return true;
                }
            }
        }

    }
    return true;
}

void Websocket::Send(char * str) {
    char cmd[100];
    if (wifi_use) {
        wifi->putc('\x00');
        sprintf(cmd, "%s%c", str, '\xff');
        wifi->Send(cmd, "NO");
    } else if (eth_use) {
        sprintf(cmd, "%c%s%c", 0x00, str, 0xff);
        Net::poll();
        sock.send(cmd, strlen(cmd + 1) + 1);
    }
}

bool Websocket::read(char * message) {
    int i = 0;
    char char_read;

    if (!wifi->readable()) {
        message = NULL;
        return false;
    }

    if (wifi->getc() != 0x00) {
        message = NULL;
        return false;
    }

    while ( (char_read = wifi->getc()) != 0xff)
        message[i++] = char_read;

    return true;
}

bool Websocket::close() {
    if (!wifi->CmdMode()) {
        printf("Websocket::close: cannot enter in cmd mode\r\n");
        return false;
    }

    wifi->Send("close\r", "NO");

    if (!wifi->exit())
        return false;

    return true;
}



bool Websocket::connected() {
    if (wifi_use) {
        char str[10];

        wait(0.25);
        if (!wifi->CmdMode()) {
            printf("Websocket::connected: cannot enter in cmd mode\r\n");
            return false;
        }
        wait(0.25);

        wifi->Send("show c\r\n", "NO");
        wifi->read(str);

        if (str[3] == '1') {
            if (!wifi->exit()) {
                printf("Websocket::connected: cannot exit\r\n");
                return false;
            }
            return true;
        }
        if (!wifi->exit())
            printf("Websocket::connected: cannot exit\r\n");
        return false;
    } 
    else if (eth_use)
        return eth_connected;

    return true;
}





void Websocket::onTCPSocketEvent(TCPSocketEvent e) {
    switch (e) {
        case TCPSOCKET_CONNECTED:
            eth_connected = true;
            printf("TCP Socket Connected\r\n");
            break;
        case TCPSOCKET_WRITEABLE:
            eth_writeable = true;
            break;
        case TCPSOCKET_READABLE:
            printf("TCP Socket Readable\r\n");
            eth_readable = true;
            break;
        case TCPSOCKET_CONTIMEOUT:
            printf("TCP Socket Timeout\r\n");
            eth_connected = false;
            break;
        case TCPSOCKET_CONRST:
            printf("TCP Socket CONRST\r\n");
            eth_connected = false;
            break;
        case TCPSOCKET_CONABRT:
            printf("TCP Socket CONABRT\r\n");
            eth_connected = false;
            break;
        case TCPSOCKET_ERROR:
            printf("TCP Socket Error\r\n");
            eth_connected = false;
            break;
        case TCPSOCKET_DISCONNECTED:
            eth_connected = false;
            break;
        default:
            printf("DEFAULT\r\n");
    }
}