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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <dbus/dbus-marshal-validate.h>
30 int refcount; /**< reference count */
32 DBusConnection *matches_go_to; /**< Owner of the rule */
34 unsigned int flags; /**< BusMatchFlags */
43 unsigned int *arg_lens;
48 #define BUS_MATCH_ARG_IS_PATH 0x8000000u
51 bus_match_rule_new (DBusConnection *matches_go_to)
55 rule = dbus_new0 (BusMatchRule, 1);
60 rule->matches_go_to = matches_go_to;
62 #ifndef DBUS_BUILD_TESTS
63 _dbus_assert (rule->matches_go_to != NULL);
70 bus_match_rule_ref (BusMatchRule *rule)
72 _dbus_assert (rule->refcount > 0);
80 bus_match_rule_unref (BusMatchRule *rule)
82 _dbus_assert (rule->refcount > 0);
85 if (rule->refcount == 0)
87 dbus_free (rule->interface);
88 dbus_free (rule->member);
89 dbus_free (rule->sender);
90 dbus_free (rule->destination);
91 dbus_free (rule->path);
92 dbus_free (rule->arg_lens);
94 /* can't use dbus_free_string_array() since there
102 while (i < rule->args_len)
105 dbus_free (rule->args[i]);
109 dbus_free (rule->args);
116 #ifdef DBUS_ENABLE_VERBOSE_MODE
117 /* Note this function does not do escaping, so it's only
118 * good for debug spew at the moment
121 match_rule_to_string (BusMatchRule *rule)
126 if (!_dbus_string_init (&str))
129 while ((s = _dbus_strdup ("nomem")) == NULL)
130 ; /* only OK for debug spew... */
134 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
136 /* FIXME make type readable */
137 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
141 if (rule->flags & BUS_MATCH_INTERFACE)
143 if (_dbus_string_get_length (&str) > 0)
145 if (!_dbus_string_append (&str, ","))
149 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
153 if (rule->flags & BUS_MATCH_MEMBER)
155 if (_dbus_string_get_length (&str) > 0)
157 if (!_dbus_string_append (&str, ","))
161 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
165 if (rule->flags & BUS_MATCH_PATH)
167 if (_dbus_string_get_length (&str) > 0)
169 if (!_dbus_string_append (&str, ","))
173 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
177 if (rule->flags & BUS_MATCH_SENDER)
179 if (_dbus_string_get_length (&str) > 0)
181 if (!_dbus_string_append (&str, ","))
185 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
189 if (rule->flags & BUS_MATCH_DESTINATION)
191 if (_dbus_string_get_length (&str) > 0)
193 if (!_dbus_string_append (&str, ","))
197 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
201 if (rule->flags & BUS_MATCH_ARGS)
205 _dbus_assert (rule->args != NULL);
208 while (i < rule->args_len)
210 if (rule->args[i] != NULL)
214 if (_dbus_string_get_length (&str) > 0)
216 if (!_dbus_string_append (&str, ","))
220 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
222 if (!_dbus_string_append_printf (&str,
224 i, is_path ? "path" : "",
233 if (!_dbus_string_steal_data (&str, &ret))
236 _dbus_string_free (&str);
240 _dbus_string_free (&str);
243 while ((s = _dbus_strdup ("nomem")) == NULL)
244 ; /* only OK for debug spew... */
248 #endif /* DBUS_ENABLE_VERBOSE_MODE */
251 bus_match_rule_set_message_type (BusMatchRule *rule,
254 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
256 rule->message_type = type;
262 bus_match_rule_set_interface (BusMatchRule *rule,
263 const char *interface)
267 _dbus_assert (interface != NULL);
269 new = _dbus_strdup (interface);
273 rule->flags |= BUS_MATCH_INTERFACE;
274 dbus_free (rule->interface);
275 rule->interface = new;
281 bus_match_rule_set_member (BusMatchRule *rule,
286 _dbus_assert (member != NULL);
288 new = _dbus_strdup (member);
292 rule->flags |= BUS_MATCH_MEMBER;
293 dbus_free (rule->member);
300 bus_match_rule_set_sender (BusMatchRule *rule,
305 _dbus_assert (sender != NULL);
307 new = _dbus_strdup (sender);
311 rule->flags |= BUS_MATCH_SENDER;
312 dbus_free (rule->sender);
319 bus_match_rule_set_destination (BusMatchRule *rule,
320 const char *destination)
324 _dbus_assert (destination != NULL);
326 new = _dbus_strdup (destination);
330 rule->flags |= BUS_MATCH_DESTINATION;
331 dbus_free (rule->destination);
332 rule->destination = new;
338 bus_match_rule_set_path (BusMatchRule *rule,
343 _dbus_assert (path != NULL);
345 new = _dbus_strdup (path);
349 rule->flags |= BUS_MATCH_PATH;
350 dbus_free (rule->path);
357 bus_match_rule_set_arg (BusMatchRule *rule,
359 const DBusString *value,
365 _dbus_assert (value != NULL);
367 /* args_len is the number of args not including null termination
370 if (arg >= rule->args_len)
372 unsigned int *new_arg_lens;
377 new_args_len = arg + 1;
379 /* add another + 1 here for null termination */
380 new_args = dbus_realloc (rule->args,
381 sizeof (char *) * (new_args_len + 1));
382 if (new_args == NULL)
385 /* NULL the new slots */
387 while (i <= new_args_len) /* <= for null termination */
393 rule->args = new_args;
395 /* and now add to the lengths */
396 new_arg_lens = dbus_realloc (rule->arg_lens,
397 sizeof (int) * (new_args_len + 1));
399 if (new_arg_lens == NULL)
402 /* zero the new slots */
404 while (i <= new_args_len) /* <= for null termination */
410 rule->arg_lens = new_arg_lens;
411 rule->args_len = new_args_len;
414 length = _dbus_string_get_length (value);
415 if (!_dbus_string_copy_data (value, &new))
418 rule->flags |= BUS_MATCH_ARGS;
420 dbus_free (rule->args[arg]);
421 rule->arg_lens[arg] = length;
422 rule->args[arg] = new;
425 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
427 /* NULL termination didn't get busted */
428 _dbus_assert (rule->args[rule->args_len] == NULL);
429 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
434 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
437 find_key (const DBusString *str,
445 const char *key_start;
448 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
450 s = _dbus_string_get_const_data (str);
454 while (*p && ISWHITE (*p))
459 while (*p && *p != '=' && !ISWHITE (*p))
464 while (*p && ISWHITE (*p))
467 if (key_start == key_end)
469 /* Empty match rules or trailing whitespace are OK */
476 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
477 "Match rule has a key with no subsequent '=' character");
482 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
494 find_value (const DBusString *str,
506 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
508 orig_len = _dbus_string_get_length (value);
510 s = _dbus_string_get_const_data (str);
518 if (quote_char == '\0')
538 if (!_dbus_string_append_byte (value, *p))
545 else if (quote_char == '\\')
547 /* \ only counts as an escape if escaping a quote mark */
550 if (!_dbus_string_append_byte (value, '\\'))
557 if (!_dbus_string_append_byte (value, *p))
567 _dbus_assert (quote_char == '\'');
575 if (!_dbus_string_append_byte (value, *p))
589 if (quote_char == '\\')
591 if (!_dbus_string_append_byte (value, '\\'))
597 else if (quote_char == '\'')
599 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
600 "Unbalanced quotation marks in match rule");
604 _dbus_assert (quote_char == '\0');
606 /* Zero-length values are allowed */
613 _DBUS_ASSERT_ERROR_IS_SET (error);
614 _dbus_string_set_length (value, orig_len);
618 /* duplicates aren't allowed so the real legitimate max is only 6 or
619 * so. Leaving extra so we don't have to bother to update it.
620 * FIXME this is sort of busted now with arg matching, but we let
621 * you match on up to 10 args for now
623 #define MAX_RULE_TOKENS 16
625 /* this is slightly too high level to be termed a "token"
626 * but let's not be pedantic.
635 tokenize_rule (const DBusString *rule_text,
636 RuleToken tokens[MAX_RULE_TOKENS],
647 if (!_dbus_string_init (&key))
653 if (!_dbus_string_init (&value))
655 _dbus_string_free (&key);
662 while (i < MAX_RULE_TOKENS &&
663 pos < _dbus_string_get_length (rule_text))
665 _dbus_assert (tokens[i].key == NULL);
666 _dbus_assert (tokens[i].value == NULL);
668 if (!find_key (rule_text, pos, &key, &pos, error))
671 if (_dbus_string_get_length (&key) == 0)
674 if (!_dbus_string_steal_data (&key, &tokens[i].key))
680 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
683 if (!_dbus_string_steal_data (&value, &tokens[i].value))
699 while (tokens[i].key || tokens[i].value)
701 dbus_free (tokens[i].key);
702 dbus_free (tokens[i].value);
703 tokens[i].key = NULL;
704 tokens[i].value = NULL;
709 _dbus_string_free (&key);
710 _dbus_string_free (&value);
716 bus_match_rule_parse_arg_match (BusMatchRule *rule,
718 const DBusString *value,
727 /* For now, arg0='foo' always implies that 'foo' is a
728 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
729 * if we wanted, which would specify another type, in which case
730 * arg0='5' would have the 5 parsed as an int rather than string.
733 /* First we need to parse arg0 = 0, arg27 = 27 */
735 _dbus_string_init_const (&key_str, key);
736 length = _dbus_string_get_length (&key_str);
738 if (_dbus_string_get_length (&key_str) < 4)
740 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
741 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
745 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
747 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
748 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
753 ((end + 4) != length ||
754 !_dbus_string_ends_with_c_str (&key_str, "path")))
756 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
757 "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key);
761 is_path = end != length;
763 /* If we didn't check this we could allocate a huge amount of RAM */
764 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
766 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
767 "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);
771 if ((rule->flags & BUS_MATCH_ARGS) &&
772 rule->args_len > (int) arg &&
773 rule->args[arg] != NULL)
775 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
776 "Argument %d matched more than once in match rule\n", key);
780 if (!bus_match_rule_set_arg (rule, arg, value, is_path))
789 _DBUS_ASSERT_ERROR_IS_SET (error);
794 * The format is comma-separated with strings quoted with single quotes
795 * as for the shell (to escape a literal single quote, use '\'').
797 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
798 * path='/bar/foo',destination=':452345.34'
802 bus_match_rule_parse (DBusConnection *matches_go_to,
803 const DBusString *rule_text,
807 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
810 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
812 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
814 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
815 "Match rule text is %d bytes, maximum is %d",
816 _dbus_string_get_length (rule_text),
817 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
821 memset (tokens, '\0', sizeof (tokens));
823 rule = bus_match_rule_new (matches_go_to);
830 if (!tokenize_rule (rule_text, tokens, error))
834 while (tokens[i].key != NULL)
838 const char *key = tokens[i].key;
839 const char *value = tokens[i].value;
841 _dbus_string_init_const (&tmp_str, value);
842 len = _dbus_string_get_length (&tmp_str);
844 if (strcmp (key, "type") == 0)
848 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
850 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
851 "Key %s specified twice in match rule\n", key);
855 t = dbus_message_type_from_string (value);
857 if (t == DBUS_MESSAGE_TYPE_INVALID)
859 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
860 "Invalid message type (%s) in match rule\n", value);
864 if (!bus_match_rule_set_message_type (rule, t))
870 else if (strcmp (key, "sender") == 0)
872 if (rule->flags & BUS_MATCH_SENDER)
874 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
875 "Key %s specified twice in match rule\n", key);
879 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
881 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
882 "Sender name '%s' is invalid\n", value);
886 if (!bus_match_rule_set_sender (rule, value))
892 else if (strcmp (key, "interface") == 0)
894 if (rule->flags & BUS_MATCH_INTERFACE)
896 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
897 "Key %s specified twice in match rule\n", key);
901 if (!_dbus_validate_interface (&tmp_str, 0, len))
903 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
904 "Interface name '%s' is invalid\n", value);
908 if (!bus_match_rule_set_interface (rule, value))
914 else if (strcmp (key, "member") == 0)
916 if (rule->flags & BUS_MATCH_MEMBER)
918 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
919 "Key %s specified twice in match rule\n", key);
923 if (!_dbus_validate_member (&tmp_str, 0, len))
925 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
926 "Member name '%s' is invalid\n", value);
930 if (!bus_match_rule_set_member (rule, value))
936 else if (strcmp (key, "path") == 0)
938 if (rule->flags & BUS_MATCH_PATH)
940 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
941 "Key %s specified twice in match rule\n", key);
945 if (!_dbus_validate_path (&tmp_str, 0, len))
947 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
948 "Path '%s' is invalid\n", value);
952 if (!bus_match_rule_set_path (rule, value))
958 else if (strcmp (key, "destination") == 0)
960 if (rule->flags & BUS_MATCH_DESTINATION)
962 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
963 "Key %s specified twice in match rule\n", key);
967 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
969 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
970 "Destination name '%s' is invalid\n", value);
974 if (!bus_match_rule_set_destination (rule, value))
980 else if (strncmp (key, "arg", 3) == 0)
982 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
987 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
988 "Unknown key \"%s\" in match rule",
1000 _DBUS_ASSERT_ERROR_IS_SET (error);
1003 bus_match_rule_unref (rule);
1010 while (tokens[i].key || tokens[i].value)
1012 _dbus_assert (i < MAX_RULE_TOKENS);
1013 dbus_free (tokens[i].key);
1014 dbus_free (tokens[i].value);
1021 struct BusMatchmaker
1025 DBusList *all_rules;
1029 bus_matchmaker_new (void)
1031 BusMatchmaker *matchmaker;
1033 matchmaker = dbus_new0 (BusMatchmaker, 1);
1034 if (matchmaker == NULL)
1037 matchmaker->refcount = 1;
1043 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1045 _dbus_assert (matchmaker->refcount > 0);
1047 matchmaker->refcount += 1;
1053 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1055 _dbus_assert (matchmaker->refcount > 0);
1057 matchmaker->refcount -= 1;
1058 if (matchmaker->refcount == 0)
1060 while (matchmaker->all_rules != NULL)
1064 rule = matchmaker->all_rules->data;
1065 bus_match_rule_unref (rule);
1066 _dbus_list_remove_link (&matchmaker->all_rules,
1067 matchmaker->all_rules);
1070 dbus_free (matchmaker);
1074 /* The rule can't be modified after it's added. */
1076 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1079 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1081 if (!_dbus_list_append (&matchmaker->all_rules, rule))
1084 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1086 _dbus_list_remove_last (&matchmaker->all_rules, rule);
1090 bus_match_rule_ref (rule);
1092 #ifdef DBUS_ENABLE_VERBOSE_MODE
1094 char *s = match_rule_to_string (rule);
1096 _dbus_verbose ("Added match rule %s to connection %p\n",
1097 s, rule->matches_go_to);
1106 match_rule_equal (BusMatchRule *a,
1109 if (a->flags != b->flags)
1112 if (a->matches_go_to != b->matches_go_to)
1115 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1116 a->message_type != b->message_type)
1119 if ((a->flags & BUS_MATCH_MEMBER) &&
1120 strcmp (a->member, b->member) != 0)
1123 if ((a->flags & BUS_MATCH_PATH) &&
1124 strcmp (a->path, b->path) != 0)
1127 if ((a->flags & BUS_MATCH_INTERFACE) &&
1128 strcmp (a->interface, b->interface) != 0)
1131 if ((a->flags & BUS_MATCH_SENDER) &&
1132 strcmp (a->sender, b->sender) != 0)
1135 if ((a->flags & BUS_MATCH_DESTINATION) &&
1136 strcmp (a->destination, b->destination) != 0)
1139 if (a->flags & BUS_MATCH_ARGS)
1143 if (a->args_len != b->args_len)
1147 while (i < a->args_len)
1151 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1154 if (a->arg_lens[i] != b->arg_lens[i])
1157 length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
1159 if (a->args[i] != NULL)
1161 _dbus_assert (b->args[i] != NULL);
1162 if (memcmp (a->args[i], b->args[i], length) != 0)
1174 bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
1177 BusMatchRule *rule = link->data;
1179 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1180 _dbus_list_remove_link (&matchmaker->all_rules, link);
1182 #ifdef DBUS_ENABLE_VERBOSE_MODE
1184 char *s = match_rule_to_string (rule);
1186 _dbus_verbose ("Removed match rule %s for connection %p\n",
1187 s, rule->matches_go_to);
1192 bus_match_rule_unref (rule);
1196 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1199 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1200 _dbus_list_remove (&matchmaker->all_rules, rule);
1202 #ifdef DBUS_ENABLE_VERBOSE_MODE
1204 char *s = match_rule_to_string (rule);
1206 _dbus_verbose ("Removed match rule %s for connection %p\n",
1207 s, rule->matches_go_to);
1212 bus_match_rule_unref (rule);
1215 /* Remove a single rule which is equal to the given rule by value */
1217 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1218 BusMatchRule *value,
1221 /* FIXME this is an unoptimized linear scan */
1225 /* we traverse backward because bus_connection_remove_match_rule()
1226 * removes the most-recently-added rule
1228 link = _dbus_list_get_last_link (&matchmaker->all_rules);
1229 while (link != NULL)
1235 prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
1237 if (match_rule_equal (rule, value))
1239 bus_matchmaker_remove_rule_link (matchmaker, link);
1248 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1249 "The given match rule wasn't found and can't be removed");
1257 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1258 DBusConnection *disconnected)
1264 * This scans all match rules on the bus. We could avoid that
1265 * for the rules belonging to the connection, since we keep
1266 * a list of those; but for the rules that just refer to
1267 * the connection we'd need to do something more elaborate.
1271 _dbus_assert (bus_connection_is_active (disconnected));
1273 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1274 while (link != NULL)
1280 next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1282 if (rule->matches_go_to == disconnected)
1284 bus_matchmaker_remove_rule_link (matchmaker, link);
1286 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1287 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1289 /* The rule matches to/from a base service, see if it's the
1290 * one being disconnected, since we know this service name
1291 * will never be recycled.
1295 name = bus_connection_get_name (disconnected);
1296 _dbus_assert (name != NULL); /* because we're an active connection */
1298 if (((rule->flags & BUS_MATCH_SENDER) &&
1299 strcmp (rule->sender, name) == 0) ||
1300 ((rule->flags & BUS_MATCH_DESTINATION) &&
1301 strcmp (rule->destination, name) == 0))
1303 bus_matchmaker_remove_rule_link (matchmaker, link);
1312 connection_is_primary_owner (DBusConnection *connection,
1313 const char *service_name)
1315 BusService *service;
1317 BusRegistry *registry;
1319 _dbus_assert (connection != NULL);
1321 registry = bus_connection_get_registry (connection);
1323 _dbus_string_init_const (&str, service_name);
1324 service = bus_registry_lookup (registry, &str);
1326 if (service == NULL)
1327 return FALSE; /* Service doesn't exist so connection can't own it. */
1329 return bus_service_get_primary_owners_connection (service) == connection;
1333 match_rule_matches (BusMatchRule *rule,
1334 DBusConnection *sender,
1335 DBusConnection *addressed_recipient,
1336 DBusMessage *message)
1338 /* All features of the match rule are AND'd together,
1339 * so FALSE if any of them don't match.
1342 /* sender/addressed_recipient of #NULL may mean bus driver,
1343 * or for addressed_recipient may mean a message with no
1344 * specific recipient (i.e. a signal)
1347 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
1349 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1351 if (rule->message_type != dbus_message_get_type (message))
1355 if (rule->flags & BUS_MATCH_INTERFACE)
1359 _dbus_assert (rule->interface != NULL);
1361 iface = dbus_message_get_interface (message);
1365 if (strcmp (iface, rule->interface) != 0)
1369 if (rule->flags & BUS_MATCH_MEMBER)
1373 _dbus_assert (rule->member != NULL);
1375 member = dbus_message_get_member (message);
1379 if (strcmp (member, rule->member) != 0)
1383 if (rule->flags & BUS_MATCH_SENDER)
1385 _dbus_assert (rule->sender != NULL);
1389 if (strcmp (rule->sender,
1390 DBUS_SERVICE_DBUS) != 0)
1395 if (!connection_is_primary_owner (sender, rule->sender))
1400 if (rule->flags & BUS_MATCH_DESTINATION)
1402 const char *destination;
1404 _dbus_assert (rule->destination != NULL);
1406 destination = dbus_message_get_destination (message);
1407 if (destination == NULL)
1410 if (addressed_recipient == NULL)
1412 if (strcmp (rule->destination,
1413 DBUS_SERVICE_DBUS) != 0)
1418 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1423 if (rule->flags & BUS_MATCH_PATH)
1427 _dbus_assert (rule->path != NULL);
1429 path = dbus_message_get_path (message);
1433 if (strcmp (path, rule->path) != 0)
1437 if (rule->flags & BUS_MATCH_ARGS)
1440 DBusMessageIter iter;
1442 _dbus_assert (rule->args != NULL);
1444 dbus_message_iter_init (message, &iter);
1447 while (i < rule->args_len)
1450 const char *expected_arg;
1451 int expected_length;
1452 dbus_bool_t is_path;
1454 expected_arg = rule->args[i];
1455 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
1456 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
1458 current_type = dbus_message_iter_get_arg_type (&iter);
1460 if (expected_arg != NULL)
1462 const char *actual_arg;
1465 if (current_type != DBUS_TYPE_STRING)
1469 dbus_message_iter_get_basic (&iter, &actual_arg);
1470 _dbus_assert (actual_arg != NULL);
1472 actual_length = strlen (actual_arg);
1476 if (actual_length < expected_length &&
1477 actual_arg[actual_length - 1] != '/')
1480 if (expected_length < actual_length &&
1481 expected_arg[expected_length - 1] != '/')
1484 if (memcmp (actual_arg, expected_arg,
1485 MIN (actual_length, expected_length)) != 0)
1490 if (expected_length != actual_length ||
1491 memcmp (expected_arg, actual_arg, expected_length) != 0)
1497 if (current_type != DBUS_TYPE_INVALID)
1498 dbus_message_iter_next (&iter);
1508 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1509 BusConnections *connections,
1510 DBusConnection *sender,
1511 DBusConnection *addressed_recipient,
1512 DBusMessage *message,
1513 DBusList **recipients_p)
1515 /* FIXME for now this is a wholly unoptimized linear search */
1516 /* Guessing the important optimization is to skip the signal-related
1517 * match lists when processing method call and exception messages.
1518 * So separate match rule lists for signals?
1523 _dbus_assert (*recipients_p == NULL);
1525 /* This avoids sending same message to the same connection twice.
1526 * Purpose of the stamp instead of a bool is to avoid iterating over
1527 * all connections resetting the bool each time.
1529 bus_connections_increment_stamp (connections);
1531 /* addressed_recipient is already receiving the message, don't add to list.
1532 * NULL addressed_recipient means either bus driver, or this is a signal
1533 * and thus lacks a specific addressed_recipient.
1535 if (addressed_recipient != NULL)
1536 bus_connection_mark_stamp (addressed_recipient);
1538 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1539 while (link != NULL)
1545 #ifdef DBUS_ENABLE_VERBOSE_MODE
1547 char *s = match_rule_to_string (rule);
1549 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1550 s, rule->matches_go_to);
1555 if (match_rule_matches (rule,
1556 sender, addressed_recipient, message))
1558 _dbus_verbose ("Rule matched\n");
1560 /* Append to the list if we haven't already */
1561 if (bus_connection_mark_stamp (rule->matches_go_to))
1563 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1566 #ifdef DBUS_ENABLE_VERBOSE_MODE
1569 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1571 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1574 link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1580 _dbus_list_clear (recipients_p);
1584 #ifdef DBUS_BUILD_TESTS
1588 static BusMatchRule*
1589 check_parse (dbus_bool_t should_succeed,
1596 dbus_error_init (&error);
1598 _dbus_string_init_const (&str, text);
1600 rule = bus_match_rule_parse (NULL, &str, &error);
1601 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1603 dbus_error_free (&error);
1607 if (should_succeed && rule == NULL)
1609 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1610 error.name, error.message,
1611 _dbus_string_get_const_data (&str));
1615 if (!should_succeed && rule != NULL)
1617 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1618 _dbus_string_get_const_data (&str));
1622 dbus_error_free (&error);
1628 assert_large_rule (BusMatchRule *rule)
1630 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1631 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1632 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1633 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1634 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1635 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1637 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1638 _dbus_assert (rule->interface != NULL);
1639 _dbus_assert (rule->member != NULL);
1640 _dbus_assert (rule->sender != NULL);
1641 _dbus_assert (rule->destination != NULL);
1642 _dbus_assert (rule->path != NULL);
1644 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1645 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1646 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1647 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1648 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
1652 test_parsing (void *data)
1656 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
1659 assert_large_rule (rule);
1660 bus_match_rule_unref (rule);
1663 /* With extra whitespace and useless quotes */
1664 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
1667 assert_large_rule (rule);
1668 bus_match_rule_unref (rule);
1672 /* A simple signal connection */
1673 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1676 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1677 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1678 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1680 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1681 _dbus_assert (rule->interface != NULL);
1682 _dbus_assert (rule->path != NULL);
1684 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
1685 _dbus_assert (strcmp (rule->path, "/foo") == 0);
1687 bus_match_rule_unref (rule);
1691 rule = check_parse (TRUE, "arg0='foo'");
1694 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1695 _dbus_assert (rule->args != NULL);
1696 _dbus_assert (rule->args_len == 1);
1697 _dbus_assert (rule->args[0] != NULL);
1698 _dbus_assert (rule->args[1] == NULL);
1699 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
1701 bus_match_rule_unref (rule);
1704 rule = check_parse (TRUE, "arg1='foo'");
1707 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1708 _dbus_assert (rule->args != NULL);
1709 _dbus_assert (rule->args_len == 2);
1710 _dbus_assert (rule->args[0] == NULL);
1711 _dbus_assert (rule->args[1] != NULL);
1712 _dbus_assert (rule->args[2] == NULL);
1713 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
1715 bus_match_rule_unref (rule);
1718 rule = check_parse (TRUE, "arg2='foo'");
1721 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1722 _dbus_assert (rule->args != NULL);
1723 _dbus_assert (rule->args_len == 3);
1724 _dbus_assert (rule->args[0] == NULL);
1725 _dbus_assert (rule->args[1] == NULL);
1726 _dbus_assert (rule->args[2] != NULL);
1727 _dbus_assert (rule->args[3] == NULL);
1728 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
1730 bus_match_rule_unref (rule);
1733 rule = check_parse (TRUE, "arg40='foo'");
1736 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1737 _dbus_assert (rule->args != NULL);
1738 _dbus_assert (rule->args_len == 41);
1739 _dbus_assert (rule->args[0] == NULL);
1740 _dbus_assert (rule->args[1] == NULL);
1741 _dbus_assert (rule->args[40] != NULL);
1742 _dbus_assert (rule->args[41] == NULL);
1743 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
1745 bus_match_rule_unref (rule);
1748 rule = check_parse (TRUE, "arg63='foo'");
1751 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1752 _dbus_assert (rule->args != NULL);
1753 _dbus_assert (rule->args_len == 64);
1754 _dbus_assert (rule->args[0] == NULL);
1755 _dbus_assert (rule->args[1] == NULL);
1756 _dbus_assert (rule->args[63] != NULL);
1757 _dbus_assert (rule->args[64] == NULL);
1758 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
1760 bus_match_rule_unref (rule);
1763 /* Too-large argN */
1764 rule = check_parse (FALSE, "arg300='foo'");
1765 _dbus_assert (rule == NULL);
1766 rule = check_parse (FALSE, "arg64='foo'");
1767 _dbus_assert (rule == NULL);
1770 rule = check_parse (FALSE, "arg='foo'");
1771 _dbus_assert (rule == NULL);
1772 rule = check_parse (FALSE, "argv='foo'");
1773 _dbus_assert (rule == NULL);
1774 rule = check_parse (FALSE, "arg3junk='foo'");
1775 _dbus_assert (rule == NULL);
1776 rule = check_parse (FALSE, "argument='foo'");
1777 _dbus_assert (rule == NULL);
1779 /* Reject duplicates */
1780 rule = check_parse (FALSE, "type='signal',type='method_call'");
1781 _dbus_assert (rule == NULL);
1783 /* Duplicates with the argN code */
1784 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
1785 _dbus_assert (rule == NULL);
1786 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
1787 _dbus_assert (rule == NULL);
1788 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
1789 _dbus_assert (rule == NULL);
1791 /* Reject broken keys */
1792 rule = check_parse (FALSE, "blah='signal'");
1793 _dbus_assert (rule == NULL);
1795 /* Reject broken values */
1796 rule = check_parse (FALSE, "type='chouin'");
1797 _dbus_assert (rule == NULL);
1798 rule = check_parse (FALSE, "interface='abc@def++'");
1799 _dbus_assert (rule == NULL);
1800 rule = check_parse (FALSE, "service='youpi'");
1801 _dbus_assert (rule == NULL);
1803 /* Allow empty rule */
1804 rule = check_parse (TRUE, "");
1807 _dbus_assert (rule->flags == 0);
1809 bus_match_rule_unref (rule);
1812 /* All-whitespace rule is the same as empty */
1813 rule = check_parse (TRUE, " \t");
1816 _dbus_assert (rule->flags == 0);
1818 bus_match_rule_unref (rule);
1821 /* But with non-whitespace chars and no =value, it's not OK */
1822 rule = check_parse (FALSE, "type");
1823 _dbus_assert (rule == NULL);
1831 } equality_tests[] = {
1832 { "type='signal'", "type='signal'" },
1833 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
1834 { "type='signal',member='bar'", "member='bar',type='signal'" },
1835 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
1836 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
1837 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
1838 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
1839 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
1840 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
1841 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
1842 { "arg3='fool'", "arg3='fool'" },
1843 { "member='food'", "member='food'" }
1847 test_equality (void)
1852 while (i < _DBUS_N_ELEMENTS (equality_tests))
1854 BusMatchRule *first;
1855 BusMatchRule *second;
1858 first = check_parse (TRUE, equality_tests[i].first);
1859 _dbus_assert (first != NULL);
1860 second = check_parse (TRUE, equality_tests[i].second);
1861 _dbus_assert (second != NULL);
1863 if (!match_rule_equal (first, second))
1865 _dbus_warn ("rule %s and %s should have been equal\n",
1866 equality_tests[i].first,
1867 equality_tests[i].second);
1871 bus_match_rule_unref (second);
1873 /* Check that the rule is not equal to any of the
1874 * others besides its pair match
1877 while (j < _DBUS_N_ELEMENTS (equality_tests))
1881 second = check_parse (TRUE, equality_tests[j].second);
1883 if (match_rule_equal (first, second))
1885 _dbus_warn ("rule %s and %s should not have been equal\n",
1886 equality_tests[i].first,
1887 equality_tests[j].second);
1891 bus_match_rule_unref (second);
1897 bus_match_rule_unref (first);
1904 should_match_message_1[] = {
1906 "member='Frobated'",
1908 "type='signal',member='Frobated'",
1909 "type='signal',member='Frobated',arg0='foobar'",
1910 "member='Frobated',arg0='foobar'",
1911 "type='signal',arg0='foobar'",
1916 should_not_match_message_1[] = {
1917 "type='method_call'",
1919 "type='method_return'",
1920 "type='signal',member='Oopsed'",
1927 "arg0='foobar',arg1='abcdef'",
1928 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
1929 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
1934 check_matches (dbus_bool_t expected_to_match,
1936 DBusMessage *message,
1937 const char *rule_text)
1940 dbus_bool_t matched;
1942 rule = check_parse (TRUE, rule_text);
1943 _dbus_assert (rule != NULL);
1945 /* We can't test sender/destination rules since we pass NULL here */
1946 matched = match_rule_matches (rule, NULL, NULL, message);
1948 if (matched != expected_to_match)
1950 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
1951 rule_text, expected_to_match ?
1952 "match" : "not match", number);
1956 bus_match_rule_unref (rule);
1960 check_matching (DBusMessage *message,
1962 const char **should_match,
1963 const char **should_not_match)
1968 while (should_match[i] != NULL)
1970 check_matches (TRUE, number, message, should_match[i]);
1975 while (should_not_match[i] != NULL)
1977 check_matches (FALSE, number, message, should_not_match[i]);
1983 test_matching (void)
1985 DBusMessage *message1;
1986 const char *v_STRING;
1987 dbus_int32_t v_INT32;
1989 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
1990 _dbus_assert (message1 != NULL);
1991 if (!dbus_message_set_member (message1, "Frobated"))
1992 _dbus_assert_not_reached ("oom");
1994 v_STRING = "foobar";
1996 if (!dbus_message_append_args (message1,
1997 DBUS_TYPE_STRING, &v_STRING,
1998 DBUS_TYPE_INT32, &v_INT32,
2000 _dbus_assert_not_reached ("oom");
2002 check_matching (message1, 1,
2003 should_match_message_1,
2004 should_not_match_message_1);
2006 dbus_message_unref (message1);
2010 bus_signals_test (const DBusString *test_data_dir)
2012 BusMatchmaker *matchmaker;
2014 matchmaker = bus_matchmaker_new ();
2015 bus_matchmaker_ref (matchmaker);
2016 bus_matchmaker_unref (matchmaker);
2017 bus_matchmaker_unref (matchmaker);
2019 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
2020 _dbus_assert_not_reached ("Parsing match rules test failed");
2029 #endif /* DBUS_BUILD_TESTS */