Ejemplo n.º 1
0
        private void DispatchEvent(EpoxyHeaders headers, ArraySegment <byte> payload, ArraySegment <byte> layerData)
        {
            if (headers.error_code != (int)ErrorCode.OK)
            {
                Log.Error("{0}.{1}: Received event with a non-zero error code. Conversation ID: {2}",
                          this, nameof(DispatchEvent), headers.conversation_id);
                return;
            }

            IMessage request = Message.FromPayload(Unmarshal.From(payload));

            var receiveContext = new EpoxyReceiveContext(this);

            IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

            Error layerError = LayerStackUtils.ProcessOnReceive(parentTransport.LayerStack, MessageType.Event, receiveContext, bondedLayerData);

            if (layerError != null)
            {
                Log.Error("{0}.{1}: Receiving event {2}/{3} failed due to layer error (Code: {4}, Message: {5}).",
                          this, nameof(DispatchEvent), headers.conversation_id, headers.method_name,
                          layerError.error_code, layerError.message);
                return;
            }

            Task.Run(async() =>
            {
                await serviceHost.DispatchEvent(headers.method_name, receiveContext, request, connectionMetrics);
            });
        }
Ejemplo n.º 2
0
        // These end-to-end tests cover states that don't fit in functions.

        private static void AssertHeadersEqual(EpoxyHeaders expected, EpoxyHeaders actual)
        {
            Assert.AreEqual(expected.error_code, actual.error_code);
            Assert.AreEqual(expected.method_name, actual.method_name);
            Assert.AreEqual(expected.payload_type, actual.payload_type);
            Assert.AreEqual(expected.conversation_id, actual.conversation_id);
        }
        internal static ClassifyState TransitionValidFrame(
            ClassifyState state, EpoxyHeaders headers, ref FrameDisposition disposition)
        {
            if (state != ClassifyState.ValidFrame || headers == null)
            {
                return(ClassifyState.InternalStateError);
            }

            switch (headers.message_type)
            {
            case EpoxyMessageType.REQUEST:
                disposition = FrameDisposition.DeliverRequestToService;
                return(ClassifyState.ClassifiedValidFrame);

            case EpoxyMessageType.RESPONSE:
                disposition = FrameDisposition.DeliverResponseToProxy;
                return(ClassifyState.ClassifiedValidFrame);

            case EpoxyMessageType.EVENT:
                disposition = FrameDisposition.DeliverEventToService;
                return(ClassifyState.ClassifiedValidFrame);

            default:
                return(ClassifyState.InternalStateError);
            }
        }
Ejemplo n.º 4
0
        internal static ClassifyState TransitionExpectPayload(
            ClassifyState state, Frame frame, EpoxyHeaders headers, ArraySegment <byte> layerData,
            ref ArraySegment <byte> payload, ref ProtocolErrorCode?errorCode, Logger logger)
        {
            Debug.Assert(state == ClassifyState.ExpectPayload);
            Debug.Assert(frame != null);

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

            int payloadDataIndex = (layerData.Array == null ? 1 : 2);

            if (payloadDataIndex >= frame.Count)
            {
                logger.Site().Error("Frame had headers but no payload.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            var framelet = frame.Framelets[payloadDataIndex];

            if (framelet.Type != FrameletType.PayloadData)
            {
                logger.Site().Error("Frame had headers but no payload.");
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            payload = framelet.Contents;
            logger.Site().Debug("Extracted {0}-byte payload in conversation ID {1}.",
                                payload.Count, headers.conversation_id);
            return(ClassifyState.ExpectEndOfFrame);
        }
Ejemplo n.º 5
0
        // These end-to-end tests cover states that don't fit in functions.

        private static void AssertHeadersEqual(EpoxyHeaders expected, EpoxyHeaders actual)
        {
            Assert.AreEqual(expected.conversation_id, actual.conversation_id);
            Assert.AreEqual(expected.message_type, actual.message_type);
            Assert.AreEqual(expected.service_name, actual.service_name);
            Assert.AreEqual(expected.method_name, actual.method_name);
        }
        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);
        }
Ejemplo n.º 7
0
        private void DispatchResponse(EpoxyHeaders headers, ArraySegment <byte> payload, ArraySegment <byte> layerData)
        {
            IMessage response;

            if (headers.error_code != (int)ErrorCode.OK)
            {
                response = Message.FromError(Unmarshal <Error> .From(payload));
            }
            else
            {
                response = Message.FromPayload(Unmarshal.From(payload));
            }

            var receiveContext = new EpoxyReceiveContext(this);

            IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

            Error layerError = LayerStackUtils.ProcessOnReceive(parentTransport.LayerStack, MessageType.Response, receiveContext, bondedLayerData);

            if (layerError != null)
            {
                Log.Error("{0}.{1}: Receiving response {2}/{3} failed due to layer error (Code: {4}, Message: {5}).",
                          this, nameof(DispatchResponse), headers.conversation_id, headers.method_name,
                          layerError.error_code, layerError.message);
                response = Message.FromError(layerError);
            }

            if (!responseMap.Complete(headers.conversation_id, response))
            {
                Log.Error("{0}.{1}: Response for unmatched request. Conversation ID: {2}",
                          this, nameof(DispatchResponse), headers.conversation_id);
            }
        }
        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);
        }
