public static void UpdateParameterCaches(RpcMethodInfo rpcMethodInfo, HashSet <Type> alreadyCheckedTypes) { MethodInfo methodInfo = rpcMethodInfo.MethodInfo; var paramsInfo = methodInfo.GetParameters(); for (int i = 0, n = paramsInfo.Length; i < n; ++i) { ParameterInfo paramInfo = paramsInfo[i]; // Store if this parameter is Nullable if (paramInfo.HasAttribute <Nullable>()) { NullableParamCache.Add(paramInfo); } Type type = paramInfo.ParameterType; UpdateType(type, alreadyCheckedTypes); } if (rpcMethodInfo.HasReturnType) { if (rpcMethodInfo.ReturnType.IsGenericType) { foreach (Type genericArg in rpcMethodInfo.ReturnType.GetGenericArguments()) { UpdateType(genericArg, alreadyCheckedTypes); } } else { UpdateType(rpcMethodInfo.ReturnType, alreadyCheckedTypes); } } }
public MessageInfo AnalyzeMessage(byte[] data, int offset, int length) { var reader = new BinaryReader(new MemoryStream(data, offset, length)); byte header = reader.ReadByte(); if ((header & ResponseTypeFlag) == 0) { byte ifaceOrdinal = header; byte methodOrdinal = reader.ReadByte(); HandlerData handlerData = _handlersData[ifaceOrdinal]; RpcMethodInfo rpcMethodInfo = handlerData.InterfaceMethods[methodOrdinal]; return(new MessageInfo { Type = MessageType.HandlerCall, InterfaceType = RpcInterface.GetRpcInterface(ifaceOrdinal), InterfaceMethodInfo = rpcMethodInfo.MethodInfo, Handler = handlerData.Handler, }); } return(new MessageInfo { Type = MessageType.CallResult, }); }
private static RpcMethodInfo GetRpcMethodInfo(MethodInfo methodInfo) { var rpcMethodInfo = new RpcMethodInfo { MethodInfo = methodInfo, ParameterTypes = methodInfo.GetParameters(), }; Type returnType = methodInfo.ReturnType; if (returnType == typeof(void)) { return(rpcMethodInfo); } if (returnType.IsGenericType) { Type genericTypeDef = returnType.GetGenericTypeDefinition(); var genericArguments = returnType.GetGenericArguments(); Type concreteGenericTypeDef; if (genericTypeDef == typeof(IFuture <>)) { concreteGenericTypeDef = typeof(Future <>); } else if (genericTypeDef == typeof(IFutureErr <>)) { concreteGenericTypeDef = typeof(FutureErr <>); } else { throw new InvalidOperationException("Invalid return type of method " + methodInfo.DeclaringType.Name + "." + methodInfo.Name + ". Allowed types are IFuture and IFutureErr type found is " + returnType.Name); } rpcMethodInfo.ReturnType = concreteGenericTypeDef.MakeGenericType(genericArguments); } else { if (returnType == typeof(IFuture)) { rpcMethodInfo.ReturnType = typeof(Future); } else if (returnType == typeof(IFutureErr)) { rpcMethodInfo.ReturnType = typeof(FutureErr); } else { throw new InvalidOperationException("Invalid return type of method " + methodInfo.DeclaringType.Name + "." + methodInfo.Name + ". Allowed types are IFuture and IFutureErr type found is " + returnType.Name); } } return(rpcMethodInfo); }
public void BeginCall(int methodOrdinal, object context) { var clientData = (ClientData)context; _currentCallMethod = clientData.InterfaceMethods[methodOrdinal]; _currentCallFuture = null; if (_currentCallMethod.HasReturnType) { _currentCallFuture = Activator.CreateInstance(_currentCallMethod.ReturnType); ++_nextCallId; if (_nextCallId >= ResponseTypeFlag) { _nextCallId = 1; } if (_resultFutures.ContainsKey(_nextCallId)) { throw new InvalidOperationException("CallId overrun."); } _resultFutures[_nextCallId] = _currentCallFuture; } _currentCallStream = new MemoryStream(64); _currentCallWriter = new BinaryWriter(_currentCallStream); _currentCallWriter.Write((byte)clientData.InterfaceOrdinal); _currentCallWriter.Write((byte)methodOrdinal); if (_currentCallFuture != null) { _currentCallWriter.Write((byte)_nextCallId); } _currentCallArg = 0; }
private void ProcessHandlerCall(BinaryReader reader, byte ifaceOrdinal, object context) { HandlerData handlerData; if (!_handlersData.TryGetValue(ifaceOrdinal, out handlerData)) { Type ifaceType = RpcInterface.GetRpcInterface(ifaceOrdinal); if (ifaceType == null) { throw new ProtocolViolationException("Unknown RPC interface ordinal received: " + ifaceOrdinal); } MethodInfo mi = RpcInterface.GetOrderedMethods(ifaceType)[reader.ReadByte()].MethodInfo; throw new ProtocolViolationException("RPC call received for " + ifaceType.FullName + "." + mi.Name + " which does not have a handler registered."); } byte methodOrdinal = reader.ReadByte(); RpcMethodInfo rpcMethodInfo = handlerData.InterfaceMethods[methodOrdinal]; MethodInfo methodInfo = rpcMethodInfo.MethodInfo; byte callId = 0; if (rpcMethodInfo.HasReturnType) { callId = reader.ReadByte(); } var paramsInfo = methodInfo.GetParameters(); var paramValues = new object[paramsInfo.Length]; for (int i = 0, n = paramValues.Length; i < n; ++i) { paramValues[i] = BinarySerializer.DeserializeParameter(reader, paramsInfo[i]); } var callContext = new HandlerCallContext { HandlerType = handlerData.RpcInterfaceType, Handler = handlerData.Handler, Method = methodInfo, CallId = callId, Context = context, }; if (OnBeforeHandlerCall != null) { OnBeforeHandlerCall(callContext); } callContext.Result = methodInfo.Invoke(handlerData.Handler, paramValues); if (callContext.Result != null && OnDataOut != null) { Type resultFutureType = callContext.Result.GetType(); var stream = new MemoryStream(64); var writer = new BinaryWriter(stream); var header = (byte)(ResponseTypeFlag | callId); writer.Write((byte)header); resultFutureType.GetMethod("Serialize", BindingFlags.NonPublic | BindingFlags.Instance) .Invoke(callContext.Result, new object[] { writer }); OnDataOut(stream.ToArray(), 0, (int)stream.Length); } if (OnAfterHandlerCall != null) { OnAfterHandlerCall(callContext); } }
// The generated code for the proxy type is like this: // // public class IBlahServiceRpcProxy : IBlahService // { // public ICallInterceptor Interceptor; // public object Context; // // public int Blah(int param1, string param2) // { // object argsArray = Interceptor.GetArgsArray(2); // argsArray[0] = param1; // argsArray[1] = param2; // return (int) Interceptor.MethodCall(0, Context, argsArray); // } // } private static Type CreateDynamicProxyType(ModuleBuilder moduleBuilder, Type type, HashSet <Type> checkedTypes) { TypeBuilder tb = moduleBuilder.DefineType(type.Name + "RpcProxy", TypeAttributes.Public); tb.AddInterfaceImplementation(type); FieldBuilder interceptorFi = tb.DefineField("Interceptor", typeof(ICallInterceptor), FieldAttributes.Public); FieldBuilder contextFi = tb.DefineField("Context", typeof(object), FieldAttributes.Public); RpcMethodInfo[] methods = GetOrderedMethods(type); MethodInfo beginCall = typeof(ICallInterceptor).GetMethod("BeginCall"); MethodInfo genericPushArg = typeof(ICallInterceptor).GetMethod("PushArg"); MethodInfo completeCall = typeof(ICallInterceptor).GetMethod("CompleteCall"); var genericPushArgMethods = new Dictionary <Type, MethodInfo>(); for (int ord = 0; ord < methods.Length; ++ord) { RpcMethodInfo rpcMethodInfo = methods[ord]; BinarySerializer.UpdateParameterCaches(rpcMethodInfo, checkedTypes); MethodInfo methodInfo = rpcMethodInfo.MethodInfo; ParameterInfo[] paramInfo = rpcMethodInfo.ParameterTypes; var paramTypes = new Type[paramInfo.Length]; for (int i = 0, n = paramInfo.Length; i < n; ++i) { paramTypes[i] = paramInfo[i].ParameterType; if (!genericPushArgMethods.ContainsKey(paramTypes[i])) { genericPushArgMethods[paramTypes[i]] = genericPushArg.MakeGenericMethod(paramTypes[i]); } } MethodBuilder mtb = tb.DefineMethod( methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, methodInfo.ReturnType, paramTypes); ILGenerator gen = mtb.GetILGenerator(); // Interceptor.BeginCall(3, Context); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Ldc_I4, ord); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, contextFi); gen.Emit(OpCodes.Callvirt, beginCall); // Call PushArg for each argument for (int i = 0, n = paramInfo.Length; i < n; ++i) { Type paramType = paramInfo[i].ParameterType; MethodInfo pushArgMi = genericPushArgMethods[paramType]; // Interceptor.PushArg(arg_i); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Ldarg, i + 1); gen.Emit(OpCodes.Callvirt, pushArgMi); } // return Interceptor.CompleteCall(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Callvirt, completeCall); if (mtb.ReturnType == typeof(void)) { gen.Emit(OpCodes.Pop); } else { gen.Emit(OpCodes.Castclass, mtb.ReturnType); } gen.Emit(OpCodes.Ret); } return(tb.CreateType()); }