private void ParseHeader(Int32 readed)
        {
            if (!TryReadHeaderUntil(ref readed, 6))
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            Int32 headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset);

            if (!TryReadHeaderUntil(ref readed, headerlength))
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            WebSocketFrameHeader header;

            if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out header))
            {
                throw new WebSocketException("Cannot understand frame header");
            }

            CurrentHeader = header;

            if (!header.Flags.Option.IsData())
            {
                ProcessControlFrame(_clientStream);
                CurrentHeader = null;
            }
            else
            {
                _ongoingMessageAwaiting = 0;
            }
        }
Exemple #2
0
        public ArraySegment <byte> PrepareFrame(ArraySegment <byte> payload, int length, bool isCompleted, bool headerSent, WebSocketMessageType type, WebSocketExtensionFlags extensionFlags)
        {
            var mask = 0U;

            if (this.maskData)
            {
                mask = unchecked ((uint)ThreadStaticRandom.NextNotZero());
            }

            var header = WebSocketFrameHeader.Create(length, isCompleted, headerSent, mask, (WebSocketFrameOption)type, extensionFlags);

            if (header.WriteTo(payload.Array, payload.Offset - header.HeaderLength) != header.HeaderLength)
            {
                throw new WebSocketException("Wrong frame header written.");
            }

            if (this.log.IsDebugEnabled)
            {
                this.log.Debug($"({this.GetHashCode():X}) [FRAME->] {header}");
            }

            header.EncodeBytes(payload.Array, payload.Offset, length);

            return(new ArraySegment <byte>(payload.Array, payload.Offset - header.HeaderLength, length + header.HeaderLength));
        }
        internal async Task WriteInternalAsync(ArraySegment <byte> buffer, int count, bool isCompleted, bool headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags, CancellationToken cancel)
        {
            try
            {
                var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags);
                header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength);

                if (!await _writeSemaphore.WaitAsync(_options.WebSocketSendTimeout, cancel).ConfigureAwait(false))
                {
                    throw new WebSocketException("Write timeout");
                }
                await _clientStream.WriteAsync(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength, cancel).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                Close(WebSocketCloseReasons.GoingAway);
            }
            catch (InvalidOperationException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (IOException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (Exception ex)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
                throw new WebSocketException("Cannot write on WebSocket", ex);
            }
            finally
            {
                SafeEnd.ReleaseSemaphore(_writeSemaphore);
            }
        }
Exemple #4
0
        private async Task WriteInternalAsync(ArraySegment <Byte> buffer, Int32 count, Boolean isCompleted, Boolean headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags, CancellationToken cancellation)
        {
            CancellationTokenRegistration reg = cancellation.Register(this.Close, false);

            try
            {
                var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags);
                header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength);

                if (!_writeSemaphore.Wait(_options.WebSocketSendTimeout))
                {
                    throw new WebSocketException("Write timeout");
                }
                await _clientStream.WriteAsync(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength, cancellation).ConfigureAwait(false);
            }
            catch (InvalidOperationException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (IOException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (Exception ex)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
                throw new WebSocketException("Cannot write on WebSocket", ex);
            }
            finally
            {
                reg.Dispose();
                _writeSemaphore.Release();
            }
        }
        internal void WriteInternal(ArraySegment <Byte> buffer, Int32 count, Boolean isCompleted, Boolean headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags)
        {
            try
            {
                var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags);
                header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength);

                if (!_writeSemaphore.Wait(_options.WebSocketSendTimeout))
                {
                    throw new WebSocketException("Write timeout");
                }
                _clientStream.Write(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength);
            }
            catch (InvalidOperationException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (IOException)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
            }
            catch (Exception ex)
            {
                Close(WebSocketCloseReasons.UnexpectedCondition);
                throw new WebSocketException("Cannot write on WebSocket", ex);
            }
            finally
            {
                if (_isClosed == 0)
                {
                    SafeEnd.ReleaseSemaphore(_writeSemaphore);
                }
            }
        }
