/// <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.CreditUpdate: 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; } }
/// <summary> /// Sends the data. /// </summary> /// <param name="stream">The stream.</param> /// <param name="frame">The base frame.</param> private void SendFrame(SMStream stream, BaseFrame frame) { try { byte[] frameBinary = this.serializer.Serialize(frame); frame.Length = frameBinary.Length; this.webSocket.SendMessage(frameBinary); if (frame.IsFinal) { stream.State = SMStreamState.HalfClosed; } if (this.OnFrameSent != null) { this.OnFrameSent(this, new FrameEventArgs(frame)); } } catch (Exception e) { if (this.OnStreamError != null) { this.OnStreamError(this, new StreamErrorEventArgs(stream, e)); } else { throw; } } }
/// <summary> /// Opens the stream in current session. /// </summary> /// <param name="id">the stream id.</param> /// <param name="headers">The S+M headers.</param> /// <param name="isFinal">the final flag.</param> /// <returns>The Stream.</returns> private SMStream OpenStream(int id, SMHeaders headers, bool isFinal) { if (id <= this.lastSeenStreamId) { this.End(StatusCode.ProtocolError); return(null); } this.lastSeenStreamId = id; // don't have to wait for stream opening SMStream stream = new SMStream(id, this); stream.OnClose += this.OnCloseStream; stream.Open(headers, isFinal); this.streams.Add(stream); if (this.OnStreamOpened != null) { this.OnStreamOpened(this, new StreamEventArgs(stream)); } return(stream); }
/// <summary> /// Event handler for close stream. /// </summary> /// <param name="sender">Sender object.</param> /// <param name="e">The event args.</param> private void OnCloseStream(object sender, RSTEventArgs e) { SMStream stream = sender as SMStream; this.streams.Remove(stream); this.closedStreams.Add(stream); if (this.OnStreamClosed != null) { this.OnStreamClosed(this, e); } }
/// <summary> /// Process SM Data frame. /// </summary> /// <param name="frame">The data frame.</param> private void ProcessDataFrame(DataFrame frame) { if (this.OnStreamFrame != null) { SMStream stream = this.streamsStore.GetStreamById(frame.StreamId); if (stream == null) { this.SendRST(frame.StreamId, StatusCode.InvalidStream); } else { this.OnStreamFrame(this, new StreamDataEventArgs(stream, new SMData(frame.Data), frame.IsFinal)); } } }
/// <summary> /// Event handler for session frame. /// </summary> /// <param name="sender">Sender object.</param> /// <param name="e">The event args.</param> private void OnSessionFrame(object sender, ControlFrameEventArgs e) { switch (e.Frame.Type) { case FrameType.SynStream: OpenStream(e.Frame.StreamId, e.Frame.Headers, false); break; case FrameType.SynReply: SMStream stream = this.GetStreamById(e.Frame.StreamId); if (stream != null && stream.State != SMStreamState.Closed && stream.State != SMStreamState.HalfClosed) { stream.State = SMStreamState.Accepted; } break; case FrameType.CreditUpdate: CurrentCreditBalanceToServer += Convert.ToInt32(e.Frame.Headers["credit-addition"]); break; } }
/// <summary> /// Sends the RST. /// </summary> /// <param name="stream">The stream.</param> /// <param name="reason">The reason for RST.</param> public void SendRST(SMStream stream, StatusCode reason) { this.SendFrame(stream, this.builder.BuildRSTFrame(stream, reason)); }
/// <summary> /// Sends the headers. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <param name="isFin">FIN flag.</param> public void SendHeaders(SMStream stream, SMHeaders headers, bool isFin) { this.SendFrame(stream, this.builder.BuildHeadersFrame(stream, headers, isFin)); }
/// <summary> /// Sends the data. /// </summary> /// <param name="stream">The stream.</param> /// <param name="data">The data.</param> /// <param name="isFin">FIN flag.</param> public void SendData(SMStream stream, SMData data, bool isFin) { this.SendFrame(stream, this.builder.BuildDataFrame(stream, data, isFin)); }
/// <summary> /// Sends the credit update request. /// </summary> /// <param name="stream">The stream.</param> /// <param name="creditAddition">The credit addition.</param> public void SendCreditUpdate(SMStream stream, Int64 creditAddition) { this.SendFrame(this.builder.BuildCreditUpdateFrame(stream, creditAddition)); }
/// <summary> /// Sends the syn stream request. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <param name="isFin">FIN flag.</param> public void SendSynStream(SMStream stream, SMHeaders headers, bool isFin) { this.SendFrame(this.builder.BuildSynStreamFrame(stream, headers, isFin)); }
/// <summary> /// Opens the stream in current session. /// </summary> /// <param name="id">the stream id.</param> /// <param name="headers">The S+M headers.</param> /// <param name="isFinal">the final flag.</param> /// <returns>The Stream.</returns> private SMStream OpenStream(int id, SMHeaders headers, bool isFinal) { if (id <= this.lastSeenStreamId) { this.End(StatusCode.ProtocolError); return null; } this.lastSeenStreamId = id; // don't have to wait for stream opening SMStream stream = new SMStream(id, this); stream.OnClose += this.OnCloseStream; stream.Open(headers, isFinal); this.streams.Add(stream); if (this.OnStreamOpened != null) { this.OnStreamOpened(this, new StreamEventArgs(stream)); } return stream; }