예제 #1
0
		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);
				}
			}
		}
예제 #2
0
        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;
        }
예제 #3
0
		//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;
		}
예제 #4
0
        //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);
        }
예제 #5
0
        //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);
                }
            }
        }
예제 #6
0
        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);
            }
        }
예제 #7
0
		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;
		}
예제 #8
0
        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;
        }