Exemple #6
0
        public void DisposeCurrentHeaderIfFinished()
        {
            if (this.CurrentHeader != null && this.CurrentHeader.RemainingBytes < 0)
            {
                throw new InvalidOperationException("Extra bytes are read from transport connection. Report to package developer about it.");
            }

            if (this.CurrentHeader != null && this.CurrentHeader.RemainingBytes == 0)
            {
                this.CurrentHeader = null;
            }
        }
        private int GetBytesToRead(WebSocketFrameHeader header, int bufferSize)
        {
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            }

            if (header == null)
            {
                return(0);
            }

            return((int)Math.Min(bufferSize, header.RemainingBytes));
        }
        private void ParseHeader(int readed)
        {
            if (!TryReadHeaderUntil(ref readed, 6))
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            var headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset);

            if (!TryReadHeaderUntil(ref readed, headerlength))
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            ProcessHeaderFrame(headerlength);
        }
        private async Task ParseHeaderAsync(int readed)
        {
            if (await TryReadHeaderUntilAsync(readed, 6).ConfigureAwait(false) == -1)
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            var headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset);

            if (await TryReadHeaderUntilAsync(readed, headerlength).ConfigureAwait(false) == -1)
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            await ProcessHeaderFrameAsync(headerlength).ConfigureAwait(false);
        }
Exemple #10
0
        private async Task ReadHeader(CancellationToken cancellation)
        {
            Int32 readed  = 0;
            var   success = await TryReadHeaderUntil(readed, 6, cancellation).ConfigureAwait(false);

            if (!success)
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            readed += 6;
            Int32 headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset);

            success = await TryReadHeaderUntil(readed, headerlength, cancellation).ConfigureAwait(false);

            if (!success)
            {
                Close(WebSocketCloseReasons.ProtocolError);
                return;
            }

            WebSocketFrameHeader header;

            if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out header))
            {
                throw new WebSocketException("Cannot understand frame header");
            }

            CurrentHeader = header;

            if (!header.Flags.Option.IsData())
            {
                ProcessControlFrame(_clientStream);
                CurrentHeader = null;
            }
            else
            {
                _ongoingMessageAwaiting = 0;
            }

            _ping.NotifyActivity();
        }
        private void ProcessHeaderFrame(int headerlength)
        {
            if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out WebSocketFrameHeader header))
            {
                throw new WebSocketException("Cannot understand frame header");
            }

            CurrentHeader = header;

            if (!header.Flags.Option.IsData())
            {
                ProcessControlFrame();
                CurrentHeader = null;
            }
            else
            {
                _ongoingMessageAwaiting = 0;
            }

            _ping.NotifyActivity();
        }
Exemple #12
0
        private async Task ParseHeaderAsync(int read)
        {
            if (read < 2)
            {
                if (this.log.IsWarningEnabled)
                {
                    this.log.Warning($"{nameof(this.ParseHeaderAsync)} is called with only {read} bytes buffer. Minimal is 2 bytes.");
                }

                await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false);

                return;
            }

            var headerLength = WebSocketFrameHeader.GetHeaderLength(this.headerBuffer.Array, this.headerBuffer.Offset);

            if (read != headerLength)
            {
                if (this.log.IsWarningEnabled)
                {
                    this.log.Warning($"{nameof(this.ParseHeaderAsync)} is called with {read} bytes buffer. While whole header is {headerLength} bytes length.");
                }

                await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false);

                return;
            }

            WebSocketFrameHeader header;

            if (!WebSocketFrameHeader.TryParse(this.headerBuffer.Array, this.headerBuffer.Offset, headerLength, out header))
            {
                throw new WebSocketException("Frame header is malformed.");
            }

            if (this.log.IsDebugEnabled)
            {
                this.log.Debug($"({this.GetHashCode():X}) [FRAME<-] {header}");
            }

            this.CurrentHeader = header;

            if (!header.Flags.Option.IsData())
            {
                await this.ProcessControlFrameAsync().ConfigureAwait(false);

                this.CurrentHeader = null;
            }
            else
            {
                this.ongoingMessageAwaiting = 0;
            }

            try
            {
                this.pingHandler.NotifyActivity();
            }
            catch (Exception notifyPingError)
            {
                if (this.log.IsWarningEnabled)
                {
                    this.log.Warning($"({this.GetHashCode():X}) An error occurred while trying to call {this.pingHandler.GetType().Name}.{nameof(this.pingHandler.NotifyActivity)}() method.", notifyPingError);
                }
            }
        }
