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
126 match_rule_to_string (BusMatchRule *rule)
131 if (!_dbus_string_init (&str))
134 while ((s = _dbus_strdup ("nomem")) == NULL)
135 ; /* only OK for debug spew... */
139 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
141 if (!_dbus_string_append_printf (&str, "type='%s'",
142 dbus_message_type_to_string (rule->message_type)))
146 if (rule->flags & BUS_MATCH_INTERFACE)
148 if (_dbus_string_get_length (&str) > 0)
150 if (!_dbus_string_append (&str, ","))
154 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
158 if (rule->flags & BUS_MATCH_MEMBER)
160 if (_dbus_string_get_length (&str) > 0)
162 if (!_dbus_string_append (&str, ","))
166 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
170 if (rule->flags & BUS_MATCH_PATH)
172 if (_dbus_string_get_length (&str) > 0)
174 if (!_dbus_string_append (&str, ","))
178 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
182 if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
184 if (_dbus_string_get_length (&str) > 0)
186 if (!_dbus_string_append (&str, ","))
190 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
194 if (rule->flags & BUS_MATCH_SENDER)
196 if (_dbus_string_get_length (&str) > 0)
198 if (!_dbus_string_append (&str, ","))
202 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
206 if (rule->flags & BUS_MATCH_DESTINATION)
208 if (_dbus_string_get_length (&str) > 0)
210 if (!_dbus_string_append (&str, ","))
214 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
218 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
220 if (_dbus_string_get_length (&str) > 0)
222 if (!_dbus_string_append (&str, ","))
226 if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
227 (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
232 if (rule->flags & BUS_MATCH_ARGS)
236 _dbus_assert (rule->args != NULL);
239 while (i < rule->args_len)
241 if (rule->args[i] != NULL)
243 dbus_bool_t is_path, is_namespace;
245 if (_dbus_string_get_length (&str) > 0)
247 if (!_dbus_string_append (&str, ","))
251 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
252 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
254 if (!_dbus_string_append_printf (&str,
258 is_namespace ? "namespace" : "",
267 if (!_dbus_string_steal_data (&str, &ret))
270 _dbus_string_free (&str);
274 _dbus_string_free (&str);
277 while ((s = _dbus_strdup ("nomem")) == NULL)
278 ; /* only OK for debug spew... */
282 #endif /* defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS) */
285 bus_match_rule_set_message_type (BusMatchRule *rule,
288 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
290 rule->message_type = type;
296 bus_match_rule_set_interface (BusMatchRule *rule,
297 const char *interface)
301 _dbus_assert (interface != NULL);
303 new = _dbus_strdup (interface);
307 rule->flags |= BUS_MATCH_INTERFACE;
308 dbus_free (rule->interface);
309 rule->interface = new;
315 bus_match_rule_set_member (BusMatchRule *rule,
320 _dbus_assert (member != NULL);
322 new = _dbus_strdup (member);
326 rule->flags |= BUS_MATCH_MEMBER;
327 dbus_free (rule->member);
334 bus_match_rule_set_sender (BusMatchRule *rule,
339 _dbus_assert (sender != NULL);
341 new = _dbus_strdup (sender);
345 rule->flags |= BUS_MATCH_SENDER;
346 dbus_free (rule->sender);
353 bus_match_rule_set_destination (BusMatchRule *rule,
354 const char *destination)
358 _dbus_assert (destination != NULL);
360 new = _dbus_strdup (destination);
364 rule->flags |= BUS_MATCH_DESTINATION;
365 dbus_free (rule->destination);
366 rule->destination = new;
372 bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
373 dbus_bool_t is_eavesdropping)
375 if (is_eavesdropping)
376 rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
378 rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
382 bus_match_rule_set_path (BusMatchRule *rule,
384 dbus_bool_t is_namespace)
388 _dbus_assert (path != NULL);
390 new = _dbus_strdup (path);
394 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
397 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
399 rule->flags |= BUS_MATCH_PATH;
401 dbus_free (rule->path);
408 bus_match_rule_set_arg (BusMatchRule *rule,
410 const DBusString *value,
412 dbus_bool_t is_namespace)
417 _dbus_assert (value != NULL);
419 /* args_len is the number of args not including null termination
422 if (arg >= rule->args_len)
424 unsigned int *new_arg_lens;
429 new_args_len = arg + 1;
431 /* add another + 1 here for null termination */
432 new_args = dbus_realloc (rule->args,
433 sizeof (char *) * (new_args_len + 1));
434 if (new_args == NULL)
437 /* NULL the new slots */
439 while (i <= new_args_len) /* <= for null termination */
445 rule->args = new_args;
447 /* and now add to the lengths */
448 new_arg_lens = dbus_realloc (rule->arg_lens,
449 sizeof (int) * (new_args_len + 1));
451 if (new_arg_lens == NULL)
454 /* zero the new slots */
456 while (i <= new_args_len) /* <= for null termination */
462 rule->arg_lens = new_arg_lens;
463 rule->args_len = new_args_len;
466 length = _dbus_string_get_length (value);
467 if (!_dbus_string_copy_data (value, &new))
470 rule->flags |= BUS_MATCH_ARGS;
472 dbus_free (rule->args[arg]);
473 rule->arg_lens[arg] = length;
474 rule->args[arg] = new;
477 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
480 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
482 /* NULL termination didn't get busted */
483 _dbus_assert (rule->args[rule->args_len] == NULL);
484 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
489 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
492 find_key (const DBusString *str,
500 const char *key_start;
503 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
505 s = _dbus_string_get_const_data (str);
509 while (*p && ISWHITE (*p))
514 while (*p && *p != '=' && !ISWHITE (*p))
519 while (*p && ISWHITE (*p))
522 if (key_start == key_end)
524 /* Empty match rules or trailing whitespace are OK */
531 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
532 "Match rule has a key with no subsequent '=' character");
537 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
549 find_value (const DBusString *str,
561 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
563 orig_len = _dbus_string_get_length (value);
565 s = _dbus_string_get_const_data (str);
573 if (quote_char == '\0')
593 if (!_dbus_string_append_byte (value, *p))
600 else if (quote_char == '\\')
602 /* \ only counts as an escape if escaping a quote mark */
605 if (!_dbus_string_append_byte (value, '\\'))
612 if (!_dbus_string_append_byte (value, *p))
622 _dbus_assert (quote_char == '\'');
630 if (!_dbus_string_append_byte (value, *p))
644 if (quote_char == '\\')
646 if (!_dbus_string_append_byte (value, '\\'))
652 else if (quote_char == '\'')
654 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
655 "Unbalanced quotation marks in match rule");
659 _dbus_assert (quote_char == '\0');
661 /* Zero-length values are allowed */
668 _DBUS_ASSERT_ERROR_IS_SET (error);
669 _dbus_string_set_length (value, orig_len);
673 /* duplicates aren't allowed so the real legitimate max is only 6 or
674 * so. Leaving extra so we don't have to bother to update it.
675 * FIXME this is sort of busted now with arg matching, but we let
676 * you match on up to 10 args for now
678 #define MAX_RULE_TOKENS 16
680 /* this is slightly too high level to be termed a "token"
681 * but let's not be pedantic.
690 tokenize_rule (const DBusString *rule_text,
691 RuleToken tokens[MAX_RULE_TOKENS],
702 if (!_dbus_string_init (&key))
708 if (!_dbus_string_init (&value))
710 _dbus_string_free (&key);
717 while (i < MAX_RULE_TOKENS &&
718 pos < _dbus_string_get_length (rule_text))
720 _dbus_assert (tokens[i].key == NULL);
721 _dbus_assert (tokens[i].value == NULL);
723 if (!find_key (rule_text, pos, &key, &pos, error))
726 if (_dbus_string_get_length (&key) == 0)
729 if (!_dbus_string_steal_data (&key, &tokens[i].key))
735 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
738 if (!_dbus_string_steal_data (&value, &tokens[i].value))
754 while (tokens[i].key || tokens[i].value)
756 dbus_free (tokens[i].key);
757 dbus_free (tokens[i].value);
758 tokens[i].key = NULL;
759 tokens[i].value = NULL;
764 _dbus_string_free (&key);
765 _dbus_string_free (&value);
771 bus_match_rule_parse_arg_match (BusMatchRule *rule,
773 const DBusString *value,
776 dbus_bool_t is_path = FALSE;
777 dbus_bool_t is_namespace = FALSE;
783 /* For now, arg0='foo' always implies that 'foo' is a
784 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
785 * if we wanted, which would specify another type, in which case
786 * arg0='5' would have the 5 parsed as an int rather than string.
789 /* First we need to parse arg0 = 0, arg27 = 27 */
791 _dbus_string_init_const (&key_str, key);
792 length = _dbus_string_get_length (&key_str);
794 if (_dbus_string_get_length (&key_str) < 4)
796 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
797 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
801 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
803 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
804 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
810 if ((end + strlen ("path")) == length &&
811 _dbus_string_ends_with_c_str (&key_str, "path"))
815 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
817 int value_len = _dbus_string_get_length (value);
821 if (!_dbus_validate_bus_namespace (value, 0, value_len))
823 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
824 "arg0namespace='%s' is not a valid prefix of a bus name",
825 _dbus_string_get_const_data (value));
831 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
832 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
837 /* If we didn't check this we could allocate a huge amount of RAM */
838 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
840 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
841 "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);
845 if ((rule->flags & BUS_MATCH_ARGS) &&
846 rule->args_len > (int) arg &&
847 rule->args[arg] != NULL)
849 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
850 "Argument %d matched more than once in match rule\n", key);
854 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
863 _DBUS_ASSERT_ERROR_IS_SET (error);
868 * The format is comma-separated with strings quoted with single quotes
869 * as for the shell (to escape a literal single quote, use '\'').
871 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
872 * path='/bar/foo',destination=':452345.34'
876 bus_match_rule_parse (DBusConnection *matches_go_to,
877 const DBusString *rule_text,
881 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
884 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
886 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
888 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
889 "Match rule text is %d bytes, maximum is %d",
890 _dbus_string_get_length (rule_text),
891 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
895 memset (tokens, '\0', sizeof (tokens));
897 rule = bus_match_rule_new (matches_go_to);
904 if (!tokenize_rule (rule_text, tokens, error))
908 while (tokens[i].key != NULL)
912 const char *key = tokens[i].key;
913 const char *value = tokens[i].value;
915 _dbus_string_init_const (&tmp_str, value);
916 len = _dbus_string_get_length (&tmp_str);
918 if (strcmp (key, "type") == 0)
922 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
924 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
925 "Key %s specified twice in match rule\n", key);
929 t = dbus_message_type_from_string (value);
931 if (t == DBUS_MESSAGE_TYPE_INVALID)
933 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
934 "Invalid message type (%s) in match rule\n", value);
938 if (!bus_match_rule_set_message_type (rule, t))
944 else if (strcmp (key, "sender") == 0)
946 if (rule->flags & BUS_MATCH_SENDER)
948 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
949 "Key %s specified twice in match rule\n", key);
953 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
955 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
956 "Sender name '%s' is invalid\n", value);
960 if (!bus_match_rule_set_sender (rule, value))
966 else if (strcmp (key, "interface") == 0)
968 if (rule->flags & BUS_MATCH_INTERFACE)
970 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
971 "Key %s specified twice in match rule\n", key);
975 if (!_dbus_validate_interface (&tmp_str, 0, len))
977 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
978 "Interface name '%s' is invalid\n", value);
982 if (!bus_match_rule_set_interface (rule, value))
988 else if (strcmp (key, "member") == 0)
990 if (rule->flags & BUS_MATCH_MEMBER)
992 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
993 "Key %s specified twice in match rule\n", key);
997 if (!_dbus_validate_member (&tmp_str, 0, len))
999 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1000 "Member name '%s' is invalid\n", value);
1004 if (!bus_match_rule_set_member (rule, value))
1006 BUS_SET_OOM (error);
1010 else if (strcmp (key, "path") == 0 ||
1011 strcmp (key, "path_namespace") == 0)
1013 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1015 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
1017 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1018 "path or path_namespace specified twice in match rule\n");
1022 if (!_dbus_validate_path (&tmp_str, 0, len))
1024 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1025 "Path '%s' is invalid\n", value);
1029 if (!bus_match_rule_set_path (rule, value, is_namespace))
1031 BUS_SET_OOM (error);
1035 else if (strcmp (key, "destination") == 0)
1037 if (rule->flags & BUS_MATCH_DESTINATION)
1039 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1040 "Key %s specified twice in match rule\n", key);
1044 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1046 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1047 "Destination name '%s' is invalid\n", value);
1051 if (!bus_match_rule_set_destination (rule, value))
1053 BUS_SET_OOM (error);
1057 else if (strcmp (key, "eavesdrop") == 0)
1059 /* do not detect "eavesdrop" being used more than once in rule:
1060 * 1) it's not possible, it's only in the flags
1061 * 2) it might be used twice to disable eavesdropping when it's
1062 * automatically added (eg dbus-monitor/bustle) */
1064 /* we accept only "true|false" as possible values */
1065 if ((strcmp (value, "true") == 0))
1067 bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1069 else if (strcmp (value, "false") == 0)
1071 bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1075 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1076 "eavesdrop='%s' is invalid, "
1077 "it should be 'true' or 'false'\n",
1082 else if (strncmp (key, "arg", 3) == 0)
1084 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1089 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1090 "Unknown key \"%s\" in match rule",
1102 _DBUS_ASSERT_ERROR_IS_SET (error);
1105 bus_match_rule_unref (rule);
1112 while (tokens[i].key || tokens[i].value)
1114 _dbus_assert (i < MAX_RULE_TOKENS);
1115 dbus_free (tokens[i].key);
1116 dbus_free (tokens[i].value);
1123 typedef struct RulePool RulePool;
1126 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1127 DBusHashTable *rules_by_iface;
1129 /* List of BusMatchRules which don't specify an interface */
1130 DBusList *rules_without_iface;
1133 struct BusMatchmaker
1137 /* Pools of rules, grouped by the type of message they match. 0
1138 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1141 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1144 #ifdef DBUS_ENABLE_STATS
1146 bus_match_rule_dump (BusMatchmaker *matchmaker,
1147 DBusConnection *conn_filter,
1148 DBusMessageIter *arr_iter)
1152 for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++)
1158 _dbus_hash_iter_init (matchmaker->rules_by_type[i].rules_by_iface, &iter);
1159 while (_dbus_hash_iter_next (&iter))
1161 list = _dbus_hash_iter_get_value (&iter);
1162 for (link = _dbus_list_get_first_link (list);
1164 link = _dbus_list_get_next_link (list, link))
1166 BusMatchRule *rule = link->data;
1168 if (rule->matches_go_to == conn_filter)
1170 char *s = match_rule_to_string (rule);
1175 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1184 list = &matchmaker->rules_by_type[i].rules_without_iface;
1185 for (link = _dbus_list_get_first_link (list);
1187 link = _dbus_list_get_next_link (list, link))
1189 BusMatchRule *rule = link->data;
1191 if (rule->matches_go_to == conn_filter)
1193 char *s = match_rule_to_string (rule);
1198 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1213 rule_list_free (DBusList **rules)
1215 while (*rules != NULL)
1219 rule = (*rules)->data;
1220 bus_match_rule_unref (rule);
1221 _dbus_list_remove_link (rules, *rules);
1226 rule_list_ptr_free (DBusList **list)
1228 /* We have to cope with NULL because the hash table frees the "existing"
1229 * value (which is NULL) when creating a new table entry...
1233 rule_list_free (list);
1239 bus_matchmaker_new (void)
1241 BusMatchmaker *matchmaker;
1244 matchmaker = dbus_new0 (BusMatchmaker, 1);
1245 if (matchmaker == NULL)
1248 matchmaker->refcount = 1;
1250 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1252 RulePool *p = matchmaker->rules_by_type + i;
1254 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1255 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1257 if (p->rules_by_iface == NULL)
1264 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1266 RulePool *p = matchmaker->rules_by_type + i;
1268 if (p->rules_by_iface == NULL)
1271 _dbus_hash_table_unref (p->rules_by_iface);
1273 dbus_free (matchmaker);
1279 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1281 const char *interface,
1286 _dbus_assert (message_type >= 0);
1287 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1289 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1291 interface != NULL ? interface : "<null>");
1293 p = matchmaker->rules_by_type + message_type;
1295 if (interface == NULL)
1297 return &p->rules_without_iface;
1303 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1305 if (list == NULL && create)
1307 char *dupped_interface;
1309 list = dbus_new0 (DBusList *, 1);
1313 dupped_interface = _dbus_strdup (interface);
1314 if (dupped_interface == NULL)
1320 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1323 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1324 dupped_interface, list))
1327 dbus_free (dupped_interface);
1337 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1339 const char *interface,
1344 if (interface == NULL)
1350 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1351 message_type, interface);
1353 p = matchmaker->rules_by_type + message_type;
1355 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1358 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1362 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1364 _dbus_assert (matchmaker->refcount > 0);
1366 matchmaker->refcount += 1;
1372 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1374 _dbus_assert (matchmaker->refcount > 0);
1376 matchmaker->refcount -= 1;
1377 if (matchmaker->refcount == 0)
1381 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1383 RulePool *p = matchmaker->rules_by_type + i;
1385 _dbus_hash_table_unref (p->rules_by_iface);
1386 rule_list_free (&p->rules_without_iface);
1389 dbus_free (matchmaker);
1393 /* The rule can't be modified after it's added. */
1395 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1400 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1402 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1404 rule->interface != NULL ? rule->interface : "<null>");
1406 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1407 rule->interface, TRUE);
1412 if (!_dbus_list_append (rules, rule))
1415 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1417 _dbus_list_remove_last (rules, rule);
1418 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1419 rule->interface, rules);
1423 bus_match_rule_ref (rule);
1425 #ifdef DBUS_ENABLE_VERBOSE_MODE
1427 char *s = match_rule_to_string (rule);
1429 _dbus_verbose ("Added match rule %s to connection %p\n",
1430 s, rule->matches_go_to);
1439 match_rule_equal (BusMatchRule *a,
1442 if (a->flags != b->flags)
1445 if (a->matches_go_to != b->matches_go_to)
1448 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1449 a->message_type != b->message_type)
1452 if ((a->flags & BUS_MATCH_MEMBER) &&
1453 strcmp (a->member, b->member) != 0)
1456 if ((a->flags & BUS_MATCH_PATH) &&
1457 strcmp (a->path, b->path) != 0)
1460 if ((a->flags & BUS_MATCH_INTERFACE) &&
1461 strcmp (a->interface, b->interface) != 0)
1464 if ((a->flags & BUS_MATCH_SENDER) &&
1465 strcmp (a->sender, b->sender) != 0)
1468 if ((a->flags & BUS_MATCH_DESTINATION) &&
1469 strcmp (a->destination, b->destination) != 0)
1472 /* we already compared the value of flags, and
1473 * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1475 if (a->flags & BUS_MATCH_ARGS)
1479 if (a->args_len != b->args_len)
1483 while (i < a->args_len)
1487 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1490 if (a->arg_lens[i] != b->arg_lens[i])
1493 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1495 if (a->args[i] != NULL)
1497 _dbus_assert (b->args[i] != NULL);
1498 if (memcmp (a->args[i], b->args[i], length) != 0)
1510 bus_matchmaker_remove_rule_link (DBusList **rules,
1513 BusMatchRule *rule = link->data;
1515 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1516 _dbus_list_remove_link (rules, link);
1518 #ifdef DBUS_ENABLE_VERBOSE_MODE
1520 char *s = match_rule_to_string (rule);
1522 _dbus_verbose ("Removed match rule %s for connection %p\n",
1523 s, rule->matches_go_to);
1528 bus_match_rule_unref (rule);
1532 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1537 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1539 rule->interface != NULL ? rule->interface : "<null>");
1541 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1543 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1544 rule->interface, FALSE);
1546 /* We should only be asked to remove a rule by identity right after it was
1547 * added, so there should be a list for it.
1549 _dbus_assert (rules != NULL);
1551 _dbus_list_remove (rules, rule);
1552 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1555 #ifdef DBUS_ENABLE_VERBOSE_MODE
1557 char *s = match_rule_to_string (rule);
1559 _dbus_verbose ("Removed match rule %s for connection %p\n",
1560 s, rule->matches_go_to);
1565 bus_match_rule_unref (rule);
1568 /* Remove a single rule which is equal to the given rule by value */
1570 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1571 BusMatchRule *value,
1575 DBusList *link = NULL;
1577 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1578 value->message_type,
1579 value->interface != NULL ? value->interface : "<null>");
1581 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1582 value->interface, FALSE);
1586 /* we traverse backward because bus_connection_remove_match_rule()
1587 * removes the most-recently-added rule
1589 link = _dbus_list_get_last_link (rules);
1590 while (link != NULL)
1596 prev = _dbus_list_get_prev_link (rules, link);
1598 if (match_rule_equal (rule, value))
1600 bus_matchmaker_remove_rule_link (rules, link);
1610 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1611 "The given match rule wasn't found and can't be removed");
1615 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1622 rule_list_remove_by_connection (DBusList **rules,
1623 DBusConnection *connection)
1627 link = _dbus_list_get_first_link (rules);
1628 while (link != NULL)
1634 next = _dbus_list_get_next_link (rules, link);
1636 if (rule->matches_go_to == connection)
1638 bus_matchmaker_remove_rule_link (rules, link);
1640 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1641 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1643 /* The rule matches to/from a base service, see if it's the
1644 * one being disconnected, since we know this service name
1645 * will never be recycled.
1649 name = bus_connection_get_name (connection);
1650 _dbus_assert (name != NULL); /* because we're an active connection */
1652 if (((rule->flags & BUS_MATCH_SENDER) &&
1653 strcmp (rule->sender, name) == 0) ||
1654 ((rule->flags & BUS_MATCH_DESTINATION) &&
1655 strcmp (rule->destination, name) == 0))
1657 bus_matchmaker_remove_rule_link (rules, link);
1666 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1667 DBusConnection *connection)
1673 * This scans all match rules on the bus. We could avoid that
1674 * for the rules belonging to the connection, since we keep
1675 * a list of those; but for the rules that just refer to
1676 * the connection we'd need to do something more elaborate.
1679 _dbus_assert (bus_connection_is_active (connection));
1681 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1683 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1685 RulePool *p = matchmaker->rules_by_type + i;
1688 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1690 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1691 while (_dbus_hash_iter_next (&iter))
1693 DBusList **items = _dbus_hash_iter_get_value (&iter);
1695 rule_list_remove_by_connection (items, connection);
1698 _dbus_hash_iter_remove_entry (&iter);
1704 connection_is_primary_owner (DBusConnection *connection,
1705 const char *service_name)
1707 BusService *service;
1709 BusRegistry *registry;
1711 _dbus_assert (connection != NULL);
1713 registry = bus_connection_get_registry (connection);
1715 _dbus_string_init_const (&str, service_name);
1716 service = bus_registry_lookup (registry, &str);
1718 if (service == NULL)
1719 return FALSE; /* Service doesn't exist so connection can't own it. */
1721 return bus_service_get_primary_owners_connection (service) == connection;
1725 str_has_prefix (const char *str, const char *prefix)
1728 prefix_len = strlen (prefix);
1729 if (strncmp (str, prefix, prefix_len) == 0)
1736 match_rule_matches (BusMatchRule *rule,
1737 DBusConnection *sender,
1738 DBusConnection *addressed_recipient,
1739 DBusMessage *message,
1740 BusMatchFlags already_matched)
1742 dbus_bool_t wants_to_eavesdrop = FALSE;
1745 /* All features of the match rule are AND'd together,
1746 * so FALSE if any of them don't match.
1749 /* sender/addressed_recipient of #NULL may mean bus driver,
1750 * or for addressed_recipient may mean a message with no
1751 * specific recipient (i.e. a signal)
1754 /* Don't bother re-matching features we've already checked implicitly. */
1755 flags = rule->flags & (~already_matched);
1757 if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
1758 wants_to_eavesdrop = TRUE;
1760 if (flags & BUS_MATCH_MESSAGE_TYPE)
1762 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1764 if (rule->message_type != dbus_message_get_type (message))
1768 if (flags & BUS_MATCH_INTERFACE)
1772 _dbus_assert (rule->interface != NULL);
1774 iface = dbus_message_get_interface (message);
1778 if (strcmp (iface, rule->interface) != 0)
1782 if (flags & BUS_MATCH_MEMBER)
1786 _dbus_assert (rule->member != NULL);
1788 member = dbus_message_get_member (message);
1792 if (strcmp (member, rule->member) != 0)
1796 if (flags & BUS_MATCH_SENDER)
1798 _dbus_assert (rule->sender != NULL);
1802 if (strcmp (rule->sender,
1803 DBUS_SERVICE_DBUS) != 0)
1808 if (!connection_is_primary_owner (sender, rule->sender))
1813 /* Note: this part is relevant for eavesdropper rules:
1815 * 1) rule has a destination to be matched
1816 * (flag BUS_MATCH_DESTINATION present). Rule will match if:
1817 * - rule->destination matches the addressed_recipient
1819 * - wants_to_eavesdrop=TRUE
1821 * Note: (the case in which addressed_recipient is the actual rule owner
1822 * is handled elsewere in dispatch.c:bus_dispatch_matches().
1824 * 2) rule has no destination. Rule will match if:
1825 * - message has no specified destination (ie broadcasts)
1826 * (Note: this will rule out unicast method calls and unicast signals,
1827 * fixing FDO#269748)
1829 * - wants_to_eavesdrop=TRUE (destination-catch-all situation)
1831 if (flags & BUS_MATCH_DESTINATION)
1833 const char *destination;
1835 _dbus_assert (rule->destination != NULL);
1837 destination = dbus_message_get_destination (message);
1838 if (destination == NULL)
1839 /* broadcast, but this rule specified a destination: no match */
1842 /* rule owner does not intend to eavesdrop: we'll deliver only msgs
1843 * directed to it, NOT MATCHING */
1844 if (!wants_to_eavesdrop)
1847 if (addressed_recipient == NULL)
1849 if (strcmp (rule->destination,
1850 DBUS_SERVICE_DBUS) != 0)
1855 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1858 } else { /* no destination in rule */
1859 dbus_bool_t msg_is_broadcast;
1861 _dbus_assert (rule->destination == NULL);
1863 msg_is_broadcast = (dbus_message_get_destination (message) == NULL);
1865 if (!wants_to_eavesdrop && !msg_is_broadcast)
1868 /* if we are here rule owner intends to eavesdrop
1870 * message is being broadcasted */
1873 if (flags & BUS_MATCH_PATH)
1877 _dbus_assert (rule->path != NULL);
1879 path = dbus_message_get_path (message);
1883 if (strcmp (path, rule->path) != 0)
1887 if (flags & BUS_MATCH_PATH_NAMESPACE)
1892 _dbus_assert (rule->path != NULL);
1894 path = dbus_message_get_path (message);
1898 if (!str_has_prefix (path, rule->path))
1901 len = strlen (rule->path);
1903 /* Check that the actual argument is within the expected
1904 * namespace, rather than just starting with that string,
1905 * by checking that the matched prefix is followed by a '/'
1906 * or the end of the path.
1908 * Special case: the only valid path of length 1, "/",
1909 * matches everything.
1911 if (len > 1 && path[len] != '\0' && path[len] != '/')
1915 if (flags & BUS_MATCH_ARGS)
1918 DBusMessageIter iter;
1920 _dbus_assert (rule->args != NULL);
1922 dbus_message_iter_init (message, &iter);
1925 while (i < rule->args_len)
1928 const char *expected_arg;
1929 int expected_length;
1930 dbus_bool_t is_path, is_namespace;
1932 expected_arg = rule->args[i];
1933 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1934 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1935 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1937 current_type = dbus_message_iter_get_arg_type (&iter);
1939 if (expected_arg != NULL)
1941 const char *actual_arg;
1944 if (current_type != DBUS_TYPE_STRING &&
1945 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1949 dbus_message_iter_get_basic (&iter, &actual_arg);
1950 _dbus_assert (actual_arg != NULL);
1952 actual_length = strlen (actual_arg);
1956 if (actual_length < expected_length &&
1957 actual_arg[actual_length - 1] != '/')
1960 if (expected_length < actual_length &&
1961 expected_arg[expected_length - 1] != '/')
1964 if (memcmp (actual_arg, expected_arg,
1965 MIN (actual_length, expected_length)) != 0)
1968 else if (is_namespace)
1970 if (expected_length > actual_length)
1973 /* If the actual argument doesn't start with the expected
1974 * namespace, then we don't match.
1976 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
1979 if (expected_length < actual_length)
1981 /* Check that the actual argument is within the expected
1982 * namespace, rather than just starting with that string,
1983 * by checking that the matched prefix ends in a '.'.
1985 * This doesn't stop "foo.bar." matching "foo.bar..baz"
1986 * which is an invalid namespace, but at some point the
1987 * daemon can't cover up for broken services.
1989 if (actual_arg[expected_length] != '.')
1992 /* otherwise we had an exact match. */
1996 if (expected_length != actual_length ||
1997 memcmp (expected_arg, actual_arg, expected_length) != 0)
2003 if (current_type != DBUS_TYPE_INVALID)
2004 dbus_message_iter_next (&iter);
2014 get_recipients_from_list (DBusList **rules,
2015 DBusConnection *sender,
2016 DBusConnection *addressed_recipient,
2017 DBusMessage *message,
2018 DBusList **recipients_p)
2025 link = _dbus_list_get_first_link (rules);
2026 while (link != NULL)
2032 #ifdef DBUS_ENABLE_VERBOSE_MODE
2034 char *s = match_rule_to_string (rule);
2036 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
2037 s, rule->matches_go_to);
2042 if (match_rule_matches (rule,
2043 sender, addressed_recipient, message,
2044 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
2046 _dbus_verbose ("Rule matched\n");
2048 /* Append to the list if we haven't already */
2049 if (bus_connection_mark_stamp (rule->matches_go_to))
2051 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
2056 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
2060 link = _dbus_list_get_next_link (rules, link);
2067 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
2068 BusConnections *connections,
2069 DBusConnection *sender,
2070 DBusConnection *addressed_recipient,
2071 DBusMessage *message,
2072 DBusList **recipients_p)
2075 const char *interface;
2076 DBusList **neither, **just_type, **just_iface, **both;
2078 _dbus_assert (*recipients_p == NULL);
2080 /* This avoids sending same message to the same connection twice.
2081 * Purpose of the stamp instead of a bool is to avoid iterating over
2082 * all connections resetting the bool each time.
2084 bus_connections_increment_stamp (connections);
2086 /* addressed_recipient is already receiving the message, don't add to list.
2087 * NULL addressed_recipient means either bus driver, or this is a signal
2088 * and thus lacks a specific addressed_recipient.
2090 if (addressed_recipient != NULL)
2091 bus_connection_mark_stamp (addressed_recipient);
2093 type = dbus_message_get_type (message);
2094 interface = dbus_message_get_interface (message);
2096 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
2098 just_type = just_iface = both = NULL;
2100 if (interface != NULL)
2101 just_iface = bus_matchmaker_get_rules (matchmaker,
2102 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
2104 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
2106 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
2108 if (interface != NULL)
2109 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
2112 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
2113 message, recipients_p) &&
2114 get_recipients_from_list (just_iface, sender, addressed_recipient,
2115 message, recipients_p) &&
2116 get_recipients_from_list (just_type, sender, addressed_recipient,
2117 message, recipients_p) &&
2118 get_recipients_from_list (both, sender, addressed_recipient,
2119 message, recipients_p)))
2121 _dbus_list_clear (recipients_p);
2128 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2132 static BusMatchRule*
2133 check_parse (dbus_bool_t should_succeed,
2140 dbus_error_init (&error);
2142 _dbus_string_init_const (&str, text);
2144 rule = bus_match_rule_parse (NULL, &str, &error);
2145 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2147 dbus_error_free (&error);
2151 if (should_succeed && rule == NULL)
2153 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
2154 error.name, error.message,
2155 _dbus_string_get_const_data (&str));
2159 if (!should_succeed && rule != NULL)
2161 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2162 _dbus_string_get_const_data (&str));
2166 dbus_error_free (&error);
2172 assert_large_rule (BusMatchRule *rule)
2174 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2175 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2176 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2177 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2178 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2179 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2181 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2182 _dbus_assert (rule->interface != NULL);
2183 _dbus_assert (rule->member != NULL);
2184 _dbus_assert (rule->sender != NULL);
2185 _dbus_assert (rule->destination != NULL);
2186 _dbus_assert (rule->path != NULL);
2188 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2189 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2190 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2191 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2192 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2196 test_parsing (void *data)
2200 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2203 assert_large_rule (rule);
2204 bus_match_rule_unref (rule);
2207 /* With extra whitespace and useless quotes */
2208 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2211 assert_large_rule (rule);
2212 bus_match_rule_unref (rule);
2216 /* A simple signal connection */
2217 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2220 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2221 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2222 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2224 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2225 _dbus_assert (rule->interface != NULL);
2226 _dbus_assert (rule->path != NULL);
2228 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2229 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2231 bus_match_rule_unref (rule);
2235 rule = check_parse (TRUE, "arg0='foo'");
2238 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2239 _dbus_assert (rule->args != NULL);
2240 _dbus_assert (rule->args_len == 1);
2241 _dbus_assert (rule->args[0] != NULL);
2242 _dbus_assert (rule->args[1] == NULL);
2243 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2245 bus_match_rule_unref (rule);
2248 rule = check_parse (TRUE, "arg1='foo'");
2251 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2252 _dbus_assert (rule->args != NULL);
2253 _dbus_assert (rule->args_len == 2);
2254 _dbus_assert (rule->args[0] == NULL);
2255 _dbus_assert (rule->args[1] != NULL);
2256 _dbus_assert (rule->args[2] == NULL);
2257 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2259 bus_match_rule_unref (rule);
2262 rule = check_parse (TRUE, "arg2='foo'");
2265 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2266 _dbus_assert (rule->args != NULL);
2267 _dbus_assert (rule->args_len == 3);
2268 _dbus_assert (rule->args[0] == NULL);
2269 _dbus_assert (rule->args[1] == NULL);
2270 _dbus_assert (rule->args[2] != NULL);
2271 _dbus_assert (rule->args[3] == NULL);
2272 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2274 bus_match_rule_unref (rule);
2277 rule = check_parse (TRUE, "arg40='foo'");
2280 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2281 _dbus_assert (rule->args != NULL);
2282 _dbus_assert (rule->args_len == 41);
2283 _dbus_assert (rule->args[0] == NULL);
2284 _dbus_assert (rule->args[1] == NULL);
2285 _dbus_assert (rule->args[40] != NULL);
2286 _dbus_assert (rule->args[41] == NULL);
2287 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2289 bus_match_rule_unref (rule);
2292 rule = check_parse (TRUE, "arg63='foo'");
2295 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2296 _dbus_assert (rule->args != NULL);
2297 _dbus_assert (rule->args_len == 64);
2298 _dbus_assert (rule->args[0] == NULL);
2299 _dbus_assert (rule->args[1] == NULL);
2300 _dbus_assert (rule->args[63] != NULL);
2301 _dbus_assert (rule->args[64] == NULL);
2302 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2304 bus_match_rule_unref (rule);
2307 rule = check_parse (TRUE, "arg7path='/foo'");
2310 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2311 _dbus_assert (rule->args != NULL);
2312 _dbus_assert (rule->args_len == 8);
2313 _dbus_assert (rule->args[7] != NULL);
2314 _dbus_assert (rule->args[8] == NULL);
2315 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2316 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2317 == BUS_MATCH_ARG_IS_PATH);
2319 bus_match_rule_unref (rule);
2322 /* Arg 0 namespace matches */
2323 rule = check_parse (TRUE, "arg0namespace='foo'");
2326 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2327 _dbus_assert (rule->args != NULL);
2328 _dbus_assert (rule->args_len == 1);
2329 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2330 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2331 == BUS_MATCH_ARG_NAMESPACE);
2333 bus_match_rule_unref (rule);
2336 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2339 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2340 _dbus_assert (rule->args != NULL);
2341 _dbus_assert (rule->args_len == 1);
2342 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2343 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2344 == BUS_MATCH_ARG_NAMESPACE);
2346 bus_match_rule_unref (rule);
2349 /* Only arg0namespace is supported. */
2350 rule = check_parse (FALSE, "arg1namespace='foo'");
2351 _dbus_assert (rule == NULL);
2353 /* An empty string isn't a valid namespace prefix (you should just not
2354 * specify this key at all).
2356 rule = check_parse (FALSE, "arg0namespace=''");
2357 _dbus_assert (rule == NULL);
2359 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2360 * spec allowed a single trailing period, which altered the semantics) */
2361 rule = check_parse (FALSE, "arg0namespace='foo.'");
2362 _dbus_assert (rule == NULL);
2364 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2365 _dbus_assert (rule == NULL);
2367 rule = check_parse (FALSE, "arg0namespace='foo..'");
2368 _dbus_assert (rule == NULL);
2370 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2371 _dbus_assert (rule == NULL);
2373 /* Too-large argN */
2374 rule = check_parse (FALSE, "arg300='foo'");
2375 _dbus_assert (rule == NULL);
2376 rule = check_parse (FALSE, "arg64='foo'");
2377 _dbus_assert (rule == NULL);
2380 rule = check_parse (FALSE, "arg='foo'");
2381 _dbus_assert (rule == NULL);
2382 rule = check_parse (FALSE, "argv='foo'");
2383 _dbus_assert (rule == NULL);
2384 rule = check_parse (FALSE, "arg3junk='foo'");
2385 _dbus_assert (rule == NULL);
2386 rule = check_parse (FALSE, "argument='foo'");
2387 _dbus_assert (rule == NULL);
2389 /* Reject duplicates */
2390 rule = check_parse (FALSE, "type='signal',type='method_call'");
2391 _dbus_assert (rule == NULL);
2393 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2396 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2397 _dbus_assert (rule->path != NULL);
2398 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2400 bus_match_rule_unref (rule);
2403 /* Almost a duplicate */
2404 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2405 _dbus_assert (rule == NULL);
2407 /* Trailing / was supported in the initial proposal, but now isn't */
2408 rule = check_parse (FALSE, "path_namespace='/foo/'");
2409 _dbus_assert (rule == NULL);
2411 /* Duplicates with the argN code */
2412 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2413 _dbus_assert (rule == NULL);
2414 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2415 _dbus_assert (rule == NULL);
2416 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2417 _dbus_assert (rule == NULL);
2419 /* Reject broken keys */
2420 rule = check_parse (FALSE, "blah='signal'");
2421 _dbus_assert (rule == NULL);
2423 /* Reject broken values */
2424 rule = check_parse (FALSE, "type='chouin'");
2425 _dbus_assert (rule == NULL);
2426 rule = check_parse (FALSE, "interface='abc@def++'");
2427 _dbus_assert (rule == NULL);
2428 rule = check_parse (FALSE, "service='youpi'");
2429 _dbus_assert (rule == NULL);
2431 /* Allow empty rule */
2432 rule = check_parse (TRUE, "");
2435 _dbus_assert (rule->flags == 0);
2437 bus_match_rule_unref (rule);
2440 /* All-whitespace rule is the same as empty */
2441 rule = check_parse (TRUE, " \t");
2444 _dbus_assert (rule->flags == 0);
2446 bus_match_rule_unref (rule);
2449 /* But with non-whitespace chars and no =value, it's not OK */
2450 rule = check_parse (FALSE, "type");
2451 _dbus_assert (rule == NULL);
2459 } equality_tests[] = {
2460 { "type='signal'", "type='signal'" },
2461 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2462 { "type='signal',member='bar'", "member='bar',type='signal'" },
2463 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2464 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2465 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2466 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2467 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2468 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2469 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2470 { "arg3='fool'", "arg3='fool'" },
2471 { "arg0namespace='fool'", "arg0namespace='fool'" },
2472 { "member='food'", "member='food'" }
2476 test_equality (void)
2481 while (i < _DBUS_N_ELEMENTS (equality_tests))
2483 BusMatchRule *first;
2484 BusMatchRule *second;
2487 first = check_parse (TRUE, equality_tests[i].first);
2488 _dbus_assert (first != NULL);
2489 second = check_parse (TRUE, equality_tests[i].second);
2490 _dbus_assert (second != NULL);
2492 if (!match_rule_equal (first, second))
2494 _dbus_warn ("rule %s and %s should have been equal\n",
2495 equality_tests[i].first,
2496 equality_tests[i].second);
2500 bus_match_rule_unref (second);
2502 /* Check that the rule is not equal to any of the
2503 * others besides its pair match
2506 while (j < _DBUS_N_ELEMENTS (equality_tests))
2510 second = check_parse (TRUE, equality_tests[j].second);
2512 if (match_rule_equal (first, second))
2514 _dbus_warn ("rule %s and %s should not have been equal\n",
2515 equality_tests[i].first,
2516 equality_tests[j].second);
2520 bus_match_rule_unref (second);
2526 bus_match_rule_unref (first);
2533 should_match_message_1[] = {
2535 "member='Frobated'",
2537 "type='signal',member='Frobated'",
2538 "type='signal',member='Frobated',arg0='foobar'",
2539 "member='Frobated',arg0='foobar'",
2540 "type='signal',arg0='foobar'",
2541 /* The definition of argXpath matches says: "As with normal argument matches,
2542 * if the argument is exactly equal to the string given in the match rule
2543 * then the rule is satisfied." So this should match (even though the
2544 * argument is not a valid path)!
2546 "arg0path='foobar'",
2547 "arg0namespace='foobar'",
2552 should_not_match_message_1[] = {
2553 "type='method_call'",
2555 "type='method_return'",
2556 "type='signal',member='Oopsed'",
2563 "arg0='foobar',arg1='abcdef'",
2564 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2565 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2567 "arg0path='foobar/'",
2569 "arg0namespace='foo'",
2570 "arg0namespace='foo',arg1='abcdef'",
2571 "arg0namespace='moo'",
2575 #define EXAMPLE_NAME "com.example.backend.foo"
2578 should_match_message_2[] = {
2579 /* EXAMPLE_NAME is in all of these namespaces */
2580 "arg0namespace='com.example.backend'",
2581 "arg0namespace='com.example'",
2582 "arg0namespace='com'",
2584 /* If the client specifies the name exactly, with no trailing period, then
2587 "arg0namespace='com.example.backend.foo'",
2593 should_not_match_message_2[] = {
2594 /* These are not even prefixes */
2595 "arg0namespace='com.example.backend.foo.bar'",
2596 "arg0namespace='com.example.backend.foobar'",
2598 /* These are prefixes, but they're not parent namespaces. */
2599 "arg0namespace='com.example.backend.fo'",
2600 "arg0namespace='com.example.backen'",
2601 "arg0namespace='com.exampl'",
2602 "arg0namespace='co'",
2608 check_matches (dbus_bool_t expected_to_match,
2610 DBusMessage *message,
2611 const char *rule_text)
2614 dbus_bool_t matched;
2616 rule = check_parse (TRUE, rule_text);
2617 _dbus_assert (rule != NULL);
2619 /* We can't test sender/destination rules since we pass NULL here */
2620 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2622 if (matched != expected_to_match)
2624 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2625 rule_text, expected_to_match ?
2626 "match" : "not match", number);
2630 bus_match_rule_unref (rule);
2634 check_matching (DBusMessage *message,
2636 const char **should_match,
2637 const char **should_not_match)
2642 while (should_match[i] != NULL)
2644 check_matches (TRUE, number, message, should_match[i]);
2649 while (should_not_match[i] != NULL)
2651 check_matches (FALSE, number, message, should_not_match[i]);
2657 test_matching (void)
2659 DBusMessage *message1, *message2;
2660 const char *v_STRING;
2661 dbus_int32_t v_INT32;
2663 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2664 _dbus_assert (message1 != NULL);
2665 if (!dbus_message_set_member (message1, "Frobated"))
2666 _dbus_assert_not_reached ("oom");
2668 v_STRING = "foobar";
2670 if (!dbus_message_append_args (message1,
2671 DBUS_TYPE_STRING, &v_STRING,
2672 DBUS_TYPE_INT32, &v_INT32,
2674 _dbus_assert_not_reached ("oom");
2676 check_matching (message1, 1,
2677 should_match_message_1,
2678 should_not_match_message_1);
2680 dbus_message_unref (message1);
2682 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2683 _dbus_assert (message2 != NULL);
2684 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2685 _dbus_assert_not_reached ("oom");
2687 /* Obviously this isn't really a NameOwnerChanged signal. */
2688 v_STRING = EXAMPLE_NAME;
2689 if (!dbus_message_append_args (message2,
2690 DBUS_TYPE_STRING, &v_STRING,
2692 _dbus_assert_not_reached ("oom");
2694 check_matching (message2, 2,
2695 should_match_message_2,
2696 should_not_match_message_2);
2698 dbus_message_unref (message2);
2701 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2703 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2704 * from the specification. Notice that not all of them are actually legal D-Bus
2707 * The author of this test takes no responsibility for the semantics of
2708 * this match rule key.
2710 static const char *paths_that_should_be_matched[] = {
2714 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2720 /* These paths should not be matched by PATH_MATCH_RULE. */
2721 static const char *paths_that_should_not_be_matched[] = {
2730 test_path_match (int type,
2732 const char *rule_text,
2734 dbus_bool_t should_match)
2736 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2737 dbus_bool_t matched;
2739 _dbus_assert (message != NULL);
2740 if (!dbus_message_set_member (message, "Foo"))
2741 _dbus_assert_not_reached ("oom");
2743 if (!dbus_message_append_args (message,
2746 _dbus_assert_not_reached ("oom");
2748 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2750 if (matched != should_match)
2752 _dbus_warn ("Expected rule %s to %s message "
2753 "with first arg %s of type '%c', failed\n",
2755 should_match ? "match" : "not match",
2761 dbus_message_unref (message);
2765 test_path_matching (void)
2770 rule = check_parse (TRUE, PATH_MATCH_RULE);
2771 _dbus_assert (rule != NULL);
2773 for (s = paths_that_should_be_matched; *s != NULL; s++)
2774 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2776 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2778 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2780 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2782 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2783 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2786 bus_match_rule_unref (rule);
2790 path_namespace_should_match_message_1[] = {
2791 "type='signal',path_namespace='/'",
2792 "type='signal',path_namespace='/foo'",
2793 "type='signal',path_namespace='/foo/TheObjectManager'",
2798 path_namespace_should_not_match_message_1[] = {
2799 "type='signal',path_namespace='/bar'",
2800 "type='signal',path_namespace='/bar/TheObjectManager'",
2805 path_namespace_should_match_message_2[] = {
2806 "type='signal',path_namespace='/'",
2807 "type='signal',path_namespace='/foo/TheObjectManager'",
2812 path_namespace_should_not_match_message_2[] = {
2817 path_namespace_should_match_message_3[] = {
2818 "type='signal',path_namespace='/'",
2823 path_namespace_should_not_match_message_3[] = {
2824 "type='signal',path_namespace='/foo/TheObjectManager'",
2829 path_namespace_should_match_message_4[] = {
2830 "type='signal',path_namespace='/'",
2835 path_namespace_should_not_match_message_4[] = {
2836 "type='signal',path_namespace='/foo/TheObjectManager'",
2841 test_matching_path_namespace (void)
2843 DBusMessage *message1;
2844 DBusMessage *message2;
2845 DBusMessage *message3;
2846 DBusMessage *message4;
2848 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2849 _dbus_assert (message1 != NULL);
2850 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2851 _dbus_assert_not_reached ("oom");
2853 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2854 _dbus_assert (message2 != NULL);
2855 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2856 _dbus_assert_not_reached ("oom");
2858 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2859 _dbus_assert (message3 != NULL);
2860 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2861 _dbus_assert_not_reached ("oom");
2863 message4 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2864 _dbus_assert (message4 != NULL);
2865 if (!dbus_message_set_path (message4, "/"))
2866 _dbus_assert_not_reached ("oom");
2868 check_matching (message1, 1,
2869 path_namespace_should_match_message_1,
2870 path_namespace_should_not_match_message_1);
2871 check_matching (message2, 2,
2872 path_namespace_should_match_message_2,
2873 path_namespace_should_not_match_message_2);
2874 check_matching (message3, 3,
2875 path_namespace_should_match_message_3,
2876 path_namespace_should_not_match_message_3);
2877 check_matching (message4, 4,
2878 path_namespace_should_match_message_4,
2879 path_namespace_should_not_match_message_4);
2881 dbus_message_unref (message4);
2882 dbus_message_unref (message3);
2883 dbus_message_unref (message2);
2884 dbus_message_unref (message1);
2888 bus_signals_test (const DBusString *test_data_dir)
2890 BusMatchmaker *matchmaker;
2892 matchmaker = bus_matchmaker_new ();
2893 bus_matchmaker_ref (matchmaker);
2894 bus_matchmaker_unref (matchmaker);
2895 bus_matchmaker_unref (matchmaker);
2897 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2898 _dbus_assert_not_reached ("Parsing match rules test failed");
2902 test_path_matching ();
2903 test_matching_path_namespace ();
2908 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */