public void ToggleSignal (string iface, string member, Delegate dlg, bool adding) { MatchRule rule = new MatchRule (); rule.MessageType = MessageType.Signal; rule.Interface = iface; rule.Member = member; rule.Path = object_path; if (adding) { if (conn.Handlers.ContainsKey (rule)) conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg); else { conn.Handlers[rule] = dlg; conn.AddMatch (rule.ToString ()); } } else { conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch (rule.ToString ()); conn.Handlers.Remove (rule); } } }
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]; MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName(mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey(rule)) { conn.Handlers[rule] = Delegate.Combine(conn.Handlers[rule], dlg); } else { conn.Handlers[rule] = dlg; conn.AddMatch(rule.ToString()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove(conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch(rule.ToString()); conn.Handlers.Remove(rule); } } 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); reader.GetValue(out errMsg); } 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; }
//this could be made more efficient public static MatchRule Parse (string text) { MatchRule r = new MatchRule (); foreach (string propStr in text.Split (',')) { string[] parts = propStr.Split ('='); if (parts.Length < 2) throw new Exception ("No equals sign found"); if (parts.Length > 2) throw new Exception ("Too many equals signs found"); string key = parts[0].Trim (); string value = parts[1].Trim (); if (!value.StartsWith ("'") || !value.EndsWith ("'")) throw new Exception ("Too many equals signs found"); value = value.Substring (1, value.Length - 2); if (key.StartsWith ("arg")) { int argnum = Int32.Parse (key.Remove (0, "arg".Length)); if (argnum < 0 || argnum > 63) throw new Exception ("arg match must be between 0 and 63 inclusive"); if (r.Args.ContainsKey (argnum)) return null; r.Args[argnum] = value; continue; } //TODO: more consistent error handling switch (key) { case "type": if (r.MessageType != null) return null; r.MessageType = MessageFilter.StringToMessageType (value); break; case "interface": if (r.Interface != null) return null; r.Interface = value; break; case "member": if (r.Member != null) return null; r.Member = value; break; case "path": if (r.Path != null) return null; r.Path = new ObjectPath (value); break; case "sender": if (r.Sender != null) return null; r.Sender = value; break; case "destination": if (r.Destination != null) return null; r.Destination = value; break; default: if (Protocol.Verbose) Console.Error.WriteLine ("Warning: Unrecognized match rule key: " + key); break; } } return r; }
//this could be made more efficient public static MatchRule Parse(string text) { MatchRule r = new MatchRule(); foreach (string propStr in text.Split(',')) { string[] parts = propStr.Split('='); if (parts.Length < 2) { throw new Exception("No equals sign found"); } if (parts.Length > 2) { throw new Exception("Too many equals signs found"); } string key = parts[0].Trim(); string value = parts[1].Trim(); if (!value.StartsWith("'") || !value.EndsWith("'")) { throw new Exception("Too many equals signs found"); } value = value.Substring(1, value.Length - 2); if (key.StartsWith("arg")) { int argnum = Int32.Parse(key.Remove(0, "arg".Length)); if (argnum < 0 || argnum > 63) { throw new Exception("arg match must be between 0 and 63 inclusive"); } if (r.Args.ContainsKey(argnum)) { return(null); } r.Args[argnum] = value; continue; } //TODO: more consistent error handling switch (key) { case "type": if (r.MessageType != null) { return(null); } r.MessageType = MessageFilter.StringToMessageType(value); break; case "interface": if (r.Interface != null) { return(null); } r.Interface = value; break; case "member": if (r.Member != null) { return(null); } r.Member = value; break; case "path": if (r.Path != null) { return(null); } r.Path = new ObjectPath(value); break; case "sender": if (r.Sender != null) { return(null); } r.Sender = value; break; case "destination": if (r.Destination != null) { return(null); } r.Destination = value; break; default: if (Protocol.Verbose) { Console.Error.WriteLine("Warning: Unrecognized match rule key: " + key); } break; } } return(r); }
//this might need reworking with MulticastDelegate internal void HandleSignal(Message msg) { Signal signal = new Signal(msg); //TODO: this is a hack, not necessary when MatchRule is complete MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Fields.Add(FieldCode.Interface, new MatchTest(signal.Interface)); rule.Fields.Add(FieldCode.Member, new MatchTest(signal.Member)); rule.Fields.Add(FieldCode.Path, new MatchTest(signal.Path)); Delegate dlg; if (Handlers.TryGetValue(rule, out dlg)) { MethodInfo mi = dlg.GetType().GetMethod("Invoke"); bool compatible = false; Signature inSig, outSig; if (TypeImplementer.SigsForMethod(mi, out inSig, out outSig)) { if (outSig == Signature.Empty && inSig == msg.Signature) { compatible = true; } } if (!compatible) { if (Protocol.Verbose) { Console.Error.WriteLine("Signal argument mismatch: " + signal.Interface + '.' + signal.Member); } return; } try { //signals have no return value dlg.DynamicInvoke(MessageHelper.GetDynamicValues(msg, mi.GetParameters())); } catch (MemberAccessException) { throw; } catch (TargetInvocationException) { if (Protocol.Verbose) { Console.Error.WriteLine("Error: Signal handler threw exception " + signal.Member); } } } else { //TODO: how should we handle this condition? sending an Error may not be appropriate in this case if (Protocol.Verbose) { Console.Error.WriteLine("Warning: No signal handler for " + signal.Member); } } }
internal void HandleMessage(Message msg) { if (msg == null) { return; } //List<Connection> recipients = new List<Connection> (); HashSet <Connection> recipients = new HashSet <Connection> (); //HashSet<Connection> recipientsAll = new HashSet<Connection> (Connections); object fieldValue = msg.Header[FieldCode.Destination]; if (fieldValue != null) { string destination = (string)fieldValue; Connection destConn; if (Names.TryGetValue(destination, out destConn)) { recipients.Add(destConn); } else if (destination != DBusBusName && !destination.StartsWith(":") && (msg.Header.Flags & HeaderFlag.NoAutoStart) != HeaderFlag.NoAutoStart) { // Attempt activation StartProcessNamed(destination); //Thread.Sleep (5000); // TODO: Route the message to the newly activated service! activationMessages[destination] = msg; //if (Names.TryGetValue (destination, out destConn)) // recipients.Add (destConn); //else // Console.Error.WriteLine ("Couldn't route message to activated service"); } else if (destination != DBusBusName) { // Send an error when there's no hope of getting the requested reply if (msg.ReplyExpected) { // Error org.freedesktop.DBus.Error.ServiceUnknown: The name {0} was not provided by any .service files Message rmsg = MessageHelper.CreateUnknownMethodError(new MethodCall(msg)); if (rmsg != null) { //Caller.Send (rmsg); Caller.SendReal(rmsg); return; } } } } HashSet <Connection> recipientsMatchingHeader = new HashSet <Connection> (); HashSet <ArgMatchTest> a = new HashSet <ArgMatchTest> (); foreach (KeyValuePair <MatchRule, List <Connection> > pair in Rules) { if (recipients.IsSupersetOf(pair.Value)) { continue; } if (pair.Key.MatchesHeader(msg)) { a.UnionWith(pair.Key.Args); recipientsMatchingHeader.UnionWith(pair.Value); } } MatchRule.Test(a, msg); foreach (KeyValuePair <MatchRule, List <Connection> > pair in Rules) { if (recipients.IsSupersetOf(pair.Value)) { continue; } if (!recipientsMatchingHeader.IsSupersetOf(pair.Value)) { continue; } if (a.IsSupersetOf(pair.Key.Args)) { recipients.UnionWith(pair.Value); } } foreach (Connection conn in recipients) { // TODO: rewrite/don't header fields //conn.Send (msg); // TODO: Zero the Serial or not? //msg.Header.Serial = 0; ((ServerConnection)conn).SendReal(msg); } }
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]; MatchRule rule = new MatchRule (); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName (mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey (rule)) conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg); else { conn.Handlers[rule] = dlg; conn.AddMatch (rule.ToString ()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch (rule.ToString ()); conn.Handlers.Remove (rule); } } 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); reader.GetValue (out errMsg); } 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; }
public static MatchRule Parse(string text) { if (text.Length > Protocol.MaxMatchRuleLength) { throw new Exception("Match rule length exceeds maximum " + Protocol.MaxMatchRuleLength + " characters"); } MatchRule r = new MatchRule(); // TODO: Stricter validation. Tighten up the regex. // It currently succeeds and silently drops malformed test parts. for (Match m = matchRuleRegex.Match(text); m.Success; m = m.NextMatch()) { string key = m.Groups[1].Value; string value = m.Groups[2].Value; // This unescaping may not be perfect.. value = value.Replace(@"\\", @"\"); value = value.Replace(@"\'", @"'"); if (key.StartsWith("arg")) { Match mArg = argNRegex.Match(key); if (!mArg.Success) { return(null); } int argNum = (int)UInt32.Parse(mArg.Groups[1].Value); if (argNum < 0 || argNum >= Protocol.MaxMatchRuleArgs) { throw new Exception("arg match must be between 0 and " + (Protocol.MaxMatchRuleArgs - 1) + " inclusive"); } //if (r.Args.ContainsKey (argNum)) // return null; string argType = mArg.Groups[2].Value; if (argType == "path") { r.Args.Add(new ArgMatchTest(argNum, new ObjectPath(value))); } else { r.Args.Add(new ArgMatchTest(argNum, value)); } continue; } //TODO: more consistent error handling switch (key) { case "type": if (r.MessageType != null) { return(null); } r.MessageType = MessageFilter.StringToMessageType(value); break; case "interface": r.Fields[FieldCode.Interface] = new MatchTest(value); break; case "member": r.Fields[FieldCode.Member] = new MatchTest(value); break; case "path": r.Fields[FieldCode.Path] = new MatchTest(new ObjectPath(value)); break; case "sender": r.Fields[FieldCode.Sender] = new MatchTest(value); break; case "destination": r.Fields[FieldCode.Destination] = new MatchTest(value); break; default: if (Protocol.Verbose) { Console.Error.WriteLine("Warning: Unrecognized match rule key: " + key); } break; } } return(r); }
public static MatchRule Parse(string text) { if (text.Length > Protocol.MaxMatchRuleLength) throw new Exception ("Match rule length exceeds maximum " + Protocol.MaxMatchRuleLength + " characters"); MatchRule r = new MatchRule (); // TODO: Stricter validation. Tighten up the regex. // It currently succeeds and silently drops malformed test parts. for (Match m = matchRuleRegex.Match (text) ; m.Success ; m = m.NextMatch ()) { string key = m.Groups[1].Value; string value = m.Groups[2].Value; // This unescaping may not be perfect.. value = value.Replace (@"\\", @"\"); value = value.Replace (@"\'", @"'"); if (key.StartsWith ("arg")) { Match mArg = argNRegex.Match (key); if (!mArg.Success) return null; int argNum = (int)UInt32.Parse (mArg.Groups[1].Value); if (argNum < 0 || argNum >= Protocol.MaxMatchRuleArgs) throw new Exception ("arg match must be between 0 and " + (Protocol.MaxMatchRuleArgs - 1) + " inclusive"); //if (r.Args.ContainsKey (argNum)) // return null; string argType = mArg.Groups[2].Value; if (argType == "path") r.Args.Add (new ArgMatchTest (argNum, new ObjectPath (value))); else r.Args.Add (new ArgMatchTest (argNum, value)); continue; } //TODO: more consistent error handling switch (key) { case "type": if (r.MessageType != null) return null; r.MessageType = MessageFilter.StringToMessageType (value); break; case "interface": r.Fields[FieldCode.Interface] = new MatchTest (value); break; case "member": r.Fields[FieldCode.Member] = new MatchTest (value); break; case "path": r.Fields[FieldCode.Path] = new MatchTest (new ObjectPath (value)); break; case "sender": r.Fields[FieldCode.Sender] = new MatchTest (value); break; case "destination": r.Fields[FieldCode.Destination] = new MatchTest (value); break; default: if (Protocol.Verbose) Console.Error.WriteLine ("Warning: Unrecognized match rule key: " + key); break; } } return r; }