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
29 #include <dbus/dbus-marshal-validate.h>
33 int refcount; /**< reference count */
35 DBusConnection *matches_go_to; /**< Owner of the rule */
37 unsigned int flags; /**< BusMatchFlags */
46 unsigned int *arg_lens;
51 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u
52 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
54 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
57 bus_match_rule_new (DBusConnection *matches_go_to)
61 rule = dbus_new0 (BusMatchRule, 1);
66 rule->matches_go_to = matches_go_to;
68 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
69 _dbus_assert (rule->matches_go_to != NULL);
76 bus_match_rule_ref (BusMatchRule *rule)
78 _dbus_assert (rule->refcount > 0);
86 bus_match_rule_unref (BusMatchRule *rule)
88 _dbus_assert (rule->refcount > 0);
91 if (rule->refcount == 0)
93 dbus_free (rule->interface);
94 dbus_free (rule->member);
95 dbus_free (rule->sender);
96 dbus_free (rule->destination);
97 dbus_free (rule->path);
98 dbus_free (rule->arg_lens);
100 /* can't use dbus_free_string_array() since there
108 while (i < rule->args_len)
111 dbus_free (rule->args[i]);
115 dbus_free (rule->args);
122 #if defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS)
124 append_key_and_escaped_value (DBusString *str, const char *token, const char *value)
126 const char *p = value;
128 if (!_dbus_string_append_printf (str, "%s='", token))
133 const char *next = index (p, '\'');
137 if (!_dbus_string_append_printf (str, "%.*s", (int) (next - p), p))
139 /* Horrible escape sequence: single quote cannot be escaped inside
140 * a single quoted string. So we close the single quote, escape the
141 * single quote, and reopen a single quote.
143 if (!_dbus_string_append_printf (str, "'\\''"))
149 if (!_dbus_string_append_printf (str, "%s", p))
155 if (!_dbus_string_append_byte (str, '\''))
161 /* returns NULL if no memory */
163 match_rule_to_string (BusMatchRule *rule)
168 if (!_dbus_string_init (&str))
173 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
175 if (!append_key_and_escaped_value (&str, "type",
176 dbus_message_type_to_string (rule->message_type)))
180 if (rule->flags & BUS_MATCH_INTERFACE)
182 if (_dbus_string_get_length (&str) > 0)
184 if (!_dbus_string_append (&str, ","))
188 if (!append_key_and_escaped_value (&str, "interface", rule->interface))
192 if (rule->flags & BUS_MATCH_MEMBER)
194 if (_dbus_string_get_length (&str) > 0)
196 if (!_dbus_string_append (&str, ","))
200 if (!append_key_and_escaped_value (&str, "member", rule->member))
204 if (rule->flags & BUS_MATCH_PATH)
206 if (_dbus_string_get_length (&str) > 0)
208 if (!_dbus_string_append (&str, ","))
212 if (!append_key_and_escaped_value (&str, "path", rule->path))
216 if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
218 if (_dbus_string_get_length (&str) > 0)
220 if (!_dbus_string_append (&str, ","))
224 if (!append_key_and_escaped_value (&str, "path_namespace", rule->path))
228 if (rule->flags & BUS_MATCH_SENDER)
230 if (_dbus_string_get_length (&str) > 0)
232 if (!_dbus_string_append (&str, ","))
236 if (!append_key_and_escaped_value (&str, "sender", rule->sender))
240 if (rule->flags & BUS_MATCH_DESTINATION)
242 if (_dbus_string_get_length (&str) > 0)
244 if (!_dbus_string_append (&str, ","))
248 if (!append_key_and_escaped_value (&str, "destination", rule->destination))
252 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
254 if (_dbus_string_get_length (&str) > 0)
256 if (!_dbus_string_append (&str, ","))
260 if (!append_key_and_escaped_value (&str, "eavesdrop",
261 (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
266 if (rule->flags & BUS_MATCH_ARGS)
270 _dbus_assert (rule->args != NULL);
273 while (i < rule->args_len)
275 if (rule->args[i] != NULL)
277 dbus_bool_t is_path, is_namespace;
279 if (_dbus_string_get_length (&str) > 0)
281 if (!_dbus_string_append (&str, ","))
285 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
286 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
288 if (!_dbus_string_append_printf (&str,
292 is_namespace ? "namespace" : ""))
294 if (!append_key_and_escaped_value (&str, "", rule->args[i]))
302 if (!_dbus_string_steal_data (&str, &ret))
305 _dbus_string_free (&str);
309 _dbus_string_free (&str);
312 #endif /* defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS) */
315 bus_match_rule_set_message_type (BusMatchRule *rule,
318 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
320 rule->message_type = type;
326 bus_match_rule_set_interface (BusMatchRule *rule,
327 const char *interface)
331 _dbus_assert (interface != NULL);
333 new = _dbus_strdup (interface);
337 rule->flags |= BUS_MATCH_INTERFACE;
338 dbus_free (rule->interface);
339 rule->interface = new;
345 bus_match_rule_set_member (BusMatchRule *rule,
350 _dbus_assert (member != NULL);
352 new = _dbus_strdup (member);
356 rule->flags |= BUS_MATCH_MEMBER;
357 dbus_free (rule->member);
364 bus_match_rule_set_sender (BusMatchRule *rule,
369 _dbus_assert (sender != NULL);
371 new = _dbus_strdup (sender);
375 rule->flags |= BUS_MATCH_SENDER;
376 dbus_free (rule->sender);
383 bus_match_rule_set_destination (BusMatchRule *rule,
384 const char *destination)
388 _dbus_assert (destination != NULL);
390 new = _dbus_strdup (destination);
394 rule->flags |= BUS_MATCH_DESTINATION;
395 dbus_free (rule->destination);
396 rule->destination = new;
402 bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
403 dbus_bool_t is_eavesdropping)
405 if (is_eavesdropping)
406 rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
408 rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
412 bus_match_rule_set_path (BusMatchRule *rule,
414 dbus_bool_t is_namespace)
418 _dbus_assert (path != NULL);
420 new = _dbus_strdup (path);
424 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
427 rule->flags |= BUS_MATCH_PATH_NAMESPACE;
429 rule->flags |= BUS_MATCH_PATH;
431 dbus_free (rule->path);
438 bus_match_rule_set_arg (BusMatchRule *rule,
440 const DBusString *value,
442 dbus_bool_t is_namespace)
447 _dbus_assert (value != NULL);
449 /* args_len is the number of args not including null termination
452 if (arg >= rule->args_len)
454 unsigned int *new_arg_lens;
459 new_args_len = arg + 1;
461 /* add another + 1 here for null termination */
462 new_args = dbus_realloc (rule->args,
463 sizeof (char *) * (new_args_len + 1));
464 if (new_args == NULL)
467 /* NULL the new slots */
469 while (i <= new_args_len) /* <= for null termination */
475 rule->args = new_args;
477 /* and now add to the lengths */
478 new_arg_lens = dbus_realloc (rule->arg_lens,
479 sizeof (int) * (new_args_len + 1));
481 if (new_arg_lens == NULL)
484 /* zero the new slots */
486 while (i <= new_args_len) /* <= for null termination */
492 rule->arg_lens = new_arg_lens;
493 rule->args_len = new_args_len;
496 length = _dbus_string_get_length (value);
497 if (!_dbus_string_copy_data (value, &new))
500 rule->flags |= BUS_MATCH_ARGS;
502 dbus_free (rule->args[arg]);
503 rule->arg_lens[arg] = length;
504 rule->args[arg] = new;
507 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
510 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
512 /* NULL termination didn't get busted */
513 _dbus_assert (rule->args[rule->args_len] == NULL);
514 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
519 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
522 find_key (const DBusString *str,
530 const char *key_start;
533 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
535 s = _dbus_string_get_const_data (str);
539 while (*p && ISWHITE (*p))
544 while (*p && *p != '=' && !ISWHITE (*p))
549 while (*p && ISWHITE (*p))
552 if (key_start == key_end)
554 /* Empty match rules or trailing whitespace are OK */
561 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
562 "Match rule has a key with no subsequent '=' character");
567 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
579 find_value (const DBusString *str,
591 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
593 orig_len = _dbus_string_get_length (value);
595 s = _dbus_string_get_const_data (str);
603 if (quote_char == '\0')
623 if (!_dbus_string_append_byte (value, *p))
630 else if (quote_char == '\\')
632 /* \ only counts as an escape if escaping a quote mark */
635 if (!_dbus_string_append_byte (value, '\\'))
642 if (!_dbus_string_append_byte (value, *p))
652 _dbus_assert (quote_char == '\'');
660 if (!_dbus_string_append_byte (value, *p))
674 if (quote_char == '\\')
676 if (!_dbus_string_append_byte (value, '\\'))
682 else if (quote_char == '\'')
684 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
685 "Unbalanced quotation marks in match rule");
689 _dbus_assert (quote_char == '\0');
691 /* Zero-length values are allowed */
698 _DBUS_ASSERT_ERROR_IS_SET (error);
699 _dbus_string_set_length (value, orig_len);
703 /* duplicates aren't allowed so the real legitimate max is only 6 or
704 * so. Leaving extra so we don't have to bother to update it.
705 * FIXME this is sort of busted now with arg matching, but we let
706 * you match on up to 10 args for now
708 #define MAX_RULE_TOKENS 16
710 /* this is slightly too high level to be termed a "token"
711 * but let's not be pedantic.
720 tokenize_rule (const DBusString *rule_text,
721 RuleToken tokens[MAX_RULE_TOKENS],
732 if (!_dbus_string_init (&key))
738 if (!_dbus_string_init (&value))
740 _dbus_string_free (&key);
747 while (i < MAX_RULE_TOKENS &&
748 pos < _dbus_string_get_length (rule_text))
750 _dbus_assert (tokens[i].key == NULL);
751 _dbus_assert (tokens[i].value == NULL);
753 if (!find_key (rule_text, pos, &key, &pos, error))
756 if (_dbus_string_get_length (&key) == 0)
759 if (!_dbus_string_steal_data (&key, &tokens[i].key))
765 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
768 if (!_dbus_string_steal_data (&value, &tokens[i].value))
784 while (tokens[i].key || tokens[i].value)
786 dbus_free (tokens[i].key);
787 dbus_free (tokens[i].value);
788 tokens[i].key = NULL;
789 tokens[i].value = NULL;
794 _dbus_string_free (&key);
795 _dbus_string_free (&value);
801 bus_match_rule_parse_arg_match (BusMatchRule *rule,
803 const DBusString *value,
806 dbus_bool_t is_path = FALSE;
807 dbus_bool_t is_namespace = FALSE;
813 /* For now, arg0='foo' always implies that 'foo' is a
814 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
815 * if we wanted, which would specify another type, in which case
816 * arg0='5' would have the 5 parsed as an int rather than string.
819 /* First we need to parse arg0 = 0, arg27 = 27 */
821 _dbus_string_init_const (&key_str, key);
822 length = _dbus_string_get_length (&key_str);
824 if (_dbus_string_get_length (&key_str) < 4)
826 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
827 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
831 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
833 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
834 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
840 if ((end + strlen ("path")) == length &&
841 _dbus_string_ends_with_c_str (&key_str, "path"))
845 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
847 int value_len = _dbus_string_get_length (value);
851 if (!_dbus_validate_bus_namespace (value, 0, value_len))
853 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
854 "arg0namespace='%s' is not a valid prefix of a bus name",
855 _dbus_string_get_const_data (value));
861 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
862 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
867 /* If we didn't check this we could allocate a huge amount of RAM */
868 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
870 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
871 "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);
875 if ((rule->flags & BUS_MATCH_ARGS) &&
876 rule->args_len > (int) arg &&
877 rule->args[arg] != NULL)
879 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
880 "Argument %d matched more than once in match rule\n", key);
884 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
893 _DBUS_ASSERT_ERROR_IS_SET (error);
898 * The format is comma-separated with strings quoted with single quotes
899 * as for the shell (to escape a literal single quote, use '\'').
901 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
902 * path='/bar/foo',destination=':452345.34'
906 bus_match_rule_parse (DBusConnection *matches_go_to,
907 const DBusString *rule_text,
911 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
914 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
916 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
918 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
919 "Match rule text is %d bytes, maximum is %d",
920 _dbus_string_get_length (rule_text),
921 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
925 memset (tokens, '\0', sizeof (tokens));
927 rule = bus_match_rule_new (matches_go_to);
934 if (!tokenize_rule (rule_text, tokens, error))
938 while (tokens[i].key != NULL)
942 const char *key = tokens[i].key;
943 const char *value = tokens[i].value;
945 _dbus_string_init_const (&tmp_str, value);
946 len = _dbus_string_get_length (&tmp_str);
948 if (strcmp (key, "type") == 0)
952 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
954 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
955 "Key %s specified twice in match rule\n", key);
959 t = dbus_message_type_from_string (value);
961 if (t == DBUS_MESSAGE_TYPE_INVALID)
963 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
964 "Invalid message type (%s) in match rule\n", value);
968 if (!bus_match_rule_set_message_type (rule, t))
974 else if (strcmp (key, "sender") == 0)
976 if (rule->flags & BUS_MATCH_SENDER)
978 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
979 "Key %s specified twice in match rule\n", key);
983 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
985 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
986 "Sender name '%s' is invalid\n", value);
990 if (!bus_match_rule_set_sender (rule, value))
996 else if (strcmp (key, "interface") == 0)
998 if (rule->flags & BUS_MATCH_INTERFACE)
1000 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1001 "Key %s specified twice in match rule\n", key);
1005 if (!_dbus_validate_interface (&tmp_str, 0, len))
1007 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1008 "Interface name '%s' is invalid\n", value);
1012 if (!bus_match_rule_set_interface (rule, value))
1014 BUS_SET_OOM (error);
1018 else if (strcmp (key, "member") == 0)
1020 if (rule->flags & BUS_MATCH_MEMBER)
1022 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1023 "Key %s specified twice in match rule\n", key);
1027 if (!_dbus_validate_member (&tmp_str, 0, len))
1029 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1030 "Member name '%s' is invalid\n", value);
1034 if (!bus_match_rule_set_member (rule, value))
1036 BUS_SET_OOM (error);
1040 else if (strcmp (key, "path") == 0 ||
1041 strcmp (key, "path_namespace") == 0)
1043 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1045 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
1047 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1048 "path or path_namespace specified twice in match rule\n");
1052 if (!_dbus_validate_path (&tmp_str, 0, len))
1054 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1055 "Path '%s' is invalid\n", value);
1059 if (!bus_match_rule_set_path (rule, value, is_namespace))
1061 BUS_SET_OOM (error);
1065 else if (strcmp (key, "destination") == 0)
1067 if (rule->flags & BUS_MATCH_DESTINATION)
1069 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1070 "Key %s specified twice in match rule\n", key);
1074 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1076 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1077 "Destination name '%s' is invalid\n", value);
1081 if (!bus_match_rule_set_destination (rule, value))
1083 BUS_SET_OOM (error);
1087 else if (strcmp (key, "eavesdrop") == 0)
1089 /* do not detect "eavesdrop" being used more than once in rule:
1090 * 1) it's not possible, it's only in the flags
1091 * 2) it might be used twice to disable eavesdropping when it's
1092 * automatically added (eg dbus-monitor/bustle) */
1094 /* we accept only "true|false" as possible values */
1095 if ((strcmp (value, "true") == 0))
1097 bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1099 else if (strcmp (value, "false") == 0)
1101 bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1105 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1106 "eavesdrop='%s' is invalid, "
1107 "it should be 'true' or 'false'\n",
1112 else if (strncmp (key, "arg", 3) == 0)
1114 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1119 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1120 "Unknown key \"%s\" in match rule",
1132 _DBUS_ASSERT_ERROR_IS_SET (error);
1135 bus_match_rule_unref (rule);
1142 while (tokens[i].key || tokens[i].value)
1144 _dbus_assert (i < MAX_RULE_TOKENS);
1145 dbus_free (tokens[i].key);
1146 dbus_free (tokens[i].value);
1153 typedef struct RulePool RulePool;
1156 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1157 DBusHashTable *rules_by_iface;
1159 /* List of BusMatchRules which don't specify an interface */
1160 DBusList *rules_without_iface;
1163 struct BusMatchmaker
1167 /* Pools of rules, grouped by the type of message they match. 0
1168 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1171 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1174 #ifdef DBUS_ENABLE_STATS
1176 bus_match_rule_dump (BusMatchmaker *matchmaker,
1177 DBusConnection *conn_filter,
1178 DBusMessageIter *arr_iter)
1182 for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++)
1188 _dbus_hash_iter_init (matchmaker->rules_by_type[i].rules_by_iface, &iter);
1189 while (_dbus_hash_iter_next (&iter))
1191 list = _dbus_hash_iter_get_value (&iter);
1192 for (link = _dbus_list_get_first_link (list);
1194 link = _dbus_list_get_next_link (list, link))
1196 BusMatchRule *rule = link->data;
1198 if (rule->matches_go_to == conn_filter)
1200 char *s = match_rule_to_string (rule);
1205 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1214 list = &matchmaker->rules_by_type[i].rules_without_iface;
1215 for (link = _dbus_list_get_first_link (list);
1217 link = _dbus_list_get_next_link (list, link))
1219 BusMatchRule *rule = link->data;
1221 if (rule->matches_go_to == conn_filter)
1223 char *s = match_rule_to_string (rule);
1228 if (!dbus_message_iter_append_basic (arr_iter, DBUS_TYPE_STRING, &s))
1243 rule_list_free (DBusList **rules)
1245 while (*rules != NULL)
1249 rule = (*rules)->data;
1250 bus_match_rule_unref (rule);
1251 _dbus_list_remove_link (rules, *rules);
1256 rule_list_ptr_free (DBusList **list)
1258 /* We have to cope with NULL because the hash table frees the "existing"
1259 * value (which is NULL) when creating a new table entry...
1263 rule_list_free (list);
1269 bus_matchmaker_new (void)
1271 BusMatchmaker *matchmaker;
1274 matchmaker = dbus_new0 (BusMatchmaker, 1);
1275 if (matchmaker == NULL)
1278 matchmaker->refcount = 1;
1280 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1282 RulePool *p = matchmaker->rules_by_type + i;
1284 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1285 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1287 if (p->rules_by_iface == NULL)
1294 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1296 RulePool *p = matchmaker->rules_by_type + i;
1298 if (p->rules_by_iface == NULL)
1301 _dbus_hash_table_unref (p->rules_by_iface);
1303 dbus_free (matchmaker);
1309 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1311 const char *interface,
1316 _dbus_assert (message_type >= 0);
1317 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1319 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1321 interface != NULL ? interface : "<null>");
1323 p = matchmaker->rules_by_type + message_type;
1325 if (interface == NULL)
1327 return &p->rules_without_iface;
1333 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1335 if (list == NULL && create)
1337 char *dupped_interface;
1339 list = dbus_new0 (DBusList *, 1);
1343 dupped_interface = _dbus_strdup (interface);
1344 if (dupped_interface == NULL)
1350 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1353 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1354 dupped_interface, list))
1357 dbus_free (dupped_interface);
1367 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1369 const char *interface,
1374 if (interface == NULL)
1380 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1381 message_type, interface);
1383 p = matchmaker->rules_by_type + message_type;
1385 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1388 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1392 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1394 _dbus_assert (matchmaker->refcount > 0);
1396 matchmaker->refcount += 1;
1402 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1404 _dbus_assert (matchmaker->refcount > 0);
1406 matchmaker->refcount -= 1;
1407 if (matchmaker->refcount == 0)
1411 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1413 RulePool *p = matchmaker->rules_by_type + i;
1415 _dbus_hash_table_unref (p->rules_by_iface);
1416 rule_list_free (&p->rules_without_iface);
1419 dbus_free (matchmaker);
1423 /* The rule can't be modified after it's added. */
1425 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1430 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1432 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1434 rule->interface != NULL ? rule->interface : "<null>");
1436 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1437 rule->interface, TRUE);
1442 if (!_dbus_list_append (rules, rule))
1445 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1447 _dbus_list_remove_last (rules, rule);
1448 bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1449 rule->interface, rules);
1453 bus_match_rule_ref (rule);
1455 #ifdef DBUS_ENABLE_VERBOSE_MODE
1457 char *s = match_rule_to_string (rule);
1459 _dbus_verbose ("Added match rule %s to connection %p\n",
1460 s ? s : "nomem", rule->matches_go_to);
1469 match_rule_equal (BusMatchRule *a,
1472 if (a->flags != b->flags)
1475 if (a->matches_go_to != b->matches_go_to)
1478 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1479 a->message_type != b->message_type)
1482 if ((a->flags & BUS_MATCH_MEMBER) &&
1483 strcmp (a->member, b->member) != 0)
1486 if ((a->flags & BUS_MATCH_PATH) &&
1487 strcmp (a->path, b->path) != 0)
1490 if ((a->flags & BUS_MATCH_INTERFACE) &&
1491 strcmp (a->interface, b->interface) != 0)
1494 if ((a->flags & BUS_MATCH_SENDER) &&
1495 strcmp (a->sender, b->sender) != 0)
1498 if ((a->flags & BUS_MATCH_DESTINATION) &&
1499 strcmp (a->destination, b->destination) != 0)
1502 /* we already compared the value of flags, and
1503 * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1505 if (a->flags & BUS_MATCH_ARGS)
1509 if (a->args_len != b->args_len)
1513 while (i < a->args_len)
1517 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1520 if (a->arg_lens[i] != b->arg_lens[i])
1523 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1525 if (a->args[i] != NULL)
1527 _dbus_assert (b->args[i] != NULL);
1528 if (memcmp (a->args[i], b->args[i], length) != 0)
1540 bus_matchmaker_remove_rule_link (DBusList **rules,
1543 BusMatchRule *rule = link->data;
1545 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1546 _dbus_list_remove_link (rules, link);
1548 #ifdef DBUS_ENABLE_VERBOSE_MODE
1550 char *s = match_rule_to_string (rule);
1552 _dbus_verbose ("Removed match rule %s for connection %p\n",
1553 s ? s : "nomem", rule->matches_go_to);
1558 bus_match_rule_unref (rule);
1562 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1567 _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1569 rule->interface != NULL ? rule->interface : "<null>");
1571 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1573 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1574 rule->interface, FALSE);
1576 /* We should only be asked to remove a rule by identity right after it was
1577 * added, so there should be a list for it.
1579 _dbus_assert (rules != NULL);
1581 _dbus_list_remove (rules, rule);
1582 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1585 #ifdef DBUS_ENABLE_VERBOSE_MODE
1587 char *s = match_rule_to_string (rule);
1589 _dbus_verbose ("Removed match rule %s for connection %p\n",
1590 s ? s : "nomem", rule->matches_go_to);
1595 bus_match_rule_unref (rule);
1598 /* Remove a single rule which is equal to the given rule by value */
1600 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1601 BusMatchRule *value,
1605 DBusList *link = NULL;
1607 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1608 value->message_type,
1609 value->interface != NULL ? value->interface : "<null>");
1611 rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1612 value->interface, FALSE);
1616 /* we traverse backward because bus_connection_remove_match_rule()
1617 * removes the most-recently-added rule
1619 link = _dbus_list_get_last_link (rules);
1620 while (link != NULL)
1626 prev = _dbus_list_get_prev_link (rules, link);
1628 if (match_rule_equal (rule, value))
1630 bus_matchmaker_remove_rule_link (rules, link);
1640 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1641 "The given match rule wasn't found and can't be removed");
1645 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1652 rule_list_remove_by_connection (DBusList **rules,
1653 DBusConnection *connection)
1657 link = _dbus_list_get_first_link (rules);
1658 while (link != NULL)
1664 next = _dbus_list_get_next_link (rules, link);
1666 if (rule->matches_go_to == connection)
1668 bus_matchmaker_remove_rule_link (rules, link);
1670 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1671 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1673 /* The rule matches to/from a base service, see if it's the
1674 * one being disconnected, since we know this service name
1675 * will never be recycled.
1679 name = bus_connection_get_name (connection);
1680 _dbus_assert (name != NULL); /* because we're an active connection */
1682 if (((rule->flags & BUS_MATCH_SENDER) &&
1683 strcmp (rule->sender, name) == 0) ||
1684 ((rule->flags & BUS_MATCH_DESTINATION) &&
1685 strcmp (rule->destination, name) == 0))
1687 bus_matchmaker_remove_rule_link (rules, link);
1696 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1697 DBusConnection *connection)
1703 * This scans all match rules on the bus. We could avoid that
1704 * for the rules belonging to the connection, since we keep
1705 * a list of those; but for the rules that just refer to
1706 * the connection we'd need to do something more elaborate.
1709 _dbus_assert (bus_connection_is_active (connection));
1711 _dbus_verbose ("Removing all rules for connection %p\n", connection);
1713 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1715 RulePool *p = matchmaker->rules_by_type + i;
1718 rule_list_remove_by_connection (&p->rules_without_iface, connection);
1720 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1721 while (_dbus_hash_iter_next (&iter))
1723 DBusList **items = _dbus_hash_iter_get_value (&iter);
1725 rule_list_remove_by_connection (items, connection);
1728 _dbus_hash_iter_remove_entry (&iter);
1734 connection_is_primary_owner (DBusConnection *connection,
1735 const char *service_name)
1737 BusService *service;
1739 BusRegistry *registry;
1741 _dbus_assert (connection != NULL);
1743 registry = bus_connection_get_registry (connection);
1745 _dbus_string_init_const (&str, service_name);
1746 service = bus_registry_lookup (registry, &str);
1748 if (service == NULL)
1749 return FALSE; /* Service doesn't exist so connection can't own it. */
1751 return bus_service_get_primary_owners_connection (service) == connection;
1755 str_has_prefix (const char *str, const char *prefix)
1758 prefix_len = strlen (prefix);
1759 if (strncmp (str, prefix, prefix_len) == 0)
1766 match_rule_matches (BusMatchRule *rule,
1767 DBusConnection *sender,
1768 DBusConnection *addressed_recipient,
1769 DBusMessage *message,
1770 BusMatchFlags already_matched)
1772 dbus_bool_t wants_to_eavesdrop = FALSE;
1775 /* All features of the match rule are AND'd together,
1776 * so FALSE if any of them don't match.
1779 /* sender/addressed_recipient of #NULL may mean bus driver,
1780 * or for addressed_recipient may mean a message with no
1781 * specific recipient (i.e. a signal)
1784 /* Don't bother re-matching features we've already checked implicitly. */
1785 flags = rule->flags & (~already_matched);
1787 if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
1788 wants_to_eavesdrop = TRUE;
1790 if (flags & BUS_MATCH_MESSAGE_TYPE)
1792 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1794 if (rule->message_type != dbus_message_get_type (message))
1798 if (flags & BUS_MATCH_INTERFACE)
1802 _dbus_assert (rule->interface != NULL);
1804 iface = dbus_message_get_interface (message);
1808 if (strcmp (iface, rule->interface) != 0)
1812 if (flags & BUS_MATCH_MEMBER)
1816 _dbus_assert (rule->member != NULL);
1818 member = dbus_message_get_member (message);
1822 if (strcmp (member, rule->member) != 0)
1826 if (flags & BUS_MATCH_SENDER)
1828 _dbus_assert (rule->sender != NULL);
1832 if (strcmp (rule->sender,
1833 DBUS_SERVICE_DBUS) != 0)
1838 if (!connection_is_primary_owner (sender, rule->sender))
1843 /* Note: this part is relevant for eavesdropper rules:
1845 * 1) rule has a destination to be matched
1846 * (flag BUS_MATCH_DESTINATION present). Rule will match if:
1847 * - rule->destination matches the addressed_recipient
1849 * - wants_to_eavesdrop=TRUE
1851 * Note: (the case in which addressed_recipient is the actual rule owner
1852 * is handled elsewere in dispatch.c:bus_dispatch_matches().
1854 * 2) rule has no destination. Rule will match if:
1855 * - message has no specified destination (ie broadcasts)
1856 * (Note: this will rule out unicast method calls and unicast signals,
1857 * fixing FDO#269748)
1859 * - wants_to_eavesdrop=TRUE (destination-catch-all situation)
1861 if (flags & BUS_MATCH_DESTINATION)
1863 const char *destination;
1865 _dbus_assert (rule->destination != NULL);
1867 destination = dbus_message_get_destination (message);
1868 if (destination == NULL)
1869 /* broadcast, but this rule specified a destination: no match */
1872 /* rule owner does not intend to eavesdrop: we'll deliver only msgs
1873 * directed to it, NOT MATCHING */
1874 if (!wants_to_eavesdrop)
1877 if (addressed_recipient == NULL)
1879 if (strcmp (rule->destination,
1880 DBUS_SERVICE_DBUS) != 0)
1885 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1888 } else { /* no destination in rule */
1889 dbus_bool_t msg_is_broadcast;
1891 _dbus_assert (rule->destination == NULL);
1893 msg_is_broadcast = (dbus_message_get_destination (message) == NULL);
1895 if (!wants_to_eavesdrop && !msg_is_broadcast)
1898 /* if we are here rule owner intends to eavesdrop
1900 * message is being broadcasted */
1903 if (flags & BUS_MATCH_PATH)
1907 _dbus_assert (rule->path != NULL);
1909 path = dbus_message_get_path (message);
1913 if (strcmp (path, rule->path) != 0)
1917 if (flags & BUS_MATCH_PATH_NAMESPACE)
1922 _dbus_assert (rule->path != NULL);
1924 path = dbus_message_get_path (message);
1928 if (!str_has_prefix (path, rule->path))
1931 len = strlen (rule->path);
1933 /* Check that the actual argument is within the expected
1934 * namespace, rather than just starting with that string,
1935 * by checking that the matched prefix is followed by a '/'
1936 * or the end of the path.
1938 * Special case: the only valid path of length 1, "/",
1939 * matches everything.
1941 if (len > 1 && path[len] != '\0' && path[len] != '/')
1945 if (flags & BUS_MATCH_ARGS)
1948 DBusMessageIter iter;
1950 _dbus_assert (rule->args != NULL);
1952 dbus_message_iter_init (message, &iter);
1955 while (i < rule->args_len)
1958 const char *expected_arg;
1959 int expected_length;
1960 dbus_bool_t is_path, is_namespace;
1962 expected_arg = rule->args[i];
1963 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
1964 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1965 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
1967 current_type = dbus_message_iter_get_arg_type (&iter);
1969 if (expected_arg != NULL)
1971 const char *actual_arg;
1974 if (current_type != DBUS_TYPE_STRING &&
1975 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
1979 dbus_message_iter_get_basic (&iter, &actual_arg);
1980 _dbus_assert (actual_arg != NULL);
1982 actual_length = strlen (actual_arg);
1986 if (actual_length < expected_length &&
1987 actual_arg[actual_length - 1] != '/')
1990 if (expected_length < actual_length &&
1991 expected_arg[expected_length - 1] != '/')
1994 if (memcmp (actual_arg, expected_arg,
1995 MIN (actual_length, expected_length)) != 0)
1998 else if (is_namespace)
2000 if (expected_length > actual_length)
2003 /* If the actual argument doesn't start with the expected
2004 * namespace, then we don't match.
2006 if (memcmp (expected_arg, actual_arg, expected_length) != 0)
2009 if (expected_length < actual_length)
2011 /* Check that the actual argument is within the expected
2012 * namespace, rather than just starting with that string,
2013 * by checking that the matched prefix ends in a '.'.
2015 * This doesn't stop "foo.bar." matching "foo.bar..baz"
2016 * which is an invalid namespace, but at some point the
2017 * daemon can't cover up for broken services.
2019 if (actual_arg[expected_length] != '.')
2022 /* otherwise we had an exact match. */
2026 if (expected_length != actual_length ||
2027 memcmp (expected_arg, actual_arg, expected_length) != 0)
2033 if (current_type != DBUS_TYPE_INVALID)
2034 dbus_message_iter_next (&iter);
2044 get_recipients_from_list (DBusList **rules,
2045 DBusConnection *sender,
2046 DBusConnection *addressed_recipient,
2047 DBusMessage *message,
2048 DBusList **recipients_p)
2055 link = _dbus_list_get_first_link (rules);
2056 while (link != NULL)
2062 #ifdef DBUS_ENABLE_VERBOSE_MODE
2064 char *s = match_rule_to_string (rule);
2066 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
2067 s ? s : "nomem", rule->matches_go_to);
2072 if (match_rule_matches (rule,
2073 sender, addressed_recipient, message,
2074 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
2076 _dbus_verbose ("Rule matched\n");
2078 /* Append to the list if we haven't already */
2079 if (bus_connection_mark_stamp (rule->matches_go_to))
2081 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
2086 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
2090 link = _dbus_list_get_next_link (rules, link);
2097 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
2098 BusConnections *connections,
2099 DBusConnection *sender,
2100 DBusConnection *addressed_recipient,
2101 DBusMessage *message,
2102 DBusList **recipients_p)
2105 const char *interface;
2106 DBusList **neither, **just_type, **just_iface, **both;
2108 _dbus_assert (*recipients_p == NULL);
2110 /* This avoids sending same message to the same connection twice.
2111 * Purpose of the stamp instead of a bool is to avoid iterating over
2112 * all connections resetting the bool each time.
2114 bus_connections_increment_stamp (connections);
2116 /* addressed_recipient is already receiving the message, don't add to list.
2117 * NULL addressed_recipient means either bus driver, or this is a signal
2118 * and thus lacks a specific addressed_recipient.
2120 if (addressed_recipient != NULL)
2121 bus_connection_mark_stamp (addressed_recipient);
2123 type = dbus_message_get_type (message);
2124 interface = dbus_message_get_interface (message);
2126 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
2128 just_type = just_iface = both = NULL;
2130 if (interface != NULL)
2131 just_iface = bus_matchmaker_get_rules (matchmaker,
2132 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
2134 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
2136 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
2138 if (interface != NULL)
2139 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
2142 if (!(get_recipients_from_list (neither, sender, addressed_recipient,
2143 message, recipients_p) &&
2144 get_recipients_from_list (just_iface, sender, addressed_recipient,
2145 message, recipients_p) &&
2146 get_recipients_from_list (just_type, sender, addressed_recipient,
2147 message, recipients_p) &&
2148 get_recipients_from_list (both, sender, addressed_recipient,
2149 message, recipients_p)))
2151 _dbus_list_clear (recipients_p);
2158 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2162 static BusMatchRule*
2163 check_parse (dbus_bool_t should_succeed,
2170 dbus_error_init (&error);
2172 _dbus_string_init_const (&str, text);
2174 rule = bus_match_rule_parse (NULL, &str, &error);
2175 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2177 dbus_error_free (&error);
2181 if (should_succeed && rule == NULL)
2183 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
2184 error.name, error.message,
2185 _dbus_string_get_const_data (&str));
2189 if (!should_succeed && rule != NULL)
2191 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
2192 _dbus_string_get_const_data (&str));
2196 dbus_error_free (&error);
2202 assert_large_rule (BusMatchRule *rule)
2204 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2205 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
2206 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2207 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
2208 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
2209 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2211 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2212 _dbus_assert (rule->interface != NULL);
2213 _dbus_assert (rule->member != NULL);
2214 _dbus_assert (rule->sender != NULL);
2215 _dbus_assert (rule->destination != NULL);
2216 _dbus_assert (rule->path != NULL);
2218 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
2219 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
2220 _dbus_assert (strcmp (rule->member, "Foo") == 0);
2221 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
2222 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
2226 test_parsing (void *data)
2230 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
2233 assert_large_rule (rule);
2234 bus_match_rule_unref (rule);
2237 /* With extra whitespace and useless quotes */
2238 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
2241 assert_large_rule (rule);
2242 bus_match_rule_unref (rule);
2246 /* A simple signal connection */
2247 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
2250 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
2251 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
2252 _dbus_assert (rule->flags & BUS_MATCH_PATH);
2254 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
2255 _dbus_assert (rule->interface != NULL);
2256 _dbus_assert (rule->path != NULL);
2258 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
2259 _dbus_assert (strcmp (rule->path, "/foo") == 0);
2261 bus_match_rule_unref (rule);
2265 rule = check_parse (TRUE, "arg0='foo'");
2268 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2269 _dbus_assert (rule->args != NULL);
2270 _dbus_assert (rule->args_len == 1);
2271 _dbus_assert (rule->args[0] != NULL);
2272 _dbus_assert (rule->args[1] == NULL);
2273 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2275 bus_match_rule_unref (rule);
2278 rule = check_parse (TRUE, "arg1='foo'");
2281 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2282 _dbus_assert (rule->args != NULL);
2283 _dbus_assert (rule->args_len == 2);
2284 _dbus_assert (rule->args[0] == NULL);
2285 _dbus_assert (rule->args[1] != NULL);
2286 _dbus_assert (rule->args[2] == NULL);
2287 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
2289 bus_match_rule_unref (rule);
2292 rule = check_parse (TRUE, "arg2='foo'");
2295 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2296 _dbus_assert (rule->args != NULL);
2297 _dbus_assert (rule->args_len == 3);
2298 _dbus_assert (rule->args[0] == NULL);
2299 _dbus_assert (rule->args[1] == NULL);
2300 _dbus_assert (rule->args[2] != NULL);
2301 _dbus_assert (rule->args[3] == NULL);
2302 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
2304 bus_match_rule_unref (rule);
2307 rule = check_parse (TRUE, "arg40='foo'");
2310 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2311 _dbus_assert (rule->args != NULL);
2312 _dbus_assert (rule->args_len == 41);
2313 _dbus_assert (rule->args[0] == NULL);
2314 _dbus_assert (rule->args[1] == NULL);
2315 _dbus_assert (rule->args[40] != NULL);
2316 _dbus_assert (rule->args[41] == NULL);
2317 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
2319 bus_match_rule_unref (rule);
2322 rule = check_parse (TRUE, "arg63='foo'");
2325 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2326 _dbus_assert (rule->args != NULL);
2327 _dbus_assert (rule->args_len == 64);
2328 _dbus_assert (rule->args[0] == NULL);
2329 _dbus_assert (rule->args[1] == NULL);
2330 _dbus_assert (rule->args[63] != NULL);
2331 _dbus_assert (rule->args[64] == NULL);
2332 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
2334 bus_match_rule_unref (rule);
2337 rule = check_parse (TRUE, "arg7path='/foo'");
2340 _dbus_assert (rule->flags = BUS_MATCH_ARGS);
2341 _dbus_assert (rule->args != NULL);
2342 _dbus_assert (rule->args_len == 8);
2343 _dbus_assert (rule->args[7] != NULL);
2344 _dbus_assert (rule->args[8] == NULL);
2345 _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
2346 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
2347 == BUS_MATCH_ARG_IS_PATH);
2349 bus_match_rule_unref (rule);
2352 /* Arg 0 namespace matches */
2353 rule = check_parse (TRUE, "arg0namespace='foo'");
2356 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2357 _dbus_assert (rule->args != NULL);
2358 _dbus_assert (rule->args_len == 1);
2359 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
2360 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2361 == BUS_MATCH_ARG_NAMESPACE);
2363 bus_match_rule_unref (rule);
2366 rule = check_parse (TRUE, "arg0namespace='foo.bar'");
2369 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
2370 _dbus_assert (rule->args != NULL);
2371 _dbus_assert (rule->args_len == 1);
2372 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
2373 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
2374 == BUS_MATCH_ARG_NAMESPACE);
2376 bus_match_rule_unref (rule);
2379 /* Only arg0namespace is supported. */
2380 rule = check_parse (FALSE, "arg1namespace='foo'");
2381 _dbus_assert (rule == NULL);
2383 /* An empty string isn't a valid namespace prefix (you should just not
2384 * specify this key at all).
2386 rule = check_parse (FALSE, "arg0namespace=''");
2387 _dbus_assert (rule == NULL);
2389 /* Trailing periods aren't allowed (earlier versions of the arg0namespace
2390 * spec allowed a single trailing period, which altered the semantics) */
2391 rule = check_parse (FALSE, "arg0namespace='foo.'");
2392 _dbus_assert (rule == NULL);
2394 rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
2395 _dbus_assert (rule == NULL);
2397 rule = check_parse (FALSE, "arg0namespace='foo..'");
2398 _dbus_assert (rule == NULL);
2400 rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
2401 _dbus_assert (rule == NULL);
2403 /* Too-large argN */
2404 rule = check_parse (FALSE, "arg300='foo'");
2405 _dbus_assert (rule == NULL);
2406 rule = check_parse (FALSE, "arg64='foo'");
2407 _dbus_assert (rule == NULL);
2410 rule = check_parse (FALSE, "arg='foo'");
2411 _dbus_assert (rule == NULL);
2412 rule = check_parse (FALSE, "argv='foo'");
2413 _dbus_assert (rule == NULL);
2414 rule = check_parse (FALSE, "arg3junk='foo'");
2415 _dbus_assert (rule == NULL);
2416 rule = check_parse (FALSE, "argument='foo'");
2417 _dbus_assert (rule == NULL);
2419 /* Reject duplicates */
2420 rule = check_parse (FALSE, "type='signal',type='method_call'");
2421 _dbus_assert (rule == NULL);
2423 rule = check_parse (TRUE, "path_namespace='/foo/bar'");
2426 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
2427 _dbus_assert (rule->path != NULL);
2428 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
2430 bus_match_rule_unref (rule);
2433 /* Almost a duplicate */
2434 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
2435 _dbus_assert (rule == NULL);
2437 /* Trailing / was supported in the initial proposal, but now isn't */
2438 rule = check_parse (FALSE, "path_namespace='/foo/'");
2439 _dbus_assert (rule == NULL);
2441 /* Duplicates with the argN code */
2442 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
2443 _dbus_assert (rule == NULL);
2444 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
2445 _dbus_assert (rule == NULL);
2446 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
2447 _dbus_assert (rule == NULL);
2449 /* Reject broken keys */
2450 rule = check_parse (FALSE, "blah='signal'");
2451 _dbus_assert (rule == NULL);
2453 /* Reject broken values */
2454 rule = check_parse (FALSE, "type='chouin'");
2455 _dbus_assert (rule == NULL);
2456 rule = check_parse (FALSE, "interface='abc@def++'");
2457 _dbus_assert (rule == NULL);
2458 rule = check_parse (FALSE, "service='youpi'");
2459 _dbus_assert (rule == NULL);
2461 /* Allow empty rule */
2462 rule = check_parse (TRUE, "");
2465 _dbus_assert (rule->flags == 0);
2467 bus_match_rule_unref (rule);
2470 /* All-whitespace rule is the same as empty */
2471 rule = check_parse (TRUE, " \t");
2474 _dbus_assert (rule->flags == 0);
2476 bus_match_rule_unref (rule);
2479 /* But with non-whitespace chars and no =value, it's not OK */
2480 rule = check_parse (FALSE, "type");
2481 _dbus_assert (rule == NULL);
2489 } equality_tests[] = {
2490 { "type='signal'", "type='signal'" },
2491 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
2492 { "type='signal',member='bar'", "member='bar',type='signal'" },
2493 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
2494 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
2495 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
2496 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
2497 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
2498 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
2499 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
2500 { "arg3='fool'", "arg3='fool'" },
2501 { "arg0namespace='fool'", "arg0namespace='fool'" },
2502 { "member='food'", "member='food'" },
2503 { "member=escape", "member='escape'" },
2504 { "member=icecream", "member=ice'cream'" },
2505 { "arg0='comma,type=comma',type=signal", "type=signal,arg0='comma,type=comma'" },
2506 { "arg0=escap\\e", "arg0='escap\\e'" },
2507 { "arg0=Time: 8 o\\'clock", "arg0='Time: 8 o'\\''clock'" },
2511 test_equality (void)
2516 while (i < _DBUS_N_ELEMENTS (equality_tests))
2518 BusMatchRule *first;
2519 BusMatchRule *second;
2520 char *first_str, *second_str;
2521 BusMatchRule *first_reparsed, *second_reparsed;
2524 first = check_parse (TRUE, equality_tests[i].first);
2525 _dbus_assert (first != NULL);
2526 second = check_parse (TRUE, equality_tests[i].second);
2527 _dbus_assert (second != NULL);
2529 if (!match_rule_equal (first, second))
2531 _dbus_warn ("rule %s and %s should have been equal\n",
2532 equality_tests[i].first,
2533 equality_tests[i].second);
2537 /* Check match_rule_to_string */
2538 first_str = match_rule_to_string (first);
2539 _dbus_assert (first_str != NULL);
2540 second_str = match_rule_to_string (second);
2541 _dbus_assert (second_str != NULL);
2542 _dbus_assert (strcmp (first_str, second_str) == 0);
2543 first_reparsed = check_parse (TRUE, first_str);
2544 second_reparsed = check_parse (TRUE, second_str);
2545 _dbus_assert (match_rule_equal (first, first_reparsed));
2546 _dbus_assert (match_rule_equal (second, second_reparsed));
2547 bus_match_rule_unref (first_reparsed);
2548 bus_match_rule_unref (second_reparsed);
2549 dbus_free (first_str);
2550 dbus_free (second_str);
2552 bus_match_rule_unref (second);
2554 /* Check that the rule is not equal to any of the
2555 * others besides its pair match
2558 while (j < _DBUS_N_ELEMENTS (equality_tests))
2562 second = check_parse (TRUE, equality_tests[j].second);
2564 if (match_rule_equal (first, second))
2566 _dbus_warn ("rule %s and %s should not have been equal\n",
2567 equality_tests[i].first,
2568 equality_tests[j].second);
2572 bus_match_rule_unref (second);
2578 bus_match_rule_unref (first);
2585 should_match_message_1[] = {
2587 "member='Frobated'",
2589 "type='signal',member='Frobated'",
2590 "type='signal',member='Frobated',arg0='foobar'",
2591 "member='Frobated',arg0='foobar'",
2592 "type='signal',arg0='foobar'",
2593 /* The definition of argXpath matches says: "As with normal argument matches,
2594 * if the argument is exactly equal to the string given in the match rule
2595 * then the rule is satisfied." So this should match (even though the
2596 * argument is not a valid path)!
2598 "arg0path='foobar'",
2599 "arg0namespace='foobar'",
2604 should_not_match_message_1[] = {
2605 "type='method_call'",
2607 "type='method_return'",
2608 "type='signal',member='Oopsed'",
2615 "arg0='foobar',arg1='abcdef'",
2616 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
2617 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
2619 "arg0path='foobar/'",
2621 "arg0namespace='foo'",
2622 "arg0namespace='foo',arg1='abcdef'",
2623 "arg0namespace='moo'",
2627 #define EXAMPLE_NAME "com.example.backend.foo"
2630 should_match_message_2[] = {
2631 /* EXAMPLE_NAME is in all of these namespaces */
2632 "arg0namespace='com.example.backend'",
2633 "arg0namespace='com.example'",
2634 "arg0namespace='com'",
2636 /* If the client specifies the name exactly, with no trailing period, then
2639 "arg0namespace='com.example.backend.foo'",
2645 should_not_match_message_2[] = {
2646 /* These are not even prefixes */
2647 "arg0namespace='com.example.backend.foo.bar'",
2648 "arg0namespace='com.example.backend.foobar'",
2650 /* These are prefixes, but they're not parent namespaces. */
2651 "arg0namespace='com.example.backend.fo'",
2652 "arg0namespace='com.example.backen'",
2653 "arg0namespace='com.exampl'",
2654 "arg0namespace='co'",
2660 check_matches (dbus_bool_t expected_to_match,
2662 DBusMessage *message,
2663 const char *rule_text)
2666 dbus_bool_t matched;
2668 rule = check_parse (TRUE, rule_text);
2669 _dbus_assert (rule != NULL);
2671 /* We can't test sender/destination rules since we pass NULL here */
2672 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2674 if (matched != expected_to_match)
2676 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
2677 rule_text, expected_to_match ?
2678 "match" : "not match", number);
2682 bus_match_rule_unref (rule);
2686 check_matching (DBusMessage *message,
2688 const char **should_match,
2689 const char **should_not_match)
2694 while (should_match[i] != NULL)
2696 check_matches (TRUE, number, message, should_match[i]);
2701 while (should_not_match[i] != NULL)
2703 check_matches (FALSE, number, message, should_not_match[i]);
2709 test_matching (void)
2711 DBusMessage *message1, *message2;
2712 const char *v_STRING;
2713 dbus_int32_t v_INT32;
2715 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2716 _dbus_assert (message1 != NULL);
2717 if (!dbus_message_set_member (message1, "Frobated"))
2718 _dbus_assert_not_reached ("oom");
2720 v_STRING = "foobar";
2722 if (!dbus_message_append_args (message1,
2723 DBUS_TYPE_STRING, &v_STRING,
2724 DBUS_TYPE_INT32, &v_INT32,
2726 _dbus_assert_not_reached ("oom");
2728 check_matching (message1, 1,
2729 should_match_message_1,
2730 should_not_match_message_1);
2732 dbus_message_unref (message1);
2734 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2735 _dbus_assert (message2 != NULL);
2736 if (!dbus_message_set_member (message2, "NameOwnerChanged"))
2737 _dbus_assert_not_reached ("oom");
2739 /* Obviously this isn't really a NameOwnerChanged signal. */
2740 v_STRING = EXAMPLE_NAME;
2741 if (!dbus_message_append_args (message2,
2742 DBUS_TYPE_STRING, &v_STRING,
2744 _dbus_assert_not_reached ("oom");
2746 check_matching (message2, 2,
2747 should_match_message_2,
2748 should_not_match_message_2);
2750 dbus_message_unref (message2);
2753 #define PATH_MATCH_RULE "arg0path='/aa/bb/'"
2755 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
2756 * from the specification. Notice that not all of them are actually legal D-Bus
2759 * The author of this test takes no responsibility for the semantics of
2760 * this match rule key.
2762 static const char *paths_that_should_be_matched[] = {
2766 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
2772 /* These paths should not be matched by PATH_MATCH_RULE. */
2773 static const char *paths_that_should_not_be_matched[] = {
2782 test_path_match (int type,
2784 const char *rule_text,
2786 dbus_bool_t should_match)
2788 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2789 dbus_bool_t matched;
2791 _dbus_assert (message != NULL);
2792 if (!dbus_message_set_member (message, "Foo"))
2793 _dbus_assert_not_reached ("oom");
2795 if (!dbus_message_append_args (message,
2798 _dbus_assert_not_reached ("oom");
2800 matched = match_rule_matches (rule, NULL, NULL, message, 0);
2802 if (matched != should_match)
2804 _dbus_warn ("Expected rule %s to %s message "
2805 "with first arg %s of type '%c', failed\n",
2807 should_match ? "match" : "not match",
2813 dbus_message_unref (message);
2817 test_path_matching (void)
2822 rule = check_parse (TRUE, PATH_MATCH_RULE);
2823 _dbus_assert (rule != NULL);
2825 for (s = paths_that_should_be_matched; *s != NULL; s++)
2826 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
2828 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
2830 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
2832 for (s = paths_that_should_not_be_matched; *s != NULL; s++)
2834 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
2835 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
2838 bus_match_rule_unref (rule);
2842 path_namespace_should_match_message_1[] = {
2843 "type='signal',path_namespace='/'",
2844 "type='signal',path_namespace='/foo'",
2845 "type='signal',path_namespace='/foo/TheObjectManager'",
2850 path_namespace_should_not_match_message_1[] = {
2851 "type='signal',path_namespace='/bar'",
2852 "type='signal',path_namespace='/bar/TheObjectManager'",
2857 path_namespace_should_match_message_2[] = {
2858 "type='signal',path_namespace='/'",
2859 "type='signal',path_namespace='/foo/TheObjectManager'",
2864 path_namespace_should_not_match_message_2[] = {
2869 path_namespace_should_match_message_3[] = {
2870 "type='signal',path_namespace='/'",
2875 path_namespace_should_not_match_message_3[] = {
2876 "type='signal',path_namespace='/foo/TheObjectManager'",
2881 path_namespace_should_match_message_4[] = {
2882 "type='signal',path_namespace='/'",
2887 path_namespace_should_not_match_message_4[] = {
2888 "type='signal',path_namespace='/foo/TheObjectManager'",
2893 test_matching_path_namespace (void)
2895 DBusMessage *message1;
2896 DBusMessage *message2;
2897 DBusMessage *message3;
2898 DBusMessage *message4;
2900 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2901 _dbus_assert (message1 != NULL);
2902 if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
2903 _dbus_assert_not_reached ("oom");
2905 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2906 _dbus_assert (message2 != NULL);
2907 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
2908 _dbus_assert_not_reached ("oom");
2910 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2911 _dbus_assert (message3 != NULL);
2912 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
2913 _dbus_assert_not_reached ("oom");
2915 message4 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
2916 _dbus_assert (message4 != NULL);
2917 if (!dbus_message_set_path (message4, "/"))
2918 _dbus_assert_not_reached ("oom");
2920 check_matching (message1, 1,
2921 path_namespace_should_match_message_1,
2922 path_namespace_should_not_match_message_1);
2923 check_matching (message2, 2,
2924 path_namespace_should_match_message_2,
2925 path_namespace_should_not_match_message_2);
2926 check_matching (message3, 3,
2927 path_namespace_should_match_message_3,
2928 path_namespace_should_not_match_message_3);
2929 check_matching (message4, 4,
2930 path_namespace_should_match_message_4,
2931 path_namespace_should_not_match_message_4);
2933 dbus_message_unref (message4);
2934 dbus_message_unref (message3);
2935 dbus_message_unref (message2);
2936 dbus_message_unref (message1);
2940 bus_signals_test (const DBusString *test_data_dir)
2942 BusMatchmaker *matchmaker;
2944 matchmaker = bus_matchmaker_new ();
2945 bus_matchmaker_ref (matchmaker);
2946 bus_matchmaker_unref (matchmaker);
2947 bus_matchmaker_unref (matchmaker);
2949 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2950 _dbus_assert_not_reached ("Parsing match rules test failed");
2954 test_path_matching ();
2955 test_matching_path_namespace ();
2960 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */