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 */
48 bus_match_rule_new (DBusConnection *matches_go_to)
52 rule = dbus_new0 (BusMatchRule, 1);
57 rule->matches_go_to = matches_go_to;
59 #ifndef DBUS_BUILD_TESTS
60 _dbus_assert (rule->matches_go_to != NULL);
67 bus_match_rule_ref (BusMatchRule *rule)
69 _dbus_assert (rule->refcount > 0);
77 bus_match_rule_unref (BusMatchRule *rule)
79 _dbus_assert (rule->refcount > 0);
82 if (rule->refcount == 0)
84 dbus_free (rule->interface);
85 dbus_free (rule->member);
86 dbus_free (rule->sender);
87 dbus_free (rule->destination);
88 dbus_free (rule->path);
90 /* can't use dbus_free_string_array() since there
98 while (i < rule->args_len)
101 dbus_free (rule->args[i]);
105 dbus_free (rule->args);
112 #ifdef DBUS_ENABLE_VERBOSE_MODE
113 /* Note this function does not do escaping, so it's only
114 * good for debug spew at the moment
117 match_rule_to_string (BusMatchRule *rule)
122 if (!_dbus_string_init (&str))
125 while ((s = _dbus_strdup ("nomem")) == NULL)
126 ; /* only OK for debug spew... */
130 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
132 /* FIXME make type readable */
133 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
137 if (rule->flags & BUS_MATCH_INTERFACE)
139 if (_dbus_string_get_length (&str) > 0)
141 if (!_dbus_string_append (&str, ","))
145 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
149 if (rule->flags & BUS_MATCH_MEMBER)
151 if (_dbus_string_get_length (&str) > 0)
153 if (!_dbus_string_append (&str, ","))
157 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
161 if (rule->flags & BUS_MATCH_PATH)
163 if (_dbus_string_get_length (&str) > 0)
165 if (!_dbus_string_append (&str, ","))
169 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
173 if (rule->flags & BUS_MATCH_SENDER)
175 if (_dbus_string_get_length (&str) > 0)
177 if (!_dbus_string_append (&str, ","))
181 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
185 if (rule->flags & BUS_MATCH_DESTINATION)
187 if (_dbus_string_get_length (&str) > 0)
189 if (!_dbus_string_append (&str, ","))
193 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
197 if (rule->flags & BUS_MATCH_ARGS)
201 _dbus_assert (rule->args != NULL);
204 while (i < rule->args_len)
206 if (rule->args[i] != NULL)
208 if (_dbus_string_get_length (&str) > 0)
210 if (!_dbus_string_append (&str, ","))
214 if (!_dbus_string_append_printf (&str,
225 if (!_dbus_string_steal_data (&str, &ret))
228 _dbus_string_free (&str);
232 _dbus_string_free (&str);
235 while ((s = _dbus_strdup ("nomem")) == NULL)
236 ; /* only OK for debug spew... */
240 #endif /* DBUS_ENABLE_VERBOSE_MODE */
243 bus_match_rule_set_message_type (BusMatchRule *rule,
246 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
248 rule->message_type = type;
254 bus_match_rule_set_interface (BusMatchRule *rule,
255 const char *interface)
259 _dbus_assert (interface != NULL);
261 new = _dbus_strdup (interface);
265 rule->flags |= BUS_MATCH_INTERFACE;
266 dbus_free (rule->interface);
267 rule->interface = new;
273 bus_match_rule_set_member (BusMatchRule *rule,
278 _dbus_assert (member != NULL);
280 new = _dbus_strdup (member);
284 rule->flags |= BUS_MATCH_MEMBER;
285 dbus_free (rule->member);
292 bus_match_rule_set_sender (BusMatchRule *rule,
297 _dbus_assert (sender != NULL);
299 new = _dbus_strdup (sender);
303 rule->flags |= BUS_MATCH_SENDER;
304 dbus_free (rule->sender);
311 bus_match_rule_set_destination (BusMatchRule *rule,
312 const char *destination)
316 _dbus_assert (destination != NULL);
318 new = _dbus_strdup (destination);
322 rule->flags |= BUS_MATCH_DESTINATION;
323 dbus_free (rule->destination);
324 rule->destination = new;
330 bus_match_rule_set_path (BusMatchRule *rule,
335 _dbus_assert (path != NULL);
337 new = _dbus_strdup (path);
341 rule->flags |= BUS_MATCH_PATH;
342 dbus_free (rule->path);
349 bus_match_rule_set_arg (BusMatchRule *rule,
355 _dbus_assert (value != NULL);
357 new = _dbus_strdup (value);
361 /* args_len is the number of args not including null termination
364 if (arg >= rule->args_len)
370 new_args_len = arg + 1;
372 /* add another + 1 here for null termination */
373 new_args = dbus_realloc (rule->args,
374 sizeof(rule->args[0]) * (new_args_len + 1));
375 if (new_args == NULL)
381 /* NULL the new slots */
383 while (i <= new_args_len) /* <= for null termination */
389 rule->args = new_args;
390 rule->args_len = new_args_len;
393 rule->flags |= BUS_MATCH_ARGS;
395 dbus_free (rule->args[arg]);
396 rule->args[arg] = new;
398 /* NULL termination didn't get busted */
399 _dbus_assert (rule->args[rule->args_len] == NULL);
404 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
407 find_key (const DBusString *str,
415 const char *key_start;
418 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
420 s = _dbus_string_get_const_data (str);
424 while (*p && ISWHITE (*p))
429 while (*p && *p != '=' && !ISWHITE (*p))
434 while (*p && ISWHITE (*p))
437 if (key_start == key_end)
439 /* Empty match rules or trailing whitespace are OK */
446 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
447 "Match rule has a key with no subsequent '=' character");
452 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
464 find_value (const DBusString *str,
476 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
478 orig_len = _dbus_string_get_length (value);
480 s = _dbus_string_get_const_data (str);
488 if (quote_char == '\0')
508 if (!_dbus_string_append_byte (value, *p))
515 else if (quote_char == '\\')
517 /* \ only counts as an escape if escaping a quote mark */
520 if (!_dbus_string_append_byte (value, '\\'))
527 if (!_dbus_string_append_byte (value, *p))
537 _dbus_assert (quote_char == '\'');
545 if (!_dbus_string_append_byte (value, *p))
559 if (quote_char == '\\')
561 if (!_dbus_string_append_byte (value, '\\'))
567 else if (quote_char == '\'')
569 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
570 "Unbalanced quotation marks in match rule");
574 _dbus_assert (quote_char == '\0');
576 /* Zero-length values are allowed */
583 _DBUS_ASSERT_ERROR_IS_SET (error);
584 _dbus_string_set_length (value, orig_len);
588 /* duplicates aren't allowed so the real legitimate max is only 6 or
589 * so. Leaving extra so we don't have to bother to update it.
590 * FIXME this is sort of busted now with arg matching, but we let
591 * you match on up to 10 args for now
593 #define MAX_RULE_TOKENS 16
595 /* this is slightly too high level to be termed a "token"
596 * but let's not be pedantic.
605 tokenize_rule (const DBusString *rule_text,
606 RuleToken tokens[MAX_RULE_TOKENS],
617 if (!_dbus_string_init (&key))
623 if (!_dbus_string_init (&value))
625 _dbus_string_free (&key);
632 while (i < MAX_RULE_TOKENS &&
633 pos < _dbus_string_get_length (rule_text))
635 _dbus_assert (tokens[i].key == NULL);
636 _dbus_assert (tokens[i].value == NULL);
638 if (!find_key (rule_text, pos, &key, &pos, error))
641 if (_dbus_string_get_length (&key) == 0)
644 if (!_dbus_string_steal_data (&key, &tokens[i].key))
650 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
653 if (!_dbus_string_steal_data (&value, &tokens[i].value))
669 while (tokens[i].key || tokens[i].value)
671 dbus_free (tokens[i].key);
672 dbus_free (tokens[i].value);
673 tokens[i].key = NULL;
674 tokens[i].value = NULL;
679 _dbus_string_free (&key);
680 _dbus_string_free (&value);
686 bus_match_rule_parse_arg_match (BusMatchRule *rule,
688 const DBusString *value,
695 /* For now, arg0='foo' always implies that 'foo' is a
696 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
697 * if we wanted, which would specify another type, in which case
698 * arg0='5' would have the 5 parsed as an int rather than string.
701 /* First we need to parse arg0 = 0, arg27 = 27 */
703 _dbus_string_init_const (&key_str, key);
705 if (_dbus_string_get_length (&key_str) < 4)
707 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
708 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
712 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end) ||
713 end != _dbus_string_get_length (&key_str))
715 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
716 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
720 /* If we didn't check this we could allocate a huge amount of RAM */
721 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
723 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
724 "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);
728 if ((rule->flags & BUS_MATCH_ARGS) &&
729 rule->args_len > (int) arg &&
730 rule->args[arg] != NULL)
732 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
733 "Key '%s' specified twice in match rule\n", key);
737 if (!bus_match_rule_set_arg (rule, arg,
738 _dbus_string_get_const_data (value)))
747 _DBUS_ASSERT_ERROR_IS_SET (error);
752 * The format is comma-separated with strings quoted with single quotes
753 * as for the shell (to escape a literal single quote, use '\'').
755 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
756 * path='/bar/foo',destination=':452345.34'
760 bus_match_rule_parse (DBusConnection *matches_go_to,
761 const DBusString *rule_text,
765 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
768 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
770 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
772 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
773 "Match rule text is %d bytes, maximum is %d",
774 _dbus_string_get_length (rule_text),
775 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
779 memset (tokens, '\0', sizeof (tokens));
781 rule = bus_match_rule_new (matches_go_to);
788 if (!tokenize_rule (rule_text, tokens, error))
792 while (tokens[i].key != NULL)
796 const char *key = tokens[i].key;
797 const char *value = tokens[i].value;
799 _dbus_string_init_const (&tmp_str, value);
800 len = _dbus_string_get_length (&tmp_str);
802 if (strcmp (key, "type") == 0)
806 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
808 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
809 "Key %s specified twice in match rule\n", key);
813 t = dbus_message_type_from_string (value);
815 if (t == DBUS_MESSAGE_TYPE_INVALID)
817 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
818 "Invalid message type (%s) in match rule\n", value);
822 if (!bus_match_rule_set_message_type (rule, t))
828 else if (strcmp (key, "sender") == 0)
830 if (rule->flags & BUS_MATCH_SENDER)
832 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
833 "Key %s specified twice in match rule\n", key);
837 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
839 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
840 "Sender name '%s' is invalid\n", value);
844 if (!bus_match_rule_set_sender (rule, value))
850 else if (strcmp (key, "interface") == 0)
852 if (rule->flags & BUS_MATCH_INTERFACE)
854 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
855 "Key %s specified twice in match rule\n", key);
859 if (!_dbus_validate_interface (&tmp_str, 0, len))
861 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
862 "Interface name '%s' is invalid\n", value);
866 if (!bus_match_rule_set_interface (rule, value))
872 else if (strcmp (key, "member") == 0)
874 if (rule->flags & BUS_MATCH_MEMBER)
876 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
877 "Key %s specified twice in match rule\n", key);
881 if (!_dbus_validate_member (&tmp_str, 0, len))
883 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
884 "Member name '%s' is invalid\n", value);
888 if (!bus_match_rule_set_member (rule, value))
894 else if (strcmp (key, "path") == 0)
896 if (rule->flags & BUS_MATCH_PATH)
898 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
899 "Key %s specified twice in match rule\n", key);
903 if (!_dbus_validate_path (&tmp_str, 0, len))
905 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
906 "Path '%s' is invalid\n", value);
910 if (!bus_match_rule_set_path (rule, value))
916 else if (strcmp (key, "destination") == 0)
918 if (rule->flags & BUS_MATCH_DESTINATION)
920 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
921 "Key %s specified twice in match rule\n", key);
925 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
927 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
928 "Destination name '%s' is invalid\n", value);
932 if (!bus_match_rule_set_destination (rule, value))
938 else if (strncmp (key, "arg", 3) == 0)
940 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
945 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
946 "Unknown key \"%s\" in match rule",
958 _DBUS_ASSERT_ERROR_IS_SET (error);
961 bus_match_rule_unref (rule);
968 while (tokens[i].key || tokens[i].value)
970 _dbus_assert (i < MAX_RULE_TOKENS);
971 dbus_free (tokens[i].key);
972 dbus_free (tokens[i].value);
987 bus_matchmaker_new (void)
989 BusMatchmaker *matchmaker;
991 matchmaker = dbus_new0 (BusMatchmaker, 1);
992 if (matchmaker == NULL)
995 matchmaker->refcount = 1;
1001 bus_matchmaker_ref (BusMatchmaker *matchmaker)
1003 _dbus_assert (matchmaker->refcount > 0);
1005 matchmaker->refcount += 1;
1011 bus_matchmaker_unref (BusMatchmaker *matchmaker)
1013 _dbus_assert (matchmaker->refcount > 0);
1015 matchmaker->refcount -= 1;
1016 if (matchmaker->refcount == 0)
1018 while (matchmaker->all_rules != NULL)
1022 rule = matchmaker->all_rules->data;
1023 bus_match_rule_unref (rule);
1024 _dbus_list_remove_link (&matchmaker->all_rules,
1025 matchmaker->all_rules);
1028 dbus_free (matchmaker);
1032 /* The rule can't be modified after it's added. */
1034 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1037 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
1039 if (!_dbus_list_append (&matchmaker->all_rules, rule))
1042 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1044 _dbus_list_remove_last (&matchmaker->all_rules, rule);
1048 bus_match_rule_ref (rule);
1050 #ifdef DBUS_ENABLE_VERBOSE_MODE
1052 char *s = match_rule_to_string (rule);
1054 _dbus_verbose ("Added match rule %s to connection %p\n",
1055 s, rule->matches_go_to);
1064 match_rule_equal (BusMatchRule *a,
1067 if (a->flags != b->flags)
1070 if (a->matches_go_to != b->matches_go_to)
1073 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
1074 a->message_type != b->message_type)
1077 if ((a->flags & BUS_MATCH_MEMBER) &&
1078 strcmp (a->member, b->member) != 0)
1081 if ((a->flags & BUS_MATCH_PATH) &&
1082 strcmp (a->path, b->path) != 0)
1085 if ((a->flags & BUS_MATCH_INTERFACE) &&
1086 strcmp (a->interface, b->interface) != 0)
1089 if ((a->flags & BUS_MATCH_SENDER) &&
1090 strcmp (a->sender, b->sender) != 0)
1093 if ((a->flags & BUS_MATCH_DESTINATION) &&
1094 strcmp (a->destination, b->destination) != 0)
1097 if (a->flags & BUS_MATCH_ARGS)
1101 if (a->args_len != b->args_len)
1105 while (i < a->args_len)
1107 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1110 if (a->args[i] != NULL)
1112 _dbus_assert (b->args[i] != NULL);
1113 if (strcmp (a->args[i], b->args[i]) != 0)
1125 bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
1128 BusMatchRule *rule = link->data;
1130 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1131 _dbus_list_remove_link (&matchmaker->all_rules, link);
1133 #ifdef DBUS_ENABLE_VERBOSE_MODE
1135 char *s = match_rule_to_string (rule);
1137 _dbus_verbose ("Removed match rule %s for connection %p\n",
1138 s, rule->matches_go_to);
1143 bus_match_rule_unref (rule);
1147 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1150 bus_connection_remove_match_rule (rule->matches_go_to, rule);
1151 _dbus_list_remove (&matchmaker->all_rules, rule);
1153 #ifdef DBUS_ENABLE_VERBOSE_MODE
1155 char *s = match_rule_to_string (rule);
1157 _dbus_verbose ("Removed match rule %s for connection %p\n",
1158 s, rule->matches_go_to);
1163 bus_match_rule_unref (rule);
1166 /* Remove a single rule which is equal to the given rule by value */
1168 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
1169 BusMatchRule *value,
1172 /* FIXME this is an unoptimized linear scan */
1176 /* we traverse backward because bus_connection_remove_match_rule()
1177 * removes the most-recently-added rule
1179 link = _dbus_list_get_last_link (&matchmaker->all_rules);
1180 while (link != NULL)
1186 prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
1188 if (match_rule_equal (rule, value))
1190 bus_matchmaker_remove_rule_link (matchmaker, link);
1199 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1200 "The given match rule wasn't found and can't be removed");
1208 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1209 DBusConnection *disconnected)
1215 * This scans all match rules on the bus. We could avoid that
1216 * for the rules belonging to the connection, since we keep
1217 * a list of those; but for the rules that just refer to
1218 * the connection we'd need to do something more elaborate.
1222 _dbus_assert (bus_connection_is_active (disconnected));
1224 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1225 while (link != NULL)
1231 next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1233 if (rule->matches_go_to == disconnected)
1235 bus_matchmaker_remove_rule_link (matchmaker, link);
1237 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1238 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1240 /* The rule matches to/from a base service, see if it's the
1241 * one being disconnected, since we know this service name
1242 * will never be recycled.
1246 name = bus_connection_get_name (disconnected);
1247 _dbus_assert (name != NULL); /* because we're an active connection */
1249 if (((rule->flags & BUS_MATCH_SENDER) &&
1250 strcmp (rule->sender, name) == 0) ||
1251 ((rule->flags & BUS_MATCH_DESTINATION) &&
1252 strcmp (rule->destination, name) == 0))
1254 bus_matchmaker_remove_rule_link (matchmaker, link);
1263 connection_is_primary_owner (DBusConnection *connection,
1264 const char *service_name)
1266 BusService *service;
1268 BusRegistry *registry;
1270 _dbus_assert (connection != NULL);
1272 registry = bus_connection_get_registry (connection);
1274 _dbus_string_init_const (&str, service_name);
1275 service = bus_registry_lookup (registry, &str);
1277 if (service == NULL)
1278 return FALSE; /* Service doesn't exist so connection can't own it. */
1280 return bus_service_get_primary_owners_connection (service) == connection;
1284 match_rule_matches (BusMatchRule *rule,
1285 DBusConnection *sender,
1286 DBusConnection *addressed_recipient,
1287 DBusMessage *message)
1289 /* All features of the match rule are AND'd together,
1290 * so FALSE if any of them don't match.
1293 /* sender/addressed_recipient of #NULL may mean bus driver,
1294 * or for addressed_recipient may mean a message with no
1295 * specific recipient (i.e. a signal)
1298 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
1300 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1302 if (rule->message_type != dbus_message_get_type (message))
1306 if (rule->flags & BUS_MATCH_INTERFACE)
1310 _dbus_assert (rule->interface != NULL);
1312 iface = dbus_message_get_interface (message);
1316 if (strcmp (iface, rule->interface) != 0)
1320 if (rule->flags & BUS_MATCH_MEMBER)
1324 _dbus_assert (rule->member != NULL);
1326 member = dbus_message_get_member (message);
1330 if (strcmp (member, rule->member) != 0)
1334 if (rule->flags & BUS_MATCH_SENDER)
1336 _dbus_assert (rule->sender != NULL);
1340 if (strcmp (rule->sender,
1341 DBUS_SERVICE_DBUS) != 0)
1346 if (!connection_is_primary_owner (sender, rule->sender))
1351 if (rule->flags & BUS_MATCH_DESTINATION)
1353 const char *destination;
1355 _dbus_assert (rule->destination != NULL);
1357 destination = dbus_message_get_destination (message);
1358 if (destination == NULL)
1361 if (addressed_recipient == NULL)
1363 if (strcmp (rule->destination,
1364 DBUS_SERVICE_DBUS) != 0)
1369 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1374 if (rule->flags & BUS_MATCH_PATH)
1378 _dbus_assert (rule->path != NULL);
1380 path = dbus_message_get_path (message);
1384 if (strcmp (path, rule->path) != 0)
1388 if (rule->flags & BUS_MATCH_ARGS)
1391 DBusMessageIter iter;
1393 _dbus_assert (rule->args != NULL);
1395 dbus_message_iter_init (message, &iter);
1398 while (i < rule->args_len)
1401 const char *expected_arg;
1403 expected_arg = rule->args[i];
1405 current_type = dbus_message_iter_get_arg_type (&iter);
1407 if (expected_arg != NULL)
1409 const char *actual_arg;
1411 if (current_type != DBUS_TYPE_STRING)
1415 dbus_message_iter_get_basic (&iter, &actual_arg);
1416 _dbus_assert (actual_arg != NULL);
1418 if (strcmp (expected_arg, actual_arg) != 0)
1422 if (current_type != DBUS_TYPE_INVALID)
1423 dbus_message_iter_next (&iter);
1433 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1434 BusConnections *connections,
1435 DBusConnection *sender,
1436 DBusConnection *addressed_recipient,
1437 DBusMessage *message,
1438 DBusList **recipients_p)
1440 /* FIXME for now this is a wholly unoptimized linear search */
1441 /* Guessing the important optimization is to skip the signal-related
1442 * match lists when processing method call and exception messages.
1443 * So separate match rule lists for signals?
1448 _dbus_assert (*recipients_p == NULL);
1450 /* This avoids sending same message to the same connection twice.
1451 * Purpose of the stamp instead of a bool is to avoid iterating over
1452 * all connections resetting the bool each time.
1454 bus_connections_increment_stamp (connections);
1456 /* addressed_recipient is already receiving the message, don't add to list.
1457 * NULL addressed_recipient means either bus driver, or this is a signal
1458 * and thus lacks a specific addressed_recipient.
1460 if (addressed_recipient != NULL)
1461 bus_connection_mark_stamp (addressed_recipient);
1463 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1464 while (link != NULL)
1470 #ifdef DBUS_ENABLE_VERBOSE_MODE
1472 char *s = match_rule_to_string (rule);
1474 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1475 s, rule->matches_go_to);
1480 if (match_rule_matches (rule,
1481 sender, addressed_recipient, message))
1483 _dbus_verbose ("Rule matched\n");
1485 /* Append to the list if we haven't already */
1486 if (bus_connection_mark_stamp (rule->matches_go_to))
1488 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1491 #ifdef DBUS_ENABLE_VERBOSE_MODE
1494 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1496 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1499 link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1505 _dbus_list_clear (recipients_p);
1509 #ifdef DBUS_BUILD_TESTS
1513 static BusMatchRule*
1514 check_parse (dbus_bool_t should_succeed,
1521 dbus_error_init (&error);
1523 _dbus_string_init_const (&str, text);
1525 rule = bus_match_rule_parse (NULL, &str, &error);
1526 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1528 dbus_error_free (&error);
1532 if (should_succeed && rule == NULL)
1534 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1535 error.name, error.message,
1536 _dbus_string_get_const_data (&str));
1540 if (!should_succeed && rule != NULL)
1542 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1543 _dbus_string_get_const_data (&str));
1547 dbus_error_free (&error);
1553 assert_large_rule (BusMatchRule *rule)
1555 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1556 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1557 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1558 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1559 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1560 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1562 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1563 _dbus_assert (rule->interface != NULL);
1564 _dbus_assert (rule->member != NULL);
1565 _dbus_assert (rule->sender != NULL);
1566 _dbus_assert (rule->destination != NULL);
1567 _dbus_assert (rule->path != NULL);
1569 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1570 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1571 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1572 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1573 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
1577 test_parsing (void *data)
1581 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
1584 assert_large_rule (rule);
1585 bus_match_rule_unref (rule);
1588 /* With extra whitespace and useless quotes */
1589 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
1592 assert_large_rule (rule);
1593 bus_match_rule_unref (rule);
1597 /* A simple signal connection */
1598 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1601 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1602 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1603 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1605 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1606 _dbus_assert (rule->interface != NULL);
1607 _dbus_assert (rule->path != NULL);
1609 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
1610 _dbus_assert (strcmp (rule->path, "/foo") == 0);
1612 bus_match_rule_unref (rule);
1616 rule = check_parse (TRUE, "arg0='foo'");
1619 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1620 _dbus_assert (rule->args != NULL);
1621 _dbus_assert (rule->args_len == 1);
1622 _dbus_assert (rule->args[0] != NULL);
1623 _dbus_assert (rule->args[1] == NULL);
1624 _dbus_assert (strcmp (rule->args[0], "foo") == 0);
1626 bus_match_rule_unref (rule);
1629 rule = check_parse (TRUE, "arg1='foo'");
1632 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1633 _dbus_assert (rule->args != NULL);
1634 _dbus_assert (rule->args_len == 2);
1635 _dbus_assert (rule->args[0] == NULL);
1636 _dbus_assert (rule->args[1] != NULL);
1637 _dbus_assert (rule->args[2] == NULL);
1638 _dbus_assert (strcmp (rule->args[1], "foo") == 0);
1640 bus_match_rule_unref (rule);
1643 rule = check_parse (TRUE, "arg2='foo'");
1646 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1647 _dbus_assert (rule->args != NULL);
1648 _dbus_assert (rule->args_len == 3);
1649 _dbus_assert (rule->args[0] == NULL);
1650 _dbus_assert (rule->args[1] == NULL);
1651 _dbus_assert (rule->args[2] != NULL);
1652 _dbus_assert (rule->args[3] == NULL);
1653 _dbus_assert (strcmp (rule->args[2], "foo") == 0);
1655 bus_match_rule_unref (rule);
1658 rule = check_parse (TRUE, "arg40='foo'");
1661 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1662 _dbus_assert (rule->args != NULL);
1663 _dbus_assert (rule->args_len == 41);
1664 _dbus_assert (rule->args[0] == NULL);
1665 _dbus_assert (rule->args[1] == NULL);
1666 _dbus_assert (rule->args[40] != NULL);
1667 _dbus_assert (rule->args[41] == NULL);
1668 _dbus_assert (strcmp (rule->args[40], "foo") == 0);
1670 bus_match_rule_unref (rule);
1673 rule = check_parse (TRUE, "arg63='foo'");
1676 _dbus_assert (rule->flags == BUS_MATCH_ARGS);
1677 _dbus_assert (rule->args != NULL);
1678 _dbus_assert (rule->args_len == 64);
1679 _dbus_assert (rule->args[0] == NULL);
1680 _dbus_assert (rule->args[1] == NULL);
1681 _dbus_assert (rule->args[63] != NULL);
1682 _dbus_assert (rule->args[64] == NULL);
1683 _dbus_assert (strcmp (rule->args[63], "foo") == 0);
1685 bus_match_rule_unref (rule);
1688 /* Too-large argN */
1689 rule = check_parse (FALSE, "arg300='foo'");
1690 _dbus_assert (rule == NULL);
1691 rule = check_parse (FALSE, "arg64='foo'");
1692 _dbus_assert (rule == NULL);
1695 rule = check_parse (FALSE, "arg='foo'");
1696 _dbus_assert (rule == NULL);
1697 rule = check_parse (FALSE, "argv='foo'");
1698 _dbus_assert (rule == NULL);
1699 rule = check_parse (FALSE, "arg3junk='foo'");
1700 _dbus_assert (rule == NULL);
1701 rule = check_parse (FALSE, "argument='foo'");
1702 _dbus_assert (rule == NULL);
1704 /* Reject duplicates */
1705 rule = check_parse (FALSE, "type='signal',type='method_call'");
1706 _dbus_assert (rule == NULL);
1708 /* Duplicates with the argN code */
1709 rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
1710 _dbus_assert (rule == NULL);
1711 rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
1712 _dbus_assert (rule == NULL);
1713 rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
1714 _dbus_assert (rule == NULL);
1716 /* Reject broken keys */
1717 rule = check_parse (FALSE, "blah='signal'");
1718 _dbus_assert (rule == NULL);
1720 /* Reject broken values */
1721 rule = check_parse (FALSE, "type='chouin'");
1722 _dbus_assert (rule == NULL);
1723 rule = check_parse (FALSE, "interface='abc@def++'");
1724 _dbus_assert (rule == NULL);
1725 rule = check_parse (FALSE, "service='youpi'");
1726 _dbus_assert (rule == NULL);
1728 /* Allow empty rule */
1729 rule = check_parse (TRUE, "");
1732 _dbus_assert (rule->flags == 0);
1734 bus_match_rule_unref (rule);
1737 /* All-whitespace rule is the same as empty */
1738 rule = check_parse (TRUE, " \t");
1741 _dbus_assert (rule->flags == 0);
1743 bus_match_rule_unref (rule);
1746 /* But with non-whitespace chars and no =value, it's not OK */
1747 rule = check_parse (FALSE, "type");
1748 _dbus_assert (rule == NULL);
1756 } equality_tests[] = {
1757 { "type='signal'", "type='signal'" },
1758 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
1759 { "type='signal',member='bar'", "member='bar',type='signal'" },
1760 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
1761 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
1762 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
1763 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
1764 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
1765 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
1766 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
1767 { "arg3='fool'", "arg3='fool'" },
1768 { "member='food'", "member='food'" }
1772 test_equality (void)
1777 while (i < _DBUS_N_ELEMENTS (equality_tests))
1779 BusMatchRule *first;
1780 BusMatchRule *second;
1783 first = check_parse (TRUE, equality_tests[i].first);
1784 _dbus_assert (first != NULL);
1785 second = check_parse (TRUE, equality_tests[i].second);
1786 _dbus_assert (second != NULL);
1788 if (!match_rule_equal (first, second))
1790 _dbus_warn ("rule %s and %s should have been equal\n",
1791 equality_tests[i].first,
1792 equality_tests[i].second);
1796 bus_match_rule_unref (second);
1798 /* Check that the rule is not equal to any of the
1799 * others besides its pair match
1802 while (j < _DBUS_N_ELEMENTS (equality_tests))
1806 second = check_parse (TRUE, equality_tests[j].second);
1808 if (match_rule_equal (first, second))
1810 _dbus_warn ("rule %s and %s should not have been equal\n",
1811 equality_tests[i].first,
1812 equality_tests[j].second);
1816 bus_match_rule_unref (second);
1822 bus_match_rule_unref (first);
1829 should_match_message_1[] = {
1831 "member='Frobated'",
1833 "type='signal',member='Frobated'",
1834 "type='signal',member='Frobated',arg0='foobar'",
1835 "member='Frobated',arg0='foobar'",
1836 "type='signal',arg0='foobar'",
1841 should_not_match_message_1[] = {
1842 "type='method_call'",
1844 "type='method_return'",
1845 "type='signal',member='Oopsed'",
1852 "arg0='foobar',arg1='abcdef'",
1853 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
1854 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
1859 check_matches (dbus_bool_t expected_to_match,
1861 DBusMessage *message,
1862 const char *rule_text)
1865 dbus_bool_t matched;
1867 rule = check_parse (TRUE, rule_text);
1868 _dbus_assert (rule != NULL);
1870 /* We can't test sender/destination rules since we pass NULL here */
1871 matched = match_rule_matches (rule, NULL, NULL, message);
1873 if (matched != expected_to_match)
1875 _dbus_warn ("Expected rule %s to %s message %d, failed\n",
1876 rule_text, expected_to_match ?
1877 "match" : "not match", number);
1881 bus_match_rule_unref (rule);
1885 check_matching (DBusMessage *message,
1887 const char **should_match,
1888 const char **should_not_match)
1893 while (should_match[i] != NULL)
1895 check_matches (TRUE, number, message, should_match[i]);
1900 while (should_not_match[i] != NULL)
1902 check_matches (FALSE, number, message, should_not_match[i]);
1908 test_matching (void)
1910 DBusMessage *message1;
1911 const char *v_STRING;
1912 dbus_int32_t v_INT32;
1914 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
1915 _dbus_assert (message1 != NULL);
1916 if (!dbus_message_set_member (message1, "Frobated"))
1917 _dbus_assert_not_reached ("oom");
1919 v_STRING = "foobar";
1921 if (!dbus_message_append_args (message1,
1922 DBUS_TYPE_STRING, &v_STRING,
1923 DBUS_TYPE_INT32, &v_INT32,
1925 _dbus_assert_not_reached ("oom");
1927 check_matching (message1, 1,
1928 should_match_message_1,
1929 should_not_match_message_1);
1931 dbus_message_unref (message1);
1935 bus_signals_test (const DBusString *test_data_dir)
1937 BusMatchmaker *matchmaker;
1939 matchmaker = bus_matchmaker_new ();
1940 bus_matchmaker_ref (matchmaker);
1941 bus_matchmaker_unref (matchmaker);
1942 bus_matchmaker_unref (matchmaker);
1944 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
1945 _dbus_assert_not_reached ("Parsing match rules test failed");
1954 #endif /* DBUS_BUILD_TESTS */