Ejemplo n.º 9
0
        internal static ClassifyState TransitionValidFrame(
            ClassifyState state, EpoxyHeaders headers, ref FrameDisposition disposition)
        {
            if (state != ClassifyState.ValidFrame || headers == null)
            {
                return(ClassifyState.InternalStateError);
            }

            switch (headers.payload_type)
            {
            case PayloadType.Request:
                disposition = FrameDisposition.DeliverRequestToService;
                return(ClassifyState.ClassifiedValidFrame);

            case PayloadType.Response:
                disposition = FrameDisposition.DeliverResponseToProxy;
                return(ClassifyState.ClassifiedValidFrame);

            case PayloadType.Event:
                disposition = FrameDisposition.DeliverEventToService;
                return(ClassifyState.ClassifiedValidFrame);

            default:
                return(ClassifyState.InternalStateError);
            }
        }
Ejemplo n.º 10
0
        public void TransitionExpectEpoxyHeaders_Valid()
        {
            EpoxyHeaders      headers   = null;
            ProtocolErrorCode?errorCode = null;

            var after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, goodRequestFrame, ref headers, ref errorCode, LoggerTests.BlackHole);

            Assert.AreEqual(EpoxyProtocol.ClassifyState.ExpectOptionalLayerData, after);
            Assert.NotNull(headers);
            Assert.AreEqual(GoodRequestId, headers.conversation_id);
            Assert.AreEqual(GoodService, headers.service_name);
            Assert.AreEqual(GoodMethod, headers.method_name);
            Assert.AreEqual(EpoxyMessageType.REQUEST, headers.message_type);
            Assert.Null(errorCode);

            after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, goodRequestLayerDataFrame,
                ref headers, ref errorCode, LoggerTests.BlackHole);
            Assert.AreEqual(EpoxyProtocol.ClassifyState.ExpectOptionalLayerData, after);
            Assert.NotNull(headers);
            Assert.AreEqual(GoodRequestId, headers.conversation_id);
            Assert.AreEqual(GoodService, headers.service_name);
            Assert.AreEqual(GoodMethod, headers.method_name);
            Assert.AreEqual(EpoxyMessageType.REQUEST, headers.message_type);
            Assert.Null(errorCode);
        }
Ejemplo n.º 11
0
        public void TransitionExpectEpoxyHeaders_Valid()
        {
            EpoxyHeaders      headers   = null;
            ProtocolErrorCode?errorCode = null;

            var after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, goodRequestFrame, ref headers, ref errorCode);

            Assert.AreEqual(EpoxyProtocol.ClassifyState.ExpectOptionalLayerData, after);
            Assert.NotNull(headers);
            Assert.AreEqual(GoodRequestId, headers.conversation_id);
            Assert.AreEqual(0, headers.error_code);
            Assert.AreEqual(GoodMethod, headers.method_name);
            Assert.AreEqual(PayloadType.Request, headers.payload_type);
            Assert.Null(errorCode);

            after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, goodRequestLayerDataFrame,
                ref headers, ref errorCode);
            Assert.AreEqual(EpoxyProtocol.ClassifyState.ExpectOptionalLayerData, after);
            Assert.NotNull(headers);
            Assert.AreEqual(GoodRequestId, headers.conversation_id);
            Assert.AreEqual(0, headers.error_code);
            Assert.AreEqual(GoodMethod, headers.method_name);
            Assert.AreEqual(PayloadType.Request, headers.payload_type);
            Assert.Null(errorCode);
        }
