Class that represents control frame.
Inheritance: System.ServiceModel.Http2Protocol.ProtocolFrames.BaseFrame
        /// <summary>
        /// Builds the headers frame.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="headers">The headers.</param>
        /// <param name="final">if set to <c>true</c> than this frame is final for the stream.</param>
        /// <returns>Headers frame.</returns>
        public ControlFrame BuildHeadersFrame(Http2Stream stream, ProtocolHeaders headers, bool final)
        {
            ControlFrame frame = BuildControlFrame(FrameType.Headers, stream, headers);

            frame.IsFinal = final;
            return(frame);
        }
        /// <summary>
        /// Builds the SYN_STREAM frame.
        /// </summary>
        /// <param name="streamId">The stream id.</param>
        /// <param name="headers">The headers.</param>
        /// <returns>SYN_STREAM frame.</returns>
        public ControlFrame BuildSynStreamFrame(int streamId, ProtocolHeaders headers)
        {
            ControlFrame frame = BuildControlFrame(FrameType.SynStream, streamId, headers);

            frame.Priority = SYNStreamPriority;

            return(frame);
        }
        /// <summary>
        /// Builds the SYN_STREAM frame.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="headers">The headers.</param>
        /// <param name="final">Indicates that stream is not going to send any more data.</param>
        /// <returns>SYN_STREAM frame.</returns>
        public ControlFrame BuildSynStreamFrame(Http2Stream stream, ProtocolHeaders headers, bool final)
        {
            ControlFrame frame = BuildControlFrame(FrameType.SynStream, stream, headers);

            frame.Priority = SYNStreamPriority;
            frame.IsFinal  = final;

            return(frame);
        }
        /// <summary>
        /// Builds the control frame.
        /// </summary>
        /// <param name="type">The frame type.</param>
        /// <param name="streamId">The Http2 stream id.</param>
        /// <param name="headers">The headers.</param>
        /// <returns>Returns Control frame object.</returns>
        private static ControlFrame BuildControlFrame(FrameType type, int streamId, ProtocolHeaders headers)
        {
            ControlFrame frame = new ControlFrame(headers);

            frame.StreamId = streamId;
            frame.Type     = type;
            frame.Priority = ControlPriority;

            return(frame);
        }
        /// <summary>
        /// Builds the Ping frame.
        /// </summary>
        /// <param name="lastSeenGoodStreamId">The stream id.</param>
        /// <returns>Builded Ping Frame</returns>
        public ControlFrame BuildPingFrame(int streamId)
        {
            ControlFrame frame = new ControlFrame {
                StreamId = streamId
            };

            frame.Flags  = 0;
            frame.Length = 4;
            return(frame);
        }
        /// <summary>
        /// Builds the RST Frame.
        /// </summary>
        /// <param name="streamId">The stream id.</param>
        /// <param name="reason">The reason for RST.</param>
        /// <returns>RST frame.</returns>
        public ControlFrame BuildRSTFrame(int streamId, StatusCode reason)
        {
            ControlFrame frame = new ControlFrame();

            frame.StreamId   = streamId;
            frame.Type       = FrameType.RTS;
            frame.StatusCode = reason;
            frame.Priority   = RSTPriority;

            return(frame);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="WindowUpdateEventArgs" /> class.
 /// </summary>
 /// <param name="deltaWindowSize">Size of the delta window.</param>
 public WindowUpdateEventArgs(ControlFrame frame)
     : base(frame)
 {
     this.DeltaWindowSize = frame.DeltaWindowSize;
 }
        /// <summary>
        /// Serializes the control frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <returns>Serialized control frame.</returns>
        private byte[] SerializeControlFrame(ControlFrame frame)
        {
            var byteList = new List<byte>();

            byteList.Add((byte)(((frame.Version & 0xFF00) >> 8) | 0x80));
            byteList.Add((byte)(frame.Version & 0x00FF));

            byteList.Add((byte)(((Int16)frame.Type & 0xFF00) >> 8));
            byteList.Add((byte)((Int16)frame.Type & 0x00FF));

            var headersArray = new byte[0];
            switch (frame.Type)
            {
                case FrameType.SynStream:
                    byteList.Add(Convert.ToByte(frame.Flags | (frame.IsFinal ? 0x01 : 0x00)));

                    headersArray = SerializeControlFrameHeaders(frame.Headers);

                    if (headersArray.Length > 0)
                    {
                        ProcessorRun(ref headersArray, DirectionProcessType.Outbound, frame.Flags);
                    }

                    byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 10, 3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));

                    byteList.AddRange(BinaryHelper.Int32ToBytes(0));

                    byteList.Add(Convert.ToByte(frame.Priority >> 5));

                    byteList.Add(Unused);

                    break;
                case FrameType.RTS:
                    byteList.Add(0);
                    byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 8, 3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));
                    byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode));
                    break;
                case FrameType.SynReply:
                    byteList.Add(frame.Flags);
                    headersArray = SerializeControlFrameHeaders(frame.Headers);

                    if (headersArray.Length > 0)
                    {
                        ProcessorRun(ref headersArray, DirectionProcessType.Outbound, frame.Flags);
                    }

                    byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 4, 3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));
                    break;
                case FrameType.GoAway:
                    byteList.Add(frame.Flags);
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length,3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));
                    byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode));
                    break;
                case FrameType.Ping:
                    byteList.Add(frame.Flags);
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length,3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));
                    break;
                case FrameType.WindowUpdate:
                    byteList.Add(frame.Flags);
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length,3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId));
                    byteList.AddRange(BinaryHelper.Int64ToBytes(((WindowUpdateFrame)frame).DeltaWindowSize));
                    break;
                case FrameType.Settings:
                    byteList.Add(frame.Flags);
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length,3));
                    byteList.AddRange(BinaryHelper.Int32ToBytes(frame.NumberOfEntries));
                    break;
            }

            byteList.AddRange(headersArray);
            return byteList.ToArray();
        }
        /// <summary>
        /// Parses HTTP headers of Http2 control frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <param name="data">The data.</param>
        /// <param name="offset">Offset of HTTP headers in the data.</param>
        private void ParseControlFrameHeaders(ref ControlFrame frame, byte[] data, int offset)
        {
            var headers = new byte[data.Length - offset];
            Array.Copy(data, offset, headers, 0, headers.Length);
            if (headers.Length > 0)
                ProcessorRun(ref headers, DirectionProcessType.Inbound, frame.Flags);

            int headersOffset = 0;
            int numberOfKeyValue = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(headers, headersOffset, 4));
            headersOffset += 4;

            for (int i = 0; i < numberOfKeyValue; ++i)
            {
                int nameLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(headers, headersOffset, 4));
                headersOffset += 4;
                string name = Encoding.UTF8.GetString(headers, headersOffset, nameLength);
                headersOffset += nameLength;

                int valLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(headers, headersOffset, 4));
                headersOffset += 4;
                string val = Encoding.UTF8.GetString(headers, headersOffset, valLength);
                headersOffset += valLength;
                // Ensure no duplicates.
                if (frame.Headers.ContainsKey(name))
                {
                    throw new ProtocolExeption(StatusCode.InternalError);
                }

                frame.Headers.Add(name, val);
            }
        }
        /// <summary>
        /// Deserializes the data into control frame.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns>Deserialized frame.</returns>
        private BaseFrame DeserializeControlFrame(byte[] data)
        {
            FrameType type = GetFrameType(data);
            ControlFrame frame = new ControlFrame();

            switch (type)
            {
                case FrameType.RTS:
                    frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));
                    frame.StatusCode = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 12, 4));
                    break;
                case FrameType.Headers:
                case FrameType.SynReply:
                    ParseControlFrameHeader(ref frame, data);

                    frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));

                    ParseControlFrameHeaders(ref frame, data, 12);
                    break;
                case FrameType.SynStream:
                    ParseControlFrameHeader(ref frame, data);

                    frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));
                    frame.AssociatedToStreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 12, 4));
                    frame.Priority = (byte)(data[16] >> 5);
                    frame.Slot = data[17];

                    ParseControlFrameHeaders(ref frame, data, 18);
                    break;
                case FrameType.Settings:
                    int numberOfEntries = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));
                    frame = new SettingsFrame(numberOfEntries);
                    int headersOffset = 12;

                    for (int i = 0; i < numberOfEntries; i++)
                    {
                        int key = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, headersOffset, 4));
                        headersOffset += 4;
                        int value = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, headersOffset, 4));
                        headersOffset += 4;

                        frame.SettingsHeaders.Add(key, value);
                    }

                    ParseControlFrameHeader(ref frame, data);
                    break;
                case FrameType.GoAway:
                    int lastSeenGoodStreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));
                    StatusCode status = StatusCode.Success;

                    if (data.Length > 12)
                        status = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 12, 4));

                    frame = new GoAwayFrame(lastSeenGoodStreamId, status);
                    ParseControlFrameHeader(ref frame, data);
                    break;
                case FrameType.Ping:
                    int streamID = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 4, 4));
                    frame = new ControlFrame { StreamId = streamID };

                    ParseControlFrameHeader(ref frame, data);
                    break;
                case FrameType.WindowUpdate:
                    int streamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 4, 4));
                    int deltaWindowSize = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4));
                    frame = new WindowUpdateFrame(streamId, deltaWindowSize);

                    ParseControlFrameHeader(ref frame, data);
                    break;
            }
            frame.Type = type;

            return frame;
        }
        /// <summary>
        /// Parses HTTP header of Http2 control frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <param name="data">The data.</param>
        private static void ParseControlFrameHeader(ref ControlFrame frame, byte[] data)
        {
            frame.Version = BinaryHelper.Int16FromBytes(data[0], data[1], 1);
            frame.Type = (FrameType)BinaryHelper.Int16FromBytes(data[2], data[3]);

            frame.Flags = data[4]; //  it would be always 4 th byte for flags in spec.

            frame.Length = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 5, 3));
            frame.IsFinal = (frame.Flags & 0x01) != 0;
        }
 /// <summary>
 /// Builds the Ping frame.
 /// </summary>
 /// <param name="lastSeenGoodStreamId">The stream id.</param>
 /// <returns>Builded Ping Frame</returns>
 public ControlFrame BuildPingFrame(int streamId)
 {
     ControlFrame frame = new ControlFrame { StreamId = streamId };
     frame.Flags = 0;
     frame.Length = 4;
     return frame;
 }
        /// <summary>
        /// Builds the control frame.
        /// </summary>
        /// <param name="type">The frame type.</param>
        /// <param name="streamId">The Http2 stream id.</param>
        /// <param name="headers">The headers.</param>
        /// <returns>Returns Control frame object.</returns>
        private static ControlFrame BuildControlFrame(FrameType type, int streamId, ProtocolHeaders headers)
        {
            ControlFrame frame = new ControlFrame(headers);
            frame.StreamId = streamId;
            frame.Type = type;
            frame.Priority = ControlPriority;

            return frame;
        }
        /// <summary>
        /// Builds the RST Frame.
        /// </summary>
        /// <param name="streamId">The stream id.</param>
        /// <param name="reason">The reason for RST.</param>
        /// <returns>RST frame.</returns>
        public ControlFrame BuildRSTFrame(int streamId, StatusCode reason)
        {
            ControlFrame frame = new ControlFrame();
            frame.StreamId = streamId;
            frame.Type = FrameType.RTS;
            frame.StatusCode = reason;
            frame.Priority = RSTPriority;

            return frame;
        }
        /// <summary>
        /// Process Protocol control frame.
        /// </summary>
        /// <param name="frame">The control frame.</param>
        private void ProcessControlFrame(ControlFrame frame)
        {
            if (frame.Version != Version)
            {
                throw new ProtocolExeption(StatusCode.UnsupportedVersion);
            }

            if (frame.Type == FrameType.GoAway)
            {
                GoAwayFrame goAway = (GoAwayFrame)frame;
                CloseInternal(goAway.Status, goAway.LastSeenGoodStreamId, false);
            }
            else
            {
                Http2Stream stream = this.streamsStore.GetStreamById(frame.StreamId);

                // if this is rst frame - don't send error or it will go in rst loop
                if (stream == null && frame.Type != FrameType.RTS && frame.Type != FrameType.Settings && frame.Type != FrameType.SynStream)
                {
                    this.SendRST(frame.StreamId, StatusCode.InvalidStream);
                    return;
                }

                switch (frame.Type)
                {
                    case FrameType.SynStream:
                        //TODO validate syn_stream and send syn_reply or rst
                        //this.OnSessionFrame(this, new ControlFrameEventArgs(frame));
                        this.SendRST(frame.StreamId, StatusCode.RefusedStream);
                        break;
                    case FrameType.SynReply:
                        this.OnSessionFrame(this, new ControlFrameEventArgs(frame));
                        break;
                    case FrameType.Headers:
                        this.OnStreamFrame(this, new HeadersEventArgs(this.streamsStore.GetStreamById(frame.StreamId), frame.Headers));
                        break;
                    case FrameType.RTS:
                        this.OnStreamFrame(this, new RSTEventArgs(this.streamsStore.GetStreamById(frame.StreamId), frame.StatusCode));
                        break;
                    case FrameType.Ping:
                        this.OnSocketPing(this, new PingEventArgs(frame.StreamId));
                        break;
                    case FrameType.Settings:
                        OnSessionFrame(this, new SettingsEventArgs(frame));
                        break;
                    case FrameType.WindowUpdate:
                        Http2Stream http2Stream = this.streamsStore.GetStreamById(frame.StreamId);
                        http2Stream.UpdateWindowBalance(frame.DeltaWindowSize);
                        break;
                }
            }
        }
        /// <summary>
        /// Sends the frame.
        /// </summary>
        /// <param name="frame">The control frame.</param>
        private void SendFrame(ControlFrame frame)
        {
            byte[] frameBinary = this.serializer.Serialize(frame);
            frame.Length = frameBinary.Length;

            SendMessage(frameBinary);

            if (this.OnFrameSent != null)
            {
                this.OnFrameSent(this, new FrameEventArgs(frame));
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SettingsEventArgs"/> class.
 /// </summary>
 /// <param name="stream">The settings name/value pairs.</param>
 public SettingsEventArgs(ControlFrame settingsFrame)
     : base(settingsFrame)
 {
     this.SettingsHeaders = settingsFrame.SettingsHeaders;
 }