/// <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);
            }

            // Check if protocol version has already been determined (first message)
            ProtocolVersion protocolVersion;
            var             headerLength = Volatile.Read(ref _frameHeaderSize);
            var             serializer   = Volatile.Read(ref _serializer);

            if (headerLength == 0)
            {
                // The server replies the first message with the max protocol version supported
                protocolVersion = FrameHeader.GetProtocolVersion(buffer);
                serializer      = serializer.CloneWithProtocolVersion(protocolVersion);
                headerLength    = protocolVersion.GetHeaderSize();

                Volatile.Write(ref _serializer, serializer);
                Volatile.Write(ref _frameHeaderSize, headerLength);
                _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, long> >();
            var offset             = 0;

            while (offset < length)
            {
                FrameHeader header;
                int         remainingBodyLength;

                // check if header has not been read yet
                if (previousHeader == null)
                {
                    header = ReadHeader(buffer, ref offset, length, headerLength, protocolVersion);
                    if (header == null)
                    {
                        // There aren't enough bytes to read the header
                        break;
                    }

                    Connection.Logger.Verbose("Received #{0} from {1}", header.StreamId, EndPoint.EndpointFriendlyName);
                    remainingBodyLength = header.BodyLength;
                }
                else
                {
                    header              = previousHeader;
                    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;
                }

                // Get read stream
                stream = stream ?? Configuration.BufferPool.GetStream(Connection.StreamReadTag);

                // Get callback
                Action <IRequestError, Response, long> callback;
                if (header.Opcode == EventResponse.OpCode)
                {
                    callback = EventHandler;
                }
                else
                {
                    var state = RemoveFromPending(header.StreamId);
                    // State can be null when the Connection is being closed concurrently
                    // The original callback is being called with an error, use a Noop here
                    callback = state != null?state.SetCompleted() : OperationState.Noop;
                }

                // Write to read stream
                stream.Write(buffer, offset, remainingBodyLength);

                // Add callback with deserialize from stream
                operationCallbacks.AddLast(CreateResponseAction(serializer, header, callback));

                offset += remainingBodyLength;
            }

            // Invoke callbacks with read stream
            return(Connection.InvokeReadCallbacks(stream, operationCallbacks, GetTimestamp()));
        }
示例#2
0
        /// <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;
                    }
                    Connection.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(Connection.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(Connection.InvokeReadCallbacks(stream, operationCallbacks));
        }