Ejemplo n.º 12
0
        private State?DispatchRequest(EpoxyHeaders headers, EpoxyProtocol.MessageData messageData, ArraySegment <byte> layerData)
        {
            Task.Run(async() =>
            {
                var totalTime      = Stopwatch.StartNew();
                var requestMetrics = Metrics.StartRequestMetrics(ConnectionMetrics);
                var receiveContext = new EpoxyReceiveContext(this, ConnectionMetrics, requestMetrics);

                ILayerStack layerStack = null;

                IMessage result;

                if (messageData.IsError)
                {
                    logger.Site().Error("{0} Received request with an error message. Only payload messages are allowed. Conversation ID: {1}",
                                        this, headers.conversation_id);
                    result = Message.FromError(new Error
                    {
                        error_code = (int)ErrorCode.INVALID_INVOCATION,
                        message    = "Received request with an error message"
                    });
                }
                else
                {
                    IMessage request        = Message.FromPayload(Unmarshal.From(messageData.Data));
                    IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

                    Error layerError = parentTransport.GetLayerStack(requestMetrics.request_id, out layerStack);

                    if (layerError == null)
                    {
                        layerError = LayerStackUtils.ProcessOnReceive(
                            layerStack, MessageType.REQUEST, receiveContext, bondedLayerData, logger);
                    }

                    if (layerError == null)
                    {
                        result = await serviceHost.DispatchRequest(headers.service_name, headers.method_name, receiveContext, request);
                    }
                    else
                    {
                        logger.Site().Error("{0} Receiving request {1}/{2}.{3} failed due to layer error (Code: {4}, Message: {5}).",
                                            this, headers.conversation_id, headers.service_name, headers.method_name,
                                            layerError.error_code, layerError.message);

                        // Set layer error as result of this Bond method call and do not dispatch to method.
                        // Since this error will be returned to client, cleanse out internal server error details, if any.
                        result = Message.FromError(Errors.CleanseInternalServerError(layerError));
                    }
                }

                await SendReplyAsync(headers.conversation_id, result, layerStack, requestMetrics);
                Metrics.FinishRequestMetrics(requestMetrics, totalTime);
                metrics.Emit(requestMetrics);
            });

            // no state change needed
            return(null);
        }
Ejemplo n.º 13
0
        internal static Frame MessageToFrame(ulong conversationId, string methodName, PayloadType type, IMessage payload, IBonded layerData, Logger logger)
        {
            var frame = new Frame(logger);

            {
                var headers = new EpoxyHeaders
                {
                    conversation_id = conversationId,
                    payload_type    = type,
                    method_name     = methodName ?? string.Empty, // method_name is not nullable
                };

                if (payload.IsError)
                {
                    headers.error_code = payload.Error.Deserialize <Error>().error_code;
                }
                else
                {
                    headers.error_code = (int)ErrorCode.OK;
                }

                const int initialHeaderBufferSize = 150;
                var       outputBuffer            = new OutputBuffer(initialHeaderBufferSize);
                var       fastWriter = new FastBinaryWriter <OutputBuffer>(outputBuffer);
                Serialize.To(fastWriter, headers);

                frame.Add(new Framelet(FrameletType.EpoxyHeaders, outputBuffer.Data));
            }

            if (layerData != null)
            {
                const int initialLayerDataBufferSize = 150;
                var       outputBuffer  = new OutputBuffer(initialLayerDataBufferSize);
                var       compactWriter = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                // TODO: See TODO below about issues with IBonded Marshal.TO(...)
                compactWriter.WriteVersion();
                layerData.Serialize(compactWriter);
                frame.Add(new Framelet(FrameletType.LayerData, outputBuffer.Data));
            }

            {
                var userData = payload.IsError ? (IBonded)payload.Error : (IBonded)payload.RawPayload;


                const int initialPayloadBufferSize = 1024;
                var       outputBuffer             = new OutputBuffer(initialPayloadBufferSize);
                var       compactWriter            = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                // TODO: marshal dies on IBonded Marshal.To(compactWriter, request)
                // understand more deeply why and consider fixing
                compactWriter.WriteVersion();
                userData.Serialize(compactWriter);

                frame.Add(new Framelet(FrameletType.PayloadData, outputBuffer.Data));
            }

            return(frame);
        }