Exemple #13
0
        public static bool TryParse(byte[] frameStart, int offset, int headerLength, out WebSocketFrameHeader header)
        {
            if (frameStart == null)
            {
                throw new ArgumentNullException(nameof(frameStart));
            }

            header = null;

            var availableLength = frameStart.Length - offset;

            if (availableLength < 6 || availableLength < headerLength)
            {
                return(false);
            }

            var value         = frameStart[offset + 1];
            var contentLength = (long)(value >= 128 ? value - 128 : value);

            if (contentLength <= 125)
            {
                // small frame
            }
            else if (contentLength == 126)
            {
                if (availableLength < headerLength)
                {
                    return(false);
                }

                contentLength = EndianBitConverter.ToUInt16Be(frameStart, offset + 2);
            }
            else if (contentLength == 127)
            {
                if (availableLength < headerLength)
                {
                    return(false);
                }

                var length = EndianBitConverter.ToUInt64Be(frameStart, offset + 2);
                if (length > long.MaxValue)
                {
                    throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString());
                }

                contentLength = (long)length;
            }
            else
            {
                return(false);
            }

            WebSocketFrameHeaderFlags flags;

            if (!WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags))
            {
                return(false);
            }

            var maskKey = 0U;

            if (flags.MASK)
            {
                headerLength -= 4;
                maskKey       = EndianBitConverter.ToUInt32Le(frameStart, offset + headerLength);
            }

            header = new WebSocketFrameHeader
            {
                ContentLength  = contentLength,
                HeaderLength   = headerLength,
                Flags          = flags,
                RemainingBytes = contentLength,
                MaskKey        = maskKey
            };

            return(true);
        }
        public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment<Byte> keySegment, out WebSocketFrameHeader header)
        {
            header = null;

            if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength))
                return false;

            Int32 value = frameStart[offset+1];
            UInt64 contentLength = (UInt64)(value>=128?value - 128:value);

            if (contentLength <= 125)
            {
                // small frame
            }
            else if (contentLength == 126)
            {
                if (frameStart.Length < headerLength)
                    return false;

                if(BitConverter.IsLittleEndian)
                    frameStart.ReversePortion(offset + 2, 2);
                contentLength = BitConverter.ToUInt16(frameStart, 2);
            }
            else if (contentLength == 127)
            {
                if (frameStart.Length < headerLength)
                    return false;

                if (BitConverter.IsLittleEndian)
                    frameStart.ReversePortion(offset + 2, 8);
                contentLength = (UInt64)BitConverter.ToUInt64(frameStart, 2);
            }
            else
                return false;

            WebSocketFrameHeaderFlags flags;
            if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags))
            {
                header = new WebSocketFrameHeader(keySegment)
                {
                    ContentLength = contentLength,
                    HeaderLength = headerLength,
                    Flags = flags,
                    RemainingBytes = contentLength
                };

                if (flags.MASK)
                {
                    headerLength -= 4;
                    for (int i = 0; i < 4; i++)
                        header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength];
                }

                return true;
            }

            return false;
        }
        public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment <Byte> keySegment, out WebSocketFrameHeader header)
        {
            header = null;

            if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength))
            {
                return(false);
            }

            Int32  value         = frameStart[offset + 1];
            UInt64 contentLength = (UInt64)(value >= 128?value - 128:value);

            if (contentLength <= 125)
            {
                // small frame
            }
            else if (contentLength == 126)
            {
                if (frameStart.Length < headerLength)
                {
                    return(false);
                }

                if (BitConverter.IsLittleEndian)
                {
                    frameStart.ReversePortion(offset + 2, 2);
                }
                contentLength = BitConverter.ToUInt16(frameStart, 2);
            }
            else if (contentLength == 127)
            {
                if (frameStart.Length < headerLength)
                {
                    return(false);
                }

                if (BitConverter.IsLittleEndian)
                {
                    frameStart.ReversePortion(offset + 2, 8);
                }
                contentLength = (UInt64)BitConverter.ToUInt64(frameStart, 2);
            }
            else
            {
                return(false);
            }

            WebSocketFrameHeaderFlags flags;

            if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags))
            {
                header = new WebSocketFrameHeader(keySegment)
                {
                    ContentLength  = contentLength,
                    HeaderLength   = headerLength,
                    Flags          = flags,
                    RemainingBytes = contentLength
                };

                if (flags.MASK)
                {
                    headerLength -= 4;
                    for (int i = 0; i < 4; i++)
                    {
                        header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength];
                    }
                }

                return(true);
            }

            return(false);
        }
