/// <summary> /// Builds the headers frame. /// </summary> /// <param name="streamId">The stream id.</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(int streamId, SMHeaders headers, bool final) { ControlFrame frame = BuildControlFrame(FrameType.Headers, streamId, 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, SMHeaders 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(SMStream stream, SMHeaders 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 SM stream id.</param> /// <param name="headers">The headers.</param> /// <returns>Returns Control frame object.</returns> private static ControlFrame BuildControlFrame(FrameType type, int streamId, SMHeaders 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="stream">The stream.</param> /// <param name="reason">The reason for RST.</param> /// <returns>RST frame.</returns> public ControlFrame BuildRSTFrame(SMStream stream, StatusCode reason) { ControlFrame frame = new ControlFrame(); frame.StreamId = stream.StreamId; frame.Type = FrameType.RTS; frame.StatusCode = reason; frame.Priority = RSTPriority; return(frame); }
/// <summary> /// Parses HTTP headers of SM 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 static void ParseControlFrameHeaders(ref ControlFrame frame, byte[] data, int offset) { int headersCount = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, offset, 4)); offset += 4; for (int i = 0; i < headersCount; ++i) { int nameLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, offset, 4)); offset += 4; string name = Encoding.UTF8.GetString(data, offset, nameLength); offset += nameLength; int valLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, offset, 4)); offset += 4; string val = Encoding.UTF8.GetString(data, offset, valLength); offset += valLength; frame.Headers.Add(name, val); } }
/// <summary> /// Parses HTTP header of SM 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]; frame.Length = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 5, 3)); frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4), 1); frame.IsFinal = (frame.Flags & 0x01) != 0; }
/// <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)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); var headersArray = new byte[0]; switch (frame.Type) { case FrameType.SynStream: byteList.Add(Convert.ToByte(frame.Flags | (frame.IsFinal ? 0x01 : 0x00))); byteList.Add(Convert.ToByte(frame.Priority >> 5)); byteList.Add(Unused); byteList.Add(Unused); headersArray = SerializeControlFrameHeaders(frame.Headers); break; case FrameType.RTS: byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode)); break; case FrameType.SynReply: byteList.Add(frame.Flags); byteList.Add(Unused); byteList.Add(Unused); byteList.Add(Unused); headersArray = SerializeControlFrameHeaders(frame.Headers); break; case FrameType.CreditUpdate: byteList.AddRange(BinaryHelper.Int64ToBytes(((CreditUpdateFrame)frame).CreditAddition)); break; } if (headersArray.Length > 0) { ProcessorRun(ref headersArray, DirectionProcessType.Outbound, frame.Flags); } byteList.AddRange(headersArray); return byteList.ToArray(); }
/// <summary> /// Parses HTTP headers of SM 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 data, DirectionProcessType.Outbound, frame.Flags); for (int i = 0; /*i < headersCount*/ offset < data.Length; ++i) { int nameLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, offset, 4)); offset += 4; string name = Encoding.UTF8.GetString(data, offset, nameLength); offset += nameLength; int valLength = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, offset, 4)); offset += 4; string val = Encoding.UTF8.GetString(data, offset, valLength); offset += valLength; // Ensure no duplicates. if (frame.Headers.ContainsKey(name)) { throw new SMProtocolExeption(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) { var frame = new ControlFrame(); ParseControlFrameHeader(ref frame, data); switch (frame.Type) { case FrameType.RTS: frame.StatusCode = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4)); break; case FrameType.Headers: case FrameType.SynReply: ParseControlFrameHeaders(ref frame, data, 12); break; case FrameType.SynStream: frame.Priority = (byte)(data[9] >> 5); ParseControlFrameHeaders(ref frame, data, 12); break; case FrameType.CreditUpdate: ((CreditUpdateFrame)frame).CreditAddition = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 8, 4)); break; } return frame; }
/// <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; this.webSocket.SendMessage(frameBinary); if (this.OnFrameSent != null) { this.OnFrameSent(this, new FrameEventArgs(frame)); } }
/// <summary> /// Initializes a new instance of the <see cref="ControlFrameEventArgs"/> class. /// </summary> /// <param name="frame">The frame.</param> public ControlFrameEventArgs(ControlFrame frame) { this.Frame = frame; }
/// <summary> /// Builds the control frame. /// </summary> /// <param name="type">The frame type.</param> /// <param name="streamId">The SM stream id.</param> /// <param name="headers">The headers.</param> /// <returns>Returns Control frame object.</returns> private static ControlFrame BuildControlFrame(FrameType type, int streamId, SMHeaders 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> /// Serializes the control frame. /// </summary> /// <param name="frame">The frame.</param> /// <returns>Serialized control frame.</returns> private static byte[] SerializeControlFrame(ControlFrame frame) { frame.Length = 12; if (frame.Type == FrameType.RTS) { frame.Length += 4; } else { if (frame.Type == FrameType.SynStream) { frame.Length += 8; } frame.Length += 4; foreach (var header in frame.Headers) { frame.Length += 4 + header.Key.Length; frame.Length += 4 + frame.Headers[header.Key].Length; } } List<byte> 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)); byteList.Add(frame.Flags); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); if (frame.Type == FrameType.SynStream) { byteList.AddRange(BinaryHelper.Int32ToBytes(frame.AssociatedToStreamId)); byteList.Add(frame.Priority); byteList.Add(frame.Slot); byteList.Add(Unused); byteList.Add(Unused); } if (frame.Type == FrameType.RTS) { byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode)); } else { byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Headers.Count)); foreach (KeyValuePair<string, string> pair in frame.Headers) { byte[] nameBin = Encoding.UTF8.GetBytes(pair.Key); byteList.AddRange(BinaryHelper.Int32ToBytes(nameBin.Length)); byteList.AddRange(nameBin); byte[] valBin = Encoding.UTF8.GetBytes(pair.Value); byteList.AddRange(BinaryHelper.Int32ToBytes(valBin.Length)); byteList.AddRange(valBin); } } return byteList.ToArray(); }
/// <summary> /// Deserializes the data into control frame. /// </summary> /// <param name="data">The data.</param> /// <returns>Deserialized frame.</returns> private static BaseFrame DeserializeControlFrame(byte[] data) { ControlFrame frame = new ControlFrame(); ParseControlFrameHeader(ref frame, data); switch (frame.Type) { case FrameType.RTS: frame.StatusCode = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 12, 4)); break; case FrameType.Headers: case FrameType.SynReply: ParseControlFrameHeaders(ref frame, data, 12); break; case FrameType.SynStream: frame.AssociatedToStreamId = BinaryHelper.Int32FromBytes(new ArraySegment<byte>(data, 12, 4), 1); frame.Priority = (byte)(data[16] & 0x7); frame.Slot = data[17]; ParseControlFrameHeaders(ref frame, data, 20); break; } return frame; }
/// <summary> /// Process SM control frame. /// </summary> /// <param name="frame">The control frame.</param> private void ProcessControlFrame(ControlFrame frame) { if (frame.Version != Version) { throw new SMProtocolExeption(StatusCode.UnsupportedVersion); } SMStream 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) { this.SendRST(frame.StreamId, StatusCode.InvalidStream); return; } switch (frame.Type) { case FrameType.SynStream: 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; } }