Ejemplo n.º 14
0
        internal static Frame MessageToFrame(
            ulong conversationId,
            string serviceName,
            string methodName,
            EpoxyMessageType type,
            IMessage message,
            IBonded layerData,
            Logger logger)
        {
            var frame = new Frame(logger);

            {
                var headers = new EpoxyHeaders
                {
                    conversation_id = conversationId,
                    message_type    = type,
                    service_name    = serviceName ?? string.Empty, // service_name is not nullable
                    method_name     = methodName ?? string.Empty   // method_name is not nullable
                };

                const int initialHeaderBufferSize = 150;
                var       outputBuffer            = new OutputBuffer(initialHeaderBufferSize);
                var       fastWriter = new FastBinaryWriter <OutputBuffer>(outputBuffer);
                Serialize.To(fastWriter, headers);

                frame.Add(new Framelet(FrameletType.EpoxyHeaders, outputBuffer.Data));
            }

            if (layerData != null)
            {
                const int initialLayerDataBufferSize = 150;
                var       outputBuffer  = new OutputBuffer(initialLayerDataBufferSize);
                var       compactWriter = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                compactWriter.WriteVersion();
                layerData.Serialize(compactWriter);
                frame.Add(new Framelet(FrameletType.LayerData, outputBuffer.Data));
            }

            {
                FrameletType frameletType = message.IsError ? FrameletType.ErrorData : FrameletType.PayloadData;
                IBonded      userData     = message.IsError ? message.Error : message.RawPayload;

                const int initialMessageBufferSize = 1024;
                var       outputBuffer             = new OutputBuffer(initialMessageBufferSize);
                var       compactWriter            = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                compactWriter.WriteVersion();
                userData.Serialize(compactWriter);

                frame.Add(new Framelet(frameletType, outputBuffer.Data));
            }

            return(frame);
        }
Ejemplo n.º 15
0
        private State?DispatchRequest(EpoxyHeaders headers, ArraySegment <byte> payload, ArraySegment <byte> layerData)
        {
            if (headers.error_code != (int)ErrorCode.OK)
            {
                logger.Site().Error("{0} Received request with a non-zero error code. Conversation ID: {1}",
                                    this, headers.conversation_id);
                protocolError = ProtocolErrorCode.PROTOCOL_VIOLATED;
                return(State.SendProtocolError);
            }

            Task.Run(async() =>
            {
                var totalTime      = Stopwatch.StartNew();
                var requestMetrics = Metrics.StartRequestMetrics(ConnectionMetrics);
                var receiveContext = new EpoxyReceiveContext(this, ConnectionMetrics, requestMetrics);

                IMessage request        = Message.FromPayload(Unmarshal.From(payload));
                IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

                ILayerStack layerStack;
                Error layerError = parentTransport.GetLayerStack(requestMetrics.request_id, out layerStack);

                if (layerError == null)
                {
                    layerError = LayerStackUtils.ProcessOnReceive(
                        layerStack, MessageType.Request, receiveContext, bondedLayerData, logger);
                }

                IMessage result;

                if (layerError == null)
                {
                    result = await serviceHost.DispatchRequest(headers.method_name, receiveContext, request);
                }
                else
                {
                    logger.Site().Error("{0} Receiving request {1}/{2} failed due to layer error (Code: {3}, Message: {4}).",
                                        this, headers.conversation_id, headers.method_name,
                                        layerError.error_code, layerError.message);

                    // Set layer error as result of this Bond method call and do not dispatch to method.
                    // Since this error will be returned to client, cleanse out internal server error details, if any.
                    result = Message.FromError(Errors.CleanseInternalServerError(layerError));
                }

                await SendReplyAsync(headers.conversation_id, result, layerStack, requestMetrics);
                Metrics.FinishRequestMetrics(requestMetrics, totalTime);
                metrics.Emit(requestMetrics);
            });

            // no state change needed
            return(null);
        }
