[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/kugelkopf123/ArduinoHttpClient/master/src/WebSocketClient.cpp [Back]  [Original]

// (c) Copyright Arduino. 2016
// Released under Apache License, version 2.0

#include "b64.h"

#include "WebSocketClient.h"

WebSocketClient::WebSocketClient(Client& aClient, const char* aServerName, uint16_t aServerPort)
 : HttpClient(aClient, aServerName, aServerPort),
   iTxStarted(false),
   iRxSize(0)
{
}

WebSocketClient::WebSocketClient(Client& aClient, const String& aServerName, uint16_t aServerPort) 
 : HttpClient(aClient, aServerName, aServerPort),
   iTxStarted(false),
   iRxSize(0)
{
}

WebSocketClient::WebSocketClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort)
 : HttpClient(aClient, aServerAddress, aServerPort),
   iTxStarted(false),
   iRxSize(0)
{
}

int WebSocketClient::begin(const char* aPath)
{
    // start the GET request
    beginRequest();
    connectionKeepAlive();
    int status = get(aPath);

    if (status == 0)
    {
        uint8_t randomKey[16];
        char base64RandomKey[25];

        // create a random key for the connection upgrade
        for (int i = 0; i < (int)sizeof(randomKey); i++)
        {
            randomKey[i] = random(0x01, 0xff);
        }
        memset(base64RandomKey, 0x00, sizeof(base64RandomKey));
        b64_encode(randomKey, sizeof(randomKey), (unsigned char*)base64RandomKey, sizeof(base64RandomKey));

        // start the connection upgrade sequence
        sendHeader("Upgrade", "websocket");
        sendHeader("Connection", "Upgrade");
        sendHeader("Sec-WebSocket-Key", base64RandomKey);
        sendHeader("Sec-WebSocket-Version", "13");
        endRequest();

        status = responseStatusCode();

        if (status > 0)
        {
            skipResponseHeaders();
        }
    }

    iRxSize = 0;

    // status code of 101 means success
    return (status == 101) ? 0 : status;
}

int WebSocketClient::begin(const String& aPath)
{
    return begin(aPath.c_str());
}

int WebSocketClient::beginMessage(int aType)
{
    if (iTxStarted)
    {
        // fail TX already started
        return 1;
    }

    iTxStarted = true;
    iTxMessageType = (aType & 0xf);
    iTxSize = 0;

    return 0;
}

int WebSocketClient::endMessage()
{
    if (!iTxStarted)
    {
        // fail TX not started
        return 1;
    }

    // send FIN + the message type (opcode)
    HttpClient::write(0x80 | iTxMessageType);

    // the message is masked (0x80)
    // send the length
    if (iTxSize < 126)
    {
        HttpClient::write(0x80 | (uint8_t)iTxSize);
    }
    else if (iTxSize < 0xffff)
    {
        HttpClient::write(0x80 | 126);
        HttpClient::write((iTxSize >> 8) & 0xff);
        HttpClient::write((iTxSize >> 0) & 0xff);
    }
    else
    {
        HttpClient::write(0x80 | 127);
        HttpClient::write((iTxSize >> 56) & 0xff);
        HttpClient::write((iTxSize >> 48) & 0xff);
        HttpClient::write((iTxSize >> 40) & 0xff);
        HttpClient::write((iTxSize >> 32) & 0xff);
        HttpClient::write((iTxSize >> 24) & 0xff);
        HttpClient::write((iTxSize >> 16) & 0xff);
        HttpClient::write((iTxSize >> 8) & 0xff);
        HttpClient::write((iTxSize >> 0) & 0xff);
    }

    uint8_t maskKey[4];

    // create a random mask for the data and send
    for (int i = 0; i < (int)sizeof(maskKey); i++)
    {
        maskKey[i] = random(0xff);
    }
    HttpClient::write(maskKey, sizeof(maskKey));

    // mask the data and send
    for (int i = 0; i < (int)iTxSize; i++) {
        iTxBuffer[i] ^= maskKey[i % sizeof(maskKey)];
    }

    size_t txSize = iTxSize;

    iTxStarted = false;
    iTxSize = 0;

    return (HttpClient::write(iTxBuffer, txSize) == txSize) ? 0 : 1;
}

size_t WebSocketClient::write(uint8_t aByte)
{
    return write(&aByte, sizeof(aByte));
}

size_t WebSocketClient::write(const uint8_t *aBuffer, size_t aSize)
{
    if (iState < eReadingBody)
    {
        // have not upgraded the connection yet
        return HttpClient::write(aBuffer, aSize);
    }

    if (!iTxStarted)
    {
        // fail TX not   started
        return 0;
    }

    // check if the write size, fits in the buffer
    if ((iTxSize + aSize) > sizeof(iTxBuffer))
    {
        aSize = sizeof(iTxSize) - iTxSize;
    }

    // copy data into the buffer
    memcpy(iTxBuffer + iTxSize, aBuffer, aSize);

    iTxSize += aSize;
    
    return aSize;
}

int WebSocketClient::parseMessage()
{
    flushRx();

    // make sure 2 bytes (opcode + length)
    // are available
    if (HttpClient::available() < 2)
    {
        return 0;
    }

    // read open code and length
    uint8_t opcode = HttpClient::read();
    int length = HttpClient::read();

    if ((opcode & 0x0f) == 0)
    {
        // continuation, use previous opcode and update flags
        iRxOpCode |= opcode;
    }
    else
    {
        iRxOpCode = opcode;
    }

    iRxMasked = (length & 0x80);
    length &= 0x7f;

    // read the RX size
    if (length < 126)
    {
        iRxSize = length;
    }
    else if (length == 126)
    {
        iRxSize = (HttpClient::read() 

Web Proxy Viewer  |  New URL  |  Original Page