Example #1
0
        public object DecodeRpcArgument(IRpcChannel channel, IRpcObjectRepository localRepository,
                                        IRpcObjectRepository remoteRepository, IRpcSerializer serializer, RpcArgument argument, Type argumentType)
        {
            switch (argument.Type)
            {
            case RpcType.Builtin:
                if (argument.Value == null || argumentType == typeof(void))
                {
                    return(null);
                }
                if (argumentType.IsAssignableFrom(argument.Value.GetType()))
                {
                    return(argument.Value);
                }

                return(serializer.ChangeType(argument.Value, argumentType));

            case RpcType.Proxy:
                var instanceId = (int)serializer.ChangeType(argument.Value, typeof(int));
                var instance   = localRepository.GetInstance(instanceId);
                if (instance == null)
                {
                    var intfTypes = localRepository.ResolveTypes(argument.TypeId, argumentType);
                    instance = remoteRepository.GetProxyObject(channel, intfTypes, instanceId);
                }
                return(instance);

            case RpcType.Serialized:
                var type = localRepository.ResolveTypes(argument.TypeId, argumentType)[0];
                return(serializer.ChangeType(argument.Value, type));

            case RpcType.ObjectArray:
                var arrayType   = localRepository.ResolveTypes(argument.TypeId, argumentType)[0];
                var elementType = arrayType?.GetElementType() ?? throw new InvalidOperationException();
                var array       = Array.CreateInstance(elementType, (int)argument.Value);

                for (int i = 0; i < array.Length; i++)
                {
                    array.SetValue(DecodeRpcArgument(channel, localRepository, remoteRepository, serializer, argument.ArrayElements[i],
                                                     elementType), i);
                }

                return(array);

            default:
                throw new InvalidDataException();
            }
        }
Example #2
0
        protected bool HandleRemoteMessage(TChannel channel, byte[] data, RpcMessage msg)
        {
            switch (msg.Type)
            {
            case RpcMessageType.CallMethod:
            {
                Exception               resultException = null;
                RpcCallResultMessage    resultMessage;
                IRpcServerContextObject remoteRpcServerContextObject = null;
                var m = msg as RpcMethodCallMessage ?? Serializer.DeserializeMessage <RpcMethodCallMessage>(data);
                try
                {
                    LogTrace($"Received method call '{m.MethodName}' with instance id '{m.InstanceId}'");

                    var obj = LocalRepository.GetInstance(m.InstanceId);

                    MethodInfo targetMethod;
                    try
                    {
                        targetMethod = obj.GetType().GetMethod(m.MethodName,
                                                               BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                    }
                    catch (AmbiguousMatchException)
                    {
                        targetMethod = obj.GetType()
                                       .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                       .SingleOrDefault(fm =>
                                                        fm.Name == m.MethodName && fm.GetParameters().Length == m.Arguments.Length);
                    }

                    if (targetMethod == null)
                    {
                        targetMethod = FindExplicitInterfaceImplementation(obj.GetType(), m.MethodName);
                    }

                    if (targetMethod == null)
                    {
                        throw new MissingMethodException(obj.GetType().FullName, m.MethodName);
                    }

                    LogTrace($"Resolved method '{targetMethod}' on object '{obj.GetType()}'");

                    var targetParameterTypes = targetMethod.GetParameters().Select(p => p.ParameterType).ToArray();
                    var args             = new object[m.Arguments.Length];
                    var remoteRepository = GetRemoteRepository(channel);
                    var rpcChannel       = GetRpcChannelForClient(channel);
                    for (int i = 0; i < m.Arguments.Length; i++)
                    {
                        args[i] = MessageFactory.DecodeRpcArgument(rpcChannel, LocalRepository, remoteRepository,
                                                                   Serializer, m.Arguments[i], targetParameterTypes[i]);
                    }


                    remoteRpcServerContextObject = obj as IRpcServerContextObject;
                    if (remoteRpcServerContextObject != null)
                    {
                        LogTrace($"Object {m.InstanceId} implements IRpcServerContextObject, setting context");
                        remoteRpcServerContextObject.RpcChannel = channel;
                    }

                    var result = targetMethod.Invoke(obj, args);

                    LogTrace("Method called without exception.");

                    resultMessage = MessageFactory.CreateCallResultMessage(channel, LocalRepository, m, targetMethod, result);
                }
                catch (TargetInvocationException ex)
                {
                    LogTrace($"Method call resulted in exception: {ex}");
                    resultException = ex.InnerException;
                    resultMessage   = MessageFactory.CreateExceptionResultMessage(m, ex.InnerException);
                }
                catch (Exception ex)
                {
                    _logger?.LogError($"Failed to process message call: {ex}");
                    resultException = ex;
                    resultMessage   = MessageFactory.CreateExceptionResultMessage(m, ex);
                }
                finally
                {
                    if (remoteRpcServerContextObject != null)
                    {
                        LogTrace($"Object {m.InstanceId} implements IRpcServerContextObject, removing context");
                        remoteRpcServerContextObject.RpcChannel = null;
                    }
                }

                LogTrace("Serializing response.");
                byte[] response;
                try
                {
                    response = Serializer.SerializeMessage(resultMessage);
                }
                catch (Exception ex)
                {
                    if (resultMessage.Type == RpcMessageType.Exception)
                    {
                        _logger?.LogError(ex, $"Failed to serialize result exception of type '{resultException?.GetType()}'");
                        // if the exception is not serializable, do our best
                        resultMessage = MessageFactory.CreateExceptionResultMessage(m,
                                                                                    new Exception(resultException?.Message ?? "Internal Error"));
                        response = Serializer.SerializeMessage(resultMessage);
                    }
                    else
                    {
                        throw;
                    }
                }

                LogTrace("Sending response.");
                SendMessage(channel.GetStream(), response);
                LogTrace("Sent response");
                return(true);
            }

            case RpcMessageType.RemoveInstance:
            {
                var m = Serializer.DeserializeMessage <RpcRemoveInstanceMessage>(data);
                LogTrace($"Removing instance '{m.InstanceId}'");
                LocalRepository.RemoveInstance(m.InstanceId);

                var response = Serializer.SerializeMessage(new RpcMessage
                    {
                        CallId = m.CallId,
                        Type   = RpcMessageType.Ok
                    });
                SendMessage(channel.GetStream(), response);
                return(true);
            }
            }
            return(false);
        }