public async Task <Frame> ReadFrameAsync(TimeSpan timeout)
        {
            // Prep the timeout cancellation token.
            CancellationTokenSource timeoutCts = new CancellationTokenSource(timeout);

            // First read the frame headers, which should tell us how long the rest of the frame is.
            byte[] headerBytes = new byte[Frame.FrameHeaderLength];

            int totalReadBytes = 0;

            while (totalReadBytes < Frame.FrameHeaderLength)
            {
                int readBytes = await _connectionStream.ReadAsync(headerBytes, totalReadBytes, Frame.FrameHeaderLength - totalReadBytes, timeoutCts.Token).ConfigureAwait(false);

                totalReadBytes += readBytes;
                if (readBytes == 0)
                {
                    throw new Exception("Connection stream closed while attempting to read frame header.");
                }
            }

            Frame header = Frame.ReadFrom(headerBytes);

            // Read the data segment of the frame, if it is present.
            byte[] data = new byte[header.Length];

            totalReadBytes = 0;
            while (totalReadBytes < header.Length)
            {
                int readBytes = await _connectionStream.ReadAsync(data, totalReadBytes, header.Length - totalReadBytes, timeoutCts.Token).ConfigureAwait(false);

                totalReadBytes += readBytes;
                if (readBytes == 0)
                {
                    throw new Exception("Connection stream closed while attempting to read frame body.");
                }
            }

            // Construct the correct frame type and return it.
            switch (header.Type)
            {
            case FrameType.Data:
                return(DataFrame.ReadFrom(header, data));

            case FrameType.Headers:
                return(HeadersFrame.ReadFrom(header, data));

            case FrameType.Priority:
                return(PriorityFrame.ReadFrom(header, data));

            case FrameType.RstStream:
                return(RstStreamFrame.ReadFrom(header, data));

            case FrameType.Ping:
                return(PingFrame.ReadFrom(header, data));

            default:
                return(header);
            }
        }
Example #2
0
        public async Task <Frame> ReadFrameAsync(TimeSpan timeout)
        {
            // Prep the timeout cancellation token.
            CancellationTokenSource timeoutCts = new CancellationTokenSource(timeout);

            // First read the frame headers, which should tell us how long the rest of the frame is.
            byte[] headerBytes = new byte[Frame.FrameHeaderLength];
            if (!await FillBufferAsync(headerBytes, timeoutCts.Token).ConfigureAwait(false))
            {
                return(null);
            }

            Frame header = Frame.ReadFrom(headerBytes);

            // Read the data segment of the frame, if it is present.
            byte[] data = new byte[header.Length];
            if (header.Length > 0 && !await FillBufferAsync(data, timeoutCts.Token).ConfigureAwait(false))
            {
                throw new Exception("Connection stream closed while attempting to read frame body.");
            }

            if (_ignoreSettingsAck && header.Type == FrameType.Settings && header.Flags == FrameFlags.Ack)
            {
                _ignoreSettingsAck = false;
                return(await ReadFrameAsync(timeout));
            }

            if (_ignoreWindowUpdates && header.Type == FrameType.WindowUpdate)
            {
                return(await ReadFrameAsync(timeout));
            }

            // Construct the correct frame type and return it.
            switch (header.Type)
            {
            case FrameType.Data:
                return(DataFrame.ReadFrom(header, data));

            case FrameType.Headers:
                return(HeadersFrame.ReadFrom(header, data));

            case FrameType.Priority:
                return(PriorityFrame.ReadFrom(header, data));

            case FrameType.RstStream:
                return(RstStreamFrame.ReadFrom(header, data));

            case FrameType.Ping:
                return(PingFrame.ReadFrom(header, data));

            case FrameType.GoAway:
                return(GoAwayFrame.ReadFrom(header, data));

            default:
                return(header);
            }
        }
        public async Task <Frame> ReadFrameAsync(CancellationToken cancellationToken)
        {
            // First read the frame headers, which should tell us how long the rest of the frame is.
            byte[] headerBytes = new byte[Frame.FrameHeaderLength];

            try
            {
                if (!await FillBufferAsync(headerBytes, cancellationToken).ConfigureAwait(false))
                {
                    return(null);
                }
            }
            catch (IOException)
            {
                // eat errors when client aborts connection and return null.
                return(null);
            }

            Frame header = Frame.ReadFrom(headerBytes);

            // Read the data segment of the frame, if it is present.
            byte[] data = new byte[header.Length];
            if (header.Length > 0 && !await FillBufferAsync(data, cancellationToken).ConfigureAwait(false))
            {
                throw new Exception("Connection stream closed while attempting to read frame body.");
            }

            if (_ignoredSettingsAckPromise != null && header.Type == FrameType.Settings && header.Flags == FrameFlags.Ack)
            {
                _ignoredSettingsAckPromise.TrySetResult(true);
                _ignoredSettingsAckPromise = null;
                return(await ReadFrameAsync(cancellationToken).ConfigureAwait(false));
            }

            if (_ignoreWindowUpdates && header.Type == FrameType.WindowUpdate)
            {
                return(await ReadFrameAsync(cancellationToken).ConfigureAwait(false));
            }

            if (header.Type == FrameType.Ping && _transparentPingResponse)
            {
                PingFrame pingFrame = PingFrame.ReadFrom(header, data);

                bool processed = await TryProcessExpectedPingFrameAsync(pingFrame);

                return(processed ? await ReadFrameAsync(cancellationToken).ConfigureAwait(false) : pingFrame);
            }

            // Construct the correct frame type and return it.
            switch (header.Type)
            {
            case FrameType.Settings:
                return(SettingsFrame.ReadFrom(header, data));

            case FrameType.Data:
                return(DataFrame.ReadFrom(header, data));

            case FrameType.Headers:
                return(HeadersFrame.ReadFrom(header, data));

            case FrameType.Priority:
                return(PriorityFrame.ReadFrom(header, data));

            case FrameType.RstStream:
                return(RstStreamFrame.ReadFrom(header, data));

            case FrameType.Ping:
                return(PingFrame.ReadFrom(header, data));

            case FrameType.GoAway:
                return(GoAwayFrame.ReadFrom(header, data));

            case FrameType.Continuation:
                return(ContinuationFrame.ReadFrom(header, data));

            case FrameType.WindowUpdate:
                return(WindowUpdateFrame.ReadFrom(header, data));

            default:
                return(header);
            }
        }