1

I'm trying to create a WebSocket protocol myself in C# to understand how the thing works.

I made both server and client.

I'm able to handshake, send and receive messages (both client and server work well) but I have an issue sending a masked message to the client.

Here is my code to create a frame to send using the NetworkStream.Write:

private byte[] EncodeOutgoingMessage(string text, bool masked = false)
{
    /* this is how and header should be made:
     *   - first byte  -> FIN + RSV1 + RSV2 + RSV3 + OPCODE
     *   - second byte -> MASK + payload length (only 7 bits)
     *   - third, fourth, fifth and sixth bytes -> (optional) XOR encoding key bytes
     *   - following bytes -> the encoded (if a key has been used) payload
     *
     *   FIN    [1 bit]      -> 1 if the whole message is contained in this frame, 0 otherwise
     *   RSVs   [1 bit each] -> MUST be 0 unless an extension is negotiated that defines meanings for non-zero values
     *   OPCODE [4 bits]     -> defines the interpretation of the carried payload
     *
     *   MASK           [1 bit]  -> 1 if the message is XOR masked with a key, 0 otherwise
     *   payload length [7 bits] -> can be max 1111111 (127 dec), so, the payload cannot be more than 127 bytes per frame
     *
     * valid OPCODES:
     *   - 0000 [0]             -> continuation frame
     *   - 0001 [1]             -> text frame
     *   - 0010 [2]             -> binary frame
     *   - 0011 [3] to 0111 [7] -> reserved for further non-control frames
     *   - 1000 [8]             -> connection close
     *   - 1001 [9]             -> ping
     *   - 1010 [A]             -> pong
     *   - 1011 [B] to 1111 [F] -> reserved for further control frames
     */
    // in our case the first byte will be 10000001 (129 dec = 81 hex).
    // the length is going to be (masked)1 << 7 (OR) 0 + payload length.
    byte[] header = new byte[] { 0x81, (byte)((masked ? 0x1 << 7 : 0x0) + text.Length) };
    // by default the mask array is empty...
    byte[] maskKey = new byte[4];
    if(masked)
    {
        // but if needed, let's create it properly.
        Random rd = new Random();
        rd.NextBytes(maskKey);
    }
    // let's get the bytes of the message to send.
    byte[] payload = Encoding.UTF8.GetBytes(text);
    // this is going to be the whole frame to send.
    byte[] frame = new byte[header.Length + (masked ? maskKey.Length : 0) + payload.Length];
    // add the header.
    Array.Copy(header, frame, header.Length);
    // add the mask if necessary.
    if(maskKey.Length > 0)
    {
        Array.Copy(maskKey, 0, frame, header.Length, maskKey.Length);
        // let's encode the payload using the mask.
        for(int i = 0; i < payload.Length; i++)
        {
            payload[i] = (byte)(payload[i] ^ maskKey[i % maskKey.Length]);
        }
    }
    // add the payload.
    Array.Copy(payload, 0, frame, header.Length + (masked ? maskKey.Length : 0), payload.Length);
    return frame;
}

So... using

byte[] answer = EncodeOutgoingMessage("Ciao !!  :)");
stream.Write(answer, 0, answer.Length);

works great, but

byte[] answer = EncodeOutgoingMessage("Ciao !!  :)", true);
stream.Write(answer, 0, answer.Length);

will result in an incorrect string received by the client.

Can, please, someone spot what I'm doing wrong?

4
  • A frame from the server shouldn't be masked. Commented Jul 10, 2017 at 18:15
  • thanks for the answer. is this a protocol requirement or a good practice? I mean, it sounds really strange to me that the client messages are required to be sent masked whilst the server shouldn't send masked messages. Commented Jul 13, 2017 at 9:49
  • 2
    "A server MUST NOT mask any frames that it sends to the client." from tools.ietf.org/html/rfc6455#section-5.1 Commented Jul 13, 2017 at 10:43
  • whoooops... missed that section when I read the document :-P thanks again !! Commented Jul 13, 2017 at 15:02

1 Answer 1

0

I am not 100% sure but I found this: Writing WebSocket servers

When sending a frame back to the client, do not mask it and do not set the mask bit.

Maybe it helps...

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.