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_ENABLE_EMBEDDED_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 #if defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS)
122 /* Note this function does not do escaping, so it's only
123 * good for debug spew at the moment
125 /* returns NULL if no memory */
127 match_rule_to_string (BusMatchRule *rule)
132 if (!_dbus_string_init (&str))
137 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
139 if (!_dbus_string_append_printf (&str, "type='%s'",
140 dbus_message_type_to_string (rule->message_type)))
144 if (rule->flags & BUS_MATCH_INTERFACE)
146 if (_dbus_string_get_length (&str) > 0)
148 if (!_dbus_string_append (&str, ","))
152 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
156 if (rule->flags & BUS_MATCH_MEMBER)
158 if (_dbus_string_get_length (&str) > 0)
160 if (!_dbus_string_append (&str, ","))
164 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
168 if (rule->flags & BUS_MATCH_PATH)
170 if (_dbus_string_get_length (&str) > 0)
172 if (!_dbus_string_append (&str, ","))
176 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
180 if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
182 if (_dbus_string_get_length (&str) > 0)
184 if (!_dbus_string_append (&str, ","))
188 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
192 if (rule->flags & BUS_MATCH_SENDER)
194 if (_dbus_string_get_length (&str) > 0)
196 if (!_dbus_string_append (&str, ","))
200 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
204 if (rule->flags & BUS_MATCH_DESTINATION)
206 if (_dbus_string_get_length (&str) > 0)
208 if (!_dbus_string_append (&str, ","))
212 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
216 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
218 if (_dbus_string_get_length (&str) > 0)
220 if (!_dbus_string_append (&str, ","))
224 if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
225 (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
230 if (rule->flags & BUS_MATCH_ARGS)
234 _dbus_assert (rule->args != NULL);
237 while (i < rule->args_len)
239 if (rule->args[i] != NULL)
241 dbus_bool_t is_path, is_namespace;
243 if (_dbus_string_get_length (&str) > 0)
245 if (!_dbus_string_append (&str, ","))
249 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
250 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
252 if (!_dbus_string_append_printf (&str,
256 is_namespace ? "namespace" : "",
265 if (!_dbus_string_steal_data (&str, &ret))
268 _dbus_string_free (&str);
272 _dbus_string_free (&str);
275 #endif /* defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS) */
278 bus_match_rule_set_message_type (BusMatchRule *rule,
281 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
283 rule->message_type = type;
289 bus_match_rule_set_interface (BusMatchRule *rule,
290 const char *interface)
294 _dbus_assert (interface != NULL);
296 new = _dbus_strdup (interface);
300 rule->flags |= BUS_MATCH_INTERFACE;
301 dbus_free (rule->interface);
302 rule->interface = new;
308 bus_match_rule_set_member (BusMatchRule *rule,
313 _dbus_assert (member != NULL);
315 new = _dbus_strdup (member);
319 rule->flags |= BUS_MATCH_MEMBER;
320 dbus_free (rule->member);
327 bus_match_rule_set_sender (BusMatchRule *rule,
332 _dbus_assert (sender != NULL);
334 new = _dbus_strdup (sender);
338 rule->flags |= BUS_MATCH_SENDER;
339 dbus_free (rule->sender);
346 bus_match_rule_set_destination (BusMatchRule *rule,
347 const char *destination)
351 _dbus_assert (destination != NULL);
353 new = _dbus_strdup (destination);
357 rule->flags |= BUS_MATCH_DESTINATION;
358 dbus_free (rule->destination);
359 rule->destination = new;
365 bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
366 dbus_bool_t is_eavesdropping)
368 if (is_eavesdropping)
369 rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
371 rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
375 bus_match_rule_set_path (BusMatchRule *rule,
377 dbus_bool_t is_namespace)
381 _dbus_assert (path != NULL);
383 new = _dbus_strdup (path);
387 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
390 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
392 rule->flags |= BUS_MATCH_PATH;
394 dbus_free (rule->path);
401 bus_match_rule_set_arg (BusMatchRule *rule,
403 const DBusString *value,
405 dbus_bool_t is_namespace)
410 _dbus_assert (value != NULL);
412 /* args_len is the number of args not including null termination
415 if (arg >= rule->args_len)
417 unsigned int *new_arg_lens;
422 new_args_len = arg + 1;
424 /* add another + 1 here for null termination */
425 new_args = dbus_realloc (rule->args,
426 sizeof (char *) * (new_args_len + 1));
427 if (new_args == NULL)
430 /* NULL the new slots */
432 while (i <= new_args_len) /* <= for null termination */
438 rule->args = new_args;
440 /* and now add to the lengths */
441 new_arg_lens = dbus_realloc (rule->arg_lens,
442 sizeof (int) * (new_args_len + 1));
444 if (new_arg_lens == NULL)
447 /* zero the new slots */
449 while (i <= new_args_len) /* <= for null termination */
455 rule->arg_lens = new_arg_lens;
456 rule->args_len = new_args_len;
459 length = _dbus_string_get_length (value);
460 if (!_dbus_string_copy_data (value, &new))
463 rule->flags |= BUS_MATCH_ARGS;
465 dbus_free (rule->args[arg]);
466 rule->arg_lens[arg] = length;
467 rule->args[arg] = new;
470 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
473 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
475 /* NULL termination didn't get busted */
476 _dbus_assert (rule->args[rule->args_len] == NULL);
477 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
482 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
485 find_key (const DBusString *str,
493 const char *key_start;
496 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
498 s = _dbus_string_get_const_data (str);
502 while (*p && ISWHITE (*p))
507 while (*p && *p != '=' && !ISWHITE (*p))
512 while (*p && ISWHITE (*p))
515 if (key_start == key_end)
517 /* Empty match rules or trailing whitespace are OK */
524 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
525 "Match rule has a key with no subsequent '=' character");
530 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
542 find_value (const DBusString *str,
554 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
556 orig_len = _dbus_string_get_length (value);
558 s = _dbus_string_get_const_data (str);
566 if (quote_char == '\0')
586 if (!_dbus_string_append_byte (value, *p))
593 else if (quote_char == '\\')
595 /* \ only counts as an escape if escaping a quote mark */
598 if (!_dbus_string_append_byte (value, '\\'))
605 if (!_dbus_string_append_byte (value, *p))
615 _dbus_assert (quote_char == '\'');
623 if (!_dbus_string_append_byte (value, *p))
637 if (quote_char == '\\')
639 if (!_dbus_string_append_byte (value, '\\'))
645 else if (quote_char == '\'')
647 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
648 "Unbalanced quotation marks in match rule");
652 _dbus_assert (quote_char == '\0');
654 /* Zero-length values are allowed */
661 _DBUS_ASSERT_ERROR_IS_SET (error);
662 _dbus_string_set_length (value, orig_len);
666 /* duplicates aren't allowed so the real legitimate max is only 6 or
667 * so. Leaving extra so we don't have to bother to update it.
668 * FIXME this is sort of busted now with arg matching, but we let
669 * you match on up to 10 args for now
671 #define MAX_RULE_TOKENS 16
673 /* this is slightly too high level to be termed a "token"
674 * but let's not be pedantic.
683 tokenize_rule (const DBusString *rule_text,
684 RuleToken tokens[MAX_RULE_TOKENS],
695 if (!_dbus_string_init (&key))
701 if (!_dbus_string_init (&value))
703 _dbus_string_free (&key);
710 while (i < MAX_RULE_TOKENS &&
711 pos < _dbus_string_get_length (rule_text))
713 _dbus_assert (tokens[i].key == NULL);
714 _dbus_assert (tokens[i].value == NULL);
716 if (!find_key (rule_text, pos, &key, &pos, error))
719 if (_dbus_string_get_length (&key) == 0)
722 if (!_dbus_string_steal_data (&key, &tokens[i].key))
728 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
731 if (!_dbus_string_steal_data (&value, &tokens[i].value))
747 while (tokens[i].key || tokens[i].value)
749 dbus_free (tokens[i].key);
750 dbus_free (tokens[i].value);
751 tokens[i].key = NULL;
752 tokens[i].value = NULL;
757 _dbus_string_free (&key);
758 _dbus_string_free (&value);
764 bus_match_rule_parse_arg_match (BusMatchRule *rule,
766 const DBusString *value,
769 dbus_bool_t is_path = FALSE;
770 dbus_bool_t is_namespace = FALSE;
776 /* For now, arg0='foo' always implies that 'foo' is a
777 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
778 * if we wanted, which would specify another type, in which case
779 * arg0='5' would have the 5 parsed as an int rather than string.
782 /* First we need to parse arg0 = 0, arg27 = 27 */
784 _dbus_string_init_const (&key_str, key);
785 length = _dbus_string_get_length (&key_str);
787 if (_dbus_string_get_length (&key_str) < 4)
789 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
790 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
794 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
796 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
797 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
803 if ((end + strlen ("path")) == length &&
804 _dbus_string_ends_with_c_str (&key_str, "path"))
808 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
810 int value_len = _dbus_string_get_length (value);
814 if (!_dbus_validate_bus_namespace (value, 0, value_len))
816 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
817 "arg0namespace='%s' is not a valid prefix of a bus name",
818 _dbus_string_get_const_data (value));
824 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
825 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
830 /* If we didn't check this we could allocate a huge amount of RAM */
831 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
833 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
834 "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);
838 if ((rule->flags & BUS_MATCH_ARGS) &&
839 rule->args_len > (int) arg &&
840 rule->args[arg] != NULL)
842 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
843 "Argument %d matched more than once in match rule\n", key);
847 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
856 _DBUS_ASSERT_ERROR_IS_SET (error);
861 * The format is comma-separated with strings quoted with single quotes
862 * as for the shell (to escape a literal single quote, use '\'').
864 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
865 * path='/bar/foo',destination=':452345.34'
869 bus_match_rule_parse (DBusConnection *matches_go_to,
870 const DBusString *rule_text,
874 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
877 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
879 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
881 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
882 "Match rule text is %d bytes, maximum is %d",
883 _dbus_string_get_length (rule_text),
884 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
888 memset (tokens, '\0', sizeof (tokens));
890 rule = bus_match_rule_new (matches_go_to);
897 if (!tokenize_rule (rule_text, tokens, error))
901 while (tokens[i].key != NULL)
905 const char *key = tokens[i].key;
906 const char *value = tokens[i].value;
908 _dbus_string_init_const (&tmp_str, value);
909 len = _dbus_string_get_length (&tmp_str);
911 if (strcmp (key, "type") == 0)
915 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
917 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
918 "Key %s specified twice in match rule\n", key);
922 t = dbus_message_type_from_string (value);
924 if (t == DBUS_MESSAGE_TYPE_INVALID)
926 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
927 "Invalid message type (%s) in match rule\n", value);
931 if (!bus_match_rule_set_message_type (rule, t))
937 else if (strcmp (key, "sender") == 0)
939 if (rule->flags & BUS_MATCH_SENDER)
941 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
942 "Key %s specified twice in match rule\n", key);
946 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
948 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
949 "Sender name '%s' is invalid\n", value);
953 if (!bus_match_rule_set_sender (rule, value))
959 else if (strcmp (key, "interface") == 0)
961 if (rule->flags & BUS_MATCH_INTERFACE)
963 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
964 "Key %s specified twice in match rule\n", key);
968 if (!_dbus_validate_interface (&tmp_str, 0, len))
970 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
971 "Interface name '%s' is invalid\n", value);
975 if (!bus_match_rule_set_interface (rule, value))
981 else if (strcmp (key, "member") == 0)
983 if (rule->flags & BUS_MATCH_MEMBER)
985 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
986 "Key %s specified twice in match rule\n", key);
990 if (!_dbus_validate_member (&tmp_str, 0, len))
992 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
993 "Member name '%s' is invalid\n", value);
997 if (!bus_match_rule_set_member (rule, value))
1003 else if (strcmp (key, "path") == 0 ||
1004 strcmp (key, "path_namespace") == 0)
1006 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1008 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
1010 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1011 "path or path_namespace specified twice in match rule\n");
1015 if (!_dbus_validate_path (&tmp_str, 0, len))
1017 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1018 "Path '%s' is invalid\n", value);
1022 if (!bus_match_rule_set_path (rule, value, is_namespace))
1024 BUS_SET_OOM (error);
1028 else if (strcmp (key, "destination") == 0)
1030 if (rule->flags & BUS_MATCH_DESTINATION)
1032 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1033 "Key %s specified twice in match rule\n", key);
1037 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1039 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1040 "Destination name '%s' is invalid\n", value);
1044 if (!bus_match_rule_set_destination (rule, value))
1046 BUS_SET_OOM (error);
1050 else if (strcmp (key, "eavesdrop") == 0)
1052 /* do not detect "eavesdrop" being used more than once in rule:
1053 * 1) it's not possible, it's only in the flags
1054 * 2) it might be used twice to disable eavesdropping when it's
1055 * automatically added (eg dbus-monitor/bustle) */
1057 /* we accept only "true|false" as possible values */
1058 if ((strcmp (value, "true") == 0))
1060 bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1062 else if (strcmp (value, "false") == 0)
1064 bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1068 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1069 "eavesdrop='%s' is invalid, "
1070 "it should be 'true' or 'false'\n",
1075 else if (strncmp (key, "arg", 3) == 0)
1077 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1082 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1083 "Unknown key \"%s\" in match rule",
1095 _DBUS_ASSERT_ERROR_IS_SET (error);
1098 bus_match_rule_unref (rule);
1105 while (tokens[i].key || tokens[i].value)
1107 _dbus_assert (i < MAX_RULE_TOKENS);
1108 dbus_free (tokens[i].key);
1109 dbus_free (tokens[i].value);
1116 typedef struct RulePool RulePool;
1119 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1120 DBusHashTable *rules_by_iface;
1122 /* List of BusMatchRules which don't specify an interface */
1123 DBusList *rules_without_iface;
1126 struct BusMatchmaker
1130 /* Pools of rules, grouped by the type of message they match. 0
1131 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1134 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1137 #ifdef DBUS_ENABLE_STATS
1139 bus_match_rule_dump (BusMatchmaker *matchmaker,
1140 DBusConnection *conn_filter,
1141 DBusMessageIter *arr_iter)
1145 for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++)
1151 _dbus_hash_iter_init (matchmaker->rules_by_type[i].rules_by_iface, &iter);
1152 while (_dbus_hash_iter_next (&iter))
1154 list = _dbus_hash_iter_get_value (&iter);
1155 for (link = _dbus_list_get_first_link (list);
1157 link = _dbus_list_get_next_link (list, link))
1159 BusMatchRule *rule = link->data;
1161 if (rule->matches_go_to == conn_filter)
1163 char *s = match_rule_to_string (rule);
1168 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1177 list = &matchmaker->rules_by_type[i].rules_without_iface;
1178 for (link = _dbus_list_get_first_link (list);
1180 link = _dbus_list_get_next_link (list, link))
1182 BusMatchRule *rule = link->data;
1184 if (rule->matches_go_to == conn_filter)
1186 char *s = match_rule_to_string (rule);
1191 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1206 rule_list_free (DBusList **rules)
1208 while (*rules != NULL)
1212 rule = (*rules)->data;
1213 bus_match_rule_unref (rule);
1214 _dbus_list_remove_link (rules, *rules);
1219 rule_list_ptr_free (DBusList **list)
1221 /* We have to cope with NULL because the hash table frees the "existing"
1222 * value (which is NULL) when creating a new table entry...
1226 rule_list_free (list);
1232 bus_matchmaker_new (void)
1234 BusMatchmaker *matchmaker;
1237 matchmaker = dbus_new0 (BusMatchmaker, 1);
1238 if (matchmaker == NULL)
1241 matchmaker->refcount = 1;
1243 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1245 RulePool *p = matchmaker->rules_by_type + i;
1247 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1248 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1250 if (p->rules_by_iface == NULL)
1257 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1259 RulePool *p = matchmaker->rules_by_type + i;
1261 if (p->rules_by_iface == NULL)
1264 _dbus_hash_table_unref (p->rules_by_iface);
1266 dbus_free (matchmaker);
1272 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1274 const char *interface,
1279 _dbus_assert (message_type >= 0);
1280 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1282 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1284 interface != NULL ? interface : "<null>");
1286 p = matchmaker->rules_by_type + message_type;
1288 if (interface == NULL)
1290 return &p->rules_without_iface;
1296 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1298 if (list == NULL && create)
1300 char *dupped_interface;
1302 list = dbus_new0 (DBusList *, 1);
1306 dupped_interface = _dbus_strdup (interface);
1307 if (dupped_interface == NULL)
1313 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1316 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1317 dupped_interface, list))
1320 dbus_free (dupped_interface);
1330 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1332 const char *interface,
1337 if (interface == NULL)
1343 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1344 message_type, interface);
1346 p = matchmaker->rules_by_type + message_type;
1348 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1351 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1355 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1357 _dbus_assert (matchmaker->refcount > 0);
1359 matchmaker->refcount += 1;
1365 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1367 _dbus_assert (matchmaker->refcount > 0);
1369 matchmaker->refcount -= 1;
1370 if (matchmaker->refcount == 0)
1374 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1376 RulePool *p = matchmaker->rules_by_type + i;
1378 _dbus_hash_table_unref (p->rules_by_iface);
1379 rule_list_free (&p->rules_without_iface);
1382 dbus_free (matchmaker);
1386 /* The rule can't be modified after it's added. */
1388 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1393 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1395 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1397 rule->interface != NULL ? rule->interface : "<null>");
1399 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1400 rule->interface, TRUE);
1405 if (!_dbus_list_append (rules, rule))
1408 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1410 _dbus_list_remove_last (rules, rule);
1411 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1412 rule->interface, rules);
1416 bus_match_rule_ref (rule);
1418 #ifdef DBUS_ENABLE_VERBOSE_MODE
1420 char *s = match_rule_to_string (rule);
1422 _dbus_verbose ("Added match rule %s to connection %p\n",
1423 s ? s : "nomem", rule->matches_go_to);
1432 match_rule_equal (BusMatchRule *a,
1435 if (a->flags != b->flags)
1438 if (a->matches_go_to != b->matches_go_to)
1441 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1442 a->message_type != b->message_type)
1445 if ((a->flags & BUS_MATCH_MEMBER) &&
1446 strcmp (a->member, b->member) != 0)
1449 if ((a->flags & BUS_MATCH_PATH) &&
1450 strcmp (a->path, b->path) != 0)
1453 if ((a->flags & BUS_MATCH_INTERFACE) &&
1454 strcmp (a->interface, b->interface) != 0)
1457 if ((a->flags & BUS_MATCH_SENDER) &&
1458 strcmp (a->sender, b->sender) != 0)
1461 if ((a->flags & BUS_MATCH_DESTINATION) &&
1462 strcmp (a->destination, b->destination) != 0)
1465 /* we already compared the value of flags, and
1466 * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1468 if (a->flags & BUS_MATCH_ARGS)
1472 if (a->args_len != b->args_len)
1476 while (i < a->args_len)
1480 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1483 if (a->arg_lens[i] != b->arg_lens[i])
1486 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1488 if (a->args[i] != NULL)
1490 _dbus_assert (b->args[i] != NULL);
1491 if (memcmp (a->args[i], b->args[i], length) != 0)
1503 bus_matchmaker_remove_rule_link (DBusList **rules,
1506 BusMatchRule *rule = link->data;
1508 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1509 _dbus_list_remove_link (rules, link);
1511 #ifdef DBUS_ENABLE_VERBOSE_MODE
1513 char *s = match_rule_to_string (rule);
1515 _dbus_verbose ("Removed match rule %s for connection %p\n",
1516 s ? s : "nomem", rule->matches_go_to);
1521 bus_match_rule_unref (rule);
1525 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1530 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1532 rule->interface != NULL ? rule->interface : "<null>");
1534 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1536 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1537 rule->interface, FALSE);
1539 /* We should only be asked to remove a rule by identity right after it was
1540 * added, so there should be a list for it.
1542 _dbus_assert (rules != NULL);
1544 _dbus_list_remove (rules, rule);
1545 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1548 #ifdef DBUS_ENABLE_VERBOSE_MODE
1550 char *s = match_rule_to_string (rule);
1552 _dbus_verbose ("Removed match rule %s for connection %p\n",
1553 s ? s : "nomem", rule->matches_go_to);
1558 bus_match_rule_unref (rule);
1561 /* Remove a single rule which is equal to the given rule by value */
1563 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1564 BusMatchRule *value,
1568 DBusList *link = NULL;
1570 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1571 value->message_type,
1572 value->interface != NULL ? value->interface : "<null>");
1574 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1575 value->interface, FALSE);
1579 /* we traverse backward because bus_connection_remove_match_rule()
1580 * removes the most-recently-added rule
1582 link = _dbus_list_get_last_link (rules);
1583 while (link != NULL)
1589 prev = _dbus_list_get_prev_link (rules, link);
1591 if (match_rule_equal (rule, value))
1593 bus_matchmaker_remove_rule_link (rules, link);
1603 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1604 "The given match rule wasn't found and can't be removed");
1608 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1615 rule_list_remove_by_connection (DBusList **rules,
1616 DBusConnection *connection)
1620 link = _dbus_list_get_first_link (rules);
1621 while (link != NULL)
1627 next = _dbus_list_get_next_link (rules, link);
1629 if (rule->matches_go_to == connection)
1631 bus_matchmaker_remove_rule_link (rules, link);
1633 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1634 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1636 /* The rule matches to/from a base service, see if it's the
1637 * one being disconnected, since we know this service name
1638 * will never be recycled.
1642 name = bus_connection_get_name (connection);
1643 _dbus_assert (name != NULL); /* because we're an active connection */
1645 if (((rule->flags & BUS_MATCH_SENDER) &&
1646 strcmp (rule->sender, name) == 0) ||
1647 ((rule->flags & BUS_MATCH_DESTINATION) &&
1648 strcmp (rule->destination, name) == 0))
1650 bus_matchmaker_remove_rule_link (rules, link);
1659 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1660 DBusConnection *connection)
1666 * This scans all match rules on the bus. We could avoid that
1667 * for the rules belonging to the connection, since we keep
1668 * a list of those; but for the rules that just refer to
1669 * the connection we'd need to do something more elaborate.
1672 _dbus_assert (bus_connection_is_active (connection));
1674 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1676 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1678 RulePool *p = matchmaker->rules_by_type + i;
1681 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1683 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1684 while (_dbus_hash_iter_next (&iter))
1686 DBusList **items = _dbus_hash_iter_get_value (&iter);
1688 rule_list_remove_by_connection (items, connection);
1691 _dbus_hash_iter_remove_entry (&iter);
1697 connection_is_primary_owner (DBusConnection *connection,
1698 const char *service_name)
1700 BusService *service;
1702 BusRegistry *registry;
1704 _dbus_assert (connection != NULL);
1706 registry = bus_connection_get_registry (connection);
1708 _dbus_string_init_const (&str, service_name);
1709 service = bus_registry_lookup (registry, &str);
1711 if (service == NULL)
1712 return FALSE; /* Service doesn't exist so connection can't own it. */
1714 return bus_service_get_primary_owners_connection (service) == connection;
1718 str_has_prefix (const char *str, const char *prefix)
1721 prefix_len = strlen (prefix);
1722 if (strncmp (str, prefix, prefix_len) == 0)
1729 match_rule_matches (BusMatchRule *rule,
1730 DBusConnection *sender,
1731 DBusConnection *addressed_recipient,
1732 DBusMessage *message,
1733 BusMatchFlags already_matched)
1735 dbus_bool_t wants_to_eavesdrop = FALSE;
1738 /* All features of the match rule are AND'd together,
1739 * so FALSE if any of them don't match.
1742 /* sender/addressed_recipient of #NULL may mean bus driver,
1743 * or for addressed_recipient may mean a message with no
1744 * specific recipient (i.e. a signal)
1747 /* Don't bother re-matching features we've already checked implicitly. */
1748 flags = rule->flags & (~already_matched);
1750 if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
1751 wants_to_eavesdrop = TRUE;
1753 if (flags & BUS_MATCH_MESSAGE_TYPE)
1755 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1757 if (rule->message_type != dbus_message_get_type (message))
1761 if (flags & BUS_MATCH_INTERFACE)
1765 _dbus_assert (rule->interface != NULL);
1767 iface = dbus_message_get_interface (message);
1771 if (strcmp (iface, rule->interface) != 0)
1775 if (flags & BUS_MATCH_MEMBER)
1779 _dbus_assert (rule->member != NULL);
1781 member = dbus_message_get_member (message);
1785 if (strcmp (member, rule->member) != 0)
1789 if (flags & BUS_MATCH_SENDER)
1791 _dbus_assert (rule->sender != NULL);
1795 if (strcmp (rule->sender,
1796 DBUS_SERVICE_DBUS) != 0)
1801 if (!connection_is_primary_owner (sender, rule->sender))
1806 /* Note: this part is relevant for eavesdropper rules:
1808 * 1) rule has a destination to be matched
1809 * (flag BUS_MATCH_DESTINATION present). Rule will match if:
1810 * - rule->destination matches the addressed_recipient
1812 * - wants_to_eavesdrop=TRUE
1814 * Note: (the case in which addressed_recipient is the actual rule owner
1815 * is handled elsewere in dispatch.c:bus_dispatch_matches().
1817 * 2) rule has no destination. Rule will match if:
1818 * - message has no specified destination (ie broadcasts)
1819 * (Note: this will rule out unicast method calls and unicast signals,
1820 * fixing FDO#269748)
1822 * - wants_to_eavesdrop=TRUE (destination-catch-all situation)
1824 if (flags & BUS_MATCH_DESTINATION)
1826 const char *destination;
1828 _dbus_assert (rule->destination != NULL);
1830 destination = dbus_message_get_destination (message);
1831 if (destination == NULL)
1832 /* broadcast, but this rule specified a destination: no match */
1835 /* rule owner does not intend to eavesdrop: we'll deliver only msgs
1836 * directed to it, NOT MATCHING */
1837 if (!wants_to_eavesdrop)
1840 if (addressed_recipient == NULL)
1842 if (strcmp (rule->destination,
1843 DBUS_SERVICE_DBUS) != 0)
1848 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1851 } else { /* no destination in rule */
1852 dbus_bool_t msg_is_broadcast;
1854 _dbus_assert (rule->destination == NULL);
1856 msg_is_broadcast = (dbus_message_get_destination (message) == NULL);
1858 if (!wants_to_eavesdrop && !msg_is_broadcast)
1861 /* if we are here rule owner intends to eavesdrop
1863 * message is being broadcasted */
1866 if (flags & BUS_MATCH_PATH)
1870 _dbus_assert (rule->path != NULL);
1872 path = dbus_message_get_path (message);
1876 if (strcmp (path, rule->path) != 0)
1880 if (flags & BUS_MATCH_PATH_NAMESPACE)
1885 _dbus_assert (rule->path != NULL);
1887 path = dbus_message_get_path (message);
1891 if (!str_has_prefix (path, rule->path))
1894 len = strlen (rule->path);
1896 /* Check that the actual argument is within the expected
1897 * namespace, rather than just starting with that string,
1898 * by checking that the matched prefix is followed by a '/'
1899 * or the end of the path.
1901 * Special case: the only valid path of length 1, "/",
1902 * matches everything.
1904 if (len > 1 && path[len] != '\0' && path[len] != '/')
1908 if (flags & BUS_MATCH_ARGS)
1911 DBusMessageIter iter;
1913 _dbus_assert (rule->args != NULL);
1915 dbus_message_iter_init (message, &iter);
1918 while (i < rule->args_len)
1921 const char *expected_arg;
1922 int expected_length;
1923 dbus_bool_t is_path, is_namespace;
1925 expected_arg = rule->args[i];
1926 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1927 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1928 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1930 current_type = dbus_message_iter_get_arg_type (&iter);
1932 if (expected_arg != NULL)
1934 const char *actual_arg;
1937 if (current_type != DBUS_TYPE_STRING &&
1938 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1942 dbus_message_iter_get_basic (&iter, &actual_arg);
1943 _dbus_assert (actual_arg != NULL);
1945 actual_length = strlen (actual_arg);
1949 if (actual_length < expected_length &&
1950 actual_arg[actual_length - 1] != '/')
1953 if (expected_length < actual_length &&
1954 expected_arg[expected_length - 1] != '/')
1957 if (memcmp (actual_arg, expected_arg,
1958 MIN (actual_length, expected_length)) != 0)
1961 else if (is_namespace)
1963 if (expected_length > actual_length)
1966 /* If the actual argument doesn't start with the expected
1967 * namespace, then we don't match.
1969 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1972 if (expected_length < actual_length)
1974 /* Check that the actual argument is within the expected
1975 * namespace, rather than just starting with that string,
1976 * by checking that the matched prefix ends in a '.'.
1978 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1979 * which is an invalid namespace, but at some point the
1980 * daemon can't cover up for broken services.
1982 if (actual_arg[expected_length] != '.')
1985 /* otherwise we had an exact match. */
1989 if (expected_length != actual_length ||
1990 memcmp (expected_arg, actual_arg, expected_length) != 0)
1996 if (current_type != DBUS_TYPE_INVALID)
1997 dbus_message_iter_next (&iter);
2007 get_recipients_from_list (DBusList **rules,
2008 DBusConnection *sender,
2009 DBusConnection *addressed_recipient,
2010 DBusMessage *message,
2011 DBusList **recipients_p)
2018 link = _dbus_list_get_first_link (rules);
2019 while (link != NULL)
2025 #ifdef DBUS_ENABLE_VERBOSE_MODE
2027 char *s = match_rule_to_string (rule);
2029 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
2030 s ? s : "nomem", rule->matches_go_to);
2035 if (match_rule_matches (rule,
2036 sender, addressed_recipient, message,
2037 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
2039 _dbus_verbose ("Rule matched\n");
2041 /* Append to the list if we haven't already */
2042 if (bus_connection_mark_stamp (rule->matches_go_to))
2044 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
2049 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
2053 link = _dbus_list_get_next_link (rules, link);
2060 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
2061 BusConnections *connections,
2062 DBusConnection *sender,
2063 DBusConnection *addressed_recipient,
2064 DBusMessage *message,
2065 DBusList **recipients_p)
2068 const char *interface;
2069 DBusList **neither, **just_type, **just_iface, **both;
2071 _dbus_assert (*recipients_p == NULL);
2073 /* This avoids sending same message to the same connection twice.
2074 * Purpose of the stamp instead of a bool is to avoid iterating over
2075 * all connections resetting the bool each time.
2077 bus_connections_increment_stamp (connections);
2079 /* addressed_recipient is already receiving the message, don't add to list.
2080 * NULL addressed_recipient means either bus driver, or this is a signal
2081 * and thus lacks a specific addressed_recipient.
2083 if (addressed_recipient != NULL)
2084 bus_connection_mark_stamp (addressed_recipient);
2086 type = dbus_message_get_type (message);
2087 interface = dbus_message_get_interface (message);
2089 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
2091 just_type = just_iface = both = NULL;
2093 if (interface != NULL)
2094 just_iface = bus_matchmaker_get_rules (matchmaker,
2095 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
2097 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
2099 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
2101 if (interface != NULL)
2102 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
2105 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
2106 message, recipients_p) &&
2107 get_recipients_from_list (just_iface, sender, addressed_recipient,
2108 message, recipients_p) &&
2109 get_recipients_from_list (just_type, sender, addressed_recipient,
2110 message, recipients_p) &&
2111 get_recipients_from_list (both, sender, addressed_recipient,
2112 message, recipients_p)))
2114 _dbus_list_clear (recipients_p);
2121 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2125 static BusMatchRule*
2126 check_parse (dbus_bool_t should_succeed,
2133 dbus_error_init (&error);
2135 _dbus_string_init_const (&str, text);
2137 rule = bus_match_rule_parse (NULL, &str, &error);
2138 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2140 dbus_error_free (&error);
2144 if (should_succeed && rule == NULL)
2146 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
2147 error.name, error.message,
2148 _dbus_string_get_const_data (&str));
2152 if (!should_succeed && rule != NULL)
2154 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2155 _dbus_string_get_const_data (&str));
2159 dbus_error_free (&error);
2165 assert_large_rule (BusMatchRule *rule)
2167 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2168 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2169 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2170 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2171 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2172 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2174 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2175 _dbus_assert (rule->interface != NULL);
2176 _dbus_assert (rule->member != NULL);
2177 _dbus_assert (rule->sender != NULL);
2178 _dbus_assert (rule->destination != NULL);
2179 _dbus_assert (rule->path != NULL);
2181 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2182 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2183 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2184 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2185 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2189 test_parsing (void *data)
2193 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2196 assert_large_rule (rule);
2197 bus_match_rule_unref (rule);
2200 /* With extra whitespace and useless quotes */
2201 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2204 assert_large_rule (rule);
2205 bus_match_rule_unref (rule);
2209 /* A simple signal connection */
2210 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2213 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2214 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2215 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2217 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2218 _dbus_assert (rule->interface != NULL);
2219 _dbus_assert (rule->path != NULL);
2221 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2222 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2224 bus_match_rule_unref (rule);
2228 rule = check_parse (TRUE, "arg0='foo'");
2231 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2232 _dbus_assert (rule->args != NULL);
2233 _dbus_assert (rule->args_len == 1);
2234 _dbus_assert (rule->args[0] != NULL);
2235 _dbus_assert (rule->args[1] == NULL);
2236 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2238 bus_match_rule_unref (rule);
2241 rule = check_parse (TRUE, "arg1='foo'");
2244 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2245 _dbus_assert (rule->args != NULL);
2246 _dbus_assert (rule->args_len == 2);
2247 _dbus_assert (rule->args[0] == NULL);
2248 _dbus_assert (rule->args[1] != NULL);
2249 _dbus_assert (rule->args[2] == NULL);
2250 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2252 bus_match_rule_unref (rule);
2255 rule = check_parse (TRUE, "arg2='foo'");
2258 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2259 _dbus_assert (rule->args != NULL);
2260 _dbus_assert (rule->args_len == 3);
2261 _dbus_assert (rule->args[0] == NULL);
2262 _dbus_assert (rule->args[1] == NULL);
2263 _dbus_assert (rule->args[2] != NULL);
2264 _dbus_assert (rule->args[3] == NULL);
2265 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2267 bus_match_rule_unref (rule);
2270 rule = check_parse (TRUE, "arg40='foo'");
2273 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2274 _dbus_assert (rule->args != NULL);
2275 _dbus_assert (rule->args_len == 41);
2276 _dbus_assert (rule->args[0] == NULL);
2277 _dbus_assert (rule->args[1] == NULL);
2278 _dbus_assert (rule->args[40] != NULL);
2279 _dbus_assert (rule->args[41] == NULL);
2280 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2282 bus_match_rule_unref (rule);
2285 rule = check_parse (TRUE, "arg63='foo'");
2288 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2289 _dbus_assert (rule->args != NULL);
2290 _dbus_assert (rule->args_len == 64);
2291 _dbus_assert (rule->args[0] == NULL);
2292 _dbus_assert (rule->args[1] == NULL);
2293 _dbus_assert (rule->args[63] != NULL);
2294 _dbus_assert (rule->args[64] == NULL);
2295 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2297 bus_match_rule_unref (rule);
2300 rule = check_parse (TRUE, "arg7path='/foo'");
2303 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2304 _dbus_assert (rule->args != NULL);
2305 _dbus_assert (rule->args_len == 8);
2306 _dbus_assert (rule->args[7] != NULL);
2307 _dbus_assert (rule->args[8] == NULL);
2308 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2309 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2310 == BUS_MATCH_ARG_IS_PATH);
2312 bus_match_rule_unref (rule);
2315 /* Arg 0 namespace matches */
2316 rule = check_parse (TRUE, "arg0namespace='foo'");
2319 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2320 _dbus_assert (rule->args != NULL);
2321 _dbus_assert (rule->args_len == 1);
2322 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2323 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2324 == BUS_MATCH_ARG_NAMESPACE);
2326 bus_match_rule_unref (rule);
2329 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2332 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2333 _dbus_assert (rule->args != NULL);
2334 _dbus_assert (rule->args_len == 1);
2335 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2336 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2337 == BUS_MATCH_ARG_NAMESPACE);
2339 bus_match_rule_unref (rule);
2342 /* Only arg0namespace is supported. */
2343 rule = check_parse (FALSE, "arg1namespace='foo'");
2344 _dbus_assert (rule == NULL);
2346 /* An empty string isn't a valid namespace prefix (you should just not
2347 * specify this key at all).
2349 rule = check_parse (FALSE, "arg0namespace=''");
2350 _dbus_assert (rule == NULL);
2352 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2353 * spec allowed a single trailing period, which altered the semantics) */
2354 rule = check_parse (FALSE, "arg0namespace='foo.'");
2355 _dbus_assert (rule == NULL);
2357 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2358 _dbus_assert (rule == NULL);
2360 rule = check_parse (FALSE, "arg0namespace='foo..'");
2361 _dbus_assert (rule == NULL);
2363 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2364 _dbus_assert (rule == NULL);
2366 /* Too-large argN */
2367 rule = check_parse (FALSE, "arg300='foo'");
2368 _dbus_assert (rule == NULL);
2369 rule = check_parse (FALSE, "arg64='foo'");
2370 _dbus_assert (rule == NULL);
2373 rule = check_parse (FALSE, "arg='foo'");
2374 _dbus_assert (rule == NULL);
2375 rule = check_parse (FALSE, "argv='foo'");
2376 _dbus_assert (rule == NULL);
2377 rule = check_parse (FALSE, "arg3junk='foo'");
2378 _dbus_assert (rule == NULL);
2379 rule = check_parse (FALSE, "argument='foo'");
2380 _dbus_assert (rule == NULL);
2382 /* Reject duplicates */
2383 rule = check_parse (FALSE, "type='signal',type='method_call'");
2384 _dbus_assert (rule == NULL);
2386 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2389 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2390 _dbus_assert (rule->path != NULL);
2391 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2393 bus_match_rule_unref (rule);
2396 /* Almost a duplicate */
2397 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2398 _dbus_assert (rule == NULL);
2400 /* Trailing / was supported in the initial proposal, but now isn't */
2401 rule = check_parse (FALSE, "path_namespace='/foo/'");
2402 _dbus_assert (rule == NULL);
2404 /* Duplicates with the argN code */
2405 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2406 _dbus_assert (rule == NULL);
2407 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2408 _dbus_assert (rule == NULL);
2409 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2410 _dbus_assert (rule == NULL);
2412 /* Reject broken keys */
2413 rule = check_parse (FALSE, "blah='signal'");
2414 _dbus_assert (rule == NULL);
2416 /* Reject broken values */
2417 rule = check_parse (FALSE, "type='chouin'");
2418 _dbus_assert (rule == NULL);
2419 rule = check_parse (FALSE, "interface='abc@def++'");
2420 _dbus_assert (rule == NULL);
2421 rule = check_parse (FALSE, "service='youpi'");
2422 _dbus_assert (rule == NULL);
2424 /* Allow empty rule */
2425 rule = check_parse (TRUE, "");
2428 _dbus_assert (rule->flags == 0);
2430 bus_match_rule_unref (rule);
2433 /* All-whitespace rule is the same as empty */
2434 rule = check_parse (TRUE, " \t");
2437 _dbus_assert (rule->flags == 0);
2439 bus_match_rule_unref (rule);
2442 /* But with non-whitespace chars and no =value, it's not OK */
2443 rule = check_parse (FALSE, "type");
2444 _dbus_assert (rule == NULL);
2452 } equality_tests[] = {
2453 { "type='signal'", "type='signal'" },
2454 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2455 { "type='signal',member='bar'", "member='bar',type='signal'" },
2456 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2457 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2458 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2459 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2460 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2461 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2462 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2463 { "arg3='fool'", "arg3='fool'" },
2464 { "arg0namespace='fool'", "arg0namespace='fool'" },
2465 { "member='food'", "member='food'" }
2469 test_equality (void)
2474 while (i < _DBUS_N_ELEMENTS (equality_tests))
2476 BusMatchRule *first;
2477 BusMatchRule *second;
2480 first = check_parse (TRUE, equality_tests[i].first);
2481 _dbus_assert (first != NULL);
2482 second = check_parse (TRUE, equality_tests[i].second);
2483 _dbus_assert (second != NULL);
2485 if (!match_rule_equal (first, second))
2487 _dbus_warn ("rule %s and %s should have been equal\n",
2488 equality_tests[i].first,
2489 equality_tests[i].second);
2493 bus_match_rule_unref (second);
2495 /* Check that the rule is not equal to any of the
2496 * others besides its pair match
2499 while (j < _DBUS_N_ELEMENTS (equality_tests))
2503 second = check_parse (TRUE, equality_tests[j].second);
2505 if (match_rule_equal (first, second))
2507 _dbus_warn ("rule %s and %s should not have been equal\n",
2508 equality_tests[i].first,
2509 equality_tests[j].second);
2513 bus_match_rule_unref (second);
2519 bus_match_rule_unref (first);
2526 should_match_message_1[] = {
2528 "member='Frobated'",
2530 "type='signal',member='Frobated'",
2531 "type='signal',member='Frobated',arg0='foobar'",
2532 "member='Frobated',arg0='foobar'",
2533 "type='signal',arg0='foobar'",
2534 /* The definition of argXpath matches says: "As with normal argument matches,
2535 * if the argument is exactly equal to the string given in the match rule
2536 * then the rule is satisfied." So this should match (even though the
2537 * argument is not a valid path)!
2539 "arg0path='foobar'",
2540 "arg0namespace='foobar'",
2545 should_not_match_message_1[] = {
2546 "type='method_call'",
2548 "type='method_return'",
2549 "type='signal',member='Oopsed'",
2556 "arg0='foobar',arg1='abcdef'",
2557 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2558 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2560 "arg0path='foobar/'",
2562 "arg0namespace='foo'",
2563 "arg0namespace='foo',arg1='abcdef'",
2564 "arg0namespace='moo'",
2568 #define EXAMPLE_NAME "com.example.backend.foo"
2571 should_match_message_2[] = {
2572 /* EXAMPLE_NAME is in all of these namespaces */
2573 "arg0namespace='com.example.backend'",
2574 "arg0namespace='com.example'",
2575 "arg0namespace='com'",
2577 /* If the client specifies the name exactly, with no trailing period, then
2580 "arg0namespace='com.example.backend.foo'",
2586 should_not_match_message_2[] = {
2587 /* These are not even prefixes */
2588 "arg0namespace='com.example.backend.foo.bar'",
2589 "arg0namespace='com.example.backend.foobar'",
2591 /* These are prefixes, but they're not parent namespaces. */
2592 "arg0namespace='com.example.backend.fo'",
2593 "arg0namespace='com.example.backen'",
2594 "arg0namespace='com.exampl'",
2595 "arg0namespace='co'",
2601 check_matches (dbus_bool_t expected_to_match,
2603 DBusMessage *message,
2604 const char *rule_text)
2607 dbus_bool_t matched;
2609 rule = check_parse (TRUE, rule_text);
2610 _dbus_assert (rule != NULL);
2612 /* We can't test sender/destination rules since we pass NULL here */
2613 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2615 if (matched != expected_to_match)
2617 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2618 rule_text, expected_to_match ?
2619 "match" : "not match", number);
2623 bus_match_rule_unref (rule);
2627 check_matching (DBusMessage *message,
2629 const char **should_match,
2630 const char **should_not_match)
2635 while (should_match[i] != NULL)
2637 check_matches (TRUE, number, message, should_match[i]);
2642 while (should_not_match[i] != NULL)
2644 check_matches (FALSE, number, message, should_not_match[i]);
2650 test_matching (void)
2652 DBusMessage *message1, *message2;
2653 const char *v_STRING;
2654 dbus_int32_t v_INT32;
2656 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2657 _dbus_assert (message1 != NULL);
2658 if (!dbus_message_set_member (message1, "Frobated"))
2659 _dbus_assert_not_reached ("oom");
2661 v_STRING = "foobar";
2663 if (!dbus_message_append_args (message1,
2664 DBUS_TYPE_STRING, &v_STRING,
2665 DBUS_TYPE_INT32, &v_INT32,
2667 _dbus_assert_not_reached ("oom");
2669 check_matching (message1, 1,
2670 should_match_message_1,
2671 should_not_match_message_1);
2673 dbus_message_unref (message1);
2675 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2676 _dbus_assert (message2 != NULL);
2677 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2678 _dbus_assert_not_reached ("oom");
2680 /* Obviously this isn't really a NameOwnerChanged signal. */
2681 v_STRING = EXAMPLE_NAME;
2682 if (!dbus_message_append_args (message2,
2683 DBUS_TYPE_STRING, &v_STRING,
2685 _dbus_assert_not_reached ("oom");
2687 check_matching (message2, 2,
2688 should_match_message_2,
2689 should_not_match_message_2);
2691 dbus_message_unref (message2);
2694 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2696 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2697 * from the specification. Notice that not all of them are actually legal D-Bus
2700 * The author of this test takes no responsibility for the semantics of
2701 * this match rule key.
2703 static const char *paths_that_should_be_matched[] = {
2707 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2713 /* These paths should not be matched by PATH_MATCH_RULE. */
2714 static const char *paths_that_should_not_be_matched[] = {
2723 test_path_match (int type,
2725 const char *rule_text,
2727 dbus_bool_t should_match)
2729 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2730 dbus_bool_t matched;
2732 _dbus_assert (message != NULL);
2733 if (!dbus_message_set_member (message, "Foo"))
2734 _dbus_assert_not_reached ("oom");
2736 if (!dbus_message_append_args (message,
2739 _dbus_assert_not_reached ("oom");
2741 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2743 if (matched != should_match)
2745 _dbus_warn ("Expected rule %s to %s message "
2746 "with first arg %s of type '%c', failed\n",
2748 should_match ? "match" : "not match",
2754 dbus_message_unref (message);
2758 test_path_matching (void)
2763 rule = check_parse (TRUE, PATH_MATCH_RULE);
2764 _dbus_assert (rule != NULL);
2766 for (s = paths_that_should_be_matched; *s != NULL; s++)
2767 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2769 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2771 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2773 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2775 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2776 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2779 bus_match_rule_unref (rule);
2783 path_namespace_should_match_message_1[] = {
2784 "type='signal',path_namespace='/'",
2785 "type='signal',path_namespace='/foo'",
2786 "type='signal',path_namespace='/foo/TheObjectManager'",
2791 path_namespace_should_not_match_message_1[] = {
2792 "type='signal',path_namespace='/bar'",
2793 "type='signal',path_namespace='/bar/TheObjectManager'",
2798 path_namespace_should_match_message_2[] = {
2799 "type='signal',path_namespace='/'",
2800 "type='signal',path_namespace='/foo/TheObjectManager'",
2805 path_namespace_should_not_match_message_2[] = {
2810 path_namespace_should_match_message_3[] = {
2811 "type='signal',path_namespace='/'",
2816 path_namespace_should_not_match_message_3[] = {
2817 "type='signal',path_namespace='/foo/TheObjectManager'",
2822 path_namespace_should_match_message_4[] = {
2823 "type='signal',path_namespace='/'",
2828 path_namespace_should_not_match_message_4[] = {
2829 "type='signal',path_namespace='/foo/TheObjectManager'",
2834 test_matching_path_namespace (void)
2836 DBusMessage *message1;
2837 DBusMessage *message2;
2838 DBusMessage *message3;
2839 DBusMessage *message4;
2841 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2842 _dbus_assert (message1 != NULL);
2843 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2844 _dbus_assert_not_reached ("oom");
2846 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2847 _dbus_assert (message2 != NULL);
2848 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2849 _dbus_assert_not_reached ("oom");
2851 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2852 _dbus_assert (message3 != NULL);
2853 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2854 _dbus_assert_not_reached ("oom");
2856 message4 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2857 _dbus_assert (message4 != NULL);
2858 if (!dbus_message_set_path (message4, "/"))
2859 _dbus_assert_not_reached ("oom");
2861 check_matching (message1, 1,
2862 path_namespace_should_match_message_1,
2863 path_namespace_should_not_match_message_1);
2864 check_matching (message2, 2,
2865 path_namespace_should_match_message_2,
2866 path_namespace_should_not_match_message_2);
2867 check_matching (message3, 3,
2868 path_namespace_should_match_message_3,
2869 path_namespace_should_not_match_message_3);
2870 check_matching (message4, 4,
2871 path_namespace_should_match_message_4,
2872 path_namespace_should_not_match_message_4);
2874 dbus_message_unref (message4);
2875 dbus_message_unref (message3);
2876 dbus_message_unref (message2);
2877 dbus_message_unref (message1);
2881 bus_signals_test (const DBusString *test_data_dir)
2883 BusMatchmaker *matchmaker;
2885 matchmaker = bus_matchmaker_new ();
2886 bus_matchmaker_ref (matchmaker);
2887 bus_matchmaker_unref (matchmaker);
2888 bus_matchmaker_unref (matchmaker);
2890 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2891 _dbus_assert_not_reached ("Parsing match rules test failed");
2895 test_path_matching ();
2896 test_matching_path_namespace ();
2901 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */