Exemple #1
0
        public void Frame_Add_FrameletsCanBeRetreived()
        {
            var AnyOtherContents = new ArraySegment<byte>(new[] {(byte)0x00});

            var expectedFramelets = new[]
            {
                new Framelet(FrameletType.EpoxyConfig, AnyContents),
                new Framelet(FrameletType.EpoxyConfig, AnyOtherContents),
                new Framelet(FrameletType.LayerData, AnyContents),
                new Framelet(FrameletType.EpoxyConfig, AnyContents),
            };

            var frame = new Frame(4, LoggerTests.BlackHole);
            frame.Add(new Framelet(FrameletType.EpoxyConfig, AnyContents));
            frame.Add(new Framelet(FrameletType.EpoxyConfig, AnyOtherContents));
            frame.Add(new Framelet(FrameletType.LayerData, AnyContents));
            frame.Add(new Framelet(FrameletType.EpoxyConfig, AnyContents));

            Assert.AreEqual(4, frame.Count);
            Assert.AreEqual(frame.Framelets.Count, frame.Count);
            CollectionAssert.AreEqual(expectedFramelets, frame.Framelets);
        }
Exemple #2
0
        public async Task Frame_RoundTrip_Works()
        {
            var expectedFramelets = new[]
            {
                new Framelet(FrameletType.EpoxyConfig, AnyContents),
                new Framelet(FrameletType.LayerData, AnyContents),
                new Framelet(FrameletType.EpoxyConfig, AnyContents),
            };

            var frame = new Frame(LoggerTests.BlackHole);
            foreach (var framelet in expectedFramelets)
            {
                frame.Add(framelet);
            }

            var memStream = new MemoryStream();
            await frame.WriteAsync(memStream);

            memStream.Seek(0, SeekOrigin.Begin);
            var resultFrame = await Frame.ReadAsync(memStream, CancellationToken.None, LoggerTests.BlackHole);

            CollectionAssert.AreEqual(expectedFramelets, resultFrame.Framelets, DeepFrameletComparer.Instance);
        }
Exemple #3
0
        public void Frame_default_ctor_DoesntThrow()
        {
            var frame = new Frame(LoggerTests.BlackHole);

            Assert.AreEqual(0, frame.Count);
            CollectionAssert.IsEmpty(frame.Framelets);
        }
Exemple #4
0
 public void Frame_WriteAsync_EmptyFrame_Throws()
 {
     var frame = new Frame(LoggerTests.BlackHole);
     Assert.Throws<InvalidOperationException>(async () => await frame.WriteAsync(new MemoryStream()));
 }
Exemple #5
0
        public async Task Frame_WriteAsync_OneFramelet_ContentsExpected()
        {
            var frame = new Frame(LoggerTests.BlackHole);
            frame.Add(new Framelet(FrameletType.EpoxyConfig, AnyContents));

            var memStream = new MemoryStream();
            await frame.WriteAsync(memStream);

            var expectedBytes = new[]
            {
                0x01, 0x00, // frame count
                0x43, 0x47, // EpoxyConfig framelet type
                0x04, 0x00, 0x00, 0x00, // framelet length
                0x62, 0x6F, 0x6E, 0x64 // AnyContents bytes
            };
            CollectionAssert.AreEqual(expectedBytes, memStream.ToArray());
        }
