1 /* signals.c Bus signal connection implementation
3 * Copyright (C) 2003, 2005 Red Hat, Inc.
4 * Copyright 2014 Samsung Electronics
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
25 #include "dbus-signals.h"
26 #include <dbus/dbus-marshal-validate.h>
27 #include "dbus-internals.h"
28 #include "dbus-hash.h"
29 #include "dbus-list.h"
30 #include "kdbus-common.h"
34 #define SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, "Memory allocation failure in transport, regarding match rules")
38 int refcount; /**< reference count */
40 DBusConnection *matches_go_to; /**< Owner of the rule */
42 unsigned int flags; /**< MatchFlags */
51 unsigned int *arg_lens;
58 #define MATCH_ARG_FLAGS (MATCH_ARG_NAMESPACE |MATCH_ARG_IS_PATH)
61 bus_match_rule_new (DBusConnection *matches_go_to)
65 rule = dbus_new0 (MatchRule, 1);
70 rule->matches_go_to = matches_go_to;
71 rule->kdbus_cookie = 0;
73 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
74 _dbus_assert (rule->matches_go_to != NULL);
81 bus_match_rule_ref (MatchRule *rule)
83 _dbus_assert (rule->refcount > 0);
91 match_rule_unref (MatchRule *rule)
93 _dbus_assert (rule->refcount > 0);
96 if (rule->refcount == 0)
98 dbus_free (rule->interface);
99 dbus_free (rule->member);
100 dbus_free (rule->sender);
101 dbus_free (rule->destination);
102 dbus_free (rule->path);
103 dbus_free (rule->arg_lens);
105 /* can't use dbus_free_string_array() since there
113 while (i < rule->args_len)
116 dbus_free (rule->args[i]);
120 dbus_free (rule->args);
127 #ifdef DBUS_ENABLE_VERBOSE_MODE
128 /* Note this function does not do escaping, so it's only
129 * good for debug spew at the moment
132 match_rule_to_string (MatchRule *rule)
137 if (!_dbus_string_init (&str))
140 while ((s = _dbus_strdup ("nomem")) == NULL)
141 ; /* only OK for debug spew... */
145 if (rule->flags & MATCH_MESSAGE_TYPE)
147 if (!_dbus_string_append_printf (&str, "type='%s'",
148 dbus_message_type_to_string (rule->message_type)))
152 if (rule->flags & MATCH_INTERFACE)
154 if (_dbus_string_get_length (&str) > 0)
156 if (!_dbus_string_append (&str, ","))
160 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
164 if (rule->flags & MATCH_MEMBER)
166 if (_dbus_string_get_length (&str) > 0)
168 if (!_dbus_string_append (&str, ","))
172 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
176 if (rule->flags & MATCH_PATH)
178 if (_dbus_string_get_length (&str) > 0)
180 if (!_dbus_string_append (&str, ","))
184 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
188 if (rule->flags & MATCH_PATH_NAMESPACE)
190 if (_dbus_string_get_length (&str) > 0)
192 if (!_dbus_string_append (&str, ","))
196 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
200 if (rule->flags & MATCH_SENDER)
202 if (_dbus_string_get_length (&str) > 0)
204 if (!_dbus_string_append (&str, ","))
208 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
212 if (rule->flags & MATCH_DESTINATION)
214 if (_dbus_string_get_length (&str) > 0)
216 if (!_dbus_string_append (&str, ","))
220 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
224 if (rule->flags & MATCH_CLIENT_IS_EAVESDROPPING)
226 if (_dbus_string_get_length (&str) > 0)
228 if (!_dbus_string_append (&str, ","))
232 if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
233 (rule->flags & MATCH_CLIENT_IS_EAVESDROPPING) ?
238 if (rule->flags &MATCH_ARGS)
242 _dbus_assert (rule->args != NULL);
245 while (i < rule->args_len)
247 if (rule->args[i] != NULL)
249 dbus_bool_t is_path, is_namespace;
251 if (_dbus_string_get_length (&str) > 0)
253 if (!_dbus_string_append (&str, ","))
257 is_path = (rule->arg_lens[i] & MATCH_ARG_IS_PATH) != 0;
258 is_namespace = (rule->arg_lens[i] & MATCH_ARG_NAMESPACE) != 0;
260 if (!_dbus_string_append_printf (&str,
264 is_namespace ? "namespace" : "",
273 if (!_dbus_string_steal_data (&str, &ret))
276 _dbus_string_free (&str);
280 _dbus_string_free (&str);
283 while ((s = _dbus_strdup ("nomem")) == NULL)
284 ; /* only OK for debug spew... */
288 #endif /* DBUS_ENABLE_VERBOSE_MODE */
291 bus_match_rule_set_message_type (MatchRule *rule,
294 rule->flags |=MATCH_MESSAGE_TYPE;
296 rule->message_type = type;
302 bus_match_rule_set_interface (MatchRule *rule,
303 const char *interface)
307 _dbus_assert (interface != NULL);
309 new = _dbus_strdup (interface);
313 rule->flags |=MATCH_INTERFACE;
314 dbus_free (rule->interface);
315 rule->interface = new;
321 bus_match_rule_set_member (MatchRule *rule,
326 _dbus_assert (member != NULL);
328 new = _dbus_strdup (member);
332 rule->flags |=MATCH_MEMBER;
333 dbus_free (rule->member);
340 bus_match_rule_set_sender (MatchRule *rule,
345 _dbus_assert (sender != NULL);
347 new = _dbus_strdup (sender);
351 rule->flags |=MATCH_SENDER;
352 dbus_free (rule->sender);
359 bus_match_rule_set_destination (MatchRule *rule,
360 const char *destination)
364 _dbus_assert (destination != NULL);
366 new = _dbus_strdup (destination);
370 rule->flags |=MATCH_DESTINATION;
371 dbus_free (rule->destination);
372 rule->destination = new;
378 bus_match_rule_set_client_is_eavesdropping (MatchRule *rule,
379 dbus_bool_t is_eavesdropping)
381 if (is_eavesdropping)
382 rule->flags |= MATCH_CLIENT_IS_EAVESDROPPING;
384 rule->flags &= ~(MATCH_CLIENT_IS_EAVESDROPPING);
388 bus_match_rule_set_path (MatchRule *rule,
390 dbus_bool_t is_namespace)
394 _dbus_assert (path != NULL);
396 new = _dbus_strdup (path);
400 rule->flags &= ~(MATCH_PATH | MATCH_PATH_NAMESPACE);
403 rule->flags |= MATCH_PATH_NAMESPACE;
405 rule->flags |= MATCH_PATH;
407 dbus_free (rule->path);
414 bus_match_rule_set_arg (MatchRule *rule,
416 const DBusString *value,
418 dbus_bool_t is_namespace)
423 _dbus_assert (value != NULL);
425 /* args_len is the number of args not including null termination
428 if (arg >= rule->args_len)
430 unsigned int *new_arg_lens;
435 new_args_len = arg + 1;
437 /* add another + 1 here for null termination */
438 new_args = dbus_realloc (rule->args,
439 sizeof (char *) * (new_args_len + 1));
440 if (new_args == NULL)
443 /* NULL the new slots */
445 while (i <= new_args_len) /* <= for null termination */
451 rule->args = new_args;
453 /* and now add to the lengths */
454 new_arg_lens = dbus_realloc (rule->arg_lens,
455 sizeof (int) * (new_args_len + 1));
457 if (new_arg_lens == NULL)
460 /* zero the new slots */
462 while (i <= new_args_len) /* <= for null termination */
468 rule->arg_lens = new_arg_lens;
469 rule->args_len = new_args_len;
472 length = _dbus_string_get_length (value);
473 if (!_dbus_string_copy_data (value, &new))
476 rule->flags |=MATCH_ARGS;
478 dbus_free (rule->args[arg]);
479 rule->arg_lens[arg] = length;
480 rule->args[arg] = new;
483 rule->arg_lens[arg] |=MATCH_ARG_IS_PATH;
486 rule->arg_lens[arg] |=MATCH_ARG_NAMESPACE;
488 /* NULL termination didn't get busted */
489 _dbus_assert (rule->args[rule->args_len] == NULL);
490 _dbus_assert (rule->arg_lens[rule->args_len] == 0);
496 match_rule_set_cookie (MatchRule *rule, dbus_uint64_t cookie)
498 rule->kdbus_cookie = cookie;
502 match_rule_get_cookie (MatchRule *rule)
504 return rule->kdbus_cookie;
507 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
510 find_key (const DBusString *str,
518 const char *key_start;
521 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
523 s = _dbus_string_get_const_data (str);
527 while (*p && ISWHITE (*p))
532 while (*p && *p != '=' && !ISWHITE (*p))
537 while (*p && ISWHITE (*p))
540 if (key_start == key_end)
542 /* Empty match rules or trailing whitespace are OK */
549 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
550 "Match rule has a key with no subsequent '=' character");
555 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
567 find_value (const DBusString *str,
579 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
581 orig_len = _dbus_string_get_length (value);
583 s = _dbus_string_get_const_data (str);
591 if (quote_char == '\0')
611 if (!_dbus_string_append_byte (value, *p))
618 else if (quote_char == '\\')
620 /* \ only counts as an escape if escaping a quote mark */
623 if (!_dbus_string_append_byte (value, '\\'))
630 if (!_dbus_string_append_byte (value, *p))
640 _dbus_assert (quote_char == '\'');
648 if (!_dbus_string_append_byte (value, *p))
662 if (quote_char == '\\')
664 if (!_dbus_string_append_byte (value, '\\'))
670 else if (quote_char == '\'')
672 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
673 "Unbalanced quotation marks in match rule");
677 _dbus_assert (quote_char == '\0');
679 /* Zero-length values are allowed */
686 _DBUS_ASSERT_ERROR_IS_SET (error);
687 _dbus_string_set_length (value, orig_len);
691 /* duplicates aren't allowed so the real legitimate max is only 6 or
692 * so. Leaving extra so we don't have to bother to update it.
693 * FIXME this is sort of busted now with arg matching, but we let
694 * you match on up to 10 args for now
696 #define MAX_RULE_TOKENS 16
698 /* this is slightly too high level to be termed a "token"
699 * but let's not be pedantic.
708 tokenize_rule (const DBusString *rule_text,
709 RuleToken tokens[MAX_RULE_TOKENS],
720 if (!_dbus_string_init (&key))
726 if (!_dbus_string_init (&value))
728 _dbus_string_free (&key);
735 while (i < MAX_RULE_TOKENS &&
736 pos < _dbus_string_get_length (rule_text))
738 _dbus_assert (tokens[i].key == NULL);
739 _dbus_assert (tokens[i].value == NULL);
741 if (!find_key (rule_text, pos, &key, &pos, error))
744 if (_dbus_string_get_length (&key) == 0)
747 if (!_dbus_string_steal_data (&key, &tokens[i].key))
753 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
756 if (!_dbus_string_steal_data (&value, &tokens[i].value))
772 while (tokens[i].key || tokens[i].value)
774 dbus_free (tokens[i].key);
775 dbus_free (tokens[i].value);
776 tokens[i].key = NULL;
777 tokens[i].value = NULL;
782 _dbus_string_free (&key);
783 _dbus_string_free (&value);
789 bus_match_rule_parse_arg_match (MatchRule *rule,
791 const DBusString *value,
794 dbus_bool_t is_path = FALSE;
795 dbus_bool_t is_namespace = FALSE;
801 /* For now, arg0='foo' always implies that 'foo' is a
802 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
803 * if we wanted, which would specify another type, in which case
804 * arg0='5' would have the 5 parsed as an int rather than string.
807 /* First we need to parse arg0 = 0, arg27 = 27 */
809 _dbus_string_init_const (&key_str, key);
810 length = _dbus_string_get_length (&key_str);
812 if (_dbus_string_get_length (&key_str) < 4)
814 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
815 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
819 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
821 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
822 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
828 if ((end + strlen ("path")) == (size_t)length &&
829 _dbus_string_ends_with_c_str (&key_str, "path"))
833 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
835 int value_len = _dbus_string_get_length (value);
839 if (!_dbus_validate_bus_namespace (value, 0, value_len))
841 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
842 "arg0namespace='%s' is not a valid prefix of a bus name",
843 _dbus_string_get_const_data (value));
849 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
850 "Key '%s' in match rule contains junk after argument number (%lu). Only 'arg%lupath' (for example) or 'arg0namespace' are valid", key, arg, arg);
855 /* If we didn't check this we could allocate a huge amount of RAM */
856 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
858 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
859 "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);
863 if ((rule->flags &MATCH_ARGS) &&
864 rule->args_len > (int) arg &&
865 rule->args[arg] != NULL)
867 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
868 "Argument %s matched more than once in match rule\n", key);
872 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
881 _DBUS_ASSERT_ERROR_IS_SET (error);
886 * The format is comma-separated with strings quoted with single quotes
887 * as for the shell (to escape a literal single quote, use '\'').
889 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
890 * path='/bar/foo',destination=':452345.34'
894 match_rule_parse (DBusConnection *matches_go_to,
895 const DBusString *rule_text,
899 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
902 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
904 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
906 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
907 "Match rule text is %d bytes, maximum is %d",
908 _dbus_string_get_length (rule_text),
909 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
913 memset (tokens, '\0', sizeof (tokens));
915 rule = bus_match_rule_new (matches_go_to);
922 if (!tokenize_rule (rule_text, tokens, error))
926 while (tokens[i].key != NULL)
930 const char *key = tokens[i].key;
931 const char *value = tokens[i].value;
933 _dbus_string_init_const (&tmp_str, value);
934 len = _dbus_string_get_length (&tmp_str);
936 if (strcmp (key, "type") == 0)
940 if (rule->flags & MATCH_MESSAGE_TYPE)
942 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
943 "Key %s specified twice in match rule\n", key);
947 t = dbus_message_type_from_string (value);
949 if (t == DBUS_MESSAGE_TYPE_INVALID)
951 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
952 "Invalid message type (%s) in match rule\n", value);
956 if (!bus_match_rule_set_message_type (rule, t))
962 else if (strcmp (key, "sender") == 0)
964 if (rule->flags & MATCH_SENDER)
966 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
967 "Key %s specified twice in match rule\n", key);
971 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
973 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
974 "Sender name '%s' is invalid\n", value);
978 if (!bus_match_rule_set_sender (rule, value))
984 else if (strcmp (key, "interface") == 0)
986 if (rule->flags & MATCH_INTERFACE)
988 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
989 "Key %s specified twice in match rule\n", key);
993 if (!_dbus_validate_interface (&tmp_str, 0, len))
995 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
996 "Interface name '%s' is invalid\n", value);
1000 if (!bus_match_rule_set_interface (rule, value))
1006 else if (strcmp (key, "member") == 0)
1008 if (rule->flags & MATCH_MEMBER)
1010 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1011 "Key %s specified twice in match rule\n", key);
1015 if (!_dbus_validate_member (&tmp_str, 0, len))
1017 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1018 "Member name '%s' is invalid\n", value);
1022 if (!bus_match_rule_set_member (rule, value))
1028 else if (strcmp (key, "path") == 0 ||
1029 strcmp (key, "path_namespace") == 0)
1031 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
1033 if (rule->flags & (MATCH_PATH | MATCH_PATH_NAMESPACE))
1035 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1036 "path or path_namespace specified twice in match rule\n");
1040 if (!_dbus_validate_path (&tmp_str, 0, len))
1042 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1043 "Path '%s' is invalid\n", value);
1047 if (!bus_match_rule_set_path (rule, value, is_namespace))
1053 else if (strcmp (key, "destination") == 0)
1055 if (rule->flags & MATCH_DESTINATION)
1057 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1058 "Key %s specified twice in match rule\n", key);
1062 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
1064 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1065 "Destination name '%s' is invalid\n", value);
1069 if (!bus_match_rule_set_destination (rule, value))
1075 else if (strcmp (key, "eavesdrop") == 0)
1077 /* do not detect "eavesdrop" being used more than once in rule:
1078 * 1) it's not possible, it's only in the flags
1079 * 2) it might be used twice to disable eavesdropping when it's
1080 * automatically added (eg dbus-monitor/bustle) */
1082 /* we accept only "true|false" as possible values */
1083 if ((strcmp (value, "true") == 0))
1085 bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
1087 else if (strcmp (value, "false") == 0)
1089 bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
1093 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1094 "eavesdrop='%s' is invalid, "
1095 "it should be 'true' or 'false'\n",
1100 else if (strncmp (key, "arg", 3) == 0)
1102 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
1107 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
1108 "Unknown key \"%s\" in match rule",
1120 _DBUS_ASSERT_ERROR_IS_SET (error);
1123 match_rule_unref (rule);
1130 while (tokens[i].key || tokens[i].value)
1132 _dbus_assert (i < MAX_RULE_TOKENS);
1133 dbus_free (tokens[i].key);
1134 dbus_free (tokens[i].value);
1141 typedef struct RulePool RulePool;
1144 /* Maps non-NULL interface names to non-NULL (DBusList **)s */
1145 DBusHashTable *rules_by_iface;
1147 /* List of MatchRules which don't specify an interface */
1148 DBusList *rules_without_iface;
1155 /* Pools of rules, grouped by the type of message they match. 0
1156 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1159 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1165 rule_list_free (DBusList **rules)
1167 while (*rules != NULL)
1171 rule = (*rules)->data;
1172 match_rule_unref (rule);
1173 _dbus_list_remove_link (rules, *rules);
1178 rule_list_ptr_free (DBusList **list)
1180 /* We have to cope with NULL because the hash table frees the "existing"
1181 * value (which is NULL) when creating a new table entry...
1185 rule_list_free (list);
1191 matchmaker_new (void)
1193 Matchmaker *matchmaker;
1196 matchmaker = dbus_new0 (Matchmaker, 1);
1197 if (matchmaker == NULL)
1200 matchmaker->refcount = 1;
1201 matchmaker->last_cookie = 0;
1203 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1205 RulePool *p = matchmaker->rules_by_type + i;
1207 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1208 dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1210 if (p->rules_by_iface == NULL)
1217 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1219 RulePool *p = matchmaker->rules_by_type + i;
1221 if (p->rules_by_iface == NULL)
1224 _dbus_hash_table_unref (p->rules_by_iface);
1226 dbus_free (matchmaker);
1232 matchmaker_get_rules (Matchmaker *matchmaker,
1234 const char *interface,
1239 _dbus_assert (message_type >= 0);
1240 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1242 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1244 interface != NULL ? interface : "<null>");
1246 p = matchmaker->rules_by_type + message_type;
1248 if (interface == NULL)
1250 return &p->rules_without_iface;
1256 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1258 if (list == NULL && create)
1260 char *dupped_interface;
1262 list = dbus_new0 (DBusList *, 1);
1266 dupped_interface = _dbus_strdup (interface);
1267 if (dupped_interface == NULL)
1273 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1276 if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1277 dupped_interface, list))
1280 dbus_free (dupped_interface);
1290 bus_matchmaker_gc_rules (Matchmaker *matchmaker,
1292 const char *interface,
1297 if (interface == NULL)
1303 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1304 message_type, interface);
1306 p = matchmaker->rules_by_type + message_type;
1308 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1311 _dbus_hash_table_remove_string (p->rules_by_iface, interface);
1314 /* The rule can't be modified after it's added. */
1316 matchmaker_add_rule (Matchmaker *matchmaker,
1321 _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1323 rule->interface != NULL ? rule->interface : "<null>");
1325 rules = matchmaker_get_rules (matchmaker, rule->message_type,
1326 rule->interface, TRUE);
1331 if (!_dbus_list_append (rules, rule))
1334 rule->kdbus_cookie = ++(matchmaker->last_cookie);
1336 bus_match_rule_ref (rule);
1338 #ifdef DBUS_ENABLE_VERBOSE_MODE
1340 char *s = match_rule_to_string (rule);
1342 _dbus_verbose ("Added match rule %s to connection %p\n",
1343 s, rule->matches_go_to);
1352 matchmaker_get_rules_list (Matchmaker *matchmaker,
1357 list = matchmaker_get_rules (matchmaker, rule->message_type,
1358 rule->interface, FALSE);
1367 match_rule_equal_lib (MatchRule *a,
1370 if (a->flags != b->flags)
1373 if (a->matches_go_to != b->matches_go_to)
1376 if ((a->flags &MATCH_MESSAGE_TYPE) &&
1377 a->message_type != b->message_type)
1380 if ((a->flags &MATCH_MEMBER) &&
1381 strcmp (a->member, b->member) != 0)
1384 if ((a->flags &MATCH_PATH) &&
1385 strcmp (a->path, b->path) != 0)
1388 if ((a->flags &MATCH_INTERFACE) &&
1389 strcmp (a->interface, b->interface) != 0)
1392 if ((a->flags &MATCH_SENDER) &&
1393 strcmp (a->sender, b->sender) != 0)
1396 if ((a->flags &MATCH_DESTINATION) &&
1397 strcmp (a->destination, b->destination) != 0)
1400 /* we already compared the value of flags, and
1401 *MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
1403 if (a->flags &MATCH_ARGS)
1407 if (a->args_len != b->args_len)
1411 while (i < a->args_len)
1415 if ((a->args[i] != NULL) != (b->args[i] != NULL))
1418 if (a->arg_lens[i] != b->arg_lens[i])
1421 length = a->arg_lens[i] & ~MATCH_ARG_FLAGS;
1423 if (a->args[i] != NULL)
1425 _dbus_assert (b->args[i] != NULL);
1426 if (memcmp (a->args[i], b->args[i], length) != 0)
1438 bus_matchmaker_remove_rule_link (DBusList **rules,
1441 MatchRule *rule = link->data;
1443 _dbus_list_remove_link (rules, link);
1445 #ifdef DBUS_ENABLE_VERBOSE_MODE
1447 char *s = match_rule_to_string (rule);
1449 _dbus_verbose ("Removed match rule %s for connection %p\n",
1450 s, rule->matches_go_to);
1455 match_rule_unref (rule);
1458 /* Remove a single rule which is equal to the given rule by value */
1460 matchmaker_remove_rule_by_value (Matchmaker *matchmaker,
1465 DBusList *link = NULL;
1467 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1468 value->message_type,
1469 value->interface != NULL ? value->interface : "<null>");
1471 rules = matchmaker_get_rules (matchmaker, value->message_type,
1472 value->interface, FALSE);
1476 /* we traverse backward because bus_connection_remove_match_rule()
1477 * removes the most-recently-added rule
1479 link = _dbus_list_get_last_link (rules);
1480 while (link != NULL)
1486 prev = _dbus_list_get_prev_link (rules, link);
1488 if (match_rule_equal_lib (rule, value))
1490 bus_matchmaker_remove_rule_link (rules, link);
1500 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1501 "The given match rule wasn't found and can't be removed");
1505 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1512 rule_list_remove (DBusList **rules)
1516 link = _dbus_list_get_first_link (rules);
1517 while (link != NULL)
1521 next = _dbus_list_get_next_link (rules, link);
1522 bus_matchmaker_remove_rule_link (rules, link);
1528 free_matchmaker (Matchmaker *matchmaker)
1532 _dbus_verbose ("Removing all rules for connection\n");
1534 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1536 RulePool *p = matchmaker->rules_by_type + i;
1539 rule_list_remove (&p->rules_without_iface);
1541 _dbus_hash_iter_init (p->rules_by_iface, &iter);
1542 while (_dbus_hash_iter_next (&iter))
1544 DBusList **items = _dbus_hash_iter_get_value (&iter);
1546 rule_list_remove (items);
1549 _dbus_hash_iter_remove_entry (&iter);
1551 _dbus_hash_table_unref (p->rules_by_iface);
1553 dbus_free (matchmaker);
1557 _match_rule_get_message_type (MatchRule *rule)
1559 if (rule->flags & MATCH_MESSAGE_TYPE)
1560 return rule->message_type;
1562 return DBUS_MESSAGE_TYPE_INVALID;
1566 _match_rule_get_interface (MatchRule *rule)
1568 if (rule->flags & MATCH_INTERFACE)
1569 return rule->interface;
1575 _match_rule_get_member (MatchRule *rule)
1577 if (rule->flags & MATCH_MEMBER)
1578 return rule->member;
1584 _match_rule_get_sender (MatchRule *rule)
1586 if (rule->flags & MATCH_SENDER)
1587 return rule->sender;
1593 _match_rule_get_destination (MatchRule *rule)
1595 if (rule->flags & MATCH_DESTINATION)
1596 return rule->destination;
1602 _match_rule_get_path (MatchRule *rule)
1604 if (rule->flags & MATCH_PATH)
1611 _match_rule_get_path_namespace (MatchRule *rule)
1613 if (rule->flags & MATCH_PATH_NAMESPACE)
1620 _match_rule_get_args_len (MatchRule *rule)
1622 return rule->args_len;
1626 _match_rule_get_args (MatchRule *rule, int i)
1628 return rule->args[i];
1632 _match_rule_get_arg_lens (MatchRule *rule, int i)
1634 return rule->arg_lens[i];