public GuildedSocketMessage( [JsonProperty(Required = Required.Always)] SocketOpcode op, [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string?t = null, [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] JObject?d = null, [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string?s = null ) => (Opcode, EventName, RawData, MessageId) = (op, t, d, s);
/// <summary> /// Send a WebSocket frame to the client. /// </summary> /// <param name="data">Data to send.</param> /// <param name="opcode">Frame opcode.</param> /// <param name="isFIN">Whether frame has FIN bit set.</param> protected void SendFrame(byte[] data, SocketOpcode opcode = SocketOpcode.TEXT, bool isFIN = true) { byte[] header = new byte[14]; header[0] = (byte)((isFIN ? 0x80 : 0) | (byte)opcode); int idx = 2; if (data.Length < 126) { //not bothering with masking header[1] = (byte)data.Length; } else if (data.Length < 65535) { header[1] = 126; header[2] = (byte)(data.Length >> 8); header[3] = (byte)(data.Length & 0xFF); idx = 4; } else { //data.Length is `int` and apparently C#'s idea of sanity //is for the shift amount to be mod 32, so trying to //include the higher bytes here actually gives you the lower //bytes again, giving an insane length. header[1] = 127; header[2] = 0; //(byte)((data.Length >> 56) & 0xFF); header[3] = 0; //(byte)((data.Length >> 48) & 0xFF); header[4] = 0; //(byte)((data.Length >> 40) & 0xFF); header[5] = 0; //(byte)((data.Length >> 32) & 0xFF); header[6] = (byte)((data.Length >> 24) & 0xFF); header[7] = (byte)((data.Length >> 16) & 0xFF); header[8] = (byte)((data.Length >> 8) & 0xFF); header[9] = (byte)(data.Length & 0xFF); idx = 10; } stream.Write(header, 0, idx); stream.Write(data, 0, data.Length); }
/// <summary> /// Read the WebSocket frame header from the socket. /// </summary> /// <returns>The header.</returns> /// <param name="req">HttpRequest to read from.</param> /// <exception cref="OperationCanceledException">Socket closed while reading.</exception> /// <exception cref="ObjectDisposedException">Socket closed while reading.</exception> private SocketMessageHeader ReadHeader(HttpRequest req, byte[] buffer) { int idx = 0; //Read the header bytes. //XXX deal with messages < 14 bytes (header is variable length) //14 is the maximum possible length while (idx < 14) { int r = req.stream.Read(buffer, idx, 14 - idx); if (r <= 0) { throw new OperationCanceledException(); //closed } idx += r; } //WebServer.Log($"Socket got header {buffer[0]} {buffer[1]}, read {idx} bytes"); int bufLen = idx; //Decode the header. SocketMessageRawHeader header = new SocketMessageRawHeader { flagsAndOpcode = buffer[0], maskAndLength = buffer[1], }; SocketOpcode opcode = (SocketOpcode)(header.flagsAndOpcode & 0x0F); bool isFIN = (header.flagsAndOpcode & 0x80) != 0; bool isMask = (header.maskAndLength & 0x80) != 0; long length = header.maskAndLength & 0x7F; byte[] maskKey = new byte[4]; //Decode the length. if (length == 126) //XXX verify byte order { length = (buffer[2] << 8) | buffer[3]; idx = 4; } else if (length == 127) //XXX verify byte order { length = (buffer[2] << 56) | (buffer[3] << 48) | (buffer[4] << 40) | (buffer[5] << 32) | (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | buffer[9]; idx = 10; } else { idx = 2; } //Log($"Message length: {length}, opcode: {opcode}, mask: {isMask} @{idx}"); //Read the mask key. if (isMask) { maskKey[0] = buffer[idx + 0]; maskKey[1] = buffer[idx + 1]; maskKey[2] = buffer[idx + 2]; maskKey[3] = buffer[idx + 3]; //Log($"Reading mask key from buffer pos {idx}: {maskKey[0]} {maskKey[1]} {maskKey[2]} {maskKey[3]}"); idx += 4; } //else, we don't care what maskKey is, we won't use it. return(new SocketMessageHeader { opcode = opcode, isFIN = isFIN, isMask = isMask, length = length, maskKey = maskKey, headerLength = idx, readLength = bufLen, }); }