Ejemplo n.º 16
0
        internal static Frame MessageToFrame(ulong conversationId, string methodName, PayloadType type, IMessage message, IBonded layerData, Logger logger)
        {
            var frame = new Frame(logger);

            {
                var headers = new EpoxyHeaders
                {
                    conversation_id = conversationId,
                    payload_type    = type,
                    method_name     = methodName ?? string.Empty, // method_name is not nullable
                };

                if (message.IsError)
                {
                    headers.error_code = message.Error.Deserialize <Error>().error_code;
                }
                else
                {
                    headers.error_code = (int)ErrorCode.OK;
                }

                const int initialHeaderBufferSize = 150;
                var       outputBuffer            = new OutputBuffer(initialHeaderBufferSize);
                var       fastWriter = new FastBinaryWriter <OutputBuffer>(outputBuffer);
                Serialize.To(fastWriter, headers);

                frame.Add(new Framelet(FrameletType.EpoxyHeaders, outputBuffer.Data));
            }

            if (layerData != null)
            {
                const int initialLayerDataBufferSize = 150;
                var       outputBuffer  = new OutputBuffer(initialLayerDataBufferSize);
                var       compactWriter = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                compactWriter.WriteVersion();
                layerData.Serialize(compactWriter);
                frame.Add(new Framelet(FrameletType.LayerData, outputBuffer.Data));
            }

            {
                var userData = message.IsError ? (IBonded)message.Error : (IBonded)message.RawPayload;

                const int initialPayloadBufferSize = 1024;
                var       outputBuffer             = new OutputBuffer(initialPayloadBufferSize);
                var       compactWriter            = new CompactBinaryWriter <OutputBuffer>(outputBuffer);
                compactWriter.WriteVersion();
                userData.Serialize(compactWriter);

                frame.Add(new Framelet(FrameletType.PayloadData, outputBuffer.Data));
            }

            return(frame);
        }
Ejemplo n.º 17
0
        void DispatchEvent(EpoxyHeaders headers, EpoxyProtocol.MessageData messageData, ArraySegment <byte> layerData)
        {
            if (messageData.IsError)
            {
                logger.Site().Error(
                    "{0} Received event with an error message. Only payload messages are allowed. Conversation ID: {1}",
                    this,
                    headers.conversation_id);
                return;
            }

            Task.Run(
                async() =>
            {
                IMessage request   = Message.FromPayload(Unmarshal.From(messageData.Data));
                var totalTime      = Stopwatch.StartNew();
                var requestMetrics = Metrics.StartRequestMetrics(ConnectionMetrics);
                var receiveContext = new RelayEpoxyReceiveContext(this, ConnectionMetrics, requestMetrics);

                IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);
                ILayerStack layerStack;
                Error layerError = parentTransport.GetLayerStack(requestMetrics.request_id, out layerStack);

                if (layerError == null)
                {
                    layerError = LayerStackUtils.ProcessOnReceive(
                        layerStack,
                        MessageType.EVENT,
                        receiveContext,
                        bondedLayerData,
                        logger);
                }

                if (layerError != null)
                {
                    logger.Site().Error(
                        "{0}: Receiving event {1}/{2}.{3} failed due to layer error (Code: {4}, Message: {5}).",
                        this,
                        headers.conversation_id,
                        headers.service_name,
                        headers.method_name,
                        layerError.error_code,
                        layerError.message);
                    return;
                }

                await serviceHost.DispatchEvent(headers.service_name, headers.method_name, receiveContext, request);
                Metrics.FinishRequestMetrics(requestMetrics, totalTime);
                metrics.Emit(requestMetrics);
            });
        }
