public void Invoke(MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) { outArgs = new object[0]; retVal = null; exception = null; MethodInfo mi = methodBase as MethodInfo; if (mi != null && mi.IsSpecialName && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { string[] parts = methodName.Split(new char[] { '_' }, 2); string ename = parts[1]; Delegate dlg = (Delegate)inArgs[0]; ToggleSignal(Mapper.GetInterfaceName(mi), ename, dlg, parts[0] == "add"); return; } Type[] inTypes = Mapper.GetTypes(ArgDirection.In, mi.GetParameters()); Signature inSig = Signature.GetSig(inTypes); MethodCall method_call; Message callMsg; //build the outbound method call message { //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced string iface = null; if (mi != null) { iface = Mapper.GetInterfaceName(mi); } //map property accessors //TODO: this needs to be done properly, not with simple String.Replace //note that IsSpecialName is also for event accessors, but we already handled those and returned if (mi != null && mi.IsSpecialName) { methodName = methodName.Replace("get_", "Get"); methodName = methodName.Replace("set_", "Set"); } method_call = new MethodCall(object_path, iface, methodName, bus_name, inSig); callMsg = method_call.message; if (inArgs != null && inArgs.Length != 0) { MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.connection = conn; for (int i = 0; i != inTypes.Length; i++) { writer.Write(inTypes[i], inArgs[i]); } callMsg.Body = writer.ToArray(); } } //TODO: complete out parameter support /* * Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); * Signature outParmSig = Signature.GetSig (outParmTypes); * * if (outParmSig != Signature.Empty) * throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); */ Type[] outTypes = new Type[1]; outTypes[0] = mi.ReturnType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send(callMsg); return; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig(outTypes); callMsg.Header[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock(callMsg); //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues(retMsg, outTypes); if (retVals.Length != 0) { retVal = retVals[retVals.Length - 1]; } break; case MessageType.Error: //TODO: typed exceptions Error error = new Error(retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(retMsg); errMsg = reader.ReadString(); } exception = new Exception(error.ErrorName + ": " + errMsg); break; default: throw new Exception("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return; }
//not particularly efficient and needs to be generalized internal void HandleMethodCall(MessageContainer method_call) { //TODO: Ping and Introspect need to be abstracted and moved somewhere more appropriate once message filter infrastructure is complete //FIXME: these special cases are slightly broken for the case where the member but not the interface is specified in the message if (method_call.Interface == "org.freedesktop.DBus.Peer") { switch (method_call.Member) { case "Ping": Send(MessageHelper.ConstructReply(method_call)); return; case "GetMachineId": if (MachineId != UUID.Zero) { Send(MessageHelper.ConstructReply(method_call, MachineId.ToString())); return; } else { // Might want to send back an error here? } break; } } if (method_call.Interface == "org.freedesktop.DBus.Introspectable" && method_call.Member == "Introspect") { Introspector intro = new Introspector(); intro.root_path = method_call.Path; intro.WriteStart(); //FIXME: do this properly //this is messy and inefficient List <string> linkNodes = new List <string> (); int depth = method_call.Path.Decomposed.Length; foreach (ObjectPath pth in registeredObjects.Keys) { if (pth.Value == (method_call.Path.Value)) { ExportObject exo = (ExportObject)registeredObjects[pth]; exo.WriteIntrospect(intro); } else { for (ObjectPath cur = pth; cur != null; cur = cur.Parent) { if (cur.Value == method_call.Path.Value) { string linkNode = pth.Decomposed[depth]; if (!linkNodes.Contains(linkNode)) { intro.WriteNode(linkNode); linkNodes.Add(linkNode); } } } } } intro.WriteEnd(); Message reply = MessageHelper.ConstructReply(method_call, intro.Xml); Send(reply); return; } BusObject bo; if (registeredObjects.TryGetValue(method_call.Path, out bo)) { ExportObject eo = (ExportObject)bo; eo.HandleMethodCall(method_call); } else { MaybeSendUnknownMethodError(method_call); } }
public object SendMethodCallOld(string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception) { exception = null; //TODO: don't ignore retVal, exception etc. Signature inSig = String.IsNullOrEmpty(inSigStr) ? Signature.Empty : new Signature(inSigStr); MethodCall method_call = new MethodCall(object_path, iface, member, bus_name, inSig); Message callMsg = method_call.message; callMsg.Body = writer.ToArray(); //Invoke Code:: //TODO: complete out parameter support /* * Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); * Signature outParmSig = Signature.GetSig (outParmTypes); * * if (outParmSig != Signature.Empty) * throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); */ Type[] outTypes = new Type[1]; outTypes[0] = retType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send(callMsg); return(null); } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig(outTypes); callMsg.Header[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock(callMsg); object retVal = null; //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues(retMsg, outTypes); if (retVals.Length != 0) { retVal = retVals[retVals.Length - 1]; } break; case MessageType.Error: //TODO: typed exceptions Error error = new Error(retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(retMsg); errMsg = reader.ReadString(); } exception = new Exception(error.ErrorName + ": " + errMsg); break; default: throw new Exception("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return(retVal); }
//this might need reworking with MulticastDelegate internal void HandleSignal(Message msg) { var signal = MessageContainer.FromMessage(msg); //TODO: this is a hack, not necessary when MatchRule is complete MatchRule[] rules = new MatchRule[2]; rules[0] = new MatchRule(); rules[0].MessageType = MessageType.Signal; rules[0].Fields.Add(FieldCode.Interface, new MatchTest(signal.Interface)); rules[0].Fields.Add(FieldCode.Member, new MatchTest(signal.Member)); //rules[0].Fields.Add (FieldCode.Sender, new MatchTest (signal.Sender)); rules[0].Fields.Add(FieldCode.Path, new MatchTest(signal.Path)); rules[1] = new MatchRule(); rules[1].MessageType = MessageType.Signal; rules[1].Fields.Add(FieldCode.Interface, new MatchTest(signal.Interface)); rules[1].Fields.Add(FieldCode.Member, new MatchTest(signal.Member)); rules[1].Fields.Add(FieldCode.Sender, new MatchTest(signal.Sender)); rules[1].Fields.Add(FieldCode.Path, new MatchTest(signal.Path)); bool handlerFound = false; foreach (var rule in rules) { Delegate dlg; if (Handlers.TryGetValue(rule, out dlg) && dlg != null) { MethodInfo mi = dlg.GetType().GetMethod("Invoke"); bool compatible = false; Signature inSig, outSig; bool hasDisposableList; if (TypeImplementer.SigsForMethod(mi, out inSig, out outSig, out hasDisposableList)) { if (outSig == Signature.Empty && inSig == msg.Signature && !hasDisposableList) { compatible = true; } } if (!compatible) { if (ProtocolInformation.Verbose) { Console.Error.WriteLine("Signal argument mismatch: " + signal.Interface + '.' + signal.Member); } return; } //signals have no return value dlg.DynamicInvoke(MessageHelper.GetDynamicValues(msg, mi.GetParameters())); handlerFound = true; } } if (!handlerFound) { //TODO: how should we handle this condition? sending an Error may not be appropriate in this case if (ProtocolInformation.Verbose) { Console.Error.WriteLine("Warning: No signal handler for " + signal.Member); } } }