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 if (!_dbus_string_append_printf (&str, "type='%s'",
142 dbus_message_type_to_string (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_PATH_NAMESPACE)
184 if (_dbus_string_get_length (&str) > 0)
186 if (!_dbus_string_append (&str, ","))
190 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
194 if (rule->flags & BUS_MATCH_SENDER)
196 if (_dbus_string_get_length (&str) > 0)
198 if (!_dbus_string_append (&str, ","))
202 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
206 if (rule->flags & BUS_MATCH_DESTINATION)
208 if (_dbus_string_get_length (&str) > 0)
210 if (!_dbus_string_append (&str, ","))
214 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
218 if (rule->flags & BUS_MATCH_ARGS)
222 _dbus_assert (rule->args != NULL);
225 while (i < rule->args_len)
227 if (rule->args[i] != NULL)
229 dbus_bool_t is_path, is_namespace;
231 if (_dbus_string_get_length (&str) > 0)
233 if (!_dbus_string_append (&str, ","))
237 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
238 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
240 if (!_dbus_string_append_printf (&str,
244 is_namespace ? "namespace" : "",
253 if (!_dbus_string_steal_data (&str, &ret))
256 _dbus_string_free (&str);
260 _dbus_string_free (&str);
263 while ((s = _dbus_strdup ("nomem")) == NULL)
264 ; /* only OK for debug spew... */
268 #endif /* DBUS_ENABLE_VERBOSE_MODE */
271 bus_match_rule_set_message_type (BusMatchRule *rule,
274 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
276 rule->message_type = type;
282 bus_match_rule_set_interface (BusMatchRule *rule,
283 const char *interface)
287 _dbus_assert (interface != NULL);
289 new = _dbus_strdup (interface);
293 rule->flags |= BUS_MATCH_INTERFACE;
294 dbus_free (rule->interface);
295 rule->interface = new;
301 bus_match_rule_set_member (BusMatchRule *rule,
306 _dbus_assert (member != NULL);
308 new = _dbus_strdup (member);
312 rule->flags |= BUS_MATCH_MEMBER;
313 dbus_free (rule->member);
320 bus_match_rule_set_sender (BusMatchRule *rule,
325 _dbus_assert (sender != NULL);
327 new = _dbus_strdup (sender);
331 rule->flags |= BUS_MATCH_SENDER;
332 dbus_free (rule->sender);
339 bus_match_rule_set_destination (BusMatchRule *rule,
340 const char *destination)
344 _dbus_assert (destination != NULL);
346 new = _dbus_strdup (destination);
350 rule->flags |= BUS_MATCH_DESTINATION;
351 dbus_free (rule->destination);
352 rule->destination = new;
358 bus_match_rule_set_path (BusMatchRule *rule,
360 dbus_bool_t is_namespace)
364 _dbus_assert (path != NULL);
366 new = _dbus_strdup (path);
370 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
373 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
375 rule->flags |= BUS_MATCH_PATH;
377 dbus_free (rule->path);
384 bus_match_rule_set_arg (BusMatchRule *rule,
386 const DBusString *value,
388 dbus_bool_t is_namespace)
393 _dbus_assert (value != NULL);
395 /* args_len is the number of args not including null termination
398 if (arg >= rule->args_len)
400 unsigned int *new_arg_lens;
405 new_args_len = arg + 1;
407 /* add another + 1 here for null termination */
408 new_args = dbus_realloc (rule->args,
409 sizeof (char *) * (new_args_len + 1));
410 if (new_args == NULL)
413 /* NULL the new slots */
415 while (i <= new_args_len) /* <= for null termination */
421 rule->args = new_args;
423 /* and now add to the lengths */
424 new_arg_lens = dbus_realloc (rule->arg_lens,
425 sizeof (int) * (new_args_len + 1));
427 if (new_arg_lens == NULL)
430 /* zero the new slots */
432 while (i <= new_args_len) /* <= for null termination */
438 rule->arg_lens = new_arg_lens;
439 rule->args_len = new_args_len;
442 length = _dbus_string_get_length (value);
443 if (!_dbus_string_copy_data (value, &new))
446 rule->flags |= BUS_MATCH_ARGS;
448 dbus_free (rule->args[arg]);
449 rule->arg_lens[arg] = length;
450 rule->args[arg] = new;
453 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
456 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
458 /* NULL termination didn't get busted */
459 _dbus_assert (rule->args[rule->args_len] == NULL);
460 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
465 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
468 find_key (const DBusString *str,
476 const char *key_start;
479 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
481 s = _dbus_string_get_const_data (str);
485 while (*p && ISWHITE (*p))
490 while (*p && *p != '=' && !ISWHITE (*p))
495 while (*p && ISWHITE (*p))
498 if (key_start == key_end)
500 /* Empty match rules or trailing whitespace are OK */
507 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
508 "Match rule has a key with no subsequent '=' character");
513 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
525 find_value (const DBusString *str,
537 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
539 orig_len = _dbus_string_get_length (value);
541 s = _dbus_string_get_const_data (str);
549 if (quote_char == '\0')
569 if (!_dbus_string_append_byte (value, *p))
576 else if (quote_char == '\\')
578 /* \ only counts as an escape if escaping a quote mark */
581 if (!_dbus_string_append_byte (value, '\\'))
588 if (!_dbus_string_append_byte (value, *p))
598 _dbus_assert (quote_char == '\'');
606 if (!_dbus_string_append_byte (value, *p))
620 if (quote_char == '\\')
622 if (!_dbus_string_append_byte (value, '\\'))
628 else if (quote_char == '\'')
630 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
631 "Unbalanced quotation marks in match rule");
635 _dbus_assert (quote_char == '\0');
637 /* Zero-length values are allowed */
644 _DBUS_ASSERT_ERROR_IS_SET (error);
645 _dbus_string_set_length (value, orig_len);
649 /* duplicates aren't allowed so the real legitimate max is only 6 or
650 * so. Leaving extra so we don't have to bother to update it.
651 * FIXME this is sort of busted now with arg matching, but we let
652 * you match on up to 10 args for now
654 #define MAX_RULE_TOKENS 16
656 /* this is slightly too high level to be termed a "token"
657 * but let's not be pedantic.
666 tokenize_rule (const DBusString *rule_text,
667 RuleToken tokens[MAX_RULE_TOKENS],
678 if (!_dbus_string_init (&key))
684 if (!_dbus_string_init (&value))
686 _dbus_string_free (&key);
693 while (i < MAX_RULE_TOKENS &&
694 pos < _dbus_string_get_length (rule_text))
696 _dbus_assert (tokens[i].key == NULL);
697 _dbus_assert (tokens[i].value == NULL);
699 if (!find_key (rule_text, pos, &key, &pos, error))
702 if (_dbus_string_get_length (&key) == 0)
705 if (!_dbus_string_steal_data (&key, &tokens[i].key))
711 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
714 if (!_dbus_string_steal_data (&value, &tokens[i].value))
730 while (tokens[i].key || tokens[i].value)
732 dbus_free (tokens[i].key);
733 dbus_free (tokens[i].value);
734 tokens[i].key = NULL;
735 tokens[i].value = NULL;
740 _dbus_string_free (&key);
741 _dbus_string_free (&value);
747 bus_match_rule_parse_arg_match (BusMatchRule *rule,
749 const DBusString *value,
752 dbus_bool_t is_path = FALSE;
753 dbus_bool_t is_namespace = FALSE;
759 /* For now, arg0='foo' always implies that 'foo' is a
760 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
761 * if we wanted, which would specify another type, in which case
762 * arg0='5' would have the 5 parsed as an int rather than string.
765 /* First we need to parse arg0 = 0, arg27 = 27 */
767 _dbus_string_init_const (&key_str, key);
768 length = _dbus_string_get_length (&key_str);
770 if (_dbus_string_get_length (&key_str) < 4)
772 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
773 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
777 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
779 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
780 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
786 if ((end + strlen ("path")) == length &&
787 _dbus_string_ends_with_c_str (&key_str, "path"))
791 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
793 int value_len = _dbus_string_get_length (value);
797 if (!_dbus_validate_bus_namespace (value, 0, value_len))
799 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
800 "arg0namespace='%s' is not a valid prefix of a bus name",
801 _dbus_string_get_const_data (value));
807 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
808 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
813 /* If we didn't check this we could allocate a huge amount of RAM */
814 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
816 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
817 "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);
821 if ((rule->flags & BUS_MATCH_ARGS) &&
822 rule->args_len > (int) arg &&
823 rule->args[arg] != NULL)
825 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
826 "Argument %d matched more than once in match rule\n", key);
830 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
839 _DBUS_ASSERT_ERROR_IS_SET (error);
844 * The format is comma-separated with strings quoted with single quotes
845 * as for the shell (to escape a literal single quote, use '\'').
847 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
848 * path='/bar/foo',destination=':452345.34'
852 bus_match_rule_parse (DBusConnection *matches_go_to,
853 const DBusString *rule_text,
857 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
860 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
862 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
864 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
865 "Match rule text is %d bytes, maximum is %d",
866 _dbus_string_get_length (rule_text),
867 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
871 memset (tokens, '\0', sizeof (tokens));
873 rule = bus_match_rule_new (matches_go_to);
880 if (!tokenize_rule (rule_text, tokens, error))
884 while (tokens[i].key != NULL)
888 const char *key = tokens[i].key;
889 const char *value = tokens[i].value;
891 _dbus_string_init_const (&tmp_str, value);
892 len = _dbus_string_get_length (&tmp_str);
894 if (strcmp (key, "type") == 0)
898 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
900 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
901 "Key %s specified twice in match rule\n", key);
905 t = dbus_message_type_from_string (value);
907 if (t == DBUS_MESSAGE_TYPE_INVALID)
909 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
910 "Invalid message type (%s) in match rule\n", value);
914 if (!bus_match_rule_set_message_type (rule, t))
920 else if (strcmp (key, "sender") == 0)
922 if (rule->flags & BUS_MATCH_SENDER)
924 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
925 "Key %s specified twice in match rule\n", key);
929 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
931 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
932 "Sender name '%s' is invalid\n", value);
936 if (!bus_match_rule_set_sender (rule, value))
942 else if (strcmp (key, "interface") == 0)
944 if (rule->flags & BUS_MATCH_INTERFACE)
946 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
947 "Key %s specified twice in match rule\n", key);
951 if (!_dbus_validate_interface (&tmp_str, 0, len))
953 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
954 "Interface name '%s' is invalid\n", value);
958 if (!bus_match_rule_set_interface (rule, value))
964 else if (strcmp (key, "member") == 0)
966 if (rule->flags & BUS_MATCH_MEMBER)
968 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
969 "Key %s specified twice in match rule\n", key);
973 if (!_dbus_validate_member (&tmp_str, 0, len))
975 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
976 "Member name '%s' is invalid\n", value);
980 if (!bus_match_rule_set_member (rule, value))
986 else if (strcmp (key, "path") == 0 ||
987 strcmp (key, "path_namespace") == 0)
989 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
991 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
993 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
994 "path or path_namespace specified twice in match rule\n");
998 if (!_dbus_validate_path (&tmp_str, 0, len))
1000 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1001 "Path '%s' is invalid\n", value);
1005 if (!bus_match_rule_set_path (rule, value, is_namespace))
1007 BUS_SET_OOM (error);
1011 else if (strcmp (key, "destination") == 0)
1013 if (rule->flags & BUS_MATCH_DESTINATION)
1015 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1016 "Key %s specified twice in match rule\n", key);
1020 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1022 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1023 "Destination name '%s' is invalid\n", value);
1027 if (!bus_match_rule_set_destination (rule, value))
1029 BUS_SET_OOM (error);
1033 else if (strncmp (key, "arg", 3) == 0)
1035 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1040 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1041 "Unknown key \"%s\" in match rule",
1053 _DBUS_ASSERT_ERROR_IS_SET (error);
1056 bus_match_rule_unref (rule);
1063 while (tokens[i].key || tokens[i].value)
1065 _dbus_assert (i < MAX_RULE_TOKENS);
1066 dbus_free (tokens[i].key);
1067 dbus_free (tokens[i].value);
1074 typedef struct RulePool RulePool;
1077 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1078 DBusHashTable *rules_by_iface;
1080 /* List of BusMatchRules which don't specify an interface */
1081 DBusList *rules_without_iface;
1084 struct BusMatchmaker
1088 /* Pools of rules, grouped by the type of message they match. 0
1089 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1092 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1096 rule_list_free (DBusList **rules)
1098 while (*rules != NULL)
1102 rule = (*rules)->data;
1103 bus_match_rule_unref (rule);
1104 _dbus_list_remove_link (rules, *rules);
1109 rule_list_ptr_free (DBusList **list)
1111 /* We have to cope with NULL because the hash table frees the "existing"
1112 * value (which is NULL) when creating a new table entry...
1116 rule_list_free (list);
1122 bus_matchmaker_new (void)
1124 BusMatchmaker *matchmaker;
1127 matchmaker = dbus_new0 (BusMatchmaker, 1);
1128 if (matchmaker == NULL)
1131 matchmaker->refcount = 1;
1133 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1135 RulePool *p = matchmaker->rules_by_type + i;
1137 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1138 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1140 if (p->rules_by_iface == NULL)
1147 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1149 RulePool *p = matchmaker->rules_by_type + i;
1151 if (p->rules_by_iface == NULL)
1154 _dbus_hash_table_unref (p->rules_by_iface);
1156 dbus_free (matchmaker);
1162 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1164 const char *interface,
1169 _dbus_assert (message_type >= 0);
1170 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1172 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1174 interface != NULL ? interface : "<null>");
1176 p = matchmaker->rules_by_type + message_type;
1178 if (interface == NULL)
1180 return &p->rules_without_iface;
1186 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1188 if (list == NULL && create)
1190 char *dupped_interface;
1192 list = dbus_new0 (DBusList *, 1);
1196 dupped_interface = _dbus_strdup (interface);
1197 if (dupped_interface == NULL)
1203 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1206 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1207 dupped_interface, list))
1210 dbus_free (dupped_interface);
1220 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1222 const char *interface,
1227 if (interface == NULL)
1233 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1234 message_type, interface);
1236 p = matchmaker->rules_by_type + message_type;
1238 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1241 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1245 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1247 _dbus_assert (matchmaker->refcount > 0);
1249 matchmaker->refcount += 1;
1255 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1257 _dbus_assert (matchmaker->refcount > 0);
1259 matchmaker->refcount -= 1;
1260 if (matchmaker->refcount == 0)
1264 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1266 RulePool *p = matchmaker->rules_by_type + i;
1268 _dbus_hash_table_unref (p->rules_by_iface);
1269 rule_list_free (&p->rules_without_iface);
1272 dbus_free (matchmaker);
1276 /* The rule can't be modified after it's added. */
1278 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1283 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1285 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1287 rule->interface != NULL ? rule->interface : "<null>");
1289 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1290 rule->interface, TRUE);
1295 if (!_dbus_list_append (rules, rule))
1298 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1300 _dbus_list_remove_last (rules, rule);
1301 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1302 rule->interface, rules);
1306 bus_match_rule_ref (rule);
1308 #ifdef DBUS_ENABLE_VERBOSE_MODE
1310 char *s = match_rule_to_string (rule);
1312 _dbus_verbose ("Added match rule %s to connection %p\n",
1313 s, rule->matches_go_to);
1322 match_rule_equal (BusMatchRule *a,
1325 if (a->flags != b->flags)
1328 if (a->matches_go_to != b->matches_go_to)
1331 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1332 a->message_type != b->message_type)
1335 if ((a->flags & BUS_MATCH_MEMBER) &&
1336 strcmp (a->member, b->member) != 0)
1339 if ((a->flags & BUS_MATCH_PATH) &&
1340 strcmp (a->path, b->path) != 0)
1343 if ((a->flags & BUS_MATCH_INTERFACE) &&
1344 strcmp (a->interface, b->interface) != 0)
1347 if ((a->flags & BUS_MATCH_SENDER) &&
1348 strcmp (a->sender, b->sender) != 0)
1351 if ((a->flags & BUS_MATCH_DESTINATION) &&
1352 strcmp (a->destination, b->destination) != 0)
1355 if (a->flags & BUS_MATCH_ARGS)
1359 if (a->args_len != b->args_len)
1363 while (i < a->args_len)
1367 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1370 if (a->arg_lens[i] != b->arg_lens[i])
1373 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1375 if (a->args[i] != NULL)
1377 _dbus_assert (b->args[i] != NULL);
1378 if (memcmp (a->args[i], b->args[i], length) != 0)
1390 bus_matchmaker_remove_rule_link (DBusList **rules,
1393 BusMatchRule *rule = link->data;
1395 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1396 _dbus_list_remove_link (rules, link);
1398 #ifdef DBUS_ENABLE_VERBOSE_MODE
1400 char *s = match_rule_to_string (rule);
1402 _dbus_verbose ("Removed match rule %s for connection %p\n",
1403 s, rule->matches_go_to);
1408 bus_match_rule_unref (rule);
1412 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1417 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1419 rule->interface != NULL ? rule->interface : "<null>");
1421 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1423 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1424 rule->interface, FALSE);
1426 /* We should only be asked to remove a rule by identity right after it was
1427 * added, so there should be a list for it.
1429 _dbus_assert (rules != NULL);
1431 _dbus_list_remove (rules, rule);
1432 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1435 #ifdef DBUS_ENABLE_VERBOSE_MODE
1437 char *s = match_rule_to_string (rule);
1439 _dbus_verbose ("Removed match rule %s for connection %p\n",
1440 s, rule->matches_go_to);
1445 bus_match_rule_unref (rule);
1448 /* Remove a single rule which is equal to the given rule by value */
1450 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1451 BusMatchRule *value,
1455 DBusList *link = NULL;
1457 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1458 value->message_type,
1459 value->interface != NULL ? value->interface : "<null>");
1461 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1462 value->interface, FALSE);
1466 /* we traverse backward because bus_connection_remove_match_rule()
1467 * removes the most-recently-added rule
1469 link = _dbus_list_get_last_link (rules);
1470 while (link != NULL)
1476 prev = _dbus_list_get_prev_link (rules, link);
1478 if (match_rule_equal (rule, value))
1480 bus_matchmaker_remove_rule_link (rules, link);
1490 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1491 "The given match rule wasn't found and can't be removed");
1495 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1502 rule_list_remove_by_connection (DBusList **rules,
1503 DBusConnection *connection)
1507 link = _dbus_list_get_first_link (rules);
1508 while (link != NULL)
1514 next = _dbus_list_get_next_link (rules, link);
1516 if (rule->matches_go_to == connection)
1518 bus_matchmaker_remove_rule_link (rules, link);
1520 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1521 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1523 /* The rule matches to/from a base service, see if it's the
1524 * one being disconnected, since we know this service name
1525 * will never be recycled.
1529 name = bus_connection_get_name (connection);
1530 _dbus_assert (name != NULL); /* because we're an active connection */
1532 if (((rule->flags & BUS_MATCH_SENDER) &&
1533 strcmp (rule->sender, name) == 0) ||
1534 ((rule->flags & BUS_MATCH_DESTINATION) &&
1535 strcmp (rule->destination, name) == 0))
1537 bus_matchmaker_remove_rule_link (rules, link);
1546 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1547 DBusConnection *connection)
1553 * This scans all match rules on the bus. We could avoid that
1554 * for the rules belonging to the connection, since we keep
1555 * a list of those; but for the rules that just refer to
1556 * the connection we'd need to do something more elaborate.
1559 _dbus_assert (bus_connection_is_active (connection));
1561 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1563 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1565 RulePool *p = matchmaker->rules_by_type + i;
1568 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1570 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1571 while (_dbus_hash_iter_next (&iter))
1573 DBusList **items = _dbus_hash_iter_get_value (&iter);
1575 rule_list_remove_by_connection (items, connection);
1578 _dbus_hash_iter_remove_entry (&iter);
1584 connection_is_primary_owner (DBusConnection *connection,
1585 const char *service_name)
1587 BusService *service;
1589 BusRegistry *registry;
1591 _dbus_assert (connection != NULL);
1593 registry = bus_connection_get_registry (connection);
1595 _dbus_string_init_const (&str, service_name);
1596 service = bus_registry_lookup (registry, &str);
1598 if (service == NULL)
1599 return FALSE; /* Service doesn't exist so connection can't own it. */
1601 return bus_service_get_primary_owners_connection (service) == connection;
1605 str_has_prefix (const char *str, const char *prefix)
1608 prefix_len = strlen (prefix);
1609 if (strncmp (str, prefix, prefix_len) == 0)
1616 match_rule_matches (BusMatchRule *rule,
1617 DBusConnection *sender,
1618 DBusConnection *addressed_recipient,
1619 DBusMessage *message,
1620 BusMatchFlags already_matched)
1624 /* All features of the match rule are AND'd together,
1625 * so FALSE if any of them don't match.
1628 /* sender/addressed_recipient of #NULL may mean bus driver,
1629 * or for addressed_recipient may mean a message with no
1630 * specific recipient (i.e. a signal)
1633 /* Don't bother re-matching features we've already checked implicitly. */
1634 flags = rule->flags & (~already_matched);
1636 if (flags & BUS_MATCH_MESSAGE_TYPE)
1638 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1640 if (rule->message_type != dbus_message_get_type (message))
1644 if (flags & BUS_MATCH_INTERFACE)
1648 _dbus_assert (rule->interface != NULL);
1650 iface = dbus_message_get_interface (message);
1654 if (strcmp (iface, rule->interface) != 0)
1658 if (flags & BUS_MATCH_MEMBER)
1662 _dbus_assert (rule->member != NULL);
1664 member = dbus_message_get_member (message);
1668 if (strcmp (member, rule->member) != 0)
1672 if (flags & BUS_MATCH_SENDER)
1674 _dbus_assert (rule->sender != NULL);
1678 if (strcmp (rule->sender,
1679 DBUS_SERVICE_DBUS) != 0)
1684 if (!connection_is_primary_owner (sender, rule->sender))
1689 if (flags & BUS_MATCH_DESTINATION)
1691 const char *destination;
1693 _dbus_assert (rule->destination != NULL);
1695 destination = dbus_message_get_destination (message);
1696 if (destination == NULL)
1699 if (addressed_recipient == NULL)
1701 if (strcmp (rule->destination,
1702 DBUS_SERVICE_DBUS) != 0)
1707 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1712 if (flags & BUS_MATCH_PATH)
1716 _dbus_assert (rule->path != NULL);
1718 path = dbus_message_get_path (message);
1722 if (strcmp (path, rule->path) != 0)
1726 if (flags & BUS_MATCH_PATH_NAMESPACE)
1731 _dbus_assert (rule->path != NULL);
1733 path = dbus_message_get_path (message);
1737 if (!str_has_prefix (path, rule->path))
1740 len = strlen (rule->path);
1742 /* Check that the actual argument is within the expected
1743 * namespace, rather than just starting with that string,
1744 * by checking that the matched prefix is followed by a '/'
1745 * or the end of the path.
1747 if (path[len] != '\0' && path[len] != '/')
1751 if (flags & BUS_MATCH_ARGS)
1754 DBusMessageIter iter;
1756 _dbus_assert (rule->args != NULL);
1758 dbus_message_iter_init (message, &iter);
1761 while (i < rule->args_len)
1764 const char *expected_arg;
1765 int expected_length;
1766 dbus_bool_t is_path, is_namespace;
1768 expected_arg = rule->args[i];
1769 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1770 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1771 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1773 current_type = dbus_message_iter_get_arg_type (&iter);
1775 if (expected_arg != NULL)
1777 const char *actual_arg;
1780 if (current_type != DBUS_TYPE_STRING &&
1781 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1785 dbus_message_iter_get_basic (&iter, &actual_arg);
1786 _dbus_assert (actual_arg != NULL);
1788 actual_length = strlen (actual_arg);
1792 if (actual_length < expected_length &&
1793 actual_arg[actual_length - 1] != '/')
1796 if (expected_length < actual_length &&
1797 expected_arg[expected_length - 1] != '/')
1800 if (memcmp (actual_arg, expected_arg,
1801 MIN (actual_length, expected_length)) != 0)
1804 else if (is_namespace)
1806 if (expected_length > actual_length)
1809 /* If the actual argument doesn't start with the expected
1810 * namespace, then we don't match.
1812 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1815 if (expected_length < actual_length)
1817 /* Check that the actual argument is within the expected
1818 * namespace, rather than just starting with that string,
1819 * by checking that the matched prefix ends in a '.'.
1821 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1822 * which is an invalid namespace, but at some point the
1823 * daemon can't cover up for broken services.
1825 if (actual_arg[expected_length] != '.')
1828 /* otherwise we had an exact match. */
1832 if (expected_length != actual_length ||
1833 memcmp (expected_arg, actual_arg, expected_length) != 0)
1839 if (current_type != DBUS_TYPE_INVALID)
1840 dbus_message_iter_next (&iter);
1850 get_recipients_from_list (DBusList **rules,
1851 DBusConnection *sender,
1852 DBusConnection *addressed_recipient,
1853 DBusMessage *message,
1854 DBusList **recipients_p)
1861 link = _dbus_list_get_first_link (rules);
1862 while (link != NULL)
1868 #ifdef DBUS_ENABLE_VERBOSE_MODE
1870 char *s = match_rule_to_string (rule);
1872 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1873 s, rule->matches_go_to);
1878 if (match_rule_matches (rule,
1879 sender, addressed_recipient, message,
1880 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
1882 _dbus_verbose ("Rule matched\n");
1884 /* Append to the list if we haven't already */
1885 if (bus_connection_mark_stamp (rule->matches_go_to))
1887 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1890 #ifdef DBUS_ENABLE_VERBOSE_MODE
1893 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1895 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1898 link = _dbus_list_get_next_link (rules, link);
1905 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1906 BusConnections *connections,
1907 DBusConnection *sender,
1908 DBusConnection *addressed_recipient,
1909 DBusMessage *message,
1910 DBusList **recipients_p)
1913 const char *interface;
1914 DBusList **neither, **just_type, **just_iface, **both;
1916 _dbus_assert (*recipients_p == NULL);
1918 /* This avoids sending same message to the same connection twice.
1919 * Purpose of the stamp instead of a bool is to avoid iterating over
1920 * all connections resetting the bool each time.
1922 bus_connections_increment_stamp (connections);
1924 /* addressed_recipient is already receiving the message, don't add to list.
1925 * NULL addressed_recipient means either bus driver, or this is a signal
1926 * and thus lacks a specific addressed_recipient.
1928 if (addressed_recipient != NULL)
1929 bus_connection_mark_stamp (addressed_recipient);
1931 type = dbus_message_get_type (message);
1932 interface = dbus_message_get_interface (message);
1934 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
1936 just_type = just_iface = both = NULL;
1938 if (interface != NULL)
1939 just_iface = bus_matchmaker_get_rules (matchmaker,
1940 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
1942 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
1944 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
1946 if (interface != NULL)
1947 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
1950 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
1951 message, recipients_p) &&
1952 get_recipients_from_list (just_iface, sender, addressed_recipient,
1953 message, recipients_p) &&
1954 get_recipients_from_list (just_type, sender, addressed_recipient,
1955 message, recipients_p) &&
1956 get_recipients_from_list (both, sender, addressed_recipient,
1957 message, recipients_p)))
1959 _dbus_list_clear (recipients_p);
1966 #ifdef DBUS_BUILD_TESTS
1970 static BusMatchRule*
1971 check_parse (dbus_bool_t should_succeed,
1978 dbus_error_init (&error);
1980 _dbus_string_init_const (&str, text);
1982 rule = bus_match_rule_parse (NULL, &str, &error);
1983 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1985 dbus_error_free (&error);
1989 if (should_succeed && rule == NULL)
1991 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1992 error.name, error.message,
1993 _dbus_string_get_const_data (&str));
1997 if (!should_succeed && rule != NULL)
1999 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2000 _dbus_string_get_const_data (&str));
2004 dbus_error_free (&error);
2010 assert_large_rule (BusMatchRule *rule)
2012 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2013 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2014 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2015 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2016 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2017 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2019 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2020 _dbus_assert (rule->interface != NULL);
2021 _dbus_assert (rule->member != NULL);
2022 _dbus_assert (rule->sender != NULL);
2023 _dbus_assert (rule->destination != NULL);
2024 _dbus_assert (rule->path != NULL);
2026 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2027 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2028 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2029 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2030 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2034 test_parsing (void *data)
2038 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2041 assert_large_rule (rule);
2042 bus_match_rule_unref (rule);
2045 /* With extra whitespace and useless quotes */
2046 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2049 assert_large_rule (rule);
2050 bus_match_rule_unref (rule);
2054 /* A simple signal connection */
2055 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2058 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2059 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2060 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2062 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2063 _dbus_assert (rule->interface != NULL);
2064 _dbus_assert (rule->path != NULL);
2066 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2067 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2069 bus_match_rule_unref (rule);
2073 rule = check_parse (TRUE, "arg0='foo'");
2076 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2077 _dbus_assert (rule->args != NULL);
2078 _dbus_assert (rule->args_len == 1);
2079 _dbus_assert (rule->args[0] != NULL);
2080 _dbus_assert (rule->args[1] == NULL);
2081 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2083 bus_match_rule_unref (rule);
2086 rule = check_parse (TRUE, "arg1='foo'");
2089 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2090 _dbus_assert (rule->args != NULL);
2091 _dbus_assert (rule->args_len == 2);
2092 _dbus_assert (rule->args[0] == NULL);
2093 _dbus_assert (rule->args[1] != NULL);
2094 _dbus_assert (rule->args[2] == NULL);
2095 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2097 bus_match_rule_unref (rule);
2100 rule = check_parse (TRUE, "arg2='foo'");
2103 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2104 _dbus_assert (rule->args != NULL);
2105 _dbus_assert (rule->args_len == 3);
2106 _dbus_assert (rule->args[0] == NULL);
2107 _dbus_assert (rule->args[1] == NULL);
2108 _dbus_assert (rule->args[2] != NULL);
2109 _dbus_assert (rule->args[3] == NULL);
2110 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2112 bus_match_rule_unref (rule);
2115 rule = check_parse (TRUE, "arg40='foo'");
2118 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2119 _dbus_assert (rule->args != NULL);
2120 _dbus_assert (rule->args_len == 41);
2121 _dbus_assert (rule->args[0] == NULL);
2122 _dbus_assert (rule->args[1] == NULL);
2123 _dbus_assert (rule->args[40] != NULL);
2124 _dbus_assert (rule->args[41] == NULL);
2125 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2127 bus_match_rule_unref (rule);
2130 rule = check_parse (TRUE, "arg63='foo'");
2133 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2134 _dbus_assert (rule->args != NULL);
2135 _dbus_assert (rule->args_len == 64);
2136 _dbus_assert (rule->args[0] == NULL);
2137 _dbus_assert (rule->args[1] == NULL);
2138 _dbus_assert (rule->args[63] != NULL);
2139 _dbus_assert (rule->args[64] == NULL);
2140 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2142 bus_match_rule_unref (rule);
2145 rule = check_parse (TRUE, "arg7path='/foo'");
2148 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2149 _dbus_assert (rule->args != NULL);
2150 _dbus_assert (rule->args_len == 8);
2151 _dbus_assert (rule->args[7] != NULL);
2152 _dbus_assert (rule->args[8] == NULL);
2153 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2154 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2155 == BUS_MATCH_ARG_IS_PATH);
2157 bus_match_rule_unref (rule);
2160 /* Arg 0 namespace matches */
2161 rule = check_parse (TRUE, "arg0namespace='foo'");
2164 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2165 _dbus_assert (rule->args != NULL);
2166 _dbus_assert (rule->args_len == 1);
2167 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2168 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2169 == BUS_MATCH_ARG_NAMESPACE);
2171 bus_match_rule_unref (rule);
2174 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2177 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2178 _dbus_assert (rule->args != NULL);
2179 _dbus_assert (rule->args_len == 1);
2180 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2181 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2182 == BUS_MATCH_ARG_NAMESPACE);
2184 bus_match_rule_unref (rule);
2187 /* Only arg0namespace is supported. */
2188 rule = check_parse (FALSE, "arg1namespace='foo'");
2189 _dbus_assert (rule == NULL);
2191 /* An empty string isn't a valid namespace prefix (you should just not
2192 * specify this key at all).
2194 rule = check_parse (FALSE, "arg0namespace=''");
2195 _dbus_assert (rule == NULL);
2197 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2198 * spec allowed a single trailing period, which altered the semantics) */
2199 rule = check_parse (FALSE, "arg0namespace='foo.'");
2200 _dbus_assert (rule == NULL);
2202 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2203 _dbus_assert (rule == NULL);
2205 rule = check_parse (FALSE, "arg0namespace='foo..'");
2206 _dbus_assert (rule == NULL);
2208 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2209 _dbus_assert (rule == NULL);
2211 /* Too-large argN */
2212 rule = check_parse (FALSE, "arg300='foo'");
2213 _dbus_assert (rule == NULL);
2214 rule = check_parse (FALSE, "arg64='foo'");
2215 _dbus_assert (rule == NULL);
2218 rule = check_parse (FALSE, "arg='foo'");
2219 _dbus_assert (rule == NULL);
2220 rule = check_parse (FALSE, "argv='foo'");
2221 _dbus_assert (rule == NULL);
2222 rule = check_parse (FALSE, "arg3junk='foo'");
2223 _dbus_assert (rule == NULL);
2224 rule = check_parse (FALSE, "argument='foo'");
2225 _dbus_assert (rule == NULL);
2227 /* Reject duplicates */
2228 rule = check_parse (FALSE, "type='signal',type='method_call'");
2229 _dbus_assert (rule == NULL);
2231 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2234 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2235 _dbus_assert (rule->path != NULL);
2236 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2238 bus_match_rule_unref (rule);
2241 /* Almost a duplicate */
2242 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2243 _dbus_assert (rule == NULL);
2245 /* Trailing / was supported in the initial proposal, but now isn't */
2246 rule = check_parse (FALSE, "path_namespace='/foo/'");
2247 _dbus_assert (rule == NULL);
2249 /* Duplicates with the argN code */
2250 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2251 _dbus_assert (rule == NULL);
2252 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2253 _dbus_assert (rule == NULL);
2254 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2255 _dbus_assert (rule == NULL);
2257 /* Reject broken keys */
2258 rule = check_parse (FALSE, "blah='signal'");
2259 _dbus_assert (rule == NULL);
2261 /* Reject broken values */
2262 rule = check_parse (FALSE, "type='chouin'");
2263 _dbus_assert (rule == NULL);
2264 rule = check_parse (FALSE, "interface='abc@def++'");
2265 _dbus_assert (rule == NULL);
2266 rule = check_parse (FALSE, "service='youpi'");
2267 _dbus_assert (rule == NULL);
2269 /* Allow empty rule */
2270 rule = check_parse (TRUE, "");
2273 _dbus_assert (rule->flags == 0);
2275 bus_match_rule_unref (rule);
2278 /* All-whitespace rule is the same as empty */
2279 rule = check_parse (TRUE, " \t");
2282 _dbus_assert (rule->flags == 0);
2284 bus_match_rule_unref (rule);
2287 /* But with non-whitespace chars and no =value, it's not OK */
2288 rule = check_parse (FALSE, "type");
2289 _dbus_assert (rule == NULL);
2297 } equality_tests[] = {
2298 { "type='signal'", "type='signal'" },
2299 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2300 { "type='signal',member='bar'", "member='bar',type='signal'" },
2301 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2302 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2303 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2304 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2305 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2306 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2307 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2308 { "arg3='fool'", "arg3='fool'" },
2309 { "arg0namespace='fool'", "arg0namespace='fool'" },
2310 { "member='food'", "member='food'" }
2314 test_equality (void)
2319 while (i < _DBUS_N_ELEMENTS (equality_tests))
2321 BusMatchRule *first;
2322 BusMatchRule *second;
2325 first = check_parse (TRUE, equality_tests[i].first);
2326 _dbus_assert (first != NULL);
2327 second = check_parse (TRUE, equality_tests[i].second);
2328 _dbus_assert (second != NULL);
2330 if (!match_rule_equal (first, second))
2332 _dbus_warn ("rule %s and %s should have been equal\n",
2333 equality_tests[i].first,
2334 equality_tests[i].second);
2338 bus_match_rule_unref (second);
2340 /* Check that the rule is not equal to any of the
2341 * others besides its pair match
2344 while (j < _DBUS_N_ELEMENTS (equality_tests))
2348 second = check_parse (TRUE, equality_tests[j].second);
2350 if (match_rule_equal (first, second))
2352 _dbus_warn ("rule %s and %s should not have been equal\n",
2353 equality_tests[i].first,
2354 equality_tests[j].second);
2358 bus_match_rule_unref (second);
2364 bus_match_rule_unref (first);
2371 should_match_message_1[] = {
2373 "member='Frobated'",
2375 "type='signal',member='Frobated'",
2376 "type='signal',member='Frobated',arg0='foobar'",
2377 "member='Frobated',arg0='foobar'",
2378 "type='signal',arg0='foobar'",
2379 /* The definition of argXpath matches says: "As with normal argument matches,
2380 * if the argument is exactly equal to the string given in the match rule
2381 * then the rule is satisfied." So this should match (even though the
2382 * argument is not a valid path)!
2384 "arg0path='foobar'",
2385 "arg0namespace='foobar'",
2390 should_not_match_message_1[] = {
2391 "type='method_call'",
2393 "type='method_return'",
2394 "type='signal',member='Oopsed'",
2401 "arg0='foobar',arg1='abcdef'",
2402 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2403 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2405 "arg0path='foobar/'",
2407 "arg0namespace='foo'",
2408 "arg0namespace='foo',arg1='abcdef'",
2409 "arg0namespace='moo'",
2413 #define EXAMPLE_NAME "com.example.backend.foo"
2416 should_match_message_2[] = {
2417 /* EXAMPLE_NAME is in all of these namespaces */
2418 "arg0namespace='com.example.backend'",
2419 "arg0namespace='com.example'",
2420 "arg0namespace='com'",
2422 /* If the client specifies the name exactly, with no trailing period, then
2425 "arg0namespace='com.example.backend.foo'",
2431 should_not_match_message_2[] = {
2432 /* These are not even prefixes */
2433 "arg0namespace='com.example.backend.foo.bar'",
2434 "arg0namespace='com.example.backend.foobar'",
2436 /* These are prefixes, but they're not parent namespaces. */
2437 "arg0namespace='com.example.backend.fo'",
2438 "arg0namespace='com.example.backen'",
2439 "arg0namespace='com.exampl'",
2440 "arg0namespace='co'",
2446 check_matches (dbus_bool_t expected_to_match,
2448 DBusMessage *message,
2449 const char *rule_text)
2452 dbus_bool_t matched;
2454 rule = check_parse (TRUE, rule_text);
2455 _dbus_assert (rule != NULL);
2457 /* We can't test sender/destination rules since we pass NULL here */
2458 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2460 if (matched != expected_to_match)
2462 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2463 rule_text, expected_to_match ?
2464 "match" : "not match", number);
2468 bus_match_rule_unref (rule);
2472 check_matching (DBusMessage *message,
2474 const char **should_match,
2475 const char **should_not_match)
2480 while (should_match[i] != NULL)
2482 check_matches (TRUE, number, message, should_match[i]);
2487 while (should_not_match[i] != NULL)
2489 check_matches (FALSE, number, message, should_not_match[i]);
2495 test_matching (void)
2497 DBusMessage *message1, *message2;
2498 const char *v_STRING;
2499 dbus_int32_t v_INT32;
2501 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2502 _dbus_assert (message1 != NULL);
2503 if (!dbus_message_set_member (message1, "Frobated"))
2504 _dbus_assert_not_reached ("oom");
2506 v_STRING = "foobar";
2508 if (!dbus_message_append_args (message1,
2509 DBUS_TYPE_STRING, &v_STRING,
2510 DBUS_TYPE_INT32, &v_INT32,
2512 _dbus_assert_not_reached ("oom");
2514 check_matching (message1, 1,
2515 should_match_message_1,
2516 should_not_match_message_1);
2518 dbus_message_unref (message1);
2520 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2521 _dbus_assert (message2 != NULL);
2522 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2523 _dbus_assert_not_reached ("oom");
2525 /* Obviously this isn't really a NameOwnerChanged signal. */
2526 v_STRING = EXAMPLE_NAME;
2527 if (!dbus_message_append_args (message2,
2528 DBUS_TYPE_STRING, &v_STRING,
2530 _dbus_assert_not_reached ("oom");
2532 check_matching (message2, 2,
2533 should_match_message_2,
2534 should_not_match_message_2);
2536 dbus_message_unref (message2);
2539 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2541 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2542 * from the specification. Notice that not all of them are actually legal D-Bus
2545 * The author of this test takes no responsibility for the semantics of
2546 * this match rule key.
2548 static const char *paths_that_should_be_matched[] = {
2552 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2558 /* These paths should not be matched by PATH_MATCH_RULE. */
2559 static const char *paths_that_should_not_be_matched[] = {
2568 test_path_match (int type,
2570 const char *rule_text,
2572 dbus_bool_t should_match)
2574 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2575 dbus_bool_t matched;
2577 _dbus_assert (message != NULL);
2578 if (!dbus_message_set_member (message, "Foo"))
2579 _dbus_assert_not_reached ("oom");
2581 if (!dbus_message_append_args (message,
2584 _dbus_assert_not_reached ("oom");
2586 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2588 if (matched != should_match)
2590 _dbus_warn ("Expected rule %s to %s message "
2591 "with first arg %s of type '%c', failed\n",
2593 should_match ? "match" : "not match",
2599 dbus_message_unref (message);
2603 test_path_matching (void)
2608 rule = check_parse (TRUE, PATH_MATCH_RULE);
2609 _dbus_assert (rule != NULL);
2611 for (s = paths_that_should_be_matched; *s != NULL; s++)
2612 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2614 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2616 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2618 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2620 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2621 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2624 bus_match_rule_unref (rule);
2628 path_namespace_should_match_message_1[] = {
2629 "type='signal',path_namespace='/foo'",
2630 "type='signal',path_namespace='/foo/TheObjectManager'",
2635 path_namespace_should_not_match_message_1[] = {
2636 "type='signal',path_namespace='/bar'",
2637 "type='signal',path_namespace='/bar/TheObjectManager'",
2642 path_namespace_should_match_message_2[] = {
2643 "type='signal',path_namespace='/foo/TheObjectManager'",
2648 path_namespace_should_not_match_message_2[] = {
2653 path_namespace_should_match_message_3[] = {
2658 path_namespace_should_not_match_message_3[] = {
2659 "type='signal',path_namespace='/foo/TheObjectManager'",
2664 test_matching_path_namespace (void)
2666 DBusMessage *message1;
2667 DBusMessage *message2;
2668 DBusMessage *message3;
2670 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2671 _dbus_assert (message1 != NULL);
2672 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2673 _dbus_assert_not_reached ("oom");
2675 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2676 _dbus_assert (message2 != NULL);
2677 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2678 _dbus_assert_not_reached ("oom");
2680 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2681 _dbus_assert (message3 != NULL);
2682 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2683 _dbus_assert_not_reached ("oom");
2685 check_matching (message1, 1,
2686 path_namespace_should_match_message_1,
2687 path_namespace_should_not_match_message_1);
2688 check_matching (message2, 2,
2689 path_namespace_should_match_message_2,
2690 path_namespace_should_not_match_message_2);
2691 check_matching (message3, 3,
2692 path_namespace_should_match_message_3,
2693 path_namespace_should_not_match_message_3);
2695 dbus_message_unref (message3);
2696 dbus_message_unref (message2);
2697 dbus_message_unref (message1);
2701 bus_signals_test (const DBusString *test_data_dir)
2703 BusMatchmaker *matchmaker;
2705 matchmaker = bus_matchmaker_new ();
2706 bus_matchmaker_ref (matchmaker);
2707 bus_matchmaker_unref (matchmaker);
2708 bus_matchmaker_unref (matchmaker);
2710 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2711 _dbus_assert_not_reached ("Parsing match rules test failed");
2715 test_path_matching ();
2716 test_matching_path_namespace ();
2721 #endif /* DBUS_BUILD_TESTS */