public void HandleMethodCall (MethodCall method_call) { Type type = obj.GetType (); //object retObj = type.InvokeMember (msg.Member, BindingFlags.InvokeMethod, null, obj, MessageHelper.GetDynamicValues (msg)); //TODO: there is no member name mapping for properties etc. yet MethodInfo mi = Mapper.GetMethod (type, method_call); if (mi == null) { conn.MaybeSendUnknownMethodError (method_call); return; } object retObj = null; try { object[] inArgs = MessageHelper.GetDynamicValues (method_call.message, mi.GetParameters ()); retObj = mi.Invoke (obj, inArgs); } catch (TargetInvocationException e) { if (!method_call.message.ReplyExpected) return; Exception ie = e.InnerException; //TODO: complete exception sending support Error error = new Error (Mapper.GetInterfaceName (ie.GetType ()), method_call.message.Header.Serial); error.message.Signature = new Signature (DType.String); MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.connection = conn; writer.Write (ie.Message); error.message.Body = writer.ToArray (); //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) error.message.Header.Fields[FieldCode.Destination] = method_call.Sender; conn.Send (error.message); return; } if (method_call.message.ReplyExpected) { /* object[] retObjs; if (retObj == null) { retObjs = new object[0]; } else { retObjs = new object[1]; retObjs[0] = retObj; } Message reply = ConstructReplyFor (method_call, retObjs); */ Message reply = MessageHelper.ConstructReplyFor (method_call, mi.ReturnType, retObj); conn.Send (reply); } }
//this method walks the interface tree in an undefined manner and returns the first match, or if no matches are found, null //the logic needs review and cleanup //TODO: unify member name mapping as is already done with interfaces and args public static MethodInfo GetMethod (Type type, MethodCall method_call) { foreach (MemberInfo member in Mapper.GetPublicMembers (type)) { //this could be made more efficient by using the given interface name earlier and avoiding walking through all public interfaces if (method_call.Interface != null) if (GetInterfaceName (member) != method_call.Interface) continue; MethodInfo meth = null; Type[] inTypes = null; if (member is PropertyInfo) { PropertyInfo prop = member as PropertyInfo; MethodInfo getter = prop.GetGetMethod (false); MethodInfo setter = prop.GetSetMethod (false); if (getter != null && "Get" + prop.Name == method_call.Member) { meth = getter; inTypes = Type.EmptyTypes; } else if (setter != null && "Set" + prop.Name == method_call.Member) { meth = setter; inTypes = new Type[] {prop.PropertyType}; } } else { meth = member as MethodInfo; if (meth == null) continue; if (meth.Name != method_call.Member) continue; inTypes = Mapper.GetTypes (ArgDirection.In, meth.GetParameters ()); } if (meth == null || inTypes == null) continue; Signature inSig = Signature.GetSig (inTypes); if (inSig != method_call.Signature) continue; return meth; } return null; }
public virtual void HandleMethodCall(MethodCall method_call) { Type type = obj.GetType (); //object retObj = type.InvokeMember (msg.Member, BindingFlags.InvokeMethod, null, obj, MessageHelper.GetDynamicValues (msg)); //TODO: there is no member name mapping for properties etc. yet // FIXME: Inefficient to do this on every call MethodInfo mi = Mapper.GetMethod (type, method_call); if (mi == null) { conn.MaybeSendUnknownMethodError (method_call); return; } MethodCaller2 mCaller; if (!mCallers.TryGetValue (mi, out mCaller)) { //mCaller = TypeImplementer.GenCaller (mi, obj); mCaller = TypeImplementer.GenCaller2 (mi); mCallers[mi] = mCaller; } Signature inSig, outSig; TypeImplementer.SigsForMethod (mi, out inSig, out outSig); Message msg = method_call.message; MessageReader msgReader = new MessageReader (method_call.message); MessageWriter retWriter = new MessageWriter (); /* MessageWriter retWriter = null; if (msg.ReplyExpected) retWriter = new MessageWriter (); */ Exception raisedException = null; try { //mCaller (msgReader, method_call.message, retWriter); mCaller (obj, msgReader, method_call.message, retWriter); } catch (Exception e) { raisedException = e; } if (!msg.ReplyExpected) return; Message replyMsg; if (raisedException == null) { MethodReturn method_return = new MethodReturn (msg.Header.Serial); replyMsg = method_return.message; replyMsg.Body = retWriter.ToArray (); replyMsg.Signature = outSig; } else { Error error; // BusException allows precisely formatted Error messages. BusException busException = raisedException as BusException; if (busException != null) error = method_call.CreateError (busException.ErrorName, busException.ErrorMessage); else if (raisedException is ArgumentException && raisedException.TargetSite.Name == mi.Name) { // Name match trick above is a hack since we don't have the resolved MethodInfo. ArgumentException argException = (ArgumentException)raisedException; using (System.IO.StringReader sr = new System.IO.StringReader (argException.Message)) { error = method_call.CreateError ("org.freedesktop.DBus.Error.InvalidArgs", sr.ReadLine ()); } } else error = method_call.CreateError (Mapper.GetInterfaceName (raisedException.GetType ()), raisedException.Message); replyMsg = error.message; } if (method_call.Sender != null) replyMsg.Header[FieldCode.Destination] = method_call.Sender; conn.Send (replyMsg); }
public static Message ConstructDynamicReply (MethodCall method_call, MethodInfo mi, object retVal, object[] vals) { Type retType = mi.ReturnType; MethodReturn method_return = new MethodReturn (method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature outSig = Signature.GetSig (retType); outSig += Signature.GetSig (Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ())); if (outSig != Signature.Empty) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); //first write the return value, if any if (retType != null && retType != typeof (void)) writer.Write (retType, retVal); //then write the out args WriteDynamicValues (writer, mi.GetParameters (), vals); replyMsg.Body = writer.ToArray (); } //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) replyMsg.Header.Fields[FieldCode.Destination] = method_call.Sender; replyMsg.Signature = outSig; return replyMsg; }
public static Message ConstructReply (MethodCall method_call, params object[] vals) { MethodReturn method_return = new MethodReturn (method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature inSig = Signature.GetSig (vals); if (vals != null && vals.Length != 0) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); foreach (object arg in vals) writer.Write (arg.GetType (), arg); replyMsg.Body = writer.ToArray (); } //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) replyMsg.Header.Fields[FieldCode.Destination] = method_call.Sender; replyMsg.Signature = inSig; //replyMsg.WriteHeader (); return replyMsg; }
public static Message CreateUnknownMethodError (MethodCall method_call) { if (!method_call.message.ReplyExpected) return null; string errMsg = String.Format ("Method \"{0}\" with signature \"{1}\" on interface \"{2}\" doesn't exist", method_call.Member, method_call.Signature.Value, method_call.Interface); Error error = new Error ("org.freedesktop.DBus.Error.UnknownMethod", method_call.message.Header.Serial); error.message.Signature = new Signature (DType.String); MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.Write (errMsg); error.message.Body = writer.ToArray (); //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) error.message.Header.Fields[FieldCode.Destination] = method_call.Sender; return error.message; }
public object SendMethodCall (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.Fields[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; }
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.Fields[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; }
private void FetchUiaDbusNames () { var busNames = new List<string> (); IBus ibus = Bus.Session.GetObject<IBus> (DBusName, new ObjectPath (DBusPath)); // Look for buses that contain DCI.IApplication foreach (string busName in ibus.ListNames ()) { // Reading introspection data hangs on some buses // for unknown reasons, so we call Introspect // asynchronously. Note that we are using // internal dbus-sharp classes. The old // behavior was to spin off threads, but this // triggers a Mono bug on Fedora // (BNC#628639/632133) ObjectPath op = new ObjectPath (DC.Constants.ApplicationPath); MethodCall methodCall = new MethodCall (op, "org.freedesktop.DBus.Introspectable", "Introspect", busName, Signature.Empty); PendingCall pendingCall = Bus.Session.SendWithReply (methodCall.message); pendingCall.Completed += (message) => { MessageReader reader = new MessageReader (message); string data = reader.ReadString (); if (data.Contains (DC.Constants.ApplicationInterfaceName)) busNames.Add ((string)message.Header [FieldCode.Sender]); }; } Thread.Sleep (1000); lock (uiaDbusNamesLock) uiaDbusNames = busNames; }
//TODO: merge this with the above method public static Message ConstructReplyFor (MethodCall method_call, Type retType, object retVal) { MethodReturn method_return = new MethodReturn (method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature inSig = Signature.GetSig (retType); if (inSig != Signature.Empty) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.Write (retType, retVal); replyMsg.Body = writer.ToArray (); } //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) replyMsg.Header.Fields[FieldCode.Destination] = method_call.Sender; replyMsg.Signature = inSig; //replyMsg.WriteHeader (); return replyMsg; }
//this method walks the interface tree in an undefined manner and returns the first match, or if no matches are found, null //the logic needs review and cleanup //TODO: unify member name mapping as is already done with interfaces and args public static MethodInfo GetMethod(Type type, MethodCall method_call) { foreach (MemberInfo member in Mapper.GetPublicMembers(type)) { //this could be made more efficient by using the given interface name earlier and avoiding walking through all public interfaces if (method_call.Interface != null) { if (GetInterfaceName(member) != method_call.Interface) { continue; } } MethodInfo meth = null; Type[] inTypes = null; if (member is PropertyInfo) { PropertyInfo prop = member as PropertyInfo; MethodInfo getter = prop.GetGetMethod(false); MethodInfo setter = prop.GetSetMethod(false); if (getter != null && "Get" + prop.Name == method_call.Member) { meth = getter; inTypes = Type.EmptyTypes; } else if (setter != null && "Set" + prop.Name == method_call.Member) { meth = setter; inTypes = new Type[] { prop.PropertyType }; } } else { meth = member as MethodInfo; if (meth == null) { continue; } if (meth.Name != method_call.Member) { continue; } inTypes = Mapper.GetTypes(ArgDirection.In, meth.GetParameters()); } if (meth == null || inTypes == null) { continue; } Signature inSig = Signature.GetSig(inTypes); if (inSig != method_call.Signature) { continue; } return(meth); } return(null); }
//not particularly efficient and needs to be generalized internal void HandleMethodCall(MethodCall 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" && method_call.Member == "Ping") { Message reply = MessageHelper.ConstructReply(method_call); Send(reply); return; } 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]; intro.WriteType(exo.obj.GetType()); } 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); } }
internal void HandleMessage(Message msg) { //TODO: support disconnection situations properly and move this check elsewhere if (msg == null) { throw new ArgumentNullException("msg", "Cannot handle a null message; maybe the bus was disconnected"); } { object field_value; if (msg.Header.Fields.TryGetValue(FieldCode.ReplySerial, out field_value)) { uint reply_serial = (uint)field_value; PendingCall pending; if (pendingCalls.TryGetValue(reply_serial, out pending)) { if (pendingCalls.Remove(reply_serial)) { pending.Reply = msg; } return; } //we discard reply messages with no corresponding PendingCall if (Protocol.Verbose) { Console.Error.WriteLine("Unexpected reply message received: MessageType='" + msg.Header.MessageType + "', ReplySerial=" + reply_serial); } return; } } switch (msg.Header.MessageType) { case MessageType.MethodCall: MethodCall method_call = new MethodCall(msg); HandleMethodCall(method_call); break; case MessageType.Signal: //HandleSignal (msg); lock (Inbound) Inbound.Enqueue(msg); break; case MessageType.Error: //TODO: better exception handling Error error = new Error(msg); string errMsg = String.Empty; if (msg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(msg); errMsg = reader.ReadString(); } //throw new Exception ("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg); //if (Protocol.Verbose) Console.Error.WriteLine("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg); break; case MessageType.Invalid: default: throw new Exception("Invalid message received: MessageType='" + msg.Header.MessageType + "'"); } }
public virtual void HandleMethodCall(MethodCall method_call) { Type type = obj.GetType(); //object retObj = type.InvokeMember (msg.Member, BindingFlags.InvokeMethod, null, obj, MessageHelper.GetDynamicValues (msg)); //TODO: there is no member name mapping for properties etc. yet // FIXME: Inefficient to do this on every call MethodInfo mi = Mapper.GetMethod(type, method_call); if (mi == null) { conn.MaybeSendUnknownMethodError(method_call); return; } MethodCaller2 mCaller; if (!mCallers.TryGetValue(mi, out mCaller)) { //mCaller = TypeImplementer.GenCaller (mi, obj); mCaller = TypeImplementer.GenCaller2(mi); mCallers[mi] = mCaller; } Signature inSig, outSig; TypeImplementer.SigsForMethod(mi, out inSig, out outSig); Message msg = method_call.message; MessageReader msgReader = new MessageReader(method_call.message); MessageWriter retWriter = new MessageWriter(); /* * MessageWriter retWriter = null; * if (msg.ReplyExpected) * retWriter = new MessageWriter (); */ Exception raisedException = null; try { //mCaller (msgReader, method_call.message, retWriter); mCaller(obj, msgReader, method_call.message, retWriter); } catch (Exception e) { raisedException = e; } if (!msg.ReplyExpected) { return; } Message replyMsg; if (raisedException == null) { MethodReturn method_return = new MethodReturn(msg.Header.Serial); replyMsg = method_return.message; replyMsg.Body = retWriter.ToArray(); replyMsg.Signature = outSig; } else { Error error; // BusException allows precisely formatted Error messages. BusException busException = raisedException as BusException; if (busException != null) { error = method_call.CreateError(busException.ErrorName, busException.ErrorMessage); } else if (raisedException is ArgumentException && raisedException.TargetSite.Name == mi.Name) { // Name match trick above is a hack since we don't have the resolved MethodInfo. ArgumentException argException = (ArgumentException)raisedException; using (System.IO.StringReader sr = new System.IO.StringReader(argException.Message)) { error = method_call.CreateError("org.freedesktop.DBus.Error.InvalidArgs", sr.ReadLine()); } } else { error = method_call.CreateError(Mapper.GetInterfaceName(raisedException.GetType()), raisedException.Message); } replyMsg = error.message; } if (method_call.Sender != null) { replyMsg.Header[FieldCode.Destination] = method_call.Sender; } conn.Send(replyMsg); }