/// <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; } if (_frameHeaderSize == 0) { //Read the first byte of the message to determine the version of the response ProtocolVersion = FrameHeader.GetProtocolVersion(buffer); _frameHeaderSize = FrameHeader.GetSize(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); }