Ejemplo n.º 18
0
        void DispatchResponse(EpoxyHeaders headers, EpoxyProtocol.MessageData messageData, ArraySegment <byte> layerData)
        {
            IMessage response = messageData.IsError
                ? Message.FromError(Unmarshal <Error> .From(messageData.Data))
                : Message.FromPayload(Unmarshal.From(messageData.Data));

            TaskCompletionSource <IMessage> tcs = responseMap.TakeTaskCompletionSource(headers.conversation_id);

            if (tcs == null)
            {
                logger.Site().Error(
                    "{0} Response for unmatched request. Conversation ID: {1}",
                    this,
                    headers.conversation_id);
                return;
            }

            Task.Run(
                () =>
            {
                var totalTime      = Stopwatch.StartNew();
                var requestMetrics = Metrics.StartRequestMetrics(ConnectionMetrics);
                var receiveContext = new RelayEpoxyReceiveContext(this, ConnectionMetrics, requestMetrics);

                IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

                ILayerStack layerStack = tcs.Task.AsyncState as ILayerStack;

                Error layerError = LayerStackUtils.ProcessOnReceive(layerStack, MessageType.RESPONSE, receiveContext, bondedLayerData, logger);

                if (layerError != null)
                {
                    logger.Site().Error(
                        "{0} Receiving response {1}/{2}.{3} failed due to layer error (Code: {4}, Message: {5}).",
                        this,
                        headers.conversation_id,
                        headers.service_name,
                        headers.method_name,
                        layerError.error_code,
                        layerError.message);
                    response = Message.FromError(layerError);
                }

                tcs.SetResult(response);
                Metrics.FinishRequestMetrics(requestMetrics, totalTime);
                metrics.Emit(requestMetrics);
            });
        }
Ejemplo n.º 19
0
        public void TransitionExpectEpoxyHeaders_InvalidPreconditions()
        {
            EpoxyHeaders      headers   = null;
            ProtocolErrorCode?errorCode = null;

            var after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, emptyFrame, ref headers, ref errorCode, LoggerTests.BlackHole);

            Assert.AreEqual(EpoxyProtocol.ClassifyState.InternalStateError, after);
            Assert.Null(headers);
            Assert.Null(errorCode);

            after = EpoxyProtocol.TransitionExpectEpoxyHeaders(
                EpoxyProtocol.ClassifyState.ExpectEpoxyHeaders, backwardsRequestFrame, ref headers, ref errorCode, LoggerTests.BlackHole);
            Assert.AreEqual(EpoxyProtocol.ClassifyState.InternalStateError, after);
            Assert.Null(headers);
            Assert.Null(errorCode);
        }
Ejemplo n.º 20
0
        private void DispatchResponse(EpoxyHeaders headers, ArraySegment <byte> payload, ArraySegment <byte> layerData)
        {
            IMessage response;

            if (headers.error_code != (int)ErrorCode.OK)
            {
                response = Message.FromError(Unmarshal <Error> .From(payload));
            }
            else
            {
                response = Message.FromPayload(Unmarshal.From(payload));
            }

            TaskCompletionSource <IMessage> tcs = responseMap.TakeTaskCompletionSource(headers.conversation_id);

            if (tcs == null)
            {
                logger.Site().Error("{0} Response for unmatched request. Conversation ID: {1}",
                                    this, headers.conversation_id);
                return;
            }

            Task.Run(() =>
            {
                var receiveContext = new EpoxyReceiveContext(this);

                IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

                ILayerStack layerStack = tcs.Task.AsyncState as ILayerStack;

                Error layerError = LayerStackUtils.ProcessOnReceive(layerStack, MessageType.Response, receiveContext, bondedLayerData, logger);

                if (layerError != null)
                {
                    logger.Site().Error("{0} Receiving response {1}/{2} failed due to layer error (Code: {3}, Message: {4}).",
                                        this, headers.conversation_id, headers.method_name,
                                        layerError.error_code, layerError.message);
                    response = Message.FromError(layerError);
                }

                tcs.SetResult(response);
            });
        }
        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(framelet.Type == FrameletType.ErrorData, framelet.Contents);

            logger.Site().Debug(
                "Extracted {0}-byte message in conversation ID {1}.",
                messageData.Data.Count,
                headers.conversation_id);
            return(ClassifyState.ExpectEndOfFrame);
        }
