예제 #1
0
        public ResponseFrame(FrameHeader header, Stream body)
        {
            if (header == null) throw new ArgumentNullException("header");
            if (body == null) throw new ArgumentNullException("body");

            Header = header;
            Body = body;
        }
예제 #2
0
        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();
                }
            }
        }
예제 #4
0
        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();
                }
            }
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
 /// <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);
     };
 }
예제 #8
0
        /// <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);
        }
예제 #9
0
        /// <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();
            }
        }
예제 #10
0
 public ResponseFrame(FrameHeader header, Stream body)
 {
     Header = header;
     Body   = body;
 }
예제 #11
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;
                    }
                    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));
        }
예제 #12
0
 /// <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;
 }
예제 #13
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.
        }
예제 #14
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));
        }
예제 #15
0
 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");
 }
예제 #16
0
        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();
                }
            }
        }
예제 #17
0
 /// <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;
 }
예제 #18
0
 public ResponseFrame(FrameHeader header, Stream body)
 {
     Header = header;
     Body = body;
 }