private async Task Process() { try { Header frameHeader; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; while (State == WebSocketState.Open || State == WebSocketState.Closing) { int receiveCount = await _stream.ReadAsync( _receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); if (receiveCount == 0) { break; } _keepAliveTracker.OnDataReceived(); SegmentBufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); consumedLength = 0; while (true) { frameHeader = null; payload = null; payloadOffset = 0; payloadCount = 0; if (_frameBuilder.TryDecodeFrameHeader( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameHeader) && frameHeader.Length + frameHeader.PayloadLength <= _receiveBufferOffset - consumedLength) { try { if (!frameHeader.IsMasked) { await Close(WebSocketCloseCode.ProtocolError, "A server MUST close the connection upon receiving a frame that is not masked."); throw new WebSocketException(string.Format( "Server received unmasked frame [{0}] from remote [{1}].", frameHeader.OpCode, RemoteEndPoint)); } _frameBuilder.DecodePayload( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, frameHeader, out payload, out payloadOffset, out payloadCount); switch (frameHeader.OpCode) { case OpCode.Continuation: await HandleContinuationFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Text: await HandleTextFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Binary: await HandleBinaryFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Close: await HandleCloseFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Ping: await HandlePingFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Pong: await HandlePongFrame(frameHeader, payload, payloadOffset, payloadCount); break; default: { // Incoming data MUST always be validated by both clients and servers. // If, at any time, an endpoint is faced with data that it does not // understand or that violates some criteria by which the endpoint // determines safety of input, or when the endpoint sees an opening // handshake that does not correspond to the values it is expecting // (e.g., incorrect path or origin in the client request), the endpoint // MAY drop the TCP connection. If the invalid data was received after // a successful WebSocket handshake, the endpoint SHOULD send a Close // frame with an appropriate status code (Section 7.4) before proceeding // to _Close the WebSocket Connection_. Use of a Close frame with an // appropriate status code can help in diagnosing the problem. If the // invalid data is sent during the WebSocket handshake, the server // SHOULD return an appropriate HTTP [RFC2616] status code. await Close(WebSocketCloseCode.InvalidMessageType); throw new NotSupportedException( string.Format("Not support received opcode [{0}].", (byte)frameHeader.OpCode)); } } } catch (Exception ex) { _log.Error(string.Format("Session [{0}] exception occurred, [{1}].", this, ex.Message), ex); throw; } finally { consumedLength += frameHeader.Length + frameHeader.PayloadLength; } } else { break; } } if (_receiveBuffer != null && _receiveBuffer.Array != null) { SegmentBufferDeflector.ShiftBuffer(_bufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } } } catch (ObjectDisposedException) { // looking forward to a graceful quit from the ReadAsync but the inside EndRead will raise the ObjectDisposedException, // so a gracefully close for the socket should be a Shutdown, but we cannot avoid the Close triggers this happen. } catch (Exception ex) { await HandleReceiveOperationException(ex); } finally { await InternalClose(true); // read async buffer returned, remote notifies closed } }
private void ReceiveBuffer(int receiveCount) { _keepAliveTracker.OnDataReceived(); SegmentBufferDeflector.ReplaceBuffer(_configuration.BufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); Header frameHeader; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; while (true) { if (_frameBuilder.TryDecodeFrameHeader( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameHeader) && frameHeader.Length + frameHeader.PayloadLength <= _receiveBufferOffset - consumedLength) { try { if (frameHeader.IsMasked) { Close(WebSocketCloseCode.ProtocolError, "A client MUST close a connection if it detects a masked frame."); throw new WebSocketException(string.Format( "Client received masked frame [{0}] from remote [{1}].", frameHeader.OpCode, RemoteEndPoint)); } _frameBuilder.DecodePayload( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, frameHeader, out payload, out payloadOffset, out payloadCount); switch (frameHeader.OpCode) { case OpCode.Continuation: HandleContinuationFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Text: HandleTextFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Binary: HandleBinaryFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Close: HandleCloseFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Ping: HandlePingFrame(frameHeader, payload, payloadOffset, payloadCount); break; case OpCode.Pong: HandlePongFrame(frameHeader, payload, payloadOffset, payloadCount); break; default: { // Incoming data MUST always be validated by both clients and servers. // If, at any time, an endpoint is faced with data that it does not // understand or that violates some criteria by which the endpoint // determines safety of input, or when the endpoint sees an opening // handshake that does not correspond to the values it is expecting // (e.g., incorrect path or origin in the client request), the endpoint // MAY drop the TCP connection. If the invalid data was received after // a successful WebSocket handshake, the endpoint SHOULD send a Close // frame with an appropriate status code (Section 7.4) before proceeding // to _Close the WebSocket Connection_. Use of a Close frame with an // appropriate status code can help in diagnosing the problem. If the // invalid data is sent during the WebSocket handshake, the server // SHOULD return an appropriate HTTP [RFC2616] status code. Close(WebSocketCloseCode.InvalidMessageType); throw new NotSupportedException( string.Format("Not support received opcode [{0}].", (byte)frameHeader.OpCode)); } } } catch (Exception ex) { _log(ex.Message); throw; } finally { consumedLength += frameHeader.Length + frameHeader.PayloadLength; } } else { break; } } if (_receiveBuffer != null && _receiveBuffer.Array != null) { SegmentBufferDeflector.ShiftBuffer(_configuration.BufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } }
private async Task <bool> OpenHandshake() { bool handshakeResult = false; try { int terminatorIndex = -1; while (!WebSocketHelpers.FindHttpMessageTerminator(_receiveBuffer.Array, _receiveBuffer.Offset, _receiveBufferOffset, out terminatorIndex)) { int receiveCount = await _stream.ReadAsync( _receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); if (receiveCount == 0) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive zero bytes.", RemoteEndPoint)); } SegmentBufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); if (_receiveBufferOffset > 2048) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive weird stream.", RemoteEndPoint)); } } string secWebSocketKey = string.Empty; string path = string.Empty; string query = string.Empty; handshakeResult = WebSocketServerHandshaker.HandleOpenningHandshakeRequest( this, _receiveBuffer.Array, _receiveBuffer.Offset, terminatorIndex + Consts.HttpMessageTerminator.Length, out secWebSocketKey, out path, out query); _module = _routeResolver.Resolve(path, query); if (_module == null) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to cannot identify the resource name [{1}{2}].", RemoteEndPoint, path, query)); } if (handshakeResult) { var responseBuffer = WebSocketServerHandshaker.CreateOpenningHandshakeResponse(this, secWebSocketKey); await _stream.WriteAsync(responseBuffer, 0, responseBuffer.Length); } SegmentBufferDeflector.ShiftBuffer( _bufferManager, terminatorIndex + Consts.HttpMessageTerminator.Length, ref _receiveBuffer, ref _receiveBufferOffset); } catch (WebSocketHandshakeException ex) { _log.Error(string.Format("Session [{0}] exception occurred, [{1}].", this, ex.Message), ex); handshakeResult = false; } catch (Exception) { handshakeResult = false; throw; } return(handshakeResult); }
private bool OpenHandshake() { bool handshakeResult = false; try { var requestBuffer = WebSocketClientHandshaker.CreateOpenningHandshakeRequest(this, out _secWebSocketKey); var ar = _stream.BeginWrite(requestBuffer, 0, requestBuffer.Length, null, _stream); if (!ar.AsyncWaitHandle.WaitOne(ConnectTimeout)) { Close(WebSocketCloseCode.ProtocolError, "Opening handshake timeout."); throw new TimeoutException(string.Format( "Handshake with remote [{0}] timeout [{1}].", RemoteEndPoint, ConnectTimeout)); } _stream.EndWrite(ar); int terminatorIndex = -1; while (!WebSocketHelpers.FindHttpMessageTerminator(_receiveBuffer.Array, _receiveBuffer.Offset, _receiveBufferOffset, out terminatorIndex)) { ar = _stream.BeginRead( _receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset, null, _stream); if (!ar.AsyncWaitHandle.WaitOne(ConnectTimeout)) { Close(WebSocketCloseCode.ProtocolError, "Opening handshake timeout."); throw new TimeoutException(string.Format( "Handshake with remote [{0}] timeout [{1}].", RemoteEndPoint, ConnectTimeout)); } int receiveCount = _stream.EndRead(ar); if (receiveCount == 0) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive zero bytes.", RemoteEndPoint)); } SegmentBufferDeflector.ReplaceBuffer(_configuration.BufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); if (_receiveBufferOffset > 2048) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive weird stream.", RemoteEndPoint)); } } handshakeResult = WebSocketClientHandshaker.VerifyOpenningHandshakeResponse( this, _receiveBuffer.Array, _receiveBuffer.Offset, terminatorIndex + Consts.HttpMessageTerminator.Length, _secWebSocketKey); SegmentBufferDeflector.ShiftBuffer( _configuration.BufferManager, terminatorIndex + Consts.HttpMessageTerminator.Length, ref _receiveBuffer, ref _receiveBufferOffset); } catch (WebSocketHandshakeException ex) { _log(ex.Message); handshakeResult = false; } catch (Exception) { handshakeResult = false; throw; } return(handshakeResult); }