public ResponseFrame(FrameHeader header, Stream body) { if (header == null) throw new ArgumentNullException("header"); if (body == null) throw new ArgumentNullException("body"); Header = header; Body = body; }
public Frame(FrameHeader header, Stream body, Serializer serializer) { if (header == null) { throw new ArgumentNullException("header"); } if (body == null) { throw new ArgumentNullException("body"); } if (serializer == null) { throw new ArgumentNullException("serializer"); } _header = header; _body = body; _serializer = serializer; }
public override IEnumerable<ResponseFrame> Process(byte[] buffer, int size, Stream stream, IProtoBufComporessor compressor) { Init(buffer, size); while (AreMore()) { byte b = GetByte(); switch (ByteIdx) { case 0: TmpFrameHeader.Version = b; break; case 1: TmpFrameHeader.Flags = b; break; case 2: TmpFrameHeader.StreamId = b; break; case 3: TmpFrameHeader.Opcode = b; break; case 4: { TmpFrameHeader.Len[0] = b; } break; case 5: TmpFrameHeader.Len[1] = b; break; case 6: TmpFrameHeader.Len[2] = b; break; case 7: TmpFrameHeader.Len[3] = b; _bodyLen = TypeInterpreter.BytesToInt32(TmpFrameHeader.Len, 0); TmpFrame = TmpFrameHeader.MakeFrame(new BufferedProtoBuf(_bodyLen, ((TmpFrameHeader.Flags & 0x01) == 0x01) ? compressor : null)); yield return TmpFrame; break; default: { TmpFrame.RawStream.WriteByte(b); } break; } ByteIdx++; if (ByteIdx - 8 >= _bodyLen) { ByteIdx = 0; _bodyLen = int.MaxValue; TmpFrameHeader = new FrameHeader(); } } }
public virtual IEnumerable<ResponseFrame> Process(byte[] buffer, int size, Stream stream, IProtoBufComporessor compressor) { Init(buffer, size); int bodyLen = int.MaxValue; while (AreMore()) { byte b = GetByte(); switch (ByteIdx) { case 0: TmpFrameHeader.Version = b; break; case 1: TmpFrameHeader.Flags = b; break; case 2: TmpFrameHeader.StreamId = b; break; case 3: TmpFrameHeader.Opcode = b; break; case 4: { TmpFrameHeader.Len[0] = b; } break; case 5: TmpFrameHeader.Len[1] = b; break; case 6: TmpFrameHeader.Len[2] = b; break; case 7: TmpFrameHeader.Len[3] = b; bodyLen = TypeInterpreter.BytesToInt32(TmpFrameHeader.Len, 0); TmpFrame = TmpFrameHeader.MakeFrame(new StreamProtoBuf(stream, ((TmpFrameHeader.Flags & 0x01) == 0x01) ? compressor : null)); yield return TmpFrame; break; default: throw new DriverInternalError("Invalid state"); } ByteIdx++; if (ByteIdx >= FrameHeader.Size) { ByteIdx = 0; TmpFrameHeader = new FrameHeader(); } } }
/// <summary> /// Parses the first 8 bytes and returns a FrameHeader /// </summary> public static FrameHeader ParseResponseHeader(byte version, byte[] buffer, int offset) { var header = new FrameHeader() { _versionByte = buffer[offset++], Flags = buffer[offset++] }; if (version < 3) { //Stream id is a signed byte in v1 and v2 of the protocol header.StreamId = (sbyte)buffer[offset++]; } else { header.StreamId = BitConverter.ToInt16(new byte[] { buffer[offset + 1], buffer[offset] }, 0); offset += 2; } header.Opcode = buffer[offset++]; header.Len = buffer.Skip(offset).Take(4).ToArray(); return(header); }
/// <summary> /// Parses the first 8 or 9 bytes and returns a FrameHeader /// </summary> public static FrameHeader ParseResponseHeader(ProtocolVersion version, byte[] buffer, int offset) { var header = new FrameHeader() { _versionByte = buffer[offset++], Flags = (HeaderFlag)buffer[offset++] }; if (!version.Uses2BytesStreamIds()) { //Stream id is a signed byte in v1 and v2 of the protocol header.StreamId = (sbyte)buffer[offset++]; } else { header.StreamId = BeConverter.ToInt16(buffer, offset); offset += 2; } header.Opcode = buffer[offset++]; header.BodyLength = BeConverter.ToInt32(Utils.SliceBuffer(buffer, offset, 4)); return(header); }
/// <summary> /// Returns an action that capture the parameters closure /// </summary> private Action<MemoryStream> CreateResponseAction(FrameHeader header, Action<Exception, Response> callback) { var compressor = Compressor; var bufferPool = Configuration.BufferPool; var decompressorBuffer = _decompressorBuffer; return stream => { Response response = null; Exception ex = null; var nextPosition = stream.Position + header.BodyLength; try { Stream plainTextStream = stream; if (header.Flags.HasFlag(FrameHeader.HeaderFlag.Compression)) { var compressedBodyStream = bufferPool.GetStream(typeof (Connection) + "/Decompress", header.BodyLength); Utils.CopyStream(stream, compressedBodyStream, header.BodyLength, decompressorBuffer); compressedBodyStream.Position = 0; plainTextStream = compressor.Decompress(compressedBodyStream); plainTextStream.Position = 0; } response = FrameParser.Parse(new Frame(header, plainTextStream)); } catch (Exception catchedException) { ex = catchedException; } if (response is ErrorResponse) { //Create an exception from the response error ex = ((ErrorResponse)response).Output.CreateException(); response = null; } //We must advance the position of the stream manually in case it was not correctly parsed stream.Position = nextPosition; callback(ex, response); }; }
/// <summary> /// Returns an action that capture the parameters closure /// </summary> private Action <MemoryStream> CreateResponseAction(FrameHeader header, Action <Exception, Response> callback) { var compressor = Compressor; void DeserializeResponseStream(MemoryStream stream) { Response response = null; Exception ex = null; var nextPosition = stream.Position + header.BodyLength; try { Stream plainTextStream = stream; if (header.Flags.HasFlag(FrameHeader.HeaderFlag.Compression)) { plainTextStream = compressor.Decompress(new WrappedStream(stream, header.BodyLength)); plainTextStream.Position = 0; } response = FrameParser.Parse(new Frame(header, plainTextStream, _serializer)); } catch (Exception catchedException) { ex = catchedException; } if (response is ErrorResponse) { //Create an exception from the response error ex = ((ErrorResponse)response).Output.CreateException(); response = null; } //We must advance the position of the stream manually in case it was not correctly parsed stream.Position = nextPosition; callback(ex, response); } return(DeserializeResponseStream); }
/// <summary> /// Saves the current read state (header and body stream) for the next read event. /// </summary> private void StoreReadState(FrameHeader header, MemoryStream stream, byte[] buffer, int offset, int length, bool hasReadFromStream) { MemoryStream nextMessageStream; if (!hasReadFromStream && stream != null) { // There hasn't been any operations completed with this buffer, reuse the current stream nextMessageStream = stream; } else { // Allocate a new stream for store in it nextMessageStream = Configuration.BufferPool.GetStream(StreamReadTag); } nextMessageStream.Write(buffer, offset, length - offset); Volatile.Write(ref _readStream, nextMessageStream); Volatile.Write(ref _receivingHeader, header); if (_isCanceled) { // Connection was disposed since we started to store the buffer, try to dispose the stream Interlocked.Exchange(ref _readStream, null)?.Dispose(); } }
public ResponseFrame(FrameHeader header, Stream body) { Header = header; Body = body; }
/// <summary> /// Deserializes each frame header and copies the body bytes into a single buffer. /// </summary> /// <returns>True if a full operation (streamId) has been processed.</returns> internal bool ReadParse(byte[] buffer, int length) { if (length <= 0) { return(false); } ProtocolVersion protocolVersion; var headerLength = Volatile.Read(ref _frameHeaderSize); if (headerLength == 0) { // The server replies the first message with the max protocol version supported protocolVersion = FrameHeader.GetProtocolVersion(buffer); _serializer.ProtocolVersion = protocolVersion; headerLength = FrameHeader.GetSize(protocolVersion); Volatile.Write(ref _frameHeaderSize, headerLength); } else { protocolVersion = _serializer.ProtocolVersion; } // Use _readStream to buffer between messages, when the body is not contained in a single read call var stream = Interlocked.Exchange(ref _readStream, null); var previousHeader = Interlocked.Exchange(ref _receivingHeader, null); if (previousHeader != null && stream == null) { // This connection has been disposed return(false); } var operationCallbacks = new LinkedList <Action <MemoryStream> >(); var offset = 0; while (offset < length) { var header = previousHeader; int remainingBodyLength; if (header == null) { header = ReadHeader(buffer, ref offset, length, headerLength, protocolVersion); if (header == null) { // There aren't enough bytes to read the header break; } Logger.Verbose("Received #{0} from {1}", header.StreamId, Address); remainingBodyLength = header.BodyLength; } else { previousHeader = null; remainingBodyLength = header.BodyLength - (int)stream.Length; } if (remainingBodyLength > length - offset) { // The buffer does not contains the body for the current frame, store it for later StoreReadState(header, stream, buffer, offset, length, operationCallbacks.Count > 0); break; } stream = stream ?? Configuration.BufferPool.GetStream(StreamReadTag); var state = header.Opcode != EventResponse.OpCode ? RemoveFromPending(header.StreamId) : new OperationState(EventHandler); stream.Write(buffer, offset, remainingBodyLength); // State can be null when the Connection is being closed concurrently // The original callback is being called with an error, use a Noop here var callback = state != null?state.SetCompleted() : OperationState.Noop; operationCallbacks.AddLast(CreateResponseAction(header, callback)); offset += remainingBodyLength; } return(InvokeReadCallbacks(stream, operationCallbacks)); }
/// <summary> /// Parses the first 8 or 9 bytes and returns a FrameHeader /// </summary> public static FrameHeader ParseResponseHeader(byte version, byte[] buffer, int offset) { var header = new FrameHeader() { _versionByte = buffer[offset++], Flags = (HeaderFlag)buffer[offset++] }; if (version < 3) { //Stream id is a signed byte in v1 and v2 of the protocol header.StreamId = (sbyte)buffer[offset++]; } else { header.StreamId = BeConverter.ToInt16(buffer, offset); offset += 2; } header.Opcode = buffer[offset++]; header.BodyLength = BeConverter.ToInt32(Utils.SliceBuffer(buffer, offset, 4)); return header; }
/// <summary> /// Parses the bytes received into a frame. Uses the internal operation state to do the callbacks. /// Returns true if a full operation (streamId) has been processed and there is one available. /// </summary> /// <param name="buffer">Byte buffer to read</param> /// <param name="offset">Offset within the buffer</param> /// <param name="count">Length of bytes to be read from the buffer</param> /// <returns>True if a full operation (streamId) has been processed.</returns> protected virtual bool ReadParse(byte[] buffer, int offset, int count) { var state = _receivingOperation; if (state == null) { if (_minimalBuffer != null) { buffer = Utils.JoinBuffers(_minimalBuffer, 0, _minimalBuffer.Length, buffer, offset, count); offset = 0; count = buffer.Length; } var headerSize = FrameHeader.GetSize(ProtocolVersion); if (count < headerSize) { //There is not enough data to read the header _minimalBuffer = Utils.SliceBuffer(buffer, offset, count); return(false); } _minimalBuffer = null; var header = FrameHeader.ParseResponseHeader(ProtocolVersion, buffer, offset); if (!header.IsValidResponse()) { _logger.Error("Not a response header"); } offset += headerSize; count -= headerSize; if (header.Opcode != EventResponse.OpCode) { //Its a response to a previous request state = _pendingOperations[header.StreamId]; } else { //Its an event state = new OperationState { Callback = EventHandler }; } state.Header = header; _receivingOperation = state; } var countAdded = state.AppendBody(buffer, offset, count); if (!state.IsBodyComplete) { //Nothing finished return(false); } _logger.Verbose("Read #{0} for Opcode {1} from host {2}", state.Header.StreamId, state.Header.Opcode, Address); //Stop reference it as the current receiving operation _receivingOperation = null; if (state.Header.Opcode != EventResponse.OpCode) { //Remove from pending _pendingOperations.TryRemove(state.Header.StreamId, out state); //Release the streamId _freeOperations.Push(state.Header.StreamId); } try { var response = ReadParseResponse(state.Header, state.BodyStream); state.InvokeCallback(null, response); } catch (Exception ex) { state.InvokeCallback(ex); } if (countAdded < count) { //There is more data, from the next frame ReadParse(buffer, offset + countAdded, count - countAdded); } return(true); //There isn't enough data to read the whole frame. //It is already buffered, carry on. }
/// <summary> /// Parses the bytes received into a frame. Uses the internal operation state to do the callbacks. /// Returns true if a full operation (streamId) has been processed and there is one available. /// </summary> /// <returns>True if a full operation (streamId) has been processed.</returns> internal bool ReadParse(byte[] buffer, int length) { if (length <= 0) { return(false); } byte protocolVersion; if (_frameHeaderSize == 0) { //The server replies the first message with the max protocol version supported protocolVersion = FrameHeader.GetProtocolVersion(buffer); _serializer.ProtocolVersion = protocolVersion; _frameHeaderSize = FrameHeader.GetSize(protocolVersion); } else { protocolVersion = _serializer.ProtocolVersion; } //Use _readStream to buffer between messages, under low pressure, it should be null most of the times var stream = Interlocked.Exchange(ref _readStream, null); var operationCallbacks = new LinkedList <Action <MemoryStream> >(); var offset = 0; if (_minimalBuffer != null) { //use a negative offset to identify that there is a previous header buffer offset = -1 * _minimalBuffer.Length; } while (offset < length) { FrameHeader header; //The remaining body length to read from this buffer int remainingBodyLength; if (_receivingHeader == null) { if (length - offset < _frameHeaderSize) { _minimalBuffer = offset >= 0 ? Utils.SliceBuffer(buffer, offset, length - offset) : //it should almost never be the case there isn't enough bytes to read the header more than once // ReSharper disable once PossibleNullReferenceException Utils.JoinBuffers(_minimalBuffer, 0, _minimalBuffer.Length, buffer, 0, length); break; } if (offset >= 0) { header = FrameHeader.ParseResponseHeader(protocolVersion, buffer, offset); } else { header = FrameHeader.ParseResponseHeader(protocolVersion, _minimalBuffer, buffer); _minimalBuffer = null; } Logger.Verbose("Received #{0} from {1}", header.StreamId, Address); offset += _frameHeaderSize; remainingBodyLength = header.BodyLength; } else { header = _receivingHeader; remainingBodyLength = header.BodyLength - (int)stream.Length; _receivingHeader = null; } if (remainingBodyLength > length - offset) { //the buffer does not contains the body for this frame, buffer for later MemoryStream nextMessageStream; if (operationCallbacks.Count == 0 && stream != null) { //There hasn't been any operations completed with this buffer //And there is a previous stream: reuse it nextMessageStream = stream; } else { nextMessageStream = Configuration.BufferPool.GetStream(typeof(Connection) + "/Read"); } nextMessageStream.Write(buffer, offset, length - offset); Interlocked.Exchange(ref _readStream, nextMessageStream); _receivingHeader = header; break; } stream = stream ?? Configuration.BufferPool.GetStream(typeof(Connection) + "/Read"); OperationState state; if (header.Opcode != EventResponse.OpCode) { state = RemoveFromPending(header.StreamId); } else { //Its an event state = new OperationState(EventHandler); } stream.Write(buffer, offset, remainingBodyLength); var callback = state.SetCompleted(); operationCallbacks.AddLast(CreateResponseAction(header, callback)); offset += remainingBodyLength; } return(InvokeReadCallbacks(stream, operationCallbacks)); }
public Frame(FrameHeader header, Stream body, ISerializer serializer) { _header = header ?? throw new ArgumentNullException("header"); _body = body ?? throw new ArgumentNullException("body"); _serializer = serializer ?? throw new ArgumentNullException("serializer"); }
public override IEnumerable <ResponseFrame> Process(byte[] buffer, int size, Stream stream, IProtoBufComporessor compressor) { Init(buffer, size); while (AreMore()) { byte b = GetByte(); switch (ByteIdx) { case 0: TmpFrameHeader.Version = b; break; case 1: TmpFrameHeader.Flags = b; break; case 2: TmpFrameHeader.StreamId = b; break; case 3: TmpFrameHeader.Opcode = b; break; case 4: { TmpFrameHeader.Len[0] = b; } break; case 5: TmpFrameHeader.Len[1] = b; break; case 6: TmpFrameHeader.Len[2] = b; break; case 7: TmpFrameHeader.Len[3] = b; _bodyLen = TypeInterpreter.BytesToInt32(TmpFrameHeader.Len, 0); TmpFrame = TmpFrameHeader.MakeFrame(new BufferedProtoBuf(_bodyLen, ((TmpFrameHeader.Flags & 0x01) == 0x01) ? compressor : null)); yield return(TmpFrame); break; default: { TmpFrame.RawStream.WriteByte(b); } break; } ByteIdx++; if (ByteIdx - 8 >= _bodyLen) { ByteIdx = 0; _bodyLen = int.MaxValue; TmpFrameHeader = new FrameHeader(); } } }
/// <summary> /// Parses the first 8 bytes and returns a FrameHeader /// </summary> public static FrameHeader ParseResponseHeader(byte version, byte[] buffer, int offset) { var header = new FrameHeader() { _versionByte = buffer[offset++], Flags = (HeaderFlag)buffer[offset++] }; if (version < 3) { //Stream id is a signed byte in v1 and v2 of the protocol header.StreamId = (sbyte)buffer[offset++]; } else { header.StreamId = BitConverter.ToInt16(new byte[] { buffer[offset + 1], buffer[offset] }, 0); offset += 2; } header.Opcode = buffer[offset++]; header.Len = buffer.Skip(offset).Take(4).ToArray(); return header; }