Ejemplo n.º 22
0
        private State?DispatchRequest(EpoxyHeaders headers, ArraySegment <byte> payload, ArraySegment <byte> layerData)
        {
            if (headers.error_code != (int)ErrorCode.OK)
            {
                Log.Error("{0}.{1}: Received request with a non-zero error code. Conversation ID: {2}",
                          this, nameof(DispatchRequest), headers.conversation_id);
                protocolError = ProtocolErrorCode.PROTOCOL_VIOLATED;
                return(State.SendProtocolError);
            }

            IMessage request = Message.FromPayload(Unmarshal.From(payload));

            var receiveContext = new EpoxyReceiveContext(this);

            IBonded bondedLayerData = (layerData.Array == null) ? null : Unmarshal.From(layerData);

            Error layerError = LayerStackUtils.ProcessOnReceive(parentTransport.LayerStack, MessageType.Request, receiveContext, bondedLayerData);

            Task.Run(async() =>
            {
                IMessage result;

                if (layerError == null)
                {
                    result = await serviceHost.DispatchRequest(headers.method_name, receiveContext, request,
                                                               connectionMetrics);
                }
                else
                {
                    Log.Error("{0}.{1}: Receiving request {2}/{3} failed due to layer error (Code: {4}, Message: {5}).",
                              this, nameof(DispatchRequest), headers.conversation_id, headers.method_name,
                              layerError.error_code, layerError.message);
                    result = Message.FromError(layerError);
                }

                await SendReplyAsync(headers.conversation_id, result);
            });

            // no state change needed
            return(null);
        }
        internal static ClassifyState TransitionFrameComplete(
            ClassifyState state, EpoxyHeaders headers, ref ProtocolErrorCode?errorCode, Logger logger)
        {
            if (state != ClassifyState.FrameComplete || headers == null)
            {
                return(ClassifyState.InternalStateError);
            }

            switch (headers.message_type)
            {
            case EpoxyMessageType.REQUEST:
            case EpoxyMessageType.RESPONSE:
            case EpoxyMessageType.EVENT:
                return(ClassifyState.ValidFrame);

            default:
                logger.Site().Warning("Received unrecognized message type {0}.", headers.message_type);
                errorCode = ProtocolErrorCode.NOT_SUPPORTED;
                return(ClassifyState.MalformedFrame);
            }
        }
Ejemplo n.º 24
0
        internal static ClassifyState TransitionFrameComplete(
            ClassifyState state, EpoxyHeaders headers, ref ProtocolErrorCode?errorCode, Logger logger)
        {
            if (state != ClassifyState.FrameComplete || headers == null)
            {
                return(ClassifyState.InternalStateError);
            }

            switch (headers.payload_type)
            {
            case PayloadType.Request:
            case PayloadType.Response:
            case PayloadType.Event:
                return(ClassifyState.ValidFrame);

            default:
                logger.Site().Warning("Received unrecognized payload type {0}.", headers.payload_type);
                errorCode = ProtocolErrorCode.NOT_SUPPORTED;
                return(ClassifyState.MalformedFrame);
            }
        }