Exemple #6
0
        internal static ClassifyState TransitionExpectFirstFramelet(
            ClassifyState state, Frame frame, ref ProtocolErrorCode? errorCode, Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectFirstFramelet);
            Debug.Assert(frame != null);

            if (frame.Framelets.Count == 0)
            {
                logger.Site().Error("Frame was empty.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }

            switch (frame.Framelets[0].Type)
            {
                case FrameletType.EpoxyHeaders:
                    return ClassifyState.ExpectEpoxyHeaders;

                case FrameletType.EpoxyConfig:
                    return ClassifyState.ExpectConfig;

                case FrameletType.ProtocolError:
                    return ClassifyState.ExpectProtocolError;

                default:
                    logger.Site().Error("Frame began with invalid FrameletType {0}.", frame.Framelets[0].Type);
                    errorCode = ProtocolErrorCode.MALFORMED_DATA;
                    return ClassifyState.MalformedFrame;
            }
        }
Exemple #7
0
        public void Frame_Add_AddMoreThanInt32TotalSize_Throws()
        {
            var largeContents = new ArraySegment<byte>(new byte[2 * 65535]);
            int numFramesToAdd = Int32.MaxValue/largeContents.Count;

            var frame = new Frame(numFramesToAdd, LoggerTests.BlackHole);
            for (int i = 0; i < numFramesToAdd - 1; ++i)
            {
                frame.Add(new Framelet(FrameletType.LayerData, largeContents));
            }

            Assert.That(
                () => frame.Add(new Framelet(FrameletType.LayerData, largeContents)),
                Throws.InvalidOperationException.With.Message.ContainsSubstring("Exceeded maximum size of frame"));
        }
Exemple #8
0
        internal static ClassifyState TransitionExpectProtocolError(
            ClassifyState state, Frame frame, ref ProtocolError error, ref FrameDisposition disposition, Logger logger)
        {
            if (state != ClassifyState.ExpectProtocolError || frame == null || frame.Count == 0
                || frame.Framelets[0].Type != FrameletType.ProtocolError)
            {
                return ClassifyState.InternalStateError;
            }

            if (frame.Count > 1)
            {
                logger.Site().Error("Protocol error frame had trailing framelets.");
                return ClassifyState.ErrorInErrorFrame;
            }

            var framelet = frame.Framelets[0];

            var inputBuffer = new InputBuffer(framelet.Contents);
            var fastBinaryReader = new FastBinaryReader<InputBuffer>(inputBuffer, version: 1);
            switch (errorDeserializer.TryDeserialize(fastBinaryReader, out error))
            {
                case Deserialize.Result.Success:
                    break;

                default:
                    logger.Site().Error("Didn't get a valid {0}.", nameof(ProtocolError));
                    return ClassifyState.ErrorInErrorFrame;
            }

            logger.Site().Debug("Deserialized {0} with code {1}.", nameof(ProtocolError), error.error_code);
            disposition = FrameDisposition.HandleProtocolError;
            return ClassifyState.ClassifiedValidFrame;
        }
Exemple #9
0
        public void Frame_Add_TotalCount_Updated()
        {
            var frame = new Frame(2, LoggerTests.BlackHole);

            int expectedSize = 2;
            Assert.AreEqual(expectedSize, frame.TotalSize);

            frame.Add(new Framelet(FrameletType.LayerData, AnyContents));
            expectedSize += 2 + 4 + AnyContents.Count;
            Assert.AreEqual(expectedSize, frame.TotalSize);

            frame.Add(new Framelet(FrameletType.ProtocolError, AnyContents));
            expectedSize += 2 + 4 + AnyContents.Count;
            Assert.AreEqual(expectedSize, frame.TotalSize);
        }
Exemple #10
0
        internal static ClassifyState TransitionExpectEndOfFrame(
            ClassifyState state, Frame frame, ArraySegment<byte> layerData, ref ProtocolErrorCode? errorCode,
            Logger logger)
        {
            // FIXME: Change all of these to asserts.
            if (state != ClassifyState.ExpectEndOfFrame || frame == null)
            {
                return ClassifyState.InternalStateError;
            }

            var validFrameSize = (layerData.Array == null ? 2 : 3);
            if (frame.Count == validFrameSize)
            {
                return ClassifyState.FrameComplete;
            }
            else
            {
                logger.Site().Error("Frame had trailing framelets.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }
        }
Exemple #11
0
        internal static ClassifyState TransitionExpectConfig(
            ClassifyState state, Frame frame, ref ProtocolErrorCode? errorCode, ref FrameDisposition disposition,
            Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectConfig);
            Debug.Assert(frame != null);

            if (frame.Count == 0 || frame.Framelets[0].Type != FrameletType.EpoxyConfig)
            {
                return ClassifyState.InternalStateError;
            }

            if (frame.Count != 1)
            {
                logger.Site().Error("Config frame had trailing framelets.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }

            var framelet = frame.Framelets[0];

            var inputBuffer = new InputBuffer(framelet.Contents);
            var fastBinaryReader = new FastBinaryReader<InputBuffer>(inputBuffer, version: 1);

            // We don't currently do anything with the config aside from try to deserialize it.
            EpoxyConfig config;
            switch (configDeserializer.TryDeserialize(fastBinaryReader, out config))
            {
                case Deserialize.Result.Success:
                    break;

                default:
                    logger.Site().Error("Didn't get a valid {0}.", nameof(EpoxyConfig));
                    errorCode = ProtocolErrorCode.MALFORMED_DATA;
                    return ClassifyState.MalformedFrame;
            }

            disposition = FrameDisposition.ProcessConfig;
            return ClassifyState.ClassifiedValidFrame;
        }
Exemple #12
0
        internal static ClassifyState TransitionExpectMessageData(
            ClassifyState state, Frame frame, EpoxyHeaders headers, ArraySegment<byte> layerData,
            ref MessageData messageData, ref ProtocolErrorCode? errorCode, Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectMessageData);
            Debug.Assert(frame != null);

            if (headers == null)
            {
                return ClassifyState.InternalStateError;
            }

            int messageDataIndex = (layerData.Array == null ? 1 : 2);
            if (messageDataIndex >= frame.Count)
            {
                logger.Site().Error("Frame had headers but no message data.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }

            var framelet = frame.Framelets[messageDataIndex];
            if (framelet.Type != FrameletType.PayloadData && framelet.Type != FrameletType.ErrorData)
            {
                logger.Site().Error("Frame had headers but no message data. Unexpected framelet type {0}", (int)framelet.Type);
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }

            messageData = new MessageData(
                isError: framelet.Type == FrameletType.ErrorData,
                data: framelet.Contents);

            logger.Site().Debug("Extracted {0}-byte message in conversation ID {1}.",
                messageData.Data.Count, headers.conversation_id);
            return ClassifyState.ExpectEndOfFrame;
        }
Exemple #13
0
        internal static ClassifyState TransitionExpectOptionalLayerData(
            ClassifyState state, Frame frame, EpoxyHeaders headers, ref ArraySegment<byte> layerData,
            ref ProtocolErrorCode? errorCode, Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectOptionalLayerData);
            Debug.Assert(frame != null);

            if (headers == null)
            {
                return ClassifyState.InternalStateError;
            }

            if (frame.Count < 2)
            {
                logger.Site().Error("Frame had headers but no message data.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return ClassifyState.MalformedFrame;
            }

            var framelet = frame.Framelets[1];
            if (framelet.Type == FrameletType.LayerData)
            {
                layerData = framelet.Contents;
                logger.Site().Debug("Extracted {0}-byte layer data in conversation ID {1}.",
                    layerData.Count, headers.conversation_id);
            }

            return ClassifyState.ExpectMessageData;
        }
Exemple #14
0
        internal static ClassifyState TransitionExpectEpoxyHeaders(
            ClassifyState state, Frame frame, ref EpoxyHeaders headers, ref ProtocolErrorCode? errorCode, Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectEpoxyHeaders);
            Debug.Assert(frame != null);

            if (frame.Count == 0 || frame.Framelets[0].Type != FrameletType.EpoxyHeaders)
            {
                return ClassifyState.InternalStateError;
            }

            var framelet = frame.Framelets[0];
            var inputBuffer = new InputBuffer(framelet.Contents);
            var fastBinaryReader = new FastBinaryReader<InputBuffer>(inputBuffer, version: 1);
            switch (headersDeserializer.TryDeserialize(fastBinaryReader, out headers))
            {
                case Deserialize.Result.Success:
                    break;

                default:
                    logger.Site().Error("Didn't get a valid {0}.", nameof(EpoxyHeaders));
                    errorCode = ProtocolErrorCode.MALFORMED_DATA;
                    return ClassifyState.MalformedFrame;
            }

            logger.Site().Debug("Deserialized {0} with conversation ID {1} and message type {2}.",
                nameof(EpoxyHeaders), headers.conversation_id, headers.message_type);
            return ClassifyState.ExpectOptionalLayerData;
        }
Exemple #15
0
        public static async Task<Frame> ReadAsync(Stream stream, CancellationToken ct, Logger logger)
        {
            try
            {
                var frameletCount = await ReadUInt16Async(stream, ct);
                if (frameletCount == 0)
                {
                    throw new EpoxyProtocolErrorException("Zero framelets");
                }

                var frame = new Frame(frameletCount, logger);

                while (frameletCount > 0)
                {
                    if (ct.IsCancellationRequested)
                    {
                        return null;
                    }

                    var frameletType = await ReadUInt16Async(stream, ct);
                    if (!Framelet.IsKnownType(frameletType))
                    {
                        throw new EpoxyProtocolErrorException("Unknown framelet type: " + frameletType);
                    }

                    var frameletLength = await ReadUInt32Async(stream, ct);
                    if (frameletLength > int.MaxValue)
                    {
                        throw new EpoxyProtocolErrorException("Framelet too big: " + frameletLength);
                    }

                    byte[] frameletContents = await ReadBufferAsync(stream, unchecked((int)frameletLength), ct);
                    frame.Add(new Framelet((FrameletType)frameletType, new ArraySegment<byte>(frameletContents)));

                    --frameletCount;
                }

                return frame;
            }
            catch (Exception ex) when (ex is OperationCanceledException || ex is EndOfStreamException || ex is ObjectDisposedException)
            {
                return null;
            }
        }
Exemple #16
0
        public void Frame_Add_AddMoreThanUInt16Framelets_Throws()
        {
            var frame = new Frame((int)UInt16.MaxValue + 1, LoggerTests.BlackHole);
            for (int i = 0; i < UInt16.MaxValue; ++i)
            {
                frame.Add(new Framelet(FrameletType.LayerData, AnyContents));
            }

            Assert.That(
                () => frame.Add(new Framelet(FrameletType.PayloadData, AnyContents)),
                Throws.InvalidOperationException.With.Message.ContainsSubstring("Exceeded maximum allowed count of framelets"));
        }
Exemple #17
0
        public static void CreateFrames()
        {
            // Set up the non-empty layer data we'll use.
            Bond.IBonded goodLayerObject = new Bond.Bonded<Dummy>(dummyObject);
            var outputBuffer = new OutputBuffer();
            var compactWriter = new CompactBinaryWriter<OutputBuffer>(outputBuffer);
            compactWriter.WriteVersion();
            goodLayerObject.Serialize(compactWriter);
            goodLayerData = outputBuffer.Data;

            // Good frames, from which we can pull good framelets to build bad frames.
            goodRequestFrame = EpoxyConnection.MessageToFrame(
                GoodRequestId, GoodService, GoodMethod, EpoxyMessageType.REQUEST, meaninglessPayload, null, LoggerTests.BlackHole);
            goodRequestLayerDataFrame = EpoxyConnection.MessageToFrame(
                GoodRequestId, GoodService, GoodMethod, EpoxyMessageType.REQUEST, meaninglessPayload, goodLayerObject, LoggerTests.BlackHole);

            goodResponseFrame = EpoxyConnection.MessageToFrame(
                GoodResponseId, GoodService, GoodMethod, EpoxyMessageType.RESPONSE, meaninglessPayload, null, LoggerTests.BlackHole);
            goodErrorResponseFrame = EpoxyConnection.MessageToFrame(
                GoodResponseId, GoodService, GoodMethod, EpoxyMessageType.RESPONSE, meaninglessError, null, LoggerTests.BlackHole);

            goodEventFrame = EpoxyConnection.MessageToFrame(
                GoodRequestId, GoodService, GoodMethod, EpoxyMessageType.EVENT, meaninglessPayload, null, LoggerTests.BlackHole);

            configFrame = EpoxyConnection.MakeConfigFrame(LoggerTests.BlackHole);
            protocolErrorFrame = EpoxyConnection.MakeProtocolErrorFrame(MeaninglessErrorCode, null, LoggerTests.BlackHole);

            var goodFrameletCount = goodRequestFrame.Count;

            // Bad frames made of good framelets.
            shortRequestFrame = new Frame(goodFrameletCount - 1, LoggerTests.BlackHole);
            for (var i = 0; i < goodFrameletCount - 1; i++)
            {
                shortRequestFrame.Add(goodRequestFrame.Framelets[i]);
            }

            doubleHeadersRequestFrame = new Frame(goodFrameletCount + 1, LoggerTests.BlackHole);
            doubleHeadersRequestFrame.Add(goodRequestFrame.Framelets[0]);
            for (var i = 0; i < goodFrameletCount; i++)
            {
                doubleHeadersRequestFrame.Add(goodRequestFrame.Framelets[i]);
            }

            headersConfigRequestFrame = new Frame(2, LoggerTests.BlackHole);
            headersConfigRequestFrame.Add(goodRequestFrame.Framelets[0]);
            headersConfigRequestFrame.Add(configFrame.Framelets[0]);

            doublePayloadRequestFrame = new Frame(goodFrameletCount + 1, LoggerTests.BlackHole);
            for (var i = 0; i < goodFrameletCount; i++)
            {
                doublePayloadRequestFrame.Add(goodRequestFrame.Framelets[i]);
            }
            doublePayloadRequestFrame.Add(goodRequestFrame.Framelets[goodFrameletCount - 1]);

            backwardsRequestFrame = new Frame(goodFrameletCount, LoggerTests.BlackHole);
            foreach (var framelet in goodRequestFrame.Framelets.Reverse())
            {
                backwardsRequestFrame.Add(framelet);
            }

            doubleProtocolErrorFrame = EpoxyConnection.MakeProtocolErrorFrame(MeaninglessErrorCode, null, LoggerTests.BlackHole);
            doubleProtocolErrorFrame.Add(doubleProtocolErrorFrame.Framelets[0]);

            configFrameExtra = EpoxyConnection.MakeConfigFrame(LoggerTests.BlackHole);
            configFrameExtra.Add(goodRequestFrame.Framelets[0]);

            // Bad frames made of bad framelets.
            var invalidConfigData = new ArraySegment<byte>(new byte[] { 0x01 });
            configFrameBadConfigData = new Frame(1, LoggerTests.BlackHole);
            configFrameBadConfigData.Add(new Framelet(FrameletType.EpoxyConfig, invalidConfigData));
        }
Exemple #18
0
        internal static ClassifyResult Classify(Frame frame, Logger logger)
        {
            if (frame == null)
            {
                return new ClassifyResult
                {
                    Disposition = FrameDisposition.Indeterminate
                };
            }

            logger.Site().Debug("Processing {0} framelets.", frame.Count);

            var state = ClassifyState.ExpectFirstFramelet;
            var disposition = FrameDisposition.Indeterminate;
            EpoxyHeaders headers = null;
            var layerData = new ArraySegment<byte>();
            var messageData = default(MessageData);
            ProtocolError error = null;
            ProtocolErrorCode? errorCode = null;
            uint transitions = 0;
            while (true)
            {
                // If it looks like we have a bug and are looping forever, bail out of the state machine.
                if (transitions++ > maximumTransitions)
                {
                    return new ClassifyResult
                    {
                        Disposition = FrameDisposition.Indeterminate
                    };
                }

                switch (state)
                {
                    case ClassifyState.ExpectFirstFramelet:
                        state = TransitionExpectFirstFramelet(state, frame, ref errorCode, logger);
                        continue;

                    case ClassifyState.ExpectEpoxyHeaders:
                        state = TransitionExpectEpoxyHeaders(state, frame, ref headers, ref errorCode, logger);
                        continue;

                    case ClassifyState.ExpectOptionalLayerData:
                        state = TransitionExpectOptionalLayerData(state, frame, headers, ref layerData, ref errorCode, logger);
                        continue;

                    case ClassifyState.ExpectMessageData:
                        state = TransitionExpectMessageData(state, frame, headers, layerData, ref messageData, ref errorCode, logger);
                        continue;

                    case ClassifyState.ExpectEndOfFrame:
                        state = TransitionExpectEndOfFrame(state, frame, layerData, ref errorCode, logger);
                        continue;

                    case ClassifyState.FrameComplete:
                        state = TransitionFrameComplete(state, headers, ref errorCode, logger);
                        continue;

                    case ClassifyState.ValidFrame:
                        state = TransitionValidFrame(state, headers, ref disposition);
                        continue;

                    case ClassifyState.ExpectConfig:
                        state = TransitionExpectConfig(state, frame, ref errorCode, ref disposition, logger);
                        continue;

                    case ClassifyState.ExpectProtocolError:
                        state = TransitionExpectProtocolError(state, frame, ref error, ref disposition, logger);
                        continue;

                    case ClassifyState.ClassifiedValidFrame:
                        if (disposition == FrameDisposition.Indeterminate)
                        {
                            state = ClassifyState.InternalStateError;
                            continue;
                        }

                        return new ClassifyResult
                        {
                            Disposition = disposition,
                            Headers = headers,
                            LayerData = layerData,
                            MessageData = messageData,
                            Error = error
                        };

                    case ClassifyState.MalformedFrame:
                        if (errorCode == null)
                        {
                            state = ClassifyState.InternalStateError;
                            continue;
                        }

                        return new ClassifyResult
                        {
                            Disposition = FrameDisposition.SendProtocolError,
                            ErrorCode = errorCode
                        };

                    case ClassifyState.ErrorInErrorFrame:
                        return new ClassifyResult
                        {
                            Disposition = FrameDisposition.HangUp,
                            Error = new ProtocolError
                            {
                                error_code = ProtocolErrorCode.ERROR_IN_ERROR
                            }
                        };

                    case ClassifyState.InternalStateError:
                        return new ClassifyResult
                        {
                            Disposition = FrameDisposition.Indeterminate
                        };

                    default:
                        logger.Site().Error("Unhandled state {0}. Dropping frame.", state);
                        return new ClassifyResult
                        {
                            Disposition = FrameDisposition.Indeterminate
                        };
                }
            }
        }