예제 #1
0
        /// <summary>
        /// Reads the header from the buffer, using previous
        /// </summary>
        private FrameHeader ReadHeader(byte[] buffer, ref int offset, int length, int headerLength,
                                       ProtocolVersion version)
        {
            if (offset == 0)
            {
                var previousHeaderBuffer = Interlocked.Exchange(ref _minHeaderBuffer, null);
                if (previousHeaderBuffer != null)
                {
                    if (previousHeaderBuffer.Length + length < headerLength)
                    {
                        // Unlikely scenario where there were a few bytes for a header buffer and the new bytes are
                        // not enough to complete the header
                        Volatile.Write(ref _minHeaderBuffer,
                                       Utils.JoinBuffers(previousHeaderBuffer, 0, previousHeaderBuffer.Length, buffer, 0, length));
                        return(null);
                    }
                    offset += headerLength - previousHeaderBuffer.Length;
                    // Use the previous and the current buffer to build the header
                    return(FrameHeader.ParseResponseHeader(version, previousHeaderBuffer, buffer));
                }
            }
            if (length - offset < headerLength)
            {
                // There aren't enough bytes in the current buffer to read the header, store it for later
                Volatile.Write(ref _minHeaderBuffer, Utils.SliceBuffer(buffer, offset, length - offset));
                return(null);
            }
            // The header is contained in the current buffer
            var header = FrameHeader.ParseResponseHeader(version, buffer, offset);

            offset += headerLength;
            return(header);
        }
예제 #2
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>
        /// <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.
        }
예제 #3
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);
            }
            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));
        }