1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* signals.c Bus signal connection implementation
4 * Copyright (C) 2003, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <dbus/dbus-marshal-validate.h>
32 int refcount; /**< reference count */
34 DBusConnection *matches_go_to; /**< Owner of the rule */
36 unsigned int flags; /**< BusMatchFlags */
45 unsigned int *arg_lens;
50 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u
51 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
53 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
56 bus_match_rule_new (DBusConnection *matches_go_to)
60 rule = dbus_new0 (BusMatchRule, 1);
65 rule->matches_go_to = matches_go_to;
67 #ifndef DBUS_BUILD_TESTS
68 _dbus_assert (rule->matches_go_to != NULL);
75 bus_match_rule_ref (BusMatchRule *rule)
77 _dbus_assert (rule->refcount > 0);
85 bus_match_rule_unref (BusMatchRule *rule)
87 _dbus_assert (rule->refcount > 0);
90 if (rule->refcount == 0)
92 dbus_free (rule->interface);
93 dbus_free (rule->member);
94 dbus_free (rule->sender);
95 dbus_free (rule->destination);
96 dbus_free (rule->path);
97 dbus_free (rule->arg_lens);
99 /* can't use dbus_free_string_array() since there
107 while (i < rule->args_len)
110 dbus_free (rule->args[i]);
114 dbus_free (rule->args);
121 #ifdef DBUS_ENABLE_VERBOSE_MODE
122 /* Note this function does not do escaping, so it's only
123 * good for debug spew at the moment
126 match_rule_to_string (BusMatchRule *rule)
131 if (!_dbus_string_init (&str))
134 while ((s = _dbus_strdup ("nomem")) == NULL)
135 ; /* only OK for debug spew... */
139 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
141 if (rule->message_type == DBUS_MESSAGE_TYPE_INVALID)
143 if (!_dbus_string_append_printf (&str, "type='INVALID'"))
146 else if (rule->message_type == DBUS_MESSAGE_TYPE_METHOD_CALL)
148 if (!_dbus_string_append_printf (&str, "type='method_call'"))
151 else if (rule->message_type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
153 if (!_dbus_string_append_printf (&str, "type='method_return'"))
156 else if (rule->message_type == DBUS_MESSAGE_TYPE_ERROR)
158 if (!_dbus_string_append_printf (&str, "type='error'"))
161 else if (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL)
163 if (!_dbus_string_append_printf (&str, "type='signal'"))
168 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
173 if (rule->flags & BUS_MATCH_INTERFACE)
175 if (_dbus_string_get_length (&str) > 0)
177 if (!_dbus_string_append (&str, ","))
181 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
185 if (rule->flags & BUS_MATCH_MEMBER)
187 if (_dbus_string_get_length (&str) > 0)
189 if (!_dbus_string_append (&str, ","))
193 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
197 if (rule->flags & BUS_MATCH_PATH)
199 if (_dbus_string_get_length (&str) > 0)
201 if (!_dbus_string_append (&str, ","))
205 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
209 if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
211 if (_dbus_string_get_length (&str) > 0)
213 if (!_dbus_string_append (&str, ","))
217 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
221 if (rule->flags & BUS_MATCH_SENDER)
223 if (_dbus_string_get_length (&str) > 0)
225 if (!_dbus_string_append (&str, ","))
229 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
233 if (rule->flags & BUS_MATCH_DESTINATION)
235 if (_dbus_string_get_length (&str) > 0)
237 if (!_dbus_string_append (&str, ","))
241 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
245 if (rule->flags & BUS_MATCH_ARGS)
249 _dbus_assert (rule->args != NULL);
252 while (i < rule->args_len)
254 if (rule->args[i] != NULL)
256 dbus_bool_t is_path, is_namespace;
258 if (_dbus_string_get_length (&str) > 0)
260 if (!_dbus_string_append (&str, ","))
264 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
265 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
267 if (!_dbus_string_append_printf (&str,
271 is_namespace ? "namespace" : "",
280 if (!_dbus_string_steal_data (&str, &ret))
283 _dbus_string_free (&str);
287 _dbus_string_free (&str);
290 while ((s = _dbus_strdup ("nomem")) == NULL)
291 ; /* only OK for debug spew... */
295 #endif /* DBUS_ENABLE_VERBOSE_MODE */
298 bus_match_rule_set_message_type (BusMatchRule *rule,
301 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
303 rule->message_type = type;
309 bus_match_rule_set_interface (BusMatchRule *rule,
310 const char *interface)
314 _dbus_assert (interface != NULL);
316 new = _dbus_strdup (interface);
320 rule->flags |= BUS_MATCH_INTERFACE;
321 dbus_free (rule->interface);
322 rule->interface = new;
328 bus_match_rule_set_member (BusMatchRule *rule,
333 _dbus_assert (member != NULL);
335 new = _dbus_strdup (member);
339 rule->flags |= BUS_MATCH_MEMBER;
340 dbus_free (rule->member);
347 bus_match_rule_set_sender (BusMatchRule *rule,
352 _dbus_assert (sender != NULL);
354 new = _dbus_strdup (sender);
358 rule->flags |= BUS_MATCH_SENDER;
359 dbus_free (rule->sender);
366 bus_match_rule_set_destination (BusMatchRule *rule,
367 const char *destination)
371 _dbus_assert (destination != NULL);
373 new = _dbus_strdup (destination);
377 rule->flags |= BUS_MATCH_DESTINATION;
378 dbus_free (rule->destination);
379 rule->destination = new;
385 bus_match_rule_set_path (BusMatchRule *rule,
387 dbus_bool_t is_namespace)
391 _dbus_assert (path != NULL);
393 new = _dbus_strdup (path);
397 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
400 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
402 rule->flags |= BUS_MATCH_PATH;
404 dbus_free (rule->path);
411 bus_match_rule_set_arg (BusMatchRule *rule,
413 const DBusString *value,
415 dbus_bool_t is_namespace)
420 _dbus_assert (value != NULL);
422 /* args_len is the number of args not including null termination
425 if (arg >= rule->args_len)
427 unsigned int *new_arg_lens;
432 new_args_len = arg + 1;
434 /* add another + 1 here for null termination */
435 new_args = dbus_realloc (rule->args,
436 sizeof (char *) * (new_args_len + 1));
437 if (new_args == NULL)
440 /* NULL the new slots */
442 while (i <= new_args_len) /* <= for null termination */
448 rule->args = new_args;
450 /* and now add to the lengths */
451 new_arg_lens = dbus_realloc (rule->arg_lens,
452 sizeof (int) * (new_args_len + 1));
454 if (new_arg_lens == NULL)
457 /* zero the new slots */
459 while (i <= new_args_len) /* <= for null termination */
465 rule->arg_lens = new_arg_lens;
466 rule->args_len = new_args_len;
469 length = _dbus_string_get_length (value);
470 if (!_dbus_string_copy_data (value, &new))
473 rule->flags |= BUS_MATCH_ARGS;
475 dbus_free (rule->args[arg]);
476 rule->arg_lens[arg] = length;
477 rule->args[arg] = new;
480 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
483 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
485 /* NULL termination didn't get busted */
486 _dbus_assert (rule->args[rule->args_len] == NULL);
487 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
492 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
495 find_key (const DBusString *str,
503 const char *key_start;
506 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
508 s = _dbus_string_get_const_data (str);
512 while (*p && ISWHITE (*p))
517 while (*p && *p != '=' && !ISWHITE (*p))
522 while (*p && ISWHITE (*p))
525 if (key_start == key_end)
527 /* Empty match rules or trailing whitespace are OK */
534 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
535 "Match rule has a key with no subsequent '=' character");
540 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
552 find_value (const DBusString *str,
564 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
566 orig_len = _dbus_string_get_length (value);
568 s = _dbus_string_get_const_data (str);
576 if (quote_char == '\0')
596 if (!_dbus_string_append_byte (value, *p))
603 else if (quote_char == '\\')
605 /* \ only counts as an escape if escaping a quote mark */
608 if (!_dbus_string_append_byte (value, '\\'))
615 if (!_dbus_string_append_byte (value, *p))
625 _dbus_assert (quote_char == '\'');
633 if (!_dbus_string_append_byte (value, *p))
647 if (quote_char == '\\')
649 if (!_dbus_string_append_byte (value, '\\'))
655 else if (quote_char == '\'')
657 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
658 "Unbalanced quotation marks in match rule");
662 _dbus_assert (quote_char == '\0');
664 /* Zero-length values are allowed */
671 _DBUS_ASSERT_ERROR_IS_SET (error);
672 _dbus_string_set_length (value, orig_len);
676 /* duplicates aren't allowed so the real legitimate max is only 6 or
677 * so. Leaving extra so we don't have to bother to update it.
678 * FIXME this is sort of busted now with arg matching, but we let
679 * you match on up to 10 args for now
681 #define MAX_RULE_TOKENS 16
683 /* this is slightly too high level to be termed a "token"
684 * but let's not be pedantic.
693 tokenize_rule (const DBusString *rule_text,
694 RuleToken tokens[MAX_RULE_TOKENS],
705 if (!_dbus_string_init (&key))
711 if (!_dbus_string_init (&value))
713 _dbus_string_free (&key);
720 while (i < MAX_RULE_TOKENS &&
721 pos < _dbus_string_get_length (rule_text))
723 _dbus_assert (tokens[i].key == NULL);
724 _dbus_assert (tokens[i].value == NULL);
726 if (!find_key (rule_text, pos, &key, &pos, error))
729 if (_dbus_string_get_length (&key) == 0)
732 if (!_dbus_string_steal_data (&key, &tokens[i].key))
738 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
741 if (!_dbus_string_steal_data (&value, &tokens[i].value))
757 while (tokens[i].key || tokens[i].value)
759 dbus_free (tokens[i].key);
760 dbus_free (tokens[i].value);
761 tokens[i].key = NULL;
762 tokens[i].value = NULL;
767 _dbus_string_free (&key);
768 _dbus_string_free (&value);
774 bus_match_rule_parse_arg_match (BusMatchRule *rule,
776 const DBusString *value,
779 dbus_bool_t is_path = FALSE;
780 dbus_bool_t is_namespace = FALSE;
786 /* For now, arg0='foo' always implies that 'foo' is a
787 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
788 * if we wanted, which would specify another type, in which case
789 * arg0='5' would have the 5 parsed as an int rather than string.
792 /* First we need to parse arg0 = 0, arg27 = 27 */
794 _dbus_string_init_const (&key_str, key);
795 length = _dbus_string_get_length (&key_str);
797 if (_dbus_string_get_length (&key_str) < 4)
799 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
800 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
804 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
806 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
807 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
813 if ((end + strlen ("path")) == length &&
814 _dbus_string_ends_with_c_str (&key_str, "path"))
818 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
820 int value_len = _dbus_string_get_length (value);
824 if (!_dbus_validate_bus_namespace (value, 0, value_len))
826 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
827 "arg0namespace='%s' is not a valid prefix of a bus name",
828 _dbus_string_get_const_data (value));
834 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
835 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
840 /* If we didn't check this we could allocate a huge amount of RAM */
841 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
843 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
844 "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);
848 if ((rule->flags & BUS_MATCH_ARGS) &&
849 rule->args_len > (int) arg &&
850 rule->args[arg] != NULL)
852 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
853 "Argument %d matched more than once in match rule\n", key);
857 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
866 _DBUS_ASSERT_ERROR_IS_SET (error);
871 * The format is comma-separated with strings quoted with single quotes
872 * as for the shell (to escape a literal single quote, use '\'').
874 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
875 * path='/bar/foo',destination=':452345.34'
879 bus_match_rule_parse (DBusConnection *matches_go_to,
880 const DBusString *rule_text,
884 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
887 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
889 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
891 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
892 "Match rule text is %d bytes, maximum is %d",
893 _dbus_string_get_length (rule_text),
894 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
898 memset (tokens, '\0', sizeof (tokens));
900 rule = bus_match_rule_new (matches_go_to);
907 if (!tokenize_rule (rule_text, tokens, error))
911 while (tokens[i].key != NULL)
915 const char *key = tokens[i].key;
916 const char *value = tokens[i].value;
918 _dbus_string_init_const (&tmp_str, value);
919 len = _dbus_string_get_length (&tmp_str);
921 if (strcmp (key, "type") == 0)
925 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
927 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
928 "Key %s specified twice in match rule\n", key);
932 t = dbus_message_type_from_string (value);
934 if (t == DBUS_MESSAGE_TYPE_INVALID)
936 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
937 "Invalid message type (%s) in match rule\n", value);
941 if (!bus_match_rule_set_message_type (rule, t))
947 else if (strcmp (key, "sender") == 0)
949 if (rule->flags & BUS_MATCH_SENDER)
951 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
952 "Key %s specified twice in match rule\n", key);
956 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
958 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
959 "Sender name '%s' is invalid\n", value);
963 if (!bus_match_rule_set_sender (rule, value))
969 else if (strcmp (key, "interface") == 0)
971 if (rule->flags & BUS_MATCH_INTERFACE)
973 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
974 "Key %s specified twice in match rule\n", key);
978 if (!_dbus_validate_interface (&tmp_str, 0, len))
980 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
981 "Interface name '%s' is invalid\n", value);
985 if (!bus_match_rule_set_interface (rule, value))
991 else if (strcmp (key, "member") == 0)
993 if (rule->flags & BUS_MATCH_MEMBER)
995 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
996 "Key %s specified twice in match rule\n", key);
1000 if (!_dbus_validate_member (&tmp_str, 0, len))
1002 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1003 "Member name '%s' is invalid\n", value);
1007 if (!bus_match_rule_set_member (rule, value))
1009 BUS_SET_OOM (error);
1013 else if (strcmp (key, "path") == 0 ||
1014 strcmp (key, "path_namespace") == 0)
1016 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1018 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
1020 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1021 "path or path_namespace specified twice in match rule\n");
1025 if (!_dbus_validate_path (&tmp_str, 0, len))
1027 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1028 "Path '%s' is invalid\n", value);
1032 if (!bus_match_rule_set_path (rule, value, is_namespace))
1034 BUS_SET_OOM (error);
1038 else if (strcmp (key, "destination") == 0)
1040 if (rule->flags & BUS_MATCH_DESTINATION)
1042 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1043 "Key %s specified twice in match rule\n", key);
1047 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1049 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1050 "Destination name '%s' is invalid\n", value);
1054 if (!bus_match_rule_set_destination (rule, value))
1056 BUS_SET_OOM (error);
1060 else if (strncmp (key, "arg", 3) == 0)
1062 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1067 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1068 "Unknown key \"%s\" in match rule",
1080 _DBUS_ASSERT_ERROR_IS_SET (error);
1083 bus_match_rule_unref (rule);
1090 while (tokens[i].key || tokens[i].value)
1092 _dbus_assert (i < MAX_RULE_TOKENS);
1093 dbus_free (tokens[i].key);
1094 dbus_free (tokens[i].value);
1101 typedef struct RulePool RulePool;
1104 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1105 DBusHashTable *rules_by_iface;
1107 /* List of BusMatchRules which don't specify an interface */
1108 DBusList *rules_without_iface;
1111 struct BusMatchmaker
1115 /* Pools of rules, grouped by the type of message they match. 0
1116 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1119 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1123 rule_list_free (DBusList **rules)
1125 while (*rules != NULL)
1129 rule = (*rules)->data;
1130 bus_match_rule_unref (rule);
1131 _dbus_list_remove_link (rules, *rules);
1136 rule_list_ptr_free (DBusList **list)
1138 /* We have to cope with NULL because the hash table frees the "existing"
1139 * value (which is NULL) when creating a new table entry...
1143 rule_list_free (list);
1149 bus_matchmaker_new (void)
1151 BusMatchmaker *matchmaker;
1154 matchmaker = dbus_new0 (BusMatchmaker, 1);
1155 if (matchmaker == NULL)
1158 matchmaker->refcount = 1;
1160 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1162 RulePool *p = matchmaker->rules_by_type + i;
1164 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1165 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1167 if (p->rules_by_iface == NULL)
1174 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1176 RulePool *p = matchmaker->rules_by_type + i;
1178 if (p->rules_by_iface == NULL)
1181 _dbus_hash_table_unref (p->rules_by_iface);
1183 dbus_free (matchmaker);
1189 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1191 const char *interface,
1196 _dbus_assert (message_type >= 0);
1197 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1199 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1201 interface != NULL ? interface : "<null>");
1203 p = matchmaker->rules_by_type + message_type;
1205 if (interface == NULL)
1207 return &p->rules_without_iface;
1213 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1215 if (list == NULL && create)
1217 char *dupped_interface;
1219 list = dbus_new0 (DBusList *, 1);
1223 dupped_interface = _dbus_strdup (interface);
1224 if (dupped_interface == NULL)
1230 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1233 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1234 dupped_interface, list))
1237 dbus_free (dupped_interface);
1247 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1249 const char *interface,
1254 if (interface == NULL)
1260 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1261 message_type, interface);
1263 p = matchmaker->rules_by_type + message_type;
1265 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1268 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1272 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1274 _dbus_assert (matchmaker->refcount > 0);
1276 matchmaker->refcount += 1;
1282 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1284 _dbus_assert (matchmaker->refcount > 0);
1286 matchmaker->refcount -= 1;
1287 if (matchmaker->refcount == 0)
1291 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1293 RulePool *p = matchmaker->rules_by_type + i;
1295 _dbus_hash_table_unref (p->rules_by_iface);
1296 rule_list_free (&p->rules_without_iface);
1299 dbus_free (matchmaker);
1303 /* The rule can't be modified after it's added. */
1305 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1310 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1312 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1314 rule->interface != NULL ? rule->interface : "<null>");
1316 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1317 rule->interface, TRUE);
1322 if (!_dbus_list_append (rules, rule))
1325 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1327 _dbus_list_remove_last (rules, rule);
1328 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1329 rule->interface, rules);
1333 bus_match_rule_ref (rule);
1335 #ifdef DBUS_ENABLE_VERBOSE_MODE
1337 char *s = match_rule_to_string (rule);
1339 _dbus_verbose ("Added match rule %s to connection %p\n",
1340 s, rule->matches_go_to);
1349 match_rule_equal (BusMatchRule *a,
1352 if (a->flags != b->flags)
1355 if (a->matches_go_to != b->matches_go_to)
1358 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1359 a->message_type != b->message_type)
1362 if ((a->flags & BUS_MATCH_MEMBER) &&
1363 strcmp (a->member, b->member) != 0)
1366 if ((a->flags & BUS_MATCH_PATH) &&
1367 strcmp (a->path, b->path) != 0)
1370 if ((a->flags & BUS_MATCH_INTERFACE) &&
1371 strcmp (a->interface, b->interface) != 0)
1374 if ((a->flags & BUS_MATCH_SENDER) &&
1375 strcmp (a->sender, b->sender) != 0)
1378 if ((a->flags & BUS_MATCH_DESTINATION) &&
1379 strcmp (a->destination, b->destination) != 0)
1382 if (a->flags & BUS_MATCH_ARGS)
1386 if (a->args_len != b->args_len)
1390 while (i < a->args_len)
1394 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1397 if (a->arg_lens[i] != b->arg_lens[i])
1400 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1402 if (a->args[i] != NULL)
1404 _dbus_assert (b->args[i] != NULL);
1405 if (memcmp (a->args[i], b->args[i], length) != 0)
1417 bus_matchmaker_remove_rule_link (DBusList **rules,
1420 BusMatchRule *rule = link->data;
1422 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1423 _dbus_list_remove_link (rules, link);
1425 #ifdef DBUS_ENABLE_VERBOSE_MODE
1427 char *s = match_rule_to_string (rule);
1429 _dbus_verbose ("Removed match rule %s for connection %p\n",
1430 s, rule->matches_go_to);
1435 bus_match_rule_unref (rule);
1439 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1444 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1446 rule->interface != NULL ? rule->interface : "<null>");
1448 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1450 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1451 rule->interface, FALSE);
1453 /* We should only be asked to remove a rule by identity right after it was
1454 * added, so there should be a list for it.
1456 _dbus_assert (rules != NULL);
1458 _dbus_list_remove (rules, rule);
1459 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1462 #ifdef DBUS_ENABLE_VERBOSE_MODE
1464 char *s = match_rule_to_string (rule);
1466 _dbus_verbose ("Removed match rule %s for connection %p\n",
1467 s, rule->matches_go_to);
1472 bus_match_rule_unref (rule);
1475 /* Remove a single rule which is equal to the given rule by value */
1477 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1478 BusMatchRule *value,
1482 DBusList *link = NULL;
1484 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1485 value->message_type,
1486 value->interface != NULL ? value->interface : "<null>");
1488 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1489 value->interface, FALSE);
1493 /* we traverse backward because bus_connection_remove_match_rule()
1494 * removes the most-recently-added rule
1496 link = _dbus_list_get_last_link (rules);
1497 while (link != NULL)
1503 prev = _dbus_list_get_prev_link (rules, link);
1505 if (match_rule_equal (rule, value))
1507 bus_matchmaker_remove_rule_link (rules, link);
1517 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1518 "The given match rule wasn't found and can't be removed");
1522 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1529 rule_list_remove_by_connection (DBusList **rules,
1530 DBusConnection *connection)
1534 link = _dbus_list_get_first_link (rules);
1535 while (link != NULL)
1541 next = _dbus_list_get_next_link (rules, link);
1543 if (rule->matches_go_to == connection)
1545 bus_matchmaker_remove_rule_link (rules, link);
1547 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1548 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1550 /* The rule matches to/from a base service, see if it's the
1551 * one being disconnected, since we know this service name
1552 * will never be recycled.
1556 name = bus_connection_get_name (connection);
1557 _dbus_assert (name != NULL); /* because we're an active connection */
1559 if (((rule->flags & BUS_MATCH_SENDER) &&
1560 strcmp (rule->sender, name) == 0) ||
1561 ((rule->flags & BUS_MATCH_DESTINATION) &&
1562 strcmp (rule->destination, name) == 0))
1564 bus_matchmaker_remove_rule_link (rules, link);
1573 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1574 DBusConnection *connection)
1580 * This scans all match rules on the bus. We could avoid that
1581 * for the rules belonging to the connection, since we keep
1582 * a list of those; but for the rules that just refer to
1583 * the connection we'd need to do something more elaborate.
1586 _dbus_assert (bus_connection_is_active (connection));
1588 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1590 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1592 RulePool *p = matchmaker->rules_by_type + i;
1595 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1597 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1598 while (_dbus_hash_iter_next (&iter))
1600 DBusList **items = _dbus_hash_iter_get_value (&iter);
1602 rule_list_remove_by_connection (items, connection);
1605 _dbus_hash_iter_remove_entry (&iter);
1611 connection_is_primary_owner (DBusConnection *connection,
1612 const char *service_name)
1614 BusService *service;
1616 BusRegistry *registry;
1618 _dbus_assert (connection != NULL);
1620 registry = bus_connection_get_registry (connection);
1622 _dbus_string_init_const (&str, service_name);
1623 service = bus_registry_lookup (registry, &str);
1625 if (service == NULL)
1626 return FALSE; /* Service doesn't exist so connection can't own it. */
1628 return bus_service_get_primary_owners_connection (service) == connection;
1632 str_has_prefix (const char *str, const char *prefix)
1635 prefix_len = strlen (prefix);
1636 if (strncmp (str, prefix, prefix_len) == 0)
1643 match_rule_matches (BusMatchRule *rule,
1644 DBusConnection *sender,
1645 DBusConnection *addressed_recipient,
1646 DBusMessage *message,
1647 BusMatchFlags already_matched)
1651 /* All features of the match rule are AND'd together,
1652 * so FALSE if any of them don't match.
1655 /* sender/addressed_recipient of #NULL may mean bus driver,
1656 * or for addressed_recipient may mean a message with no
1657 * specific recipient (i.e. a signal)
1660 /* Don't bother re-matching features we've already checked implicitly. */
1661 flags = rule->flags & (~already_matched);
1663 if (flags & BUS_MATCH_MESSAGE_TYPE)
1665 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1667 if (rule->message_type != dbus_message_get_type (message))
1671 if (flags & BUS_MATCH_INTERFACE)
1675 _dbus_assert (rule->interface != NULL);
1677 iface = dbus_message_get_interface (message);
1681 if (strcmp (iface, rule->interface) != 0)
1685 if (flags & BUS_MATCH_MEMBER)
1689 _dbus_assert (rule->member != NULL);
1691 member = dbus_message_get_member (message);
1695 if (strcmp (member, rule->member) != 0)
1699 if (flags & BUS_MATCH_SENDER)
1701 _dbus_assert (rule->sender != NULL);
1705 if (strcmp (rule->sender,
1706 DBUS_SERVICE_DBUS) != 0)
1711 if (!connection_is_primary_owner (sender, rule->sender))
1716 if (flags & BUS_MATCH_DESTINATION)
1718 const char *destination;
1720 _dbus_assert (rule->destination != NULL);
1722 destination = dbus_message_get_destination (message);
1723 if (destination == NULL)
1726 if (addressed_recipient == NULL)
1728 if (strcmp (rule->destination,
1729 DBUS_SERVICE_DBUS) != 0)
1734 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1739 if (flags & BUS_MATCH_PATH)
1743 _dbus_assert (rule->path != NULL);
1745 path = dbus_message_get_path (message);
1749 if (strcmp (path, rule->path) != 0)
1753 if (flags & BUS_MATCH_PATH_NAMESPACE)
1758 _dbus_assert (rule->path != NULL);
1760 path = dbus_message_get_path (message);
1764 if (!str_has_prefix (path, rule->path))
1767 len = strlen (rule->path);
1769 /* Check that the actual argument is within the expected
1770 * namespace, rather than just starting with that string,
1771 * by checking that the matched prefix is followed by a '/'
1772 * or the end of the path.
1774 if (path[len] != '\0' && path[len] != '/')
1778 if (flags & BUS_MATCH_ARGS)
1781 DBusMessageIter iter;
1783 _dbus_assert (rule->args != NULL);
1785 dbus_message_iter_init (message, &iter);
1788 while (i < rule->args_len)
1791 const char *expected_arg;
1792 int expected_length;
1793 dbus_bool_t is_path, is_namespace;
1795 expected_arg = rule->args[i];
1796 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1797 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1798 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1800 current_type = dbus_message_iter_get_arg_type (&iter);
1802 if (expected_arg != NULL)
1804 const char *actual_arg;
1807 if (current_type != DBUS_TYPE_STRING &&
1808 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1812 dbus_message_iter_get_basic (&iter, &actual_arg);
1813 _dbus_assert (actual_arg != NULL);
1815 actual_length = strlen (actual_arg);
1819 if (actual_length < expected_length &&
1820 actual_arg[actual_length - 1] != '/')
1823 if (expected_length < actual_length &&
1824 expected_arg[expected_length - 1] != '/')
1827 if (memcmp (actual_arg, expected_arg,
1828 MIN (actual_length, expected_length)) != 0)
1831 else if (is_namespace)
1833 if (expected_length > actual_length)
1836 /* If the actual argument doesn't start with the expected
1837 * namespace, then we don't match.
1839 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1842 if (expected_length < actual_length)
1844 /* Check that the actual argument is within the expected
1845 * namespace, rather than just starting with that string,
1846 * by checking that the matched prefix ends in a '.'.
1848 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1849 * which is an invalid namespace, but at some point the
1850 * daemon can't cover up for broken services.
1852 if (actual_arg[expected_length] != '.')
1855 /* otherwise we had an exact match. */
1859 if (expected_length != actual_length ||
1860 memcmp (expected_arg, actual_arg, expected_length) != 0)
1866 if (current_type != DBUS_TYPE_INVALID)
1867 dbus_message_iter_next (&iter);
1877 get_recipients_from_list (DBusList **rules,
1878 DBusConnection *sender,
1879 DBusConnection *addressed_recipient,
1880 DBusMessage *message,
1881 DBusList **recipients_p)
1888 link = _dbus_list_get_first_link (rules);
1889 while (link != NULL)
1895 #ifdef DBUS_ENABLE_VERBOSE_MODE
1897 char *s = match_rule_to_string (rule);
1899 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1900 s, rule->matches_go_to);
1905 if (match_rule_matches (rule,
1906 sender, addressed_recipient, message,
1907 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
1909 _dbus_verbose ("Rule matched\n");
1911 /* Append to the list if we haven't already */
1912 if (bus_connection_mark_stamp (rule->matches_go_to))
1914 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1917 #ifdef DBUS_ENABLE_VERBOSE_MODE
1920 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1922 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1925 link = _dbus_list_get_next_link (rules, link);
1932 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1933 BusConnections *connections,
1934 DBusConnection *sender,
1935 DBusConnection *addressed_recipient,
1936 DBusMessage *message,
1937 DBusList **recipients_p)
1940 const char *interface;
1941 DBusList **neither, **just_type, **just_iface, **both;
1943 _dbus_assert (*recipients_p == NULL);
1945 /* This avoids sending same message to the same connection twice.
1946 * Purpose of the stamp instead of a bool is to avoid iterating over
1947 * all connections resetting the bool each time.
1949 bus_connections_increment_stamp (connections);
1951 /* addressed_recipient is already receiving the message, don't add to list.
1952 * NULL addressed_recipient means either bus driver, or this is a signal
1953 * and thus lacks a specific addressed_recipient.
1955 if (addressed_recipient != NULL)
1956 bus_connection_mark_stamp (addressed_recipient);
1958 type = dbus_message_get_type (message);
1959 interface = dbus_message_get_interface (message);
1961 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
1963 just_type = just_iface = both = NULL;
1965 if (interface != NULL)
1966 just_iface = bus_matchmaker_get_rules (matchmaker,
1967 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
1969 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
1971 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
1973 if (interface != NULL)
1974 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
1977 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
1978 message, recipients_p) &&
1979 get_recipients_from_list (just_iface, sender, addressed_recipient,
1980 message, recipients_p) &&
1981 get_recipients_from_list (just_type, sender, addressed_recipient,
1982 message, recipients_p) &&
1983 get_recipients_from_list (both, sender, addressed_recipient,
1984 message, recipients_p)))
1986 _dbus_list_clear (recipients_p);
1993 #ifdef DBUS_BUILD_TESTS
1997 static BusMatchRule*
1998 check_parse (dbus_bool_t should_succeed,
2005 dbus_error_init (&error);
2007 _dbus_string_init_const (&str, text);
2009 rule = bus_match_rule_parse (NULL, &str, &error);
2010 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2012 dbus_error_free (&error);
2016 if (should_succeed && rule == NULL)
2018 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
2019 error.name, error.message,
2020 _dbus_string_get_const_data (&str));
2024 if (!should_succeed && rule != NULL)
2026 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2027 _dbus_string_get_const_data (&str));
2031 dbus_error_free (&error);
2037 assert_large_rule (BusMatchRule *rule)
2039 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2040 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2041 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2042 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2043 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2044 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2046 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2047 _dbus_assert (rule->interface != NULL);
2048 _dbus_assert (rule->member != NULL);
2049 _dbus_assert (rule->sender != NULL);
2050 _dbus_assert (rule->destination != NULL);
2051 _dbus_assert (rule->path != NULL);
2053 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2054 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2055 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2056 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2057 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2061 test_parsing (void *data)
2065 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2068 assert_large_rule (rule);
2069 bus_match_rule_unref (rule);
2072 /* With extra whitespace and useless quotes */
2073 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2076 assert_large_rule (rule);
2077 bus_match_rule_unref (rule);
2081 /* A simple signal connection */
2082 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2085 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2086 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2087 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2089 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2090 _dbus_assert (rule->interface != NULL);
2091 _dbus_assert (rule->path != NULL);
2093 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2094 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2096 bus_match_rule_unref (rule);
2100 rule = check_parse (TRUE, "arg0='foo'");
2103 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2104 _dbus_assert (rule->args != NULL);
2105 _dbus_assert (rule->args_len == 1);
2106 _dbus_assert (rule->args[0] != NULL);
2107 _dbus_assert (rule->args[1] == NULL);
2108 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2110 bus_match_rule_unref (rule);
2113 rule = check_parse (TRUE, "arg1='foo'");
2116 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2117 _dbus_assert (rule->args != NULL);
2118 _dbus_assert (rule->args_len == 2);
2119 _dbus_assert (rule->args[0] == NULL);
2120 _dbus_assert (rule->args[1] != NULL);
2121 _dbus_assert (rule->args[2] == NULL);
2122 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2124 bus_match_rule_unref (rule);
2127 rule = check_parse (TRUE, "arg2='foo'");
2130 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2131 _dbus_assert (rule->args != NULL);
2132 _dbus_assert (rule->args_len == 3);
2133 _dbus_assert (rule->args[0] == NULL);
2134 _dbus_assert (rule->args[1] == NULL);
2135 _dbus_assert (rule->args[2] != NULL);
2136 _dbus_assert (rule->args[3] == NULL);
2137 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2139 bus_match_rule_unref (rule);
2142 rule = check_parse (TRUE, "arg40='foo'");
2145 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2146 _dbus_assert (rule->args != NULL);
2147 _dbus_assert (rule->args_len == 41);
2148 _dbus_assert (rule->args[0] == NULL);
2149 _dbus_assert (rule->args[1] == NULL);
2150 _dbus_assert (rule->args[40] != NULL);
2151 _dbus_assert (rule->args[41] == NULL);
2152 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2154 bus_match_rule_unref (rule);
2157 rule = check_parse (TRUE, "arg63='foo'");
2160 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2161 _dbus_assert (rule->args != NULL);
2162 _dbus_assert (rule->args_len == 64);
2163 _dbus_assert (rule->args[0] == NULL);
2164 _dbus_assert (rule->args[1] == NULL);
2165 _dbus_assert (rule->args[63] != NULL);
2166 _dbus_assert (rule->args[64] == NULL);
2167 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2169 bus_match_rule_unref (rule);
2172 rule = check_parse (TRUE, "arg7path='/foo'");
2175 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2176 _dbus_assert (rule->args != NULL);
2177 _dbus_assert (rule->args_len == 8);
2178 _dbus_assert (rule->args[7] != NULL);
2179 _dbus_assert (rule->args[8] == NULL);
2180 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2181 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2182 == BUS_MATCH_ARG_IS_PATH);
2184 bus_match_rule_unref (rule);
2187 /* Arg 0 namespace matches */
2188 rule = check_parse (TRUE, "arg0namespace='foo'");
2191 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2192 _dbus_assert (rule->args != NULL);
2193 _dbus_assert (rule->args_len == 1);
2194 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2195 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2196 == BUS_MATCH_ARG_NAMESPACE);
2198 bus_match_rule_unref (rule);
2201 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2204 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2205 _dbus_assert (rule->args != NULL);
2206 _dbus_assert (rule->args_len == 1);
2207 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2208 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2209 == BUS_MATCH_ARG_NAMESPACE);
2211 bus_match_rule_unref (rule);
2214 /* Only arg0namespace is supported. */
2215 rule = check_parse (FALSE, "arg1namespace='foo'");
2216 _dbus_assert (rule == NULL);
2218 /* An empty string isn't a valid namespace prefix (you should just not
2219 * specify this key at all).
2221 rule = check_parse (FALSE, "arg0namespace=''");
2222 _dbus_assert (rule == NULL);
2224 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2225 * spec allowed a single trailing period, which altered the semantics) */
2226 rule = check_parse (FALSE, "arg0namespace='foo.'");
2227 _dbus_assert (rule == NULL);
2229 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2230 _dbus_assert (rule == NULL);
2232 rule = check_parse (FALSE, "arg0namespace='foo..'");
2233 _dbus_assert (rule == NULL);
2235 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2236 _dbus_assert (rule == NULL);
2238 /* Too-large argN */
2239 rule = check_parse (FALSE, "arg300='foo'");
2240 _dbus_assert (rule == NULL);
2241 rule = check_parse (FALSE, "arg64='foo'");
2242 _dbus_assert (rule == NULL);
2245 rule = check_parse (FALSE, "arg='foo'");
2246 _dbus_assert (rule == NULL);
2247 rule = check_parse (FALSE, "argv='foo'");
2248 _dbus_assert (rule == NULL);
2249 rule = check_parse (FALSE, "arg3junk='foo'");
2250 _dbus_assert (rule == NULL);
2251 rule = check_parse (FALSE, "argument='foo'");
2252 _dbus_assert (rule == NULL);
2254 /* Reject duplicates */
2255 rule = check_parse (FALSE, "type='signal',type='method_call'");
2256 _dbus_assert (rule == NULL);
2258 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2261 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2262 _dbus_assert (rule->path != NULL);
2263 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2265 bus_match_rule_unref (rule);
2268 /* Almost a duplicate */
2269 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2270 _dbus_assert (rule == NULL);
2272 /* Trailing / was supported in the initial proposal, but now isn't */
2273 rule = check_parse (FALSE, "path_namespace='/foo/'");
2274 _dbus_assert (rule == NULL);
2276 /* Duplicates with the argN code */
2277 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2278 _dbus_assert (rule == NULL);
2279 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2280 _dbus_assert (rule == NULL);
2281 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2282 _dbus_assert (rule == NULL);
2284 /* Reject broken keys */
2285 rule = check_parse (FALSE, "blah='signal'");
2286 _dbus_assert (rule == NULL);
2288 /* Reject broken values */
2289 rule = check_parse (FALSE, "type='chouin'");
2290 _dbus_assert (rule == NULL);
2291 rule = check_parse (FALSE, "interface='abc@def++'");
2292 _dbus_assert (rule == NULL);
2293 rule = check_parse (FALSE, "service='youpi'");
2294 _dbus_assert (rule == NULL);
2296 /* Allow empty rule */
2297 rule = check_parse (TRUE, "");
2300 _dbus_assert (rule->flags == 0);
2302 bus_match_rule_unref (rule);
2305 /* All-whitespace rule is the same as empty */
2306 rule = check_parse (TRUE, " \t");
2309 _dbus_assert (rule->flags == 0);
2311 bus_match_rule_unref (rule);
2314 /* But with non-whitespace chars and no =value, it's not OK */
2315 rule = check_parse (FALSE, "type");
2316 _dbus_assert (rule == NULL);
2324 } equality_tests[] = {
2325 { "type='signal'", "type='signal'" },
2326 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2327 { "type='signal',member='bar'", "member='bar',type='signal'" },
2328 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2329 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2330 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2331 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2332 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2333 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2334 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2335 { "arg3='fool'", "arg3='fool'" },
2336 { "arg0namespace='fool'", "arg0namespace='fool'" },
2337 { "member='food'", "member='food'" }
2341 test_equality (void)
2346 while (i < _DBUS_N_ELEMENTS (equality_tests))
2348 BusMatchRule *first;
2349 BusMatchRule *second;
2352 first = check_parse (TRUE, equality_tests[i].first);
2353 _dbus_assert (first != NULL);
2354 second = check_parse (TRUE, equality_tests[i].second);
2355 _dbus_assert (second != NULL);
2357 if (!match_rule_equal (first, second))
2359 _dbus_warn ("rule %s and %s should have been equal\n",
2360 equality_tests[i].first,
2361 equality_tests[i].second);
2365 bus_match_rule_unref (second);
2367 /* Check that the rule is not equal to any of the
2368 * others besides its pair match
2371 while (j < _DBUS_N_ELEMENTS (equality_tests))
2375 second = check_parse (TRUE, equality_tests[j].second);
2377 if (match_rule_equal (first, second))
2379 _dbus_warn ("rule %s and %s should not have been equal\n",
2380 equality_tests[i].first,
2381 equality_tests[j].second);
2385 bus_match_rule_unref (second);
2391 bus_match_rule_unref (first);
2398 should_match_message_1[] = {
2400 "member='Frobated'",
2402 "type='signal',member='Frobated'",
2403 "type='signal',member='Frobated',arg0='foobar'",
2404 "member='Frobated',arg0='foobar'",
2405 "type='signal',arg0='foobar'",
2406 /* The definition of argXpath matches says: "As with normal argument matches,
2407 * if the argument is exactly equal to the string given in the match rule
2408 * then the rule is satisfied." So this should match (even though the
2409 * argument is not a valid path)!
2411 "arg0path='foobar'",
2412 "arg0namespace='foobar'",
2417 should_not_match_message_1[] = {
2418 "type='method_call'",
2420 "type='method_return'",
2421 "type='signal',member='Oopsed'",
2428 "arg0='foobar',arg1='abcdef'",
2429 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2430 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2432 "arg0path='foobar/'",
2434 "arg0namespace='foo'",
2435 "arg0namespace='foo',arg1='abcdef'",
2436 "arg0namespace='moo'",
2440 #define EXAMPLE_NAME "com.example.backend.foo"
2443 should_match_message_2[] = {
2444 /* EXAMPLE_NAME is in all of these namespaces */
2445 "arg0namespace='com.example.backend'",
2446 "arg0namespace='com.example'",
2447 "arg0namespace='com'",
2449 /* If the client specifies the name exactly, with no trailing period, then
2452 "arg0namespace='com.example.backend.foo'",
2458 should_not_match_message_2[] = {
2459 /* These are not even prefixes */
2460 "arg0namespace='com.example.backend.foo.bar'",
2461 "arg0namespace='com.example.backend.foobar'",
2463 /* These are prefixes, but they're not parent namespaces. */
2464 "arg0namespace='com.example.backend.fo'",
2465 "arg0namespace='com.example.backen'",
2466 "arg0namespace='com.exampl'",
2467 "arg0namespace='co'",
2473 check_matches (dbus_bool_t expected_to_match,
2475 DBusMessage *message,
2476 const char *rule_text)
2479 dbus_bool_t matched;
2481 rule = check_parse (TRUE, rule_text);
2482 _dbus_assert (rule != NULL);
2484 /* We can't test sender/destination rules since we pass NULL here */
2485 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2487 if (matched != expected_to_match)
2489 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2490 rule_text, expected_to_match ?
2491 "match" : "not match", number);
2495 bus_match_rule_unref (rule);
2499 check_matching (DBusMessage *message,
2501 const char **should_match,
2502 const char **should_not_match)
2507 while (should_match[i] != NULL)
2509 check_matches (TRUE, number, message, should_match[i]);
2514 while (should_not_match[i] != NULL)
2516 check_matches (FALSE, number, message, should_not_match[i]);
2522 test_matching (void)
2524 DBusMessage *message1, *message2;
2525 const char *v_STRING;
2526 dbus_int32_t v_INT32;
2528 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2529 _dbus_assert (message1 != NULL);
2530 if (!dbus_message_set_member (message1, "Frobated"))
2531 _dbus_assert_not_reached ("oom");
2533 v_STRING = "foobar";
2535 if (!dbus_message_append_args (message1,
2536 DBUS_TYPE_STRING, &v_STRING,
2537 DBUS_TYPE_INT32, &v_INT32,
2539 _dbus_assert_not_reached ("oom");
2541 check_matching (message1, 1,
2542 should_match_message_1,
2543 should_not_match_message_1);
2545 dbus_message_unref (message1);
2547 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2548 _dbus_assert (message2 != NULL);
2549 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2550 _dbus_assert_not_reached ("oom");
2552 /* Obviously this isn't really a NameOwnerChanged signal. */
2553 v_STRING = EXAMPLE_NAME;
2554 if (!dbus_message_append_args (message2,
2555 DBUS_TYPE_STRING, &v_STRING,
2557 _dbus_assert_not_reached ("oom");
2559 check_matching (message2, 2,
2560 should_match_message_2,
2561 should_not_match_message_2);
2563 dbus_message_unref (message2);
2566 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2568 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2569 * from the specification. Notice that not all of them are actually legal D-Bus
2572 * The author of this test takes no responsibility for the semantics of
2573 * this match rule key.
2575 static const char *paths_that_should_be_matched[] = {
2579 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2585 /* These paths should not be matched by PATH_MATCH_RULE. */
2586 static const char *paths_that_should_not_be_matched[] = {
2595 test_path_match (int type,
2597 const char *rule_text,
2599 dbus_bool_t should_match)
2601 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2602 dbus_bool_t matched;
2604 _dbus_assert (message != NULL);
2605 if (!dbus_message_set_member (message, "Foo"))
2606 _dbus_assert_not_reached ("oom");
2608 if (!dbus_message_append_args (message,
2611 _dbus_assert_not_reached ("oom");
2613 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2615 if (matched != should_match)
2617 _dbus_warn ("Expected rule %s to %s message "
2618 "with first arg %s of type '%c', failed\n",
2620 should_match ? "match" : "not match",
2626 dbus_message_unref (message);
2630 test_path_matching (void)
2635 rule = check_parse (TRUE, PATH_MATCH_RULE);
2636 _dbus_assert (rule != NULL);
2638 for (s = paths_that_should_be_matched; *s != NULL; s++)
2639 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2641 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2643 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2645 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2647 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2648 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2651 bus_match_rule_unref (rule);
2655 path_namespace_should_match_message_1[] = {
2656 "type='signal',path_namespace='/foo'",
2657 "type='signal',path_namespace='/foo/TheObjectManager'",
2662 path_namespace_should_not_match_message_1[] = {
2663 "type='signal',path_namespace='/bar'",
2664 "type='signal',path_namespace='/bar/TheObjectManager'",
2669 path_namespace_should_match_message_2[] = {
2670 "type='signal',path_namespace='/foo/TheObjectManager'",
2675 path_namespace_should_not_match_message_2[] = {
2680 path_namespace_should_match_message_3[] = {
2685 path_namespace_should_not_match_message_3[] = {
2686 "type='signal',path_namespace='/foo/TheObjectManager'",
2691 test_matching_path_namespace (void)
2693 DBusMessage *message1;
2694 DBusMessage *message2;
2695 DBusMessage *message3;
2697 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2698 _dbus_assert (message1 != NULL);
2699 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2700 _dbus_assert_not_reached ("oom");
2702 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2703 _dbus_assert (message2 != NULL);
2704 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2705 _dbus_assert_not_reached ("oom");
2707 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2708 _dbus_assert (message3 != NULL);
2709 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2710 _dbus_assert_not_reached ("oom");
2712 check_matching (message1, 1,
2713 path_namespace_should_match_message_1,
2714 path_namespace_should_not_match_message_1);
2715 check_matching (message2, 2,
2716 path_namespace_should_match_message_2,
2717 path_namespace_should_not_match_message_2);
2718 check_matching (message3, 3,
2719 path_namespace_should_match_message_3,
2720 path_namespace_should_not_match_message_3);
2722 dbus_message_unref (message3);
2723 dbus_message_unref (message2);
2724 dbus_message_unref (message1);
2728 bus_signals_test (const DBusString *test_data_dir)
2730 BusMatchmaker *matchmaker;
2732 matchmaker = bus_matchmaker_new ();
2733 bus_matchmaker_ref (matchmaker);
2734 bus_matchmaker_unref (matchmaker);
2735 bus_matchmaker_unref (matchmaker);
2737 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2738 _dbus_assert_not_reached ("Parsing match rules test failed");
2742 test_path_matching ();
2743 test_matching_path_namespace ();
2748 #endif /* DBUS_BUILD_TESTS */