Exemple #16
0
        public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment <Byte> keySegment, out WebSocketFrameHeader header)
        {
            header = null;

            if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength))
            {
                return(false);
            }

            Int32 value         = frameStart[offset + 1];
            Int64 contentLength = (Int64)(value >= 128?value - 128:value);

            if (contentLength <= 125)
            {
                // small frame
            }
            else if (contentLength == 126)
            {
                if (frameStart.Length < headerLength)
                {
                    return(false);
                }

                if (BitConverter.IsLittleEndian)
                {
                    frameStart.ReversePortion(offset + 2, 2);
                }
                contentLength = BitConverter.ToUInt16(frameStart, 2);
            }
            else if (contentLength == 127)
            {
                if (frameStart.Length < headerLength)
                {
                    return(false);
                }

                if (BitConverter.IsLittleEndian)
                {
                    frameStart.ReversePortion(offset + 2, 8);
                }

                UInt64 length = BitConverter.ToUInt64(frameStart, 2);
                if (length > Int64.MaxValue)
                {
                    throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString());
                }

                contentLength = (Int64)length;
            }
            else
            {
                return(false);
            }

            WebSocketFrameHeaderFlags flags;

            if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags))
            {
                header = new WebSocketFrameHeader(keySegment)
                {
                    ContentLength  = contentLength,
                    HeaderLength   = headerLength,
                    Flags          = flags,
                    RemainingBytes = contentLength
                };

                if (flags.MASK)
                {
                    headerLength -= 4;
                    for (int i = 0; i < 4; i++)
                    {
                        header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength];
                    }
                }

                return(true);
            }

            return(false);
        }
        public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment<Byte> keySegment, out WebSocketFrameHeader header)
        {
            header = null;

            if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength))
                return false;

            Int32 value = frameStart[offset+1];
            Int64 contentLength = (Int64)(value>=128?value - 128:value);

            if (contentLength <= 125)
            {
                // small frame
            }
            else if (contentLength == 126)
            {
                if (frameStart.Length < headerLength)
                    return false;

                if(BitConverter.IsLittleEndian)
                    frameStart.ReversePortion(offset + 2, 2);
                contentLength = BitConverter.ToUInt16(frameStart, 2);
            }
            else if (contentLength == 127)
            {
                if (frameStart.Length < headerLength)
                    return false;

                if (BitConverter.IsLittleEndian)
                    frameStart.ReversePortion(offset + 2, 8);

                UInt64 length = BitConverter.ToUInt64(frameStart, 2);
                if(length > Int64.MaxValue)
                {
                    throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString());
                }

                contentLength = (Int64)length;
            }
            else
                return false;

            WebSocketFrameHeaderFlags flags;
            if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags))
            {
                header = new WebSocketFrameHeader(keySegment)
                {
                    ContentLength = contentLength,
                    HeaderLength = headerLength,
                    Flags = flags,
                    RemainingBytes = contentLength
                };

                if (flags.MASK)
                {
                    headerLength -= 4;
                    for (int i = 0; i < 4; i++)
                        header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength];
                }

                return true;
            }

            return false; 
        }
Exemple #18
0
        public async Task AwaitHeaderAsync(CancellationToken cancellation)
        {
            this.CheckForDoubleRead();
            try
            {
                while (this.IsConnected && this.CurrentHeader == null)
                {
                    var buffered = 0;
                    var estimatedHeaderLength = 2;
                    // try read minimal frame first
                    while (buffered < estimatedHeaderLength && !cancellation.IsCancellationRequested)
                    {
                        var read = await this.networkConnection.ReadAsync(this.headerBuffer.Array, this.headerBuffer.Offset + buffered, estimatedHeaderLength - buffered, cancellation).ConfigureAwait(false);

                        if (read == 0)
                        {
                            buffered = 0;
                            break;
                        }

                        buffered += read;
                        if (buffered >= 2)
                        {
                            estimatedHeaderLength = WebSocketFrameHeader.GetHeaderLength(this.headerBuffer.Array, this.headerBuffer.Offset);
                        }
                    }

                    if (buffered == 0 || cancellation.IsCancellationRequested)
                    {
                        if (buffered == 0)
                        {
                            if (this.log.IsDebugEnabled)
                            {
                                this.log.Debug($"({this.GetHashCode():X}) Connection has been closed while async awaiting header.");
                            }
                        }
                        await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false);

                        return;
                    }

                    await this.ParseHeaderAsync(buffered).ConfigureAwait(false);
                }
            }
            catch (Exception awaitHeaderError) when(awaitHeaderError.Unwrap() is ThreadAbortException == false)
            {
                if (!this.IsConnected)
                {
                    return;
                }

                var awaitHeaderErrorUnwrap = awaitHeaderError.Unwrap();

                if (this.log.IsDebugEnabled && awaitHeaderErrorUnwrap is OperationCanceledException == false && this.IsConnected)
                {
                    this.log.Debug($"({this.GetHashCode():X}) An error occurred while async awaiting header.", awaitHeaderErrorUnwrap);
                }

                if (this.IsConnected)
                {
                    await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false);
                }

                if (awaitHeaderErrorUnwrap is WebSocketException == false && awaitHeaderErrorUnwrap is OperationCanceledException == false)
                {
                    throw new WebSocketException("Read operation on WebSocket stream is failed. More detailed information in inner exception.", awaitHeaderErrorUnwrap);
                }
                else
                {
                    throw;
                }
            }
        }