Ejemplo n.º 25
0
        internal static ClassifyState TransitionExpectOptionalLayerData(
            ClassifyState state, Frame frame, EpoxyHeaders headers, ref ArraySegment <byte> layerData,
            ref ProtocolErrorCode?errorCode)
        {
            Debug.Assert(state == ClassifyState.ExpectOptionalLayerData);
            Debug.Assert(frame != null);

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

            if (frame.Count < 2)
            {
                Log.Error("{0}.{1}: Frame did not continue with LayerData or PayloadData.",
                          nameof(EpoxyProtocol), nameof(TransitionExpectEpoxyHeaders));
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            if (frame.Framelets[1].Type == FrameletType.PayloadData)
            {
                return(ClassifyState.ExpectPayload);
            }

            var framelet = frame.Framelets[1];

            if (framelet.Type != FrameletType.LayerData)
            {
                Log.Error("{0}.{1}: Frame did not continue with LayerData or PayloadData.",
                          nameof(EpoxyProtocol), nameof(TransitionExpectOptionalLayerData));
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            layerData = framelet.Contents;
            Log.Debug("{0}.{1}: Extracted {2}-byte layer data in conversation ID {3}.",
                      nameof(EpoxyProtocol), nameof(TransitionExpectOptionalLayerData), layerData.Count, headers.conversation_id);
            return(ClassifyState.ExpectPayload);
        }
Ejemplo n.º 26
0
        internal static ClassifyState TransitionExpectPayload(
            ClassifyState state, Frame frame, EpoxyHeaders headers, ArraySegment <byte> layerData,
            ref ArraySegment <byte> payload, ref ProtocolErrorCode?errorCode)
        {
            Debug.Assert(state == ClassifyState.ExpectPayload);
            Debug.Assert(frame != null);

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

            int payloadDataIndex = (layerData.Array == null ? 1 : 2);

            if (payloadDataIndex >= frame.Count)
            {
                Log.Error("{0}.{1}: Frame did not continue with PayloadData.",
                          nameof(EpoxyProtocol), nameof(TransitionExpectEpoxyHeaders));
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            var framelet = frame.Framelets[payloadDataIndex];

            if (framelet.Type != FrameletType.PayloadData)
            {
                Log.Error("{0}.{1}: Frame did not continue with PayloadData.",
                          nameof(EpoxyProtocol), nameof(TransitionExpectEpoxyHeaders));
                errorCode = ProtocolErrorCode.MALFORMED_DATA;
                return(ClassifyState.MalformedFrame);
            }

            payload = framelet.Contents;
            Log.Debug("{0}.{1}: Extracted {2}-byte payload in conversation ID {3}.",
                      nameof(EpoxyProtocol), nameof(TransitionExpectPayload), payload.Count, headers.conversation_id);
            return(ClassifyState.ExpectEndOfFrame);
        }
        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
                    });
                }
            }
        }
Ejemplo n.º 28
0
        // These end-to-end tests cover states that don't fit in functions.

        private static void AssertHeadersEqual(EpoxyHeaders expected, EpoxyHeaders actual)
        {
            Assert.AreEqual(expected.conversation_id, actual.conversation_id);
            Assert.AreEqual(expected.message_type, actual.message_type);
            Assert.AreEqual(expected.service_name, actual.service_name);
            Assert.AreEqual(expected.method_name, actual.method_name);
        }
Ejemplo n.º 29
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;
        }
Ejemplo n.º 30
0
        internal static ClassifyState TransitionValidFrame(
            ClassifyState state, EpoxyHeaders headers, ref FrameDisposition disposition)
        {
            if (state != ClassifyState.ValidFrame || headers == null)
            {
                return ClassifyState.InternalStateError;
            }

            switch (headers.message_type)
            {
                case EpoxyMessageType.REQUEST:
                    disposition = FrameDisposition.DeliverRequestToService;
                    return ClassifyState.ClassifiedValidFrame;

                case EpoxyMessageType.RESPONSE:
                    disposition = FrameDisposition.DeliverResponseToProxy;
                    return ClassifyState.ClassifiedValidFrame;

                case EpoxyMessageType.EVENT:
                    disposition = FrameDisposition.DeliverEventToService;
                    return ClassifyState.ClassifiedValidFrame;

                default:
                    return ClassifyState.InternalStateError;
            }
        }
Ejemplo n.º 31
0
        internal static ClassifyState TransitionFrameComplete(
            ClassifyState state, EpoxyHeaders headers, ref ProtocolErrorCode? errorCode, Logger logger)
        {
            if (state != ClassifyState.FrameComplete || headers == null)
            {
                return ClassifyState.InternalStateError;
            }

            switch (headers.message_type)
            {
                case EpoxyMessageType.REQUEST:
                case EpoxyMessageType.RESPONSE:
                case EpoxyMessageType.EVENT:
                    return ClassifyState.ValidFrame;

                default:
                    logger.Site().Warning("Received unrecognized message type {0}.", headers.message_type);
                    errorCode = ProtocolErrorCode.NOT_SUPPORTED;
                    return ClassifyState.MalformedFrame;
            }
        }
Ejemplo n.º 32
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;
        }
Ejemplo n.º 33
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;
        }