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 */
46 unsigned int *arg_lens;
51 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u
52 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
54 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
57 bus_match_rule_new (DBusConnection *matches_go_to)
61 rule = dbus_new0 (BusMatchRule, 1);
66 rule->matches_go_to = matches_go_to;
68 #ifndef DBUS_BUILD_TESTS
69 _dbus_assert (rule->matches_go_to != NULL);
76 bus_match_rule_ref (BusMatchRule *rule)
78 _dbus_assert (rule->refcount > 0);
86 bus_match_rule_unref (BusMatchRule *rule)
88 _dbus_assert (rule->refcount > 0);
91 if (rule->refcount == 0)
93 dbus_free (rule->interface);
94 dbus_free (rule->member);
95 dbus_free (rule->sender);
96 dbus_free (rule->destination);
97 dbus_free (rule->path);
98 dbus_free (rule->path_prefix);
99 dbus_free (rule->arg_lens);
101 /* can't use dbus_free_string_array() since there
109 while (i < rule->args_len)
112 dbus_free (rule->args[i]);
116 dbus_free (rule->args);
123 #ifdef DBUS_ENABLE_VERBOSE_MODE
124 /* Note this function does not do escaping, so it's only
125 * good for debug spew at the moment
128 match_rule_to_string (BusMatchRule *rule)
133 if (!_dbus_string_init (&str))
136 while ((s = _dbus_strdup ("nomem")) == NULL)
137 ; /* only OK for debug spew... */
141 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
143 if (rule->message_type == DBUS_MESSAGE_TYPE_INVALID)
145 if (!_dbus_string_append_printf (&str, "type='INVALID'"))
148 else if (rule->message_type == DBUS_MESSAGE_TYPE_METHOD_CALL)
150 if (!_dbus_string_append_printf (&str, "type='method_call'"))
153 else if (rule->message_type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
155 if (!_dbus_string_append_printf (&str, "type='method_return'"))
158 else if (rule->message_type == DBUS_MESSAGE_TYPE_ERROR)
160 if (!_dbus_string_append_printf (&str, "type='error'"))
163 else if (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL)
165 if (!_dbus_string_append_printf (&str, "type='signal'"))
170 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
175 if (rule->flags & BUS_MATCH_INTERFACE)
177 if (_dbus_string_get_length (&str) > 0)
179 if (!_dbus_string_append (&str, ","))
183 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
187 if (rule->flags & BUS_MATCH_MEMBER)
189 if (_dbus_string_get_length (&str) > 0)
191 if (!_dbus_string_append (&str, ","))
195 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
199 if (rule->flags & BUS_MATCH_PATH)
201 if (_dbus_string_get_length (&str) > 0)
203 if (!_dbus_string_append (&str, ","))
207 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
211 if (rule->flags & BUS_MATCH_PATH_PREFIX)
213 if (_dbus_string_get_length (&str) > 0)
215 if (!_dbus_string_append (&str, ","))
219 if (!_dbus_string_append_printf (&str, "path_prefix='%s'", rule->path_prefix))
223 if (rule->flags & BUS_MATCH_SENDER)
225 if (_dbus_string_get_length (&str) > 0)
227 if (!_dbus_string_append (&str, ","))
231 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
235 if (rule->flags & BUS_MATCH_DESTINATION)
237 if (_dbus_string_get_length (&str) > 0)
239 if (!_dbus_string_append (&str, ","))
243 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
247 if (rule->flags & BUS_MATCH_ARGS)
251 _dbus_assert (rule->args != NULL);
254 while (i < rule->args_len)
256 if (rule->args[i] != NULL)
258 dbus_bool_t is_path, is_namespace;
260 if (_dbus_string_get_length (&str) > 0)
262 if (!_dbus_string_append (&str, ","))
266 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
267 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
269 if (!_dbus_string_append_printf (&str,
273 is_namespace ? "namespace" : "",
282 if (!_dbus_string_steal_data (&str, &ret))
285 _dbus_string_free (&str);
289 _dbus_string_free (&str);
292 while ((s = _dbus_strdup ("nomem")) == NULL)
293 ; /* only OK for debug spew... */
297 #endif /* DBUS_ENABLE_VERBOSE_MODE */
300 bus_match_rule_set_message_type (BusMatchRule *rule,
303 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
305 rule->message_type = type;
311 bus_match_rule_set_interface (BusMatchRule *rule,
312 const char *interface)
316 _dbus_assert (interface != NULL);
318 new = _dbus_strdup (interface);
322 rule->flags |= BUS_MATCH_INTERFACE;
323 dbus_free (rule->interface);
324 rule->interface = new;
330 bus_match_rule_set_member (BusMatchRule *rule,
335 _dbus_assert (member != NULL);
337 new = _dbus_strdup (member);
341 rule->flags |= BUS_MATCH_MEMBER;
342 dbus_free (rule->member);
349 bus_match_rule_set_sender (BusMatchRule *rule,
354 _dbus_assert (sender != NULL);
356 new = _dbus_strdup (sender);
360 rule->flags |= BUS_MATCH_SENDER;
361 dbus_free (rule->sender);
368 bus_match_rule_set_destination (BusMatchRule *rule,
369 const char *destination)
373 _dbus_assert (destination != NULL);
375 new = _dbus_strdup (destination);
379 rule->flags |= BUS_MATCH_DESTINATION;
380 dbus_free (rule->destination);
381 rule->destination = new;
387 bus_match_rule_set_path (BusMatchRule *rule,
392 _dbus_assert (path != NULL);
394 new = _dbus_strdup (path);
398 rule->flags |= BUS_MATCH_PATH;
399 dbus_free (rule->path);
406 bus_match_rule_set_path_prefix (BusMatchRule *rule,
407 const char *path_prefix)
411 _dbus_assert (path_prefix != NULL);
413 new = _dbus_strdup (path_prefix);
417 rule->flags |= BUS_MATCH_PATH_PREFIX;
418 dbus_free (rule->path_prefix);
419 rule->path_prefix = new;
425 bus_match_rule_set_arg (BusMatchRule *rule,
427 const DBusString *value,
429 dbus_bool_t is_namespace)
434 _dbus_assert (value != NULL);
436 /* args_len is the number of args not including null termination
439 if (arg >= rule->args_len)
441 unsigned int *new_arg_lens;
446 new_args_len = arg + 1;
448 /* add another + 1 here for null termination */
449 new_args = dbus_realloc (rule->args,
450 sizeof (char *) * (new_args_len + 1));
451 if (new_args == NULL)
454 /* NULL the new slots */
456 while (i <= new_args_len) /* <= for null termination */
462 rule->args = new_args;
464 /* and now add to the lengths */
465 new_arg_lens = dbus_realloc (rule->arg_lens,
466 sizeof (int) * (new_args_len + 1));
468 if (new_arg_lens == NULL)
471 /* zero the new slots */
473 while (i <= new_args_len) /* <= for null termination */
479 rule->arg_lens = new_arg_lens;
480 rule->args_len = new_args_len;
483 length = _dbus_string_get_length (value);
484 if (!_dbus_string_copy_data (value, &new))
487 rule->flags |= BUS_MATCH_ARGS;
489 dbus_free (rule->args[arg]);
490 rule->arg_lens[arg] = length;
491 rule->args[arg] = new;
494 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
497 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
499 /* NULL termination didn't get busted */
500 _dbus_assert (rule->args[rule->args_len] == NULL);
501 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
506 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
509 find_key (const DBusString *str,
517 const char *key_start;
520 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
522 s = _dbus_string_get_const_data (str);
526 while (*p && ISWHITE (*p))
531 while (*p && *p != '=' && !ISWHITE (*p))
536 while (*p && ISWHITE (*p))
539 if (key_start == key_end)
541 /* Empty match rules or trailing whitespace are OK */
548 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
549 "Match rule has a key with no subsequent '=' character");
554 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
566 find_value (const DBusString *str,
578 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
580 orig_len = _dbus_string_get_length (value);
582 s = _dbus_string_get_const_data (str);
590 if (quote_char == '\0')
610 if (!_dbus_string_append_byte (value, *p))
617 else if (quote_char == '\\')
619 /* \ only counts as an escape if escaping a quote mark */
622 if (!_dbus_string_append_byte (value, '\\'))
629 if (!_dbus_string_append_byte (value, *p))
639 _dbus_assert (quote_char == '\'');
647 if (!_dbus_string_append_byte (value, *p))
661 if (quote_char == '\\')
663 if (!_dbus_string_append_byte (value, '\\'))
669 else if (quote_char == '\'')
671 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
672 "Unbalanced quotation marks in match rule");
676 _dbus_assert (quote_char == '\0');
678 /* Zero-length values are allowed */
685 _DBUS_ASSERT_ERROR_IS_SET (error);
686 _dbus_string_set_length (value, orig_len);
690 /* duplicates aren't allowed so the real legitimate max is only 6 or
691 * so. Leaving extra so we don't have to bother to update it.
692 * FIXME this is sort of busted now with arg matching, but we let
693 * you match on up to 10 args for now
695 #define MAX_RULE_TOKENS 16
697 /* this is slightly too high level to be termed a "token"
698 * but let's not be pedantic.
707 tokenize_rule (const DBusString *rule_text,
708 RuleToken tokens[MAX_RULE_TOKENS],
719 if (!_dbus_string_init (&key))
725 if (!_dbus_string_init (&value))
727 _dbus_string_free (&key);
734 while (i < MAX_RULE_TOKENS &&
735 pos < _dbus_string_get_length (rule_text))
737 _dbus_assert (tokens[i].key == NULL);
738 _dbus_assert (tokens[i].value == NULL);
740 if (!find_key (rule_text, pos, &key, &pos, error))
743 if (_dbus_string_get_length (&key) == 0)
746 if (!_dbus_string_steal_data (&key, &tokens[i].key))
752 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
755 if (!_dbus_string_steal_data (&value, &tokens[i].value))
771 while (tokens[i].key || tokens[i].value)
773 dbus_free (tokens[i].key);
774 dbus_free (tokens[i].value);
775 tokens[i].key = NULL;
776 tokens[i].value = NULL;
781 _dbus_string_free (&key);
782 _dbus_string_free (&value);
788 bus_match_rule_parse_arg_match (BusMatchRule *rule,
790 const DBusString *value,
793 dbus_bool_t is_path = FALSE;
794 dbus_bool_t is_namespace = FALSE;
800 /* For now, arg0='foo' always implies that 'foo' is a
801 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
802 * if we wanted, which would specify another type, in which case
803 * arg0='5' would have the 5 parsed as an int rather than string.
806 /* First we need to parse arg0 = 0, arg27 = 27 */
808 _dbus_string_init_const (&key_str, key);
809 length = _dbus_string_get_length (&key_str);
811 if (_dbus_string_get_length (&key_str) < 4)
813 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
814 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
818 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
820 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
821 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
827 if ((end + strlen ("path")) == length &&
828 _dbus_string_ends_with_c_str (&key_str, "path"))
832 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
834 int value_len = _dbus_string_get_length (value);
839 _dbus_string_get_byte (value, value_len - 1) == '.')
842 if (!_dbus_validate_bus_namespace (value, 0, value_len))
844 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
845 "arg0namespace='%s' is not a valid (optionally "
846 "period-terminated) prefix of a bus name",
847 _dbus_string_get_const_data (value));
853 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
854 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
859 /* If we didn't check this we could allocate a huge amount of RAM */
860 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
862 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
863 "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);
867 if ((rule->flags & BUS_MATCH_ARGS) &&
868 rule->args_len > (int) arg &&
869 rule->args[arg] != NULL)
871 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
872 "Argument %d matched more than once in match rule\n", key);
876 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
885 _DBUS_ASSERT_ERROR_IS_SET (error);
890 * The format is comma-separated with strings quoted with single quotes
891 * as for the shell (to escape a literal single quote, use '\'').
893 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
894 * path='/bar/foo',destination=':452345.34'
898 bus_match_rule_parse (DBusConnection *matches_go_to,
899 const DBusString *rule_text,
903 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
906 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
908 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
910 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
911 "Match rule text is %d bytes, maximum is %d",
912 _dbus_string_get_length (rule_text),
913 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
917 memset (tokens, '\0', sizeof (tokens));
919 rule = bus_match_rule_new (matches_go_to);
926 if (!tokenize_rule (rule_text, tokens, error))
930 while (tokens[i].key != NULL)
934 const char *key = tokens[i].key;
935 const char *value = tokens[i].value;
937 _dbus_string_init_const (&tmp_str, value);
938 len = _dbus_string_get_length (&tmp_str);
940 if (strcmp (key, "type") == 0)
944 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
946 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
947 "Key %s specified twice in match rule\n", key);
951 t = dbus_message_type_from_string (value);
953 if (t == DBUS_MESSAGE_TYPE_INVALID)
955 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
956 "Invalid message type (%s) in match rule\n", value);
960 if (!bus_match_rule_set_message_type (rule, t))
966 else if (strcmp (key, "sender") == 0)
968 if (rule->flags & BUS_MATCH_SENDER)
970 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
971 "Key %s specified twice in match rule\n", key);
975 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
977 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
978 "Sender name '%s' is invalid\n", value);
982 if (!bus_match_rule_set_sender (rule, value))
988 else if (strcmp (key, "interface") == 0)
990 if (rule->flags & BUS_MATCH_INTERFACE)
992 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
993 "Key %s specified twice in match rule\n", key);
997 if (!_dbus_validate_interface (&tmp_str, 0, len))
999 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1000 "Interface name '%s' is invalid\n", value);
1004 if (!bus_match_rule_set_interface (rule, value))
1006 BUS_SET_OOM (error);
1010 else if (strcmp (key, "member") == 0)
1012 if (rule->flags & BUS_MATCH_MEMBER)
1014 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1015 "Key %s specified twice in match rule\n", key);
1019 if (!_dbus_validate_member (&tmp_str, 0, len))
1021 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1022 "Member name '%s' is invalid\n", value);
1026 if (!bus_match_rule_set_member (rule, value))
1028 BUS_SET_OOM (error);
1032 else if (strcmp (key, "path") == 0)
1034 if (rule->flags & BUS_MATCH_PATH)
1036 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1037 "Key %s specified twice in match rule\n", key);
1041 if (!_dbus_validate_path (&tmp_str, 0, len))
1043 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1044 "Path '%s' is invalid\n", value);
1048 if (!bus_match_rule_set_path (rule, value))
1050 BUS_SET_OOM (error);
1054 else if (strcmp (key, "path_prefix") == 0)
1056 int path_prefix_len;
1058 if (rule->flags & BUS_MATCH_PATH_PREFIX)
1060 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1061 "Key %s specified twice in match rule\n", key);
1065 path_prefix_len = len;
1066 if (_dbus_string_ends_with_c_str (&tmp_str, "/"))
1069 if (!_dbus_validate_path (&tmp_str, 0, path_prefix_len))
1071 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1072 "Path prefix '%s' is invalid\n", value);
1076 if (!bus_match_rule_set_path_prefix (rule, value))
1078 BUS_SET_OOM (error);
1082 else if (strcmp (key, "destination") == 0)
1084 if (rule->flags & BUS_MATCH_DESTINATION)
1086 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1087 "Key %s specified twice in match rule\n", key);
1091 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1093 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1094 "Destination name '%s' is invalid\n", value);
1098 if (!bus_match_rule_set_destination (rule, value))
1100 BUS_SET_OOM (error);
1104 else if (strncmp (key, "arg", 3) == 0)
1106 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1111 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1112 "Unknown key \"%s\" in match rule",
1124 _DBUS_ASSERT_ERROR_IS_SET (error);
1127 bus_match_rule_unref (rule);
1134 while (tokens[i].key || tokens[i].value)
1136 _dbus_assert (i < MAX_RULE_TOKENS);
1137 dbus_free (tokens[i].key);
1138 dbus_free (tokens[i].value);
1145 typedef struct RulePool RulePool;
1148 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1149 DBusHashTable *rules_by_iface;
1151 /* List of BusMatchRules which don't specify an interface */
1152 DBusList *rules_without_iface;
1155 struct BusMatchmaker
1159 /* Pools of rules, grouped by the type of message they match. 0
1160 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1163 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1167 rule_list_free (DBusList **rules)
1169 while (*rules != NULL)
1173 rule = (*rules)->data;
1174 bus_match_rule_unref (rule);
1175 _dbus_list_remove_link (rules, *rules);
1180 rule_list_ptr_free (DBusList **list)
1182 /* We have to cope with NULL because the hash table frees the "existing"
1183 * value (which is NULL) when creating a new table entry...
1187 rule_list_free (list);
1193 bus_matchmaker_new (void)
1195 BusMatchmaker *matchmaker;
1198 matchmaker = dbus_new0 (BusMatchmaker, 1);
1199 if (matchmaker == NULL)
1202 matchmaker->refcount = 1;
1204 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1206 RulePool *p = matchmaker->rules_by_type + i;
1208 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1209 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1211 if (p->rules_by_iface == NULL)
1218 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1220 RulePool *p = matchmaker->rules_by_type + i;
1222 if (p->rules_by_iface == NULL)
1225 _dbus_hash_table_unref (p->rules_by_iface);
1227 dbus_free (matchmaker);
1233 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1235 const char *interface,
1240 _dbus_assert (message_type >= 0);
1241 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1243 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1245 interface != NULL ? interface : "<null>");
1247 p = matchmaker->rules_by_type + message_type;
1249 if (interface == NULL)
1251 return &p->rules_without_iface;
1257 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1259 if (list == NULL && create)
1261 char *dupped_interface;
1263 list = dbus_new0 (DBusList *, 1);
1267 dupped_interface = _dbus_strdup (interface);
1268 if (dupped_interface == NULL)
1274 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1277 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1278 dupped_interface, list))
1281 dbus_free (dupped_interface);
1291 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1293 const char *interface,
1298 if (interface == NULL)
1304 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1305 message_type, interface);
1307 p = matchmaker->rules_by_type + message_type;
1309 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1312 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1316 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1318 _dbus_assert (matchmaker->refcount > 0);
1320 matchmaker->refcount += 1;
1326 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1328 _dbus_assert (matchmaker->refcount > 0);
1330 matchmaker->refcount -= 1;
1331 if (matchmaker->refcount == 0)
1335 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1337 RulePool *p = matchmaker->rules_by_type + i;
1339 _dbus_hash_table_unref (p->rules_by_iface);
1340 rule_list_free (&p->rules_without_iface);
1343 dbus_free (matchmaker);
1347 /* The rule can't be modified after it's added. */
1349 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1354 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1356 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1358 rule->interface != NULL ? rule->interface : "<null>");
1360 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1361 rule->interface, TRUE);
1366 if (!_dbus_list_append (rules, rule))
1369 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1371 _dbus_list_remove_last (rules, rule);
1372 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1373 rule->interface, rules);
1377 bus_match_rule_ref (rule);
1379 #ifdef DBUS_ENABLE_VERBOSE_MODE
1381 char *s = match_rule_to_string (rule);
1383 _dbus_verbose ("Added match rule %s to connection %p\n",
1384 s, rule->matches_go_to);
1393 match_rule_equal (BusMatchRule *a,
1396 if (a->flags != b->flags)
1399 if (a->matches_go_to != b->matches_go_to)
1402 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1403 a->message_type != b->message_type)
1406 if ((a->flags & BUS_MATCH_MEMBER) &&
1407 strcmp (a->member, b->member) != 0)
1410 if ((a->flags & BUS_MATCH_PATH) &&
1411 strcmp (a->path, b->path) != 0)
1414 if ((a->flags & BUS_MATCH_PATH_PREFIX) &&
1415 strcmp (a->path_prefix, b->path_prefix) != 0)
1418 if ((a->flags & BUS_MATCH_INTERFACE) &&
1419 strcmp (a->interface, b->interface) != 0)
1422 if ((a->flags & BUS_MATCH_SENDER) &&
1423 strcmp (a->sender, b->sender) != 0)
1426 if ((a->flags & BUS_MATCH_DESTINATION) &&
1427 strcmp (a->destination, b->destination) != 0)
1430 if (a->flags & BUS_MATCH_ARGS)
1434 if (a->args_len != b->args_len)
1438 while (i < a->args_len)
1442 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1445 if (a->arg_lens[i] != b->arg_lens[i])
1448 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1450 if (a->args[i] != NULL)
1452 _dbus_assert (b->args[i] != NULL);
1453 if (memcmp (a->args[i], b->args[i], length) != 0)
1465 bus_matchmaker_remove_rule_link (DBusList **rules,
1468 BusMatchRule *rule = link->data;
1470 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1471 _dbus_list_remove_link (rules, link);
1473 #ifdef DBUS_ENABLE_VERBOSE_MODE
1475 char *s = match_rule_to_string (rule);
1477 _dbus_verbose ("Removed match rule %s for connection %p\n",
1478 s, rule->matches_go_to);
1483 bus_match_rule_unref (rule);
1487 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1492 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1494 rule->interface != NULL ? rule->interface : "<null>");
1496 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1498 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1499 rule->interface, FALSE);
1501 /* We should only be asked to remove a rule by identity right after it was
1502 * added, so there should be a list for it.
1504 _dbus_assert (rules != NULL);
1506 _dbus_list_remove (rules, rule);
1507 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1510 #ifdef DBUS_ENABLE_VERBOSE_MODE
1512 char *s = match_rule_to_string (rule);
1514 _dbus_verbose ("Removed match rule %s for connection %p\n",
1515 s, rule->matches_go_to);
1520 bus_match_rule_unref (rule);
1523 /* Remove a single rule which is equal to the given rule by value */
1525 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1526 BusMatchRule *value,
1530 DBusList *link = NULL;
1532 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1533 value->message_type,
1534 value->interface != NULL ? value->interface : "<null>");
1536 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1537 value->interface, FALSE);
1541 /* we traverse backward because bus_connection_remove_match_rule()
1542 * removes the most-recently-added rule
1544 link = _dbus_list_get_last_link (rules);
1545 while (link != NULL)
1551 prev = _dbus_list_get_prev_link (rules, link);
1553 if (match_rule_equal (rule, value))
1555 bus_matchmaker_remove_rule_link (rules, link);
1565 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1566 "The given match rule wasn't found and can't be removed");
1570 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1577 rule_list_remove_by_connection (DBusList **rules,
1578 DBusConnection *connection)
1582 link = _dbus_list_get_first_link (rules);
1583 while (link != NULL)
1589 next = _dbus_list_get_next_link (rules, link);
1591 if (rule->matches_go_to == connection)
1593 bus_matchmaker_remove_rule_link (rules, link);
1595 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1596 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1598 /* The rule matches to/from a base service, see if it's the
1599 * one being disconnected, since we know this service name
1600 * will never be recycled.
1604 name = bus_connection_get_name (connection);
1605 _dbus_assert (name != NULL); /* because we're an active connection */
1607 if (((rule->flags & BUS_MATCH_SENDER) &&
1608 strcmp (rule->sender, name) == 0) ||
1609 ((rule->flags & BUS_MATCH_DESTINATION) &&
1610 strcmp (rule->destination, name) == 0))
1612 bus_matchmaker_remove_rule_link (rules, link);
1621 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1622 DBusConnection *connection)
1628 * This scans all match rules on the bus. We could avoid that
1629 * for the rules belonging to the connection, since we keep
1630 * a list of those; but for the rules that just refer to
1631 * the connection we'd need to do something more elaborate.
1634 _dbus_assert (bus_connection_is_active (connection));
1636 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1638 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1640 RulePool *p = matchmaker->rules_by_type + i;
1643 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1645 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1646 while (_dbus_hash_iter_next (&iter))
1648 DBusList **items = _dbus_hash_iter_get_value (&iter);
1650 rule_list_remove_by_connection (items, connection);
1653 _dbus_hash_iter_remove_entry (&iter);
1659 connection_is_primary_owner (DBusConnection *connection,
1660 const char *service_name)
1662 BusService *service;
1664 BusRegistry *registry;
1666 _dbus_assert (connection != NULL);
1668 registry = bus_connection_get_registry (connection);
1670 _dbus_string_init_const (&str, service_name);
1671 service = bus_registry_lookup (registry, &str);
1673 if (service == NULL)
1674 return FALSE; /* Service doesn't exist so connection can't own it. */
1676 return bus_service_get_primary_owners_connection (service) == connection;
1680 str_has_prefix (const char *str, const char *prefix)
1683 prefix_len = strlen (prefix);
1684 if (strncmp (str, prefix, prefix_len) == 0)
1691 match_rule_matches (BusMatchRule *rule,
1692 DBusConnection *sender,
1693 DBusConnection *addressed_recipient,
1694 DBusMessage *message,
1695 BusMatchFlags already_matched)
1699 /* All features of the match rule are AND'd together,
1700 * so FALSE if any of them don't match.
1703 /* sender/addressed_recipient of #NULL may mean bus driver,
1704 * or for addressed_recipient may mean a message with no
1705 * specific recipient (i.e. a signal)
1708 /* Don't bother re-matching features we've already checked implicitly. */
1709 flags = rule->flags & (~already_matched);
1711 if (flags & BUS_MATCH_MESSAGE_TYPE)
1713 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1715 if (rule->message_type != dbus_message_get_type (message))
1719 if (flags & BUS_MATCH_INTERFACE)
1723 _dbus_assert (rule->interface != NULL);
1725 iface = dbus_message_get_interface (message);
1729 if (strcmp (iface, rule->interface) != 0)
1733 if (flags & BUS_MATCH_MEMBER)
1737 _dbus_assert (rule->member != NULL);
1739 member = dbus_message_get_member (message);
1743 if (strcmp (member, rule->member) != 0)
1747 if (flags & BUS_MATCH_SENDER)
1749 _dbus_assert (rule->sender != NULL);
1753 if (strcmp (rule->sender,
1754 DBUS_SERVICE_DBUS) != 0)
1759 if (!connection_is_primary_owner (sender, rule->sender))
1764 if (flags & BUS_MATCH_DESTINATION)
1766 const char *destination;
1768 _dbus_assert (rule->destination != NULL);
1770 destination = dbus_message_get_destination (message);
1771 if (destination == NULL)
1774 if (addressed_recipient == NULL)
1776 if (strcmp (rule->destination,
1777 DBUS_SERVICE_DBUS) != 0)
1782 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1787 if (flags & BUS_MATCH_PATH)
1791 _dbus_assert (rule->path != NULL);
1793 path = dbus_message_get_path (message);
1797 if (strcmp (path, rule->path) != 0)
1801 if (flags & BUS_MATCH_PATH_PREFIX)
1806 _dbus_assert (rule->path_prefix != NULL);
1808 path = dbus_message_get_path (message);
1812 if (!str_has_prefix (path, rule->path_prefix))
1815 len = strlen (rule->path_prefix);
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 either ends in a '/',
1820 * or is followed by a '/' or the end of the path.
1822 if (rule->path_prefix[len - 1] != '/' &&
1823 path[len] != '\0' && path[len] != '/')
1827 if (flags & BUS_MATCH_ARGS)
1830 DBusMessageIter iter;
1832 _dbus_assert (rule->args != NULL);
1834 dbus_message_iter_init (message, &iter);
1837 while (i < rule->args_len)
1840 const char *expected_arg;
1841 int expected_length;
1842 dbus_bool_t is_path, is_namespace;
1844 expected_arg = rule->args[i];
1845 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1846 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1847 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1849 current_type = dbus_message_iter_get_arg_type (&iter);
1851 if (expected_arg != NULL)
1853 const char *actual_arg;
1856 if (current_type != DBUS_TYPE_STRING &&
1857 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1861 dbus_message_iter_get_basic (&iter, &actual_arg);
1862 _dbus_assert (actual_arg != NULL);
1864 actual_length = strlen (actual_arg);
1868 if (actual_length < expected_length &&
1869 actual_arg[actual_length - 1] != '/')
1872 if (expected_length < actual_length &&
1873 expected_arg[expected_length - 1] != '/')
1876 if (memcmp (actual_arg, expected_arg,
1877 MIN (actual_length, expected_length)) != 0)
1880 else if (is_namespace)
1882 if (expected_length > actual_length)
1885 /* If the actual argument doesn't start with the expected
1886 * namespace, then we don't match.
1888 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1891 if (expected_length < actual_length)
1893 /* Check that the actual argument is within the expected
1894 * namespace, rather than just starting with that string,
1895 * by checking that the matched prefix ends in a '.'.
1897 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1898 * which is an invalid namespace, but at some point the
1899 * daemon can't cover up for broken services.
1901 int expected_period_index;
1903 if (expected_arg[expected_length - 1] == '.')
1904 expected_period_index = expected_length - 1;
1906 expected_period_index = expected_length;
1908 if (actual_arg[expected_period_index] != '.')
1911 /* otherwise we had an exact match. */
1915 if (expected_length != actual_length ||
1916 memcmp (expected_arg, actual_arg, expected_length) != 0)
1922 if (current_type != DBUS_TYPE_INVALID)
1923 dbus_message_iter_next (&iter);
1933 get_recipients_from_list (DBusList **rules,
1934 DBusConnection *sender,
1935 DBusConnection *addressed_recipient,
1936 DBusMessage *message,
1937 DBusList **recipients_p)
1944 link = _dbus_list_get_first_link (rules);
1945 while (link != NULL)
1951 #ifdef DBUS_ENABLE_VERBOSE_MODE
1953 char *s = match_rule_to_string (rule);
1955 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1956 s, rule->matches_go_to);
1961 if (match_rule_matches (rule,
1962 sender, addressed_recipient, message,
1963 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
1965 _dbus_verbose ("Rule matched\n");
1967 /* Append to the list if we haven't already */
1968 if (bus_connection_mark_stamp (rule->matches_go_to))
1970 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1973 #ifdef DBUS_ENABLE_VERBOSE_MODE
1976 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1978 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1981 link = _dbus_list_get_next_link (rules, link);
1988 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1989 BusConnections *connections,
1990 DBusConnection *sender,
1991 DBusConnection *addressed_recipient,
1992 DBusMessage *message,
1993 DBusList **recipients_p)
1996 const char *interface;
1997 DBusList **neither, **just_type, **just_iface, **both;
1999 _dbus_assert (*recipients_p == NULL);
2001 /* This avoids sending same message to the same connection twice.
2002 * Purpose of the stamp instead of a bool is to avoid iterating over
2003 * all connections resetting the bool each time.
2005 bus_connections_increment_stamp (connections);
2007 /* addressed_recipient is already receiving the message, don't add to list.
2008 * NULL addressed_recipient means either bus driver, or this is a signal
2009 * and thus lacks a specific addressed_recipient.
2011 if (addressed_recipient != NULL)
2012 bus_connection_mark_stamp (addressed_recipient);
2014 type = dbus_message_get_type (message);
2015 interface = dbus_message_get_interface (message);
2017 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
2019 just_type = just_iface = both = NULL;
2021 if (interface != NULL)
2022 just_iface = bus_matchmaker_get_rules (matchmaker,
2023 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
2025 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
2027 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
2029 if (interface != NULL)
2030 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
2033 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
2034 message, recipients_p) &&
2035 get_recipients_from_list (just_iface, sender, addressed_recipient,
2036 message, recipients_p) &&
2037 get_recipients_from_list (just_type, sender, addressed_recipient,
2038 message, recipients_p) &&
2039 get_recipients_from_list (both, sender, addressed_recipient,
2040 message, recipients_p)))
2042 _dbus_list_clear (recipients_p);
2049 #ifdef DBUS_BUILD_TESTS
2053 static BusMatchRule*
2054 check_parse (dbus_bool_t should_succeed,
2061 dbus_error_init (&error);
2063 _dbus_string_init_const (&str, text);
2065 rule = bus_match_rule_parse (NULL, &str, &error);
2066 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2068 dbus_error_free (&error);
2072 if (should_succeed && rule == NULL)
2074 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
2075 error.name, error.message,
2076 _dbus_string_get_const_data (&str));
2080 if (!should_succeed && rule != NULL)
2082 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2083 _dbus_string_get_const_data (&str));
2087 dbus_error_free (&error);
2093 assert_large_rule (BusMatchRule *rule)
2095 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2096 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2097 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2098 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2099 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2100 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2102 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2103 _dbus_assert (rule->interface != NULL);
2104 _dbus_assert (rule->member != NULL);
2105 _dbus_assert (rule->sender != NULL);
2106 _dbus_assert (rule->destination != NULL);
2107 _dbus_assert (rule->path != NULL);
2109 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2110 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2111 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2112 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2113 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2117 test_parsing (void *data)
2121 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2124 assert_large_rule (rule);
2125 bus_match_rule_unref (rule);
2128 /* With extra whitespace and useless quotes */
2129 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2132 assert_large_rule (rule);
2133 bus_match_rule_unref (rule);
2137 /* A simple signal connection */
2138 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2141 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2142 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2143 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2145 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2146 _dbus_assert (rule->interface != NULL);
2147 _dbus_assert (rule->path != NULL);
2149 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2150 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2152 bus_match_rule_unref (rule);
2156 rule = check_parse (TRUE, "arg0='foo'");
2159 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2160 _dbus_assert (rule->args != NULL);
2161 _dbus_assert (rule->args_len == 1);
2162 _dbus_assert (rule->args[0] != NULL);
2163 _dbus_assert (rule->args[1] == NULL);
2164 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2166 bus_match_rule_unref (rule);
2169 rule = check_parse (TRUE, "arg1='foo'");
2172 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2173 _dbus_assert (rule->args != NULL);
2174 _dbus_assert (rule->args_len == 2);
2175 _dbus_assert (rule->args[0] == NULL);
2176 _dbus_assert (rule->args[1] != NULL);
2177 _dbus_assert (rule->args[2] == NULL);
2178 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2180 bus_match_rule_unref (rule);
2183 rule = check_parse (TRUE, "arg2='foo'");
2186 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2187 _dbus_assert (rule->args != NULL);
2188 _dbus_assert (rule->args_len == 3);
2189 _dbus_assert (rule->args[0] == NULL);
2190 _dbus_assert (rule->args[1] == NULL);
2191 _dbus_assert (rule->args[2] != NULL);
2192 _dbus_assert (rule->args[3] == NULL);
2193 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2195 bus_match_rule_unref (rule);
2198 rule = check_parse (TRUE, "arg40='foo'");
2201 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2202 _dbus_assert (rule->args != NULL);
2203 _dbus_assert (rule->args_len == 41);
2204 _dbus_assert (rule->args[0] == NULL);
2205 _dbus_assert (rule->args[1] == NULL);
2206 _dbus_assert (rule->args[40] != NULL);
2207 _dbus_assert (rule->args[41] == NULL);
2208 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2210 bus_match_rule_unref (rule);
2213 rule = check_parse (TRUE, "arg63='foo'");
2216 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2217 _dbus_assert (rule->args != NULL);
2218 _dbus_assert (rule->args_len == 64);
2219 _dbus_assert (rule->args[0] == NULL);
2220 _dbus_assert (rule->args[1] == NULL);
2221 _dbus_assert (rule->args[63] != NULL);
2222 _dbus_assert (rule->args[64] == NULL);
2223 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2225 bus_match_rule_unref (rule);
2228 rule = check_parse (TRUE, "arg7path='/foo'");
2231 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2232 _dbus_assert (rule->args != NULL);
2233 _dbus_assert (rule->args_len == 8);
2234 _dbus_assert (rule->args[7] != NULL);
2235 _dbus_assert (rule->args[8] == NULL);
2236 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2237 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2238 == BUS_MATCH_ARG_IS_PATH);
2240 bus_match_rule_unref (rule);
2243 /* Arg 0 namespace matches */
2244 rule = check_parse (TRUE, "arg0namespace='foo'");
2247 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2248 _dbus_assert (rule->args != NULL);
2249 _dbus_assert (rule->args_len == 1);
2250 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2251 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2252 == BUS_MATCH_ARG_NAMESPACE);
2254 bus_match_rule_unref (rule);
2257 rule = check_parse (TRUE, "arg0namespace='foo.'");
2260 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2261 _dbus_assert (rule->args != NULL);
2262 _dbus_assert (rule->args_len == 1);
2263 _dbus_assert (strcmp (rule->args[0], "foo.") == 0);
2264 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2265 == BUS_MATCH_ARG_NAMESPACE);
2267 bus_match_rule_unref (rule);
2270 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2273 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2274 _dbus_assert (rule->args != NULL);
2275 _dbus_assert (rule->args_len == 1);
2276 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2277 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2278 == BUS_MATCH_ARG_NAMESPACE);
2280 bus_match_rule_unref (rule);
2283 rule = check_parse (TRUE, "arg0namespace='foo.bar.'");
2286 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2287 _dbus_assert (rule->args != NULL);
2288 _dbus_assert (rule->args_len == 1);
2289 _dbus_assert (strcmp (rule->args[0], "foo.bar.") == 0);
2290 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2291 == BUS_MATCH_ARG_NAMESPACE);
2293 bus_match_rule_unref (rule);
2296 /* Only arg0namespace is supported. */
2297 rule = check_parse (FALSE, "arg1namespace='foo'");
2298 _dbus_assert (rule == NULL);
2300 /* An empty string isn't a valid namespace prefix (you should just not
2301 * specify this key at all).
2303 rule = check_parse (FALSE, "arg0namespace=''");
2304 _dbus_assert (rule == NULL);
2306 /* Two trailing periods on otherwise-valid namespaces aren't allowed. */
2307 rule = check_parse (FALSE, "arg0namespace='foo..'");
2308 _dbus_assert (rule == NULL);
2310 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2311 _dbus_assert (rule == NULL);
2313 /* Too-large argN */
2314 rule = check_parse (FALSE, "arg300='foo'");
2315 _dbus_assert (rule == NULL);
2316 rule = check_parse (FALSE, "arg64='foo'");
2317 _dbus_assert (rule == NULL);
2320 rule = check_parse (FALSE, "arg='foo'");
2321 _dbus_assert (rule == NULL);
2322 rule = check_parse (FALSE, "argv='foo'");
2323 _dbus_assert (rule == NULL);
2324 rule = check_parse (FALSE, "arg3junk='foo'");
2325 _dbus_assert (rule == NULL);
2326 rule = check_parse (FALSE, "argument='foo'");
2327 _dbus_assert (rule == NULL);
2329 /* Reject duplicates */
2330 rule = check_parse (FALSE, "type='signal',type='method_call'");
2331 _dbus_assert (rule == NULL);
2333 /* Duplicates with the argN code */
2334 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2335 _dbus_assert (rule == NULL);
2336 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2337 _dbus_assert (rule == NULL);
2338 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2339 _dbus_assert (rule == NULL);
2341 /* Reject broken keys */
2342 rule = check_parse (FALSE, "blah='signal'");
2343 _dbus_assert (rule == NULL);
2345 /* Reject broken values */
2346 rule = check_parse (FALSE, "type='chouin'");
2347 _dbus_assert (rule == NULL);
2348 rule = check_parse (FALSE, "interface='abc@def++'");
2349 _dbus_assert (rule == NULL);
2350 rule = check_parse (FALSE, "service='youpi'");
2351 _dbus_assert (rule == NULL);
2353 /* Allow empty rule */
2354 rule = check_parse (TRUE, "");
2357 _dbus_assert (rule->flags == 0);
2359 bus_match_rule_unref (rule);
2362 /* All-whitespace rule is the same as empty */
2363 rule = check_parse (TRUE, " \t");
2366 _dbus_assert (rule->flags == 0);
2368 bus_match_rule_unref (rule);
2371 /* But with non-whitespace chars and no =value, it's not OK */
2372 rule = check_parse (FALSE, "type");
2373 _dbus_assert (rule == NULL);
2381 } equality_tests[] = {
2382 { "type='signal'", "type='signal'" },
2383 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2384 { "type='signal',member='bar'", "member='bar',type='signal'" },
2385 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2386 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2387 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2388 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2389 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2390 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2391 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2392 { "arg3='fool'", "arg3='fool'" },
2393 { "arg0namespace='fool'", "arg0namespace='fool'" },
2394 { "member='food'", "member='food'" }
2398 test_equality (void)
2403 while (i < _DBUS_N_ELEMENTS (equality_tests))
2405 BusMatchRule *first;
2406 BusMatchRule *second;
2409 first = check_parse (TRUE, equality_tests[i].first);
2410 _dbus_assert (first != NULL);
2411 second = check_parse (TRUE, equality_tests[i].second);
2412 _dbus_assert (second != NULL);
2414 if (!match_rule_equal (first, second))
2416 _dbus_warn ("rule %s and %s should have been equal\n",
2417 equality_tests[i].first,
2418 equality_tests[i].second);
2422 bus_match_rule_unref (second);
2424 /* Check that the rule is not equal to any of the
2425 * others besides its pair match
2428 while (j < _DBUS_N_ELEMENTS (equality_tests))
2432 second = check_parse (TRUE, equality_tests[j].second);
2434 if (match_rule_equal (first, second))
2436 _dbus_warn ("rule %s and %s should not have been equal\n",
2437 equality_tests[i].first,
2438 equality_tests[j].second);
2442 bus_match_rule_unref (second);
2448 bus_match_rule_unref (first);
2455 should_match_message_1[] = {
2457 "member='Frobated'",
2459 "type='signal',member='Frobated'",
2460 "type='signal',member='Frobated',arg0='foobar'",
2461 "member='Frobated',arg0='foobar'",
2462 "type='signal',arg0='foobar'",
2463 /* The definition of argXpath matches says: "As with normal argument matches,
2464 * if the argument is exactly equal to the string given in the match rule
2465 * then the rule is satisfied." So this should match (even though the
2466 * argument is not a valid path)!
2468 "arg0path='foobar'",
2469 "arg0namespace='foobar'",
2474 should_not_match_message_1[] = {
2475 "type='method_call'",
2477 "type='method_return'",
2478 "type='signal',member='Oopsed'",
2485 "arg0='foobar',arg1='abcdef'",
2486 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2487 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2489 "arg0path='foobar/'",
2491 "arg0namespace='foo'",
2492 "arg0namespace='foo',arg1='abcdef'",
2493 "arg0namespace='moo'",
2497 #define EXAMPLE_NAME "com.example.backend.foo"
2500 should_match_message_2[] = {
2501 /* EXAMPLE_NAME is in all of these namespaces, specified with and without a
2502 * trailing period */
2503 "arg0namespace='com.example.backend.'",
2504 "arg0namespace='com.example.backend'",
2505 "arg0namespace='com.example.'",
2506 "arg0namespace='com.example'",
2507 "arg0namespace='com.'",
2508 "arg0namespace='com'",
2510 /* If the client specifies the name exactly, with no trailing period, then
2513 "arg0namespace='com.example.backend.foo'",
2519 should_not_match_message_2[] = {
2520 /* These are not even prefixes */
2521 "arg0namespace='com.example.backend.foo.bar'",
2522 "arg0namespace='com.example.backend.foobar'",
2523 "arg0namespace='com.example.backend.fo.'",
2525 /* This should match anything within the namespace com.example.backend.foo,
2526 * not including com.example.backend.foo itself.
2528 "arg0namespace='com.example.backend.foo.'",
2530 /* These are prefixes, but they're not parent namespaces. */
2531 "arg0namespace='com.example.backend.fo'",
2532 "arg0namespace='com.example.backen'",
2533 "arg0namespace='com.exampl'",
2534 "arg0namespace='co'",
2540 check_matches (dbus_bool_t expected_to_match,
2542 DBusMessage *message,
2543 const char *rule_text)
2546 dbus_bool_t matched;
2548 rule = check_parse (TRUE, rule_text);
2549 _dbus_assert (rule != NULL);
2551 /* We can't test sender/destination rules since we pass NULL here */
2552 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2554 if (matched != expected_to_match)
2556 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2557 rule_text, expected_to_match ?
2558 "match" : "not match", number);
2562 bus_match_rule_unref (rule);
2566 check_matching (DBusMessage *message,
2568 const char **should_match,
2569 const char **should_not_match)
2574 while (should_match[i] != NULL)
2576 check_matches (TRUE, number, message, should_match[i]);
2581 while (should_not_match[i] != NULL)
2583 check_matches (FALSE, number, message, should_not_match[i]);
2589 test_matching (void)
2591 DBusMessage *message1, *message2;
2592 const char *v_STRING;
2593 dbus_int32_t v_INT32;
2595 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2596 _dbus_assert (message1 != NULL);
2597 if (!dbus_message_set_member (message1, "Frobated"))
2598 _dbus_assert_not_reached ("oom");
2600 v_STRING = "foobar";
2602 if (!dbus_message_append_args (message1,
2603 DBUS_TYPE_STRING, &v_STRING,
2604 DBUS_TYPE_INT32, &v_INT32,
2606 _dbus_assert_not_reached ("oom");
2608 check_matching (message1, 1,
2609 should_match_message_1,
2610 should_not_match_message_1);
2612 dbus_message_unref (message1);
2614 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2615 _dbus_assert (message2 != NULL);
2616 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2617 _dbus_assert_not_reached ("oom");
2619 /* Obviously this isn't really a NameOwnerChanged signal. */
2620 v_STRING = EXAMPLE_NAME;
2621 if (!dbus_message_append_args (message2,
2622 DBUS_TYPE_STRING, &v_STRING,
2624 _dbus_assert_not_reached ("oom");
2626 check_matching (message2, 2,
2627 should_match_message_2,
2628 should_not_match_message_2);
2630 dbus_message_unref (message2);
2633 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2635 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2636 * from the specification. Notice that not all of them are actually legal D-Bus
2639 * The author of this test takes no responsibility for the semantics of
2640 * this match rule key.
2642 static const char *paths_that_should_be_matched[] = {
2646 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2652 /* These paths should not be matched by PATH_MATCH_RULE. */
2653 static const char *paths_that_should_not_be_matched[] = {
2662 test_path_match (int type,
2664 const char *rule_text,
2666 dbus_bool_t should_match)
2668 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2669 dbus_bool_t matched;
2671 _dbus_assert (message != NULL);
2672 if (!dbus_message_set_member (message, "Foo"))
2673 _dbus_assert_not_reached ("oom");
2675 if (!dbus_message_append_args (message,
2678 _dbus_assert_not_reached ("oom");
2680 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2682 if (matched != should_match)
2684 _dbus_warn ("Expected rule %s to %s message "
2685 "with first arg %s of type '%c', failed\n",
2687 should_match ? "match" : "not match",
2693 dbus_message_unref (message);
2697 test_path_matching (void)
2702 rule = check_parse (TRUE, PATH_MATCH_RULE);
2703 _dbus_assert (rule != NULL);
2705 for (s = paths_that_should_be_matched; *s != NULL; s++)
2706 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2708 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2710 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2712 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2714 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2715 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2718 bus_match_rule_unref (rule);
2722 path_prefix_should_match_message_1[] = {
2723 "type='signal',path_prefix='/foo'",
2724 "type='signal',path_prefix='/foo/'",
2725 "type='signal',path_prefix='/foo/TheObjectManager'",
2730 path_prefix_should_not_match_message_1[] = {
2731 "type='signal',path_prefix='/bar'",
2732 "type='signal',path_prefix='/bar/'",
2733 "type='signal',path_prefix='/bar/TheObjectManager'",
2738 path_prefix_should_match_message_2[] = {
2739 "type='signal',path_prefix='/foo/TheObjectManager'",
2740 "type='signal',path_prefix='/foo/TheObjectManager/'",
2745 path_prefix_should_not_match_message_2[] = {
2750 path_prefix_should_match_message_3[] = {
2755 path_prefix_should_not_match_message_3[] = {
2756 "type='signal',path_prefix='/foo/TheObjectManager'",
2757 "type='signal',path_prefix='/foo/TheObjectManager/'",
2762 test_matching_path_prefix (void)
2764 DBusMessage *message1;
2765 DBusMessage *message2;
2766 DBusMessage *message3;
2768 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2769 _dbus_assert (message1 != NULL);
2770 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2771 _dbus_assert_not_reached ("oom");
2773 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2774 _dbus_assert (message2 != NULL);
2775 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2776 _dbus_assert_not_reached ("oom");
2778 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2779 _dbus_assert (message3 != NULL);
2780 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2781 _dbus_assert_not_reached ("oom");
2783 check_matching (message1, 1,
2784 path_prefix_should_match_message_1,
2785 path_prefix_should_not_match_message_1);
2786 check_matching (message2, 2,
2787 path_prefix_should_match_message_2,
2788 path_prefix_should_not_match_message_2);
2789 check_matching (message3, 3,
2790 path_prefix_should_match_message_3,
2791 path_prefix_should_not_match_message_3);
2793 dbus_message_unref (message3);
2794 dbus_message_unref (message2);
2795 dbus_message_unref (message1);
2799 bus_signals_test (const DBusString *test_data_dir)
2801 BusMatchmaker *matchmaker;
2803 matchmaker = bus_matchmaker_new ();
2804 bus_matchmaker_ref (matchmaker);
2805 bus_matchmaker_unref (matchmaker);
2806 bus_matchmaker_unref (matchmaker);
2808 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2809 _dbus_assert_not_reached ("Parsing match rules test failed");
2813 test_path_matching ();
2814 test_matching_path_prefix ();
2819 #endif /* DBUS_BUILD_TESTS */