1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* signals.c Bus signal connection implementation
4 * Copyright (C) 2003, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <dbus/dbus-marshal-validate.h>
32 int refcount; /**< reference count */
34 DBusConnection *matches_go_to; /**< Owner of the rule */
36 unsigned int flags; /**< BusMatchFlags */
45 unsigned int *arg_lens;
50 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u
51 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
53 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
56 bus_match_rule_new (DBusConnection *matches_go_to)
60 rule = dbus_new0 (BusMatchRule, 1);
65 rule->matches_go_to = matches_go_to;
67 #ifndef DBUS_BUILD_TESTS
68 _dbus_assert (rule->matches_go_to != NULL);
75 bus_match_rule_ref (BusMatchRule *rule)
77 _dbus_assert (rule->refcount > 0);
85 bus_match_rule_unref (BusMatchRule *rule)
87 _dbus_assert (rule->refcount > 0);
90 if (rule->refcount == 0)
92 dbus_free (rule->interface);
93 dbus_free (rule->member);
94 dbus_free (rule->sender);
95 dbus_free (rule->destination);
96 dbus_free (rule->path);
97 dbus_free (rule->arg_lens);
99 /* can't use dbus_free_string_array() since there
107 while (i < rule->args_len)
110 dbus_free (rule->args[i]);
114 dbus_free (rule->args);
121 #ifdef DBUS_ENABLE_VERBOSE_MODE
122 /* Note this function does not do escaping, so it's only
123 * good for debug spew at the moment
126 match_rule_to_string (BusMatchRule *rule)
131 if (!_dbus_string_init (&str))
134 while ((s = _dbus_strdup ("nomem")) == NULL)
135 ; /* only OK for debug spew... */
139 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
141 /* FIXME make type readable */
142 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
146 if (rule->flags & BUS_MATCH_INTERFACE)
148 if (_dbus_string_get_length (&str) > 0)
150 if (!_dbus_string_append (&str, ","))
154 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
158 if (rule->flags & BUS_MATCH_MEMBER)
160 if (_dbus_string_get_length (&str) > 0)
162 if (!_dbus_string_append (&str, ","))
166 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
170 if (rule->flags & BUS_MATCH_PATH)
172 if (_dbus_string_get_length (&str) > 0)
174 if (!_dbus_string_append (&str, ","))
178 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
182 if (rule->flags & BUS_MATCH_SENDER)
184 if (_dbus_string_get_length (&str) > 0)
186 if (!_dbus_string_append (&str, ","))
190 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
194 if (rule->flags & BUS_MATCH_DESTINATION)
196 if (_dbus_string_get_length (&str) > 0)
198 if (!_dbus_string_append (&str, ","))
202 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
206 if (rule->flags & BUS_MATCH_ARGS)
210 _dbus_assert (rule->args != NULL);
213 while (i < rule->args_len)
215 if (rule->args[i] != NULL)
217 dbus_bool_t is_path, is_namespace;
219 if (_dbus_string_get_length (&str) > 0)
221 if (!_dbus_string_append (&str, ","))
225 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
226 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
228 if (!_dbus_string_append_printf (&str,
232 is_namespace ? "namespace" : "",
241 if (!_dbus_string_steal_data (&str, &ret))
244 _dbus_string_free (&str);
248 _dbus_string_free (&str);
251 while ((s = _dbus_strdup ("nomem")) == NULL)
252 ; /* only OK for debug spew... */
256 #endif /* DBUS_ENABLE_VERBOSE_MODE */
259 bus_match_rule_set_message_type (BusMatchRule *rule,
262 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
264 rule->message_type = type;
270 bus_match_rule_set_interface (BusMatchRule *rule,
271 const char *interface)
275 _dbus_assert (interface != NULL);
277 new = _dbus_strdup (interface);
281 rule->flags |= BUS_MATCH_INTERFACE;
282 dbus_free (rule->interface);
283 rule->interface = new;
289 bus_match_rule_set_member (BusMatchRule *rule,
294 _dbus_assert (member != NULL);
296 new = _dbus_strdup (member);
300 rule->flags |= BUS_MATCH_MEMBER;
301 dbus_free (rule->member);
308 bus_match_rule_set_sender (BusMatchRule *rule,
313 _dbus_assert (sender != NULL);
315 new = _dbus_strdup (sender);
319 rule->flags |= BUS_MATCH_SENDER;
320 dbus_free (rule->sender);
327 bus_match_rule_set_destination (BusMatchRule *rule,
328 const char *destination)
332 _dbus_assert (destination != NULL);
334 new = _dbus_strdup (destination);
338 rule->flags |= BUS_MATCH_DESTINATION;
339 dbus_free (rule->destination);
340 rule->destination = new;
346 bus_match_rule_set_path (BusMatchRule *rule,
351 _dbus_assert (path != NULL);
353 new = _dbus_strdup (path);
357 rule->flags |= BUS_MATCH_PATH;
358 dbus_free (rule->path);
365 bus_match_rule_set_arg (BusMatchRule *rule,
367 const DBusString *value,
369 dbus_bool_t is_namespace)
374 _dbus_assert (value != NULL);
376 /* args_len is the number of args not including null termination
379 if (arg >= rule->args_len)
381 unsigned int *new_arg_lens;
386 new_args_len = arg + 1;
388 /* add another + 1 here for null termination */
389 new_args = dbus_realloc (rule->args,
390 sizeof (char *) * (new_args_len + 1));
391 if (new_args == NULL)
394 /* NULL the new slots */
396 while (i <= new_args_len) /* <= for null termination */
402 rule->args = new_args;
404 /* and now add to the lengths */
405 new_arg_lens = dbus_realloc (rule->arg_lens,
406 sizeof (int) * (new_args_len + 1));
408 if (new_arg_lens == NULL)
411 /* zero the new slots */
413 while (i <= new_args_len) /* <= for null termination */
419 rule->arg_lens = new_arg_lens;
420 rule->args_len = new_args_len;
423 length = _dbus_string_get_length (value);
424 if (!_dbus_string_copy_data (value, &new))
427 rule->flags |= BUS_MATCH_ARGS;
429 dbus_free (rule->args[arg]);
430 rule->arg_lens[arg] = length;
431 rule->args[arg] = new;
434 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
437 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
439 /* NULL termination didn't get busted */
440 _dbus_assert (rule->args[rule->args_len] == NULL);
441 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
446 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
449 find_key (const DBusString *str,
457 const char *key_start;
460 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
462 s = _dbus_string_get_const_data (str);
466 while (*p && ISWHITE (*p))
471 while (*p && *p != '=' && !ISWHITE (*p))
476 while (*p && ISWHITE (*p))
479 if (key_start == key_end)
481 /* Empty match rules or trailing whitespace are OK */
488 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
489 "Match rule has a key with no subsequent '=' character");
494 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
506 find_value (const DBusString *str,
518 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
520 orig_len = _dbus_string_get_length (value);
522 s = _dbus_string_get_const_data (str);
530 if (quote_char == '\0')
550 if (!_dbus_string_append_byte (value, *p))
557 else if (quote_char == '\\')
559 /* \ only counts as an escape if escaping a quote mark */
562 if (!_dbus_string_append_byte (value, '\\'))
569 if (!_dbus_string_append_byte (value, *p))
579 _dbus_assert (quote_char == '\'');
587 if (!_dbus_string_append_byte (value, *p))
601 if (quote_char == '\\')
603 if (!_dbus_string_append_byte (value, '\\'))
609 else if (quote_char == '\'')
611 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
612 "Unbalanced quotation marks in match rule");
616 _dbus_assert (quote_char == '\0');
618 /* Zero-length values are allowed */
625 _DBUS_ASSERT_ERROR_IS_SET (error);
626 _dbus_string_set_length (value, orig_len);
630 /* duplicates aren't allowed so the real legitimate max is only 6 or
631 * so. Leaving extra so we don't have to bother to update it.
632 * FIXME this is sort of busted now with arg matching, but we let
633 * you match on up to 10 args for now
635 #define MAX_RULE_TOKENS 16
637 /* this is slightly too high level to be termed a "token"
638 * but let's not be pedantic.
647 tokenize_rule (const DBusString *rule_text,
648 RuleToken tokens[MAX_RULE_TOKENS],
659 if (!_dbus_string_init (&key))
665 if (!_dbus_string_init (&value))
667 _dbus_string_free (&key);
674 while (i < MAX_RULE_TOKENS &&
675 pos < _dbus_string_get_length (rule_text))
677 _dbus_assert (tokens[i].key == NULL);
678 _dbus_assert (tokens[i].value == NULL);
680 if (!find_key (rule_text, pos, &key, &pos, error))
683 if (_dbus_string_get_length (&key) == 0)
686 if (!_dbus_string_steal_data (&key, &tokens[i].key))
692 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
695 if (!_dbus_string_steal_data (&value, &tokens[i].value))
711 while (tokens[i].key || tokens[i].value)
713 dbus_free (tokens[i].key);
714 dbus_free (tokens[i].value);
715 tokens[i].key = NULL;
716 tokens[i].value = NULL;
721 _dbus_string_free (&key);
722 _dbus_string_free (&value);
728 bus_match_rule_parse_arg_match (BusMatchRule *rule,
730 const DBusString *value,
733 dbus_bool_t is_path = FALSE;
734 dbus_bool_t is_namespace = FALSE;
740 /* For now, arg0='foo' always implies that 'foo' is a
741 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
742 * if we wanted, which would specify another type, in which case
743 * arg0='5' would have the 5 parsed as an int rather than string.
746 /* First we need to parse arg0 = 0, arg27 = 27 */
748 _dbus_string_init_const (&key_str, key);
749 length = _dbus_string_get_length (&key_str);
751 if (_dbus_string_get_length (&key_str) < 4)
753 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
754 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
758 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
760 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
761 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
767 if ((end + strlen ("path")) == length &&
768 _dbus_string_ends_with_c_str (&key_str, "path"))
772 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
778 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
779 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
784 /* If we didn't check this we could allocate a huge amount of RAM */
785 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
787 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
788 "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER);
792 if ((rule->flags & BUS_MATCH_ARGS) &&
793 rule->args_len > (int) arg &&
794 rule->args[arg] != NULL)
796 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
797 "Argument %d matched more than once in match rule\n", key);
801 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
810 _DBUS_ASSERT_ERROR_IS_SET (error);
815 * The format is comma-separated with strings quoted with single quotes
816 * as for the shell (to escape a literal single quote, use '\'').
818 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
819 * path='/bar/foo',destination=':452345.34'
823 bus_match_rule_parse (DBusConnection *matches_go_to,
824 const DBusString *rule_text,
828 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
831 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
833 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
835 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
836 "Match rule text is %d bytes, maximum is %d",
837 _dbus_string_get_length (rule_text),
838 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
842 memset (tokens, '\0', sizeof (tokens));
844 rule = bus_match_rule_new (matches_go_to);
851 if (!tokenize_rule (rule_text, tokens, error))
855 while (tokens[i].key != NULL)
859 const char *key = tokens[i].key;
860 const char *value = tokens[i].value;
862 _dbus_string_init_const (&tmp_str, value);
863 len = _dbus_string_get_length (&tmp_str);
865 if (strcmp (key, "type") == 0)
869 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
871 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
872 "Key %s specified twice in match rule\n", key);
876 t = dbus_message_type_from_string (value);
878 if (t == DBUS_MESSAGE_TYPE_INVALID)
880 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
881 "Invalid message type (%s) in match rule\n", value);
885 if (!bus_match_rule_set_message_type (rule, t))
891 else if (strcmp (key, "sender") == 0)
893 if (rule->flags & BUS_MATCH_SENDER)
895 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
896 "Key %s specified twice in match rule\n", key);
900 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
902 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
903 "Sender name '%s' is invalid\n", value);
907 if (!bus_match_rule_set_sender (rule, value))
913 else if (strcmp (key, "interface") == 0)
915 if (rule->flags & BUS_MATCH_INTERFACE)
917 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
918 "Key %s specified twice in match rule\n", key);
922 if (!_dbus_validate_interface (&tmp_str, 0, len))
924 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
925 "Interface name '%s' is invalid\n", value);
929 if (!bus_match_rule_set_interface (rule, value))
935 else if (strcmp (key, "member") == 0)
937 if (rule->flags & BUS_MATCH_MEMBER)
939 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
940 "Key %s specified twice in match rule\n", key);
944 if (!_dbus_validate_member (&tmp_str, 0, len))
946 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
947 "Member name '%s' is invalid\n", value);
951 if (!bus_match_rule_set_member (rule, value))
957 else if (strcmp (key, "path") == 0)
959 if (rule->flags & BUS_MATCH_PATH)
961 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
962 "Key %s specified twice in match rule\n", key);
966 if (!_dbus_validate_path (&tmp_str, 0, len))
968 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
969 "Path '%s' is invalid\n", value);
973 if (!bus_match_rule_set_path (rule, value))
979 else if (strcmp (key, "destination") == 0)
981 if (rule->flags & BUS_MATCH_DESTINATION)
983 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
984 "Key %s specified twice in match rule\n", key);
988 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
990 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
991 "Destination name '%s' is invalid\n", value);
995 if (!bus_match_rule_set_destination (rule, value))
1001 else if (strncmp (key, "arg", 3) == 0)
1003 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1008 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1009 "Unknown key \"%s\" in match rule",
1021 _DBUS_ASSERT_ERROR_IS_SET (error);
1024 bus_match_rule_unref (rule);
1031 while (tokens[i].key || tokens[i].value)
1033 _dbus_assert (i < MAX_RULE_TOKENS);
1034 dbus_free (tokens[i].key);
1035 dbus_free (tokens[i].value);
1042 typedef struct RulePool RulePool;
1045 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1046 DBusHashTable *rules_by_iface;
1048 /* List of BusMatchRules which don't specify an interface */
1049 DBusList *rules_without_iface;
1052 struct BusMatchmaker
1056 /* Pools of rules, grouped by the type of message they match. 0
1057 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1060 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1064 rule_list_free (DBusList **rules)
1066 while (*rules != NULL)
1070 rule = (*rules)->data;
1071 bus_match_rule_unref (rule);
1072 _dbus_list_remove_link (rules, *rules);
1077 rule_list_ptr_free (DBusList **list)
1079 /* We have to cope with NULL because the hash table frees the "existing"
1080 * value (which is NULL) when creating a new table entry...
1084 rule_list_free (list);
1090 bus_matchmaker_new (void)
1092 BusMatchmaker *matchmaker;
1095 matchmaker = dbus_new0 (BusMatchmaker, 1);
1096 if (matchmaker == NULL)
1099 matchmaker->refcount = 1;
1101 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1103 RulePool *p = matchmaker->rules_by_type + i;
1105 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1106 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1108 if (p->rules_by_iface == NULL)
1115 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1117 RulePool *p = matchmaker->rules_by_type + i;
1119 if (p->rules_by_iface == NULL)
1122 _dbus_hash_table_unref (p->rules_by_iface);
1129 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1131 const char *interface,
1136 _dbus_assert (message_type >= 0);
1137 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1139 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1141 interface != NULL ? interface : "<null>");
1143 p = matchmaker->rules_by_type + message_type;
1145 if (interface == NULL)
1147 return &p->rules_without_iface;
1153 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1155 if (list == NULL && create)
1157 char *dupped_interface;
1159 list = dbus_new0 (DBusList *, 1);
1163 dupped_interface = _dbus_strdup (interface);
1164 if (dupped_interface == NULL)
1170 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1173 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1174 dupped_interface, list))
1177 dbus_free (dupped_interface);
1187 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1189 const char *interface,
1194 if (interface == NULL)
1200 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1201 message_type, interface);
1203 p = matchmaker->rules_by_type + message_type;
1205 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1208 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1212 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1214 _dbus_assert (matchmaker->refcount > 0);
1216 matchmaker->refcount += 1;
1222 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1224 _dbus_assert (matchmaker->refcount > 0);
1226 matchmaker->refcount -= 1;
1227 if (matchmaker->refcount == 0)
1231 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1233 RulePool *p = matchmaker->rules_by_type + i;
1235 _dbus_hash_table_unref (p->rules_by_iface);
1236 rule_list_free (&p->rules_without_iface);
1239 dbus_free (matchmaker);
1243 /* The rule can't be modified after it's added. */
1245 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1250 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1252 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1254 rule->interface != NULL ? rule->interface : "<null>");
1256 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1257 rule->interface, TRUE);
1262 if (!_dbus_list_append (rules, rule))
1265 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1267 _dbus_list_remove_last (rules, rule);
1268 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1269 rule->interface, rules);
1273 bus_match_rule_ref (rule);
1275 #ifdef DBUS_ENABLE_VERBOSE_MODE
1277 char *s = match_rule_to_string (rule);
1279 _dbus_verbose ("Added match rule %s to connection %p\n",
1280 s, rule->matches_go_to);
1289 match_rule_equal (BusMatchRule *a,
1292 if (a->flags != b->flags)
1295 if (a->matches_go_to != b->matches_go_to)
1298 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1299 a->message_type != b->message_type)
1302 if ((a->flags & BUS_MATCH_MEMBER) &&
1303 strcmp (a->member, b->member) != 0)
1306 if ((a->flags & BUS_MATCH_PATH) &&
1307 strcmp (a->path, b->path) != 0)
1310 if ((a->flags & BUS_MATCH_INTERFACE) &&
1311 strcmp (a->interface, b->interface) != 0)
1314 if ((a->flags & BUS_MATCH_SENDER) &&
1315 strcmp (a->sender, b->sender) != 0)
1318 if ((a->flags & BUS_MATCH_DESTINATION) &&
1319 strcmp (a->destination, b->destination) != 0)
1322 if (a->flags & BUS_MATCH_ARGS)
1326 if (a->args_len != b->args_len)
1330 while (i < a->args_len)
1334 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1337 if (a->arg_lens[i] != b->arg_lens[i])
1340 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1342 if (a->args[i] != NULL)
1344 _dbus_assert (b->args[i] != NULL);
1345 if (memcmp (a->args[i], b->args[i], length) != 0)
1357 bus_matchmaker_remove_rule_link (DBusList **rules,
1360 BusMatchRule *rule = link->data;
1362 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1363 _dbus_list_remove_link (rules, link);
1365 #ifdef DBUS_ENABLE_VERBOSE_MODE
1367 char *s = match_rule_to_string (rule);
1369 _dbus_verbose ("Removed match rule %s for connection %p\n",
1370 s, rule->matches_go_to);
1375 bus_match_rule_unref (rule);
1379 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1384 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1386 rule->interface != NULL ? rule->interface : "<null>");
1388 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1390 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1391 rule->interface, FALSE);
1393 /* We should only be asked to remove a rule by identity right after it was
1394 * added, so there should be a list for it.
1396 _dbus_assert (rules != NULL);
1398 _dbus_list_remove (rules, rule);
1399 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1402 #ifdef DBUS_ENABLE_VERBOSE_MODE
1404 char *s = match_rule_to_string (rule);
1406 _dbus_verbose ("Removed match rule %s for connection %p\n",
1407 s, rule->matches_go_to);
1412 bus_match_rule_unref (rule);
1415 /* Remove a single rule which is equal to the given rule by value */
1417 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1418 BusMatchRule *value,
1422 DBusList *link = NULL;
1424 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1425 value->message_type,
1426 value->interface != NULL ? value->interface : "<null>");
1428 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1429 value->interface, FALSE);
1433 /* we traverse backward because bus_connection_remove_match_rule()
1434 * removes the most-recently-added rule
1436 link = _dbus_list_get_last_link (rules);
1437 while (link != NULL)
1443 prev = _dbus_list_get_prev_link (rules, link);
1445 if (match_rule_equal (rule, value))
1447 bus_matchmaker_remove_rule_link (rules, link);
1457 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1458 "The given match rule wasn't found and can't be removed");
1462 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1469 rule_list_remove_by_connection (DBusList **rules,
1470 DBusConnection *connection)
1474 link = _dbus_list_get_first_link (rules);
1475 while (link != NULL)
1481 next = _dbus_list_get_next_link (rules, link);
1483 if (rule->matches_go_to == connection)
1485 bus_matchmaker_remove_rule_link (rules, link);
1487 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1488 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1490 /* The rule matches to/from a base service, see if it's the
1491 * one being disconnected, since we know this service name
1492 * will never be recycled.
1496 name = bus_connection_get_name (connection);
1497 _dbus_assert (name != NULL); /* because we're an active connection */
1499 if (((rule->flags & BUS_MATCH_SENDER) &&
1500 strcmp (rule->sender, name) == 0) ||
1501 ((rule->flags & BUS_MATCH_DESTINATION) &&
1502 strcmp (rule->destination, name) == 0))
1504 bus_matchmaker_remove_rule_link (rules, link);
1513 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1514 DBusConnection *connection)
1520 * This scans all match rules on the bus. We could avoid that
1521 * for the rules belonging to the connection, since we keep
1522 * a list of those; but for the rules that just refer to
1523 * the connection we'd need to do something more elaborate.
1526 _dbus_assert (bus_connection_is_active (connection));
1528 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1530 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1532 RulePool *p = matchmaker->rules_by_type + i;
1535 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1537 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1538 while (_dbus_hash_iter_next (&iter))
1540 DBusList **items = _dbus_hash_iter_get_value (&iter);
1542 rule_list_remove_by_connection (items, connection);
1545 _dbus_hash_iter_remove_entry (&iter);
1551 connection_is_primary_owner (DBusConnection *connection,
1552 const char *service_name)
1554 BusService *service;
1556 BusRegistry *registry;
1558 _dbus_assert (connection != NULL);
1560 registry = bus_connection_get_registry (connection);
1562 _dbus_string_init_const (&str, service_name);
1563 service = bus_registry_lookup (registry, &str);
1565 if (service == NULL)
1566 return FALSE; /* Service doesn't exist so connection can't own it. */
1568 return bus_service_get_primary_owners_connection (service) == connection;
1572 match_rule_matches (BusMatchRule *rule,
1573 DBusConnection *sender,
1574 DBusConnection *addressed_recipient,
1575 DBusMessage *message,
1576 BusMatchFlags already_matched)
1580 /* All features of the match rule are AND'd together,
1581 * so FALSE if any of them don't match.
1584 /* sender/addressed_recipient of #NULL may mean bus driver,
1585 * or for addressed_recipient may mean a message with no
1586 * specific recipient (i.e. a signal)
1589 /* Don't bother re-matching features we've already checked implicitly. */
1590 flags = rule->flags & (~already_matched);
1592 if (flags & BUS_MATCH_MESSAGE_TYPE)
1594 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1596 if (rule->message_type != dbus_message_get_type (message))
1600 if (flags & BUS_MATCH_INTERFACE)
1604 _dbus_assert (rule->interface != NULL);
1606 iface = dbus_message_get_interface (message);
1610 if (strcmp (iface, rule->interface) != 0)
1614 if (flags & BUS_MATCH_MEMBER)
1618 _dbus_assert (rule->member != NULL);
1620 member = dbus_message_get_member (message);
1624 if (strcmp (member, rule->member) != 0)
1628 if (flags & BUS_MATCH_SENDER)
1630 _dbus_assert (rule->sender != NULL);
1634 if (strcmp (rule->sender,
1635 DBUS_SERVICE_DBUS) != 0)
1640 if (!connection_is_primary_owner (sender, rule->sender))
1645 if (flags & BUS_MATCH_DESTINATION)
1647 const char *destination;
1649 _dbus_assert (rule->destination != NULL);
1651 destination = dbus_message_get_destination (message);
1652 if (destination == NULL)
1655 if (addressed_recipient == NULL)
1657 if (strcmp (rule->destination,
1658 DBUS_SERVICE_DBUS) != 0)
1663 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1668 if (flags & BUS_MATCH_PATH)
1672 _dbus_assert (rule->path != NULL);
1674 path = dbus_message_get_path (message);
1678 if (strcmp (path, rule->path) != 0)
1682 if (flags & BUS_MATCH_ARGS)
1685 DBusMessageIter iter;
1687 _dbus_assert (rule->args != NULL);
1689 dbus_message_iter_init (message, &iter);
1692 while (i < rule->args_len)
1695 const char *expected_arg;
1696 int expected_length;
1697 dbus_bool_t is_path, is_namespace;
1699 expected_arg = rule->args[i];
1700 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1701 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1702 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1704 current_type = dbus_message_iter_get_arg_type (&iter);
1706 if (expected_arg != NULL)
1708 const char *actual_arg;
1711 if (current_type != DBUS_TYPE_STRING &&
1712 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1716 dbus_message_iter_get_basic (&iter, &actual_arg);
1717 _dbus_assert (actual_arg != NULL);
1719 actual_length = strlen (actual_arg);
1723 if (actual_length < expected_length &&
1724 actual_arg[actual_length - 1] != '/')
1727 if (expected_length < actual_length &&
1728 expected_arg[expected_length - 1] != '/')
1731 if (memcmp (actual_arg, expected_arg,
1732 MIN (actual_length, expected_length)) != 0)
1735 else if (is_namespace)
1737 if (expected_length > actual_length)
1740 /* If the actual argument doesn't start with the expected
1741 * namespace, then we don't match.
1743 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1746 if (expected_length < actual_length)
1748 /* Check that the actual argument is within the expected
1749 * namespace, rather than just starting with that string,
1750 * by checking that the matched prefix ends in a '.'.
1752 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1753 * which is an invalid namespace, but at some point the
1754 * daemon can't cover up for broken services.
1756 int expected_period_index;
1758 if (expected_arg[expected_length - 1] == '.')
1759 expected_period_index = expected_length - 1;
1761 expected_period_index = expected_length;
1763 if (actual_arg[expected_period_index] != '.')
1766 /* otherwise we had an exact match. */
1770 if (expected_length != actual_length ||
1771 memcmp (expected_arg, actual_arg, expected_length) != 0)
1777 if (current_type != DBUS_TYPE_INVALID)
1778 dbus_message_iter_next (&iter);
1788 get_recipients_from_list (DBusList **rules,
1789 DBusConnection *sender,
1790 DBusConnection *addressed_recipient,
1791 DBusMessage *message,
1792 DBusList **recipients_p)
1799 link = _dbus_list_get_first_link (rules);
1800 while (link != NULL)
1806 #ifdef DBUS_ENABLE_VERBOSE_MODE
1808 char *s = match_rule_to_string (rule);
1810 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1811 s, rule->matches_go_to);
1816 if (match_rule_matches (rule,
1817 sender, addressed_recipient, message,
1818 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
1820 _dbus_verbose ("Rule matched\n");
1822 /* Append to the list if we haven't already */
1823 if (bus_connection_mark_stamp (rule->matches_go_to))
1825 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1828 #ifdef DBUS_ENABLE_VERBOSE_MODE
1831 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1833 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1836 link = _dbus_list_get_next_link (rules, link);
1843 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1844 BusConnections *connections,
1845 DBusConnection *sender,
1846 DBusConnection *addressed_recipient,
1847 DBusMessage *message,
1848 DBusList **recipients_p)
1851 const char *interface;
1852 DBusList **neither, **just_type, **just_iface, **both;
1854 _dbus_assert (*recipients_p == NULL);
1856 /* This avoids sending same message to the same connection twice.
1857 * Purpose of the stamp instead of a bool is to avoid iterating over
1858 * all connections resetting the bool each time.
1860 bus_connections_increment_stamp (connections);
1862 /* addressed_recipient is already receiving the message, don't add to list.
1863 * NULL addressed_recipient means either bus driver, or this is a signal
1864 * and thus lacks a specific addressed_recipient.
1866 if (addressed_recipient != NULL)
1867 bus_connection_mark_stamp (addressed_recipient);
1869 type = dbus_message_get_type (message);
1870 interface = dbus_message_get_interface (message);
1872 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
1874 just_type = just_iface = both = NULL;
1876 if (interface != NULL)
1877 just_iface = bus_matchmaker_get_rules (matchmaker,
1878 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
1880 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
1882 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
1884 if (interface != NULL)
1885 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
1888 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
1889 message, recipients_p) &&
1890 get_recipients_from_list (just_iface, sender, addressed_recipient,
1891 message, recipients_p) &&
1892 get_recipients_from_list (just_type, sender, addressed_recipient,
1893 message, recipients_p) &&
1894 get_recipients_from_list (both, sender, addressed_recipient,
1895 message, recipients_p)))
1897 _dbus_list_clear (recipients_p);
1904 #ifdef DBUS_BUILD_TESTS
1908 static BusMatchRule*
1909 check_parse (dbus_bool_t should_succeed,
1916 dbus_error_init (&error);
1918 _dbus_string_init_const (&str, text);
1920 rule = bus_match_rule_parse (NULL, &str, &error);
1921 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1923 dbus_error_free (&error);
1927 if (should_succeed && rule == NULL)
1929 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1930 error.name, error.message,
1931 _dbus_string_get_const_data (&str));
1935 if (!should_succeed && rule != NULL)
1937 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1938 _dbus_string_get_const_data (&str));
1942 dbus_error_free (&error);
1948 assert_large_rule (BusMatchRule *rule)
1950 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1951 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1952 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1953 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1954 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1955 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1957 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1958 _dbus_assert (rule->interface != NULL);
1959 _dbus_assert (rule->member != NULL);
1960 _dbus_assert (rule->sender != NULL);
1961 _dbus_assert (rule->destination != NULL);
1962 _dbus_assert (rule->path != NULL);
1964 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1965 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1966 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1967 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1968 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
1972 test_parsing (void *data)
1976 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
1979 assert_large_rule (rule);
1980 bus_match_rule_unref (rule);
1983 /* With extra whitespace and useless quotes */
1984 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
1987 assert_large_rule (rule);
1988 bus_match_rule_unref (rule);
1992 /* A simple signal connection */
1993 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1996 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1997 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1998 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2000 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2001 _dbus_assert (rule->interface != NULL);
2002 _dbus_assert (rule->path != NULL);
2004 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2005 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2007 bus_match_rule_unref (rule);
2011 rule = check_parse (TRUE, "arg0='foo'");
2014 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2015 _dbus_assert (rule->args != NULL);
2016 _dbus_assert (rule->args_len == 1);
2017 _dbus_assert (rule->args[0] != NULL);
2018 _dbus_assert (rule->args[1] == NULL);
2019 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2021 bus_match_rule_unref (rule);
2024 rule = check_parse (TRUE, "arg1='foo'");
2027 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2028 _dbus_assert (rule->args != NULL);
2029 _dbus_assert (rule->args_len == 2);
2030 _dbus_assert (rule->args[0] == NULL);
2031 _dbus_assert (rule->args[1] != NULL);
2032 _dbus_assert (rule->args[2] == NULL);
2033 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2035 bus_match_rule_unref (rule);
2038 rule = check_parse (TRUE, "arg2='foo'");
2041 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2042 _dbus_assert (rule->args != NULL);
2043 _dbus_assert (rule->args_len == 3);
2044 _dbus_assert (rule->args[0] == NULL);
2045 _dbus_assert (rule->args[1] == NULL);
2046 _dbus_assert (rule->args[2] != NULL);
2047 _dbus_assert (rule->args[3] == NULL);
2048 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2050 bus_match_rule_unref (rule);
2053 rule = check_parse (TRUE, "arg40='foo'");
2056 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2057 _dbus_assert (rule->args != NULL);
2058 _dbus_assert (rule->args_len == 41);
2059 _dbus_assert (rule->args[0] == NULL);
2060 _dbus_assert (rule->args[1] == NULL);
2061 _dbus_assert (rule->args[40] != NULL);
2062 _dbus_assert (rule->args[41] == NULL);
2063 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2065 bus_match_rule_unref (rule);
2068 rule = check_parse (TRUE, "arg63='foo'");
2071 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2072 _dbus_assert (rule->args != NULL);
2073 _dbus_assert (rule->args_len == 64);
2074 _dbus_assert (rule->args[0] == NULL);
2075 _dbus_assert (rule->args[1] == NULL);
2076 _dbus_assert (rule->args[63] != NULL);
2077 _dbus_assert (rule->args[64] == NULL);
2078 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2080 bus_match_rule_unref (rule);
2083 rule = check_parse (TRUE, "arg7path='/foo'");
2086 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2087 _dbus_assert (rule->args != NULL);
2088 _dbus_assert (rule->args_len == 8);
2089 _dbus_assert (rule->args[7] != NULL);
2090 _dbus_assert (rule->args[8] == NULL);
2091 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2092 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2093 == BUS_MATCH_ARG_IS_PATH);
2095 bus_match_rule_unref (rule);
2098 /* Arg 0 namespace matches */
2099 rule = check_parse (TRUE, "arg0namespace='foo'");
2102 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2103 _dbus_assert (rule->args != NULL);
2104 _dbus_assert (rule->args_len == 1);
2105 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2106 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2107 == BUS_MATCH_ARG_NAMESPACE);
2109 bus_match_rule_unref (rule);
2112 rule = check_parse (FALSE, "arg1namespace='foo'");
2113 _dbus_assert (rule == NULL);
2115 /* Too-large argN */
2116 rule = check_parse (FALSE, "arg300='foo'");
2117 _dbus_assert (rule == NULL);
2118 rule = check_parse (FALSE, "arg64='foo'");
2119 _dbus_assert (rule == NULL);
2122 rule = check_parse (FALSE, "arg='foo'");
2123 _dbus_assert (rule == NULL);
2124 rule = check_parse (FALSE, "argv='foo'");
2125 _dbus_assert (rule == NULL);
2126 rule = check_parse (FALSE, "arg3junk='foo'");
2127 _dbus_assert (rule == NULL);
2128 rule = check_parse (FALSE, "argument='foo'");
2129 _dbus_assert (rule == NULL);
2131 /* Reject duplicates */
2132 rule = check_parse (FALSE, "type='signal',type='method_call'");
2133 _dbus_assert (rule == NULL);
2135 /* Duplicates with the argN code */
2136 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2137 _dbus_assert (rule == NULL);
2138 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2139 _dbus_assert (rule == NULL);
2140 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2141 _dbus_assert (rule == NULL);
2143 /* Reject broken keys */
2144 rule = check_parse (FALSE, "blah='signal'");
2145 _dbus_assert (rule == NULL);
2147 /* Reject broken values */
2148 rule = check_parse (FALSE, "type='chouin'");
2149 _dbus_assert (rule == NULL);
2150 rule = check_parse (FALSE, "interface='abc@def++'");
2151 _dbus_assert (rule == NULL);
2152 rule = check_parse (FALSE, "service='youpi'");
2153 _dbus_assert (rule == NULL);
2155 /* Allow empty rule */
2156 rule = check_parse (TRUE, "");
2159 _dbus_assert (rule->flags == 0);
2161 bus_match_rule_unref (rule);
2164 /* All-whitespace rule is the same as empty */
2165 rule = check_parse (TRUE, " \t");
2168 _dbus_assert (rule->flags == 0);
2170 bus_match_rule_unref (rule);
2173 /* But with non-whitespace chars and no =value, it's not OK */
2174 rule = check_parse (FALSE, "type");
2175 _dbus_assert (rule == NULL);
2183 } equality_tests[] = {
2184 { "type='signal'", "type='signal'" },
2185 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2186 { "type='signal',member='bar'", "member='bar',type='signal'" },
2187 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2188 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2189 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2190 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2191 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2192 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2193 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2194 { "arg3='fool'", "arg3='fool'" },
2195 { "arg0namespace='fool'", "arg0namespace='fool'" },
2196 { "member='food'", "member='food'" }
2200 test_equality (void)
2205 while (i < _DBUS_N_ELEMENTS (equality_tests))
2207 BusMatchRule *first;
2208 BusMatchRule *second;
2211 first = check_parse (TRUE, equality_tests[i].first);
2212 _dbus_assert (first != NULL);
2213 second = check_parse (TRUE, equality_tests[i].second);
2214 _dbus_assert (second != NULL);
2216 if (!match_rule_equal (first, second))
2218 _dbus_warn ("rule %s and %s should have been equal\n",
2219 equality_tests[i].first,
2220 equality_tests[i].second);
2224 bus_match_rule_unref (second);
2226 /* Check that the rule is not equal to any of the
2227 * others besides its pair match
2230 while (j < _DBUS_N_ELEMENTS (equality_tests))
2234 second = check_parse (TRUE, equality_tests[j].second);
2236 if (match_rule_equal (first, second))
2238 _dbus_warn ("rule %s and %s should not have been equal\n",
2239 equality_tests[i].first,
2240 equality_tests[j].second);
2244 bus_match_rule_unref (second);
2250 bus_match_rule_unref (first);
2257 should_match_message_1[] = {
2259 "member='Frobated'",
2261 "type='signal',member='Frobated'",
2262 "type='signal',member='Frobated',arg0='foobar'",
2263 "member='Frobated',arg0='foobar'",
2264 "type='signal',arg0='foobar'",
2265 /* The definition of argXpath matches says: "As with normal argument matches,
2266 * if the argument is exactly equal to the string given in the match rule
2267 * then the rule is satisfied." So this should match (even though the
2268 * argument is not a valid path)!
2270 "arg0path='foobar'",
2271 "arg0namespace='foobar'",
2276 should_not_match_message_1[] = {
2277 "type='method_call'",
2279 "type='method_return'",
2280 "type='signal',member='Oopsed'",
2287 "arg0='foobar',arg1='abcdef'",
2288 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2289 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2291 "arg0path='foobar/'",
2293 "arg0namespace='foo'",
2294 "arg0namespace='foo',arg1='abcdef'",
2295 "arg0namespace='moo'",
2299 #define EXAMPLE_NAME "com.example.backend.foo"
2302 should_match_message_2[] = {
2303 /* EXAMPLE_NAME is in all of these namespaces, specified with and without a
2304 * trailing period */
2305 "arg0namespace='com.example.backend.'",
2306 "arg0namespace='com.example.backend'",
2307 "arg0namespace='com.example.'",
2308 "arg0namespace='com.example'",
2309 "arg0namespace='com.'",
2310 "arg0namespace='com'",
2312 /* If the client specifies the name exactly, with no trailing period, then
2315 "arg0namespace='com.example.backend.foo'",
2321 should_not_match_message_2[] = {
2322 /* These are not even prefixes */
2323 "arg0namespace='com.example.backend.foo.bar'",
2324 "arg0namespace='com.example.backend.foobar'",
2325 "arg0namespace='com.example.backend.fo.'",
2327 /* This should match anything within the namespace com.example.backend.foo,
2328 * not including com.example.backend.foo itself.
2330 "arg0namespace='com.example.backend.foo.'",
2332 /* These are prefixes, but they're not parent namespaces. */
2333 "arg0namespace='com.example.backend.fo'",
2334 "arg0namespace='com.example.backen'",
2335 "arg0namespace='com.exampl'",
2336 "arg0namespace='co'",
2342 check_matches (dbus_bool_t expected_to_match,
2344 DBusMessage *message,
2345 const char *rule_text)
2348 dbus_bool_t matched;
2350 rule = check_parse (TRUE, rule_text);
2351 _dbus_assert (rule != NULL);
2353 /* We can't test sender/destination rules since we pass NULL here */
2354 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2356 if (matched != expected_to_match)
2358 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2359 rule_text, expected_to_match ?
2360 "match" : "not match", number);
2364 bus_match_rule_unref (rule);
2368 check_matching (DBusMessage *message,
2370 const char **should_match,
2371 const char **should_not_match)
2376 while (should_match[i] != NULL)
2378 check_matches (TRUE, number, message, should_match[i]);
2383 while (should_not_match[i] != NULL)
2385 check_matches (FALSE, number, message, should_not_match[i]);
2391 test_matching (void)
2393 DBusMessage *message1, *message2;
2394 const char *v_STRING;
2395 dbus_int32_t v_INT32;
2397 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2398 _dbus_assert (message1 != NULL);
2399 if (!dbus_message_set_member (message1, "Frobated"))
2400 _dbus_assert_not_reached ("oom");
2402 v_STRING = "foobar";
2404 if (!dbus_message_append_args (message1,
2405 DBUS_TYPE_STRING, &v_STRING,
2406 DBUS_TYPE_INT32, &v_INT32,
2408 _dbus_assert_not_reached ("oom");
2410 check_matching (message1, 1,
2411 should_match_message_1,
2412 should_not_match_message_1);
2414 dbus_message_unref (message1);
2416 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2417 _dbus_assert (message2 != NULL);
2418 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2419 _dbus_assert_not_reached ("oom");
2421 /* Obviously this isn't really a NameOwnerChanged signal. */
2422 v_STRING = EXAMPLE_NAME;
2423 if (!dbus_message_append_args (message2,
2424 DBUS_TYPE_STRING, &v_STRING,
2426 _dbus_assert_not_reached ("oom");
2428 check_matching (message2, 2,
2429 should_match_message_2,
2430 should_not_match_message_2);
2432 dbus_message_unref (message2);
2435 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2437 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2438 * from the specification. Notice that not all of them are actually legal D-Bus
2441 * The author of this test takes no responsibility for the semantics of
2442 * this match rule key.
2444 static const char *paths_that_should_be_matched[] = {
2448 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2454 /* These paths should not be matched by PATH_MATCH_RULE. */
2455 static const char *paths_that_should_not_be_matched[] = {
2464 test_path_match (int type,
2466 const char *rule_text,
2468 dbus_bool_t should_match)
2470 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2471 dbus_bool_t matched;
2473 _dbus_assert (message != NULL);
2474 if (!dbus_message_set_member (message, "Foo"))
2475 _dbus_assert_not_reached ("oom");
2477 if (!dbus_message_append_args (message,
2480 _dbus_assert_not_reached ("oom");
2482 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2484 if (matched != should_match)
2486 _dbus_warn ("Expected rule %s to %s message "
2487 "with first arg %s of type '%c', failed\n",
2489 should_match ? "match" : "not match",
2495 dbus_message_unref (message);
2499 test_path_matching (void)
2504 rule = check_parse (TRUE, PATH_MATCH_RULE);
2505 _dbus_assert (rule != NULL);
2507 for (s = paths_that_should_be_matched; *s != NULL; s++)
2508 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2510 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2512 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2514 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2516 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2517 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2520 bus_match_rule_unref (rule);
2524 bus_signals_test (const DBusString *test_data_dir)
2526 BusMatchmaker *matchmaker;
2528 matchmaker = bus_matchmaker_new ();
2529 bus_matchmaker_ref (matchmaker);
2530 bus_matchmaker_unref (matchmaker);
2531 bus_matchmaker_unref (matchmaker);
2533 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2534 _dbus_assert_not_reached ("Parsing match rules test failed");
2538 test_path_matching ();
2543 #endif /* DBUS_BUILD_TESTS */