Ejemplo n.º 1
0
 /// <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);
 }