Iceman
Iceman

Reputation: 397

How to encode binary data over 65536 bytes to websocket frame on c++

My server holds jpeg-file in std::string buffer (ANSI). I need to send it to web-client on request. I tried next:

std::string ws_encode(std::string frame) {
    string result;
    result.resize(2);
    result[0]= 130;
    if (frame.size() <= 125) {result[1]=frame.size();}
    else if (frame.size() >= 126 && frame.size() <= 65535) {
        result.resize(4);
        result[1] = 126;
        result[2] = ( frame.size() >> 8 ) && 255;
        result[3] = ( frame.size() ) && 255;
    }
    else {
        result.resize(10);
        result[1] = 127;
        result[2] = ( frame.size() >> 56 ) && 255;
        result[3] = ( frame.size() >> 48 ) && 255;
        result[4] = ( frame.size() >> 40 ) && 255;
        result[5] = ( frame.size() >> 32 ) && 255;
        result[6] = ( frame.size() >> 24 ) && 255;
        result[7] = ( frame.size() >> 16 ) && 255;
        result[8] = ( frame.size() >>  8 ) && 255;
        result[9] = ( frame.size() ) && 255;
    }
    return result+frame;
}

And then:

string encoded_frame = ws_encode(Agents["65535"].Screen); // it's a map <string id, struct Agent>, Agent has string Screen buffer for screenshots
send(client_socket, &encoded_frame[0], encoded_frame.size(), 0);

But the browser closes the connection without any explanations in console. Maybe length calculation is wrong, or not all data was sent... I don't know - writing test.txt with encoded data before send looks correct.

Could anybody help me in this task?

Upvotes: 1

Views: 939

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596156

When setting up the bytes of the payload length value, you are using the LOGICAL AND (&&) operator when you should be using the BITWISE AND (&) operator instead.

Try something more like this instead:

std::string ws_encode(char opcode, const std::string &data)
{
    string result;
    std::string::size_type size = data.size();

    if (size <= 125)
    {
        result.resize(2+size);
        result[0] = 0x80 | opcode;
        result[1] = (char) size;
    }
    else if (size <= 65535)
    {
        result.resize(4+size);
        result[0] = 0x80 | opcode;
        result[1] = 126;
        result[2] = (size >> 8) & 0xFF;
        result[3] = (size     ) & 0xFF;
    }
    else
    {
        result.resize(10+size);
        result[0] = 0x80 | opcode;
        result[1] = 127;
        result[2] = (size >> 56) & 0xFF;
        result[3] = (size >> 48) & 0xFF;
        result[4] = (size >> 40) & 0xFF;
        result[5] = (size >> 32) & 0xFF;
        result[6] = (size >> 24) & 0xFF;
        result[7] = (size >> 16) & 0xFF;
        result[8] = (size >>  8) & 0xFF;
        result[9] = (size      ) & 0xFF;
    }

    if (size > 0)
    {
        memcpy(&result[result.size()-size], data.c_str(), size);
        // or:
        // std::copy(data.begin(), data.end(), result.begin()+(result.size()-size));
    }

    return result;
}

std::string encoded_frame = ws_encode(0x02, Agents["65535"].Screen);
send(client_socket, encoded_frame.c_str(), encoded_frame.size(), 0);

Upvotes: 1

Related Questions