Пример #1
0
        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
            }
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }