private async void doRead() { while (_ct != null && !_ct.IsCancellationRequested) { try { byte[] b1 = await ReadExact(2); //options & len (2) byte[] b2 = null; //extended length byte[] b3 = null; //mask-key (4) byte[] b4 = null; //payload (x+y) if (b1 == null || b1.Length == 0) { End(); //tcp connection closed continue; } ulong len = 0; var fs = _fragStream != null; //fragment started var ft = b1[0] & 0xF0; //frame type var rsv = (b1[0] & 0x70) > 0; //reserve bits are set var op = b1[0] & 0x0F; //opcode var pl = b1[1] & 0x7F; //payload length var msk = (b1[1] & 0x80) == 0x80; //masking key set var cf = (op & 0x08) == 0x08; //control frame if (pl == 126 || pl == 127) { b2 = await ReadExact((ulong)(pl == 126 ? 2 : 8)); b2 = b2.Reverse().ToArray(); len = pl == 126 ? BitConverter.ToUInt16(b2, 0) : BitConverter.ToUInt64(b2, 0); } else { len = (ulong)pl; } if (msk) { b3 = await ReadExact(4); } b4 = await ReadExact(len); var wsf = new WebSocketFrame(); wsf.ParsePayload((WebSocketFlags)ft, (WebSocketOpCode)op, msk, len, b3, b4); //Console.WriteLine(string.Format("Got Frame {0} {1} {2} {3}", wsf.Flags.ToString(), wsf.OpCode.ToString(), wsf.PayloadLength, _sentClose)); if (!_sentClose) { if (cf) { if (wsf.OpCode == WebSocketOpCode.ConnectionClose) //client is closing the connection { if (rsv) { await Close(WebsocketCloseCode.ProtocolError, "RSV set and no extension negotiated"); End(); } else if (wsf.PayloadLength == 0) { await Close(); End(); } else if (wsf.PayloadLength == 1) { await Close(WebsocketCloseCode.ProtocolError, "Close frame code invalid"); End(); } else if (wsf.PayloadLength > 125) { await Close(WebsocketCloseCode.ProtocolError, "Close frame too long"); End(); } else { var cc = BitConverter.ToUInt16(new byte[] { wsf.Payload[1], wsf.Payload[0] }, 0); var cm = wsf.PayloadLength > 2 ? Encoding.UTF8.GetString(wsf.Payload, 2, (int)wsf.PayloadLength - 2) : null; if (cc >= 0 && cc <= 999) { await Close(WebsocketCloseCode.ProtocolError, "Close code invalid"); } else { await Close(); } End((WebsocketCloseCode)cc, cm); } } else if (wsf.PayloadLength > 125) { await Close(WebsocketCloseCode.ProtocolError, "Control frame with payload length > 125 octets"); } else if (op >= 0xB && op <= 0xF) { await Close(WebsocketCloseCode.ProtocolError, "Control frame using reserved opcode"); } else if (!wsf.Flags.HasFlag(WebSocketFlags.FinalFragment)) { await Close(WebsocketCloseCode.ProtocolError, "Fragmented control frame"); } else if (wsf.OpCode == WebSocketOpCode.Ping) { await Pong(wsf); } } else { if (rsv && Extensions.Count() == 0) { await Close(WebsocketCloseCode.ProtocolError, "RSV set and no extension negotiated"); } else if (op >= 3 && op <= 7) { await Close(WebsocketCloseCode.ProtocolError, "Data frame using reserved opcode"); } else { if (!fs && !wsf.Flags.HasFlag(WebSocketFlags.FinalFragment)) { if (wsf.OpCode == WebSocketOpCode.BinaryFrame || wsf.OpCode == WebSocketOpCode.TextFrame) { _fragStream = new MemoryStream(); _fragMessageType = wsf.OpCode; await _fragStream.WriteAsync(wsf.Payload, 0, (int)wsf.PayloadLength); } else { await Close(WebsocketCloseCode.ProtocolError, "Cant start fragmented message on continuation frame"); } } else if (fs && !wsf.Flags.HasFlag(WebSocketFlags.FinalFragment)) { if (wsf.OpCode == WebSocketOpCode.ContinuationFrame) { await _fragStream.WriteAsync(wsf.Payload, 0, (int)wsf.PayloadLength); } else { await Close(WebsocketCloseCode.ProtocolError, "Received non-continuation data frame while inside fragmented message"); } } else if (fs && wsf.Flags.HasFlag(WebSocketFlags.FinalFragment)) { if (wsf.OpCode == WebSocketOpCode.ContinuationFrame) { await _fragStream.WriteAsync(wsf.Payload, 0, (int)wsf.PayloadLength); wsf.Payload = _fragStream.ToArray(); wsf.PayloadLength = (ulong)_fragStream.Length; wsf.OpCode = _fragMessageType; await ProcessFrame(new FrameEventArgs() { Frame = wsf, WebSocket = this }); } else { await Close(WebsocketCloseCode.ProtocolError, "Received non-continuation data frame while inside fragmented message"); } _fragStream.Dispose(); _fragStream = null; } else if (!fs && wsf.OpCode == WebSocketOpCode.ContinuationFrame) { await Close(WebsocketCloseCode.ProtocolError, "Received continuation data frame outside fragmented message"); } else { await ProcessFrame(new FrameEventArgs() { Frame = wsf, WebSocket = this }); } } } } else if (cf && wsf.OpCode == WebSocketOpCode.ConnectionClose) { //Close response from client after we sent close code End(); } } catch (Exception ex) { OnError(ex); } } }
public async Task SendDataAsync(string data) { await SendFrame(await WebSocketFrame.PackData(data)); }
public async Task Pong(WebSocketFrame f) { f.OpCode = WebSocketOpCode.Pong; await SendFrame(f); }