1023
typedef struct RulePool RulePool;
1026
/* Maps non-NULL interface names to non-NULL (DBusList **)s */
1027
DBusHashTable *rules_by_iface;
1029
/* List of BusMatchRules which don't specify an interface */
1030
DBusList *rules_without_iface;
1021
1033
struct BusMatchmaker
1025
DBusList *all_rules;
1037
/* Pools of rules, grouped by the type of message they match. 0
1038
* (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
1041
RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
1045
rule_list_free (DBusList **rules)
1047
while (*rules != NULL)
1051
rule = (*rules)->data;
1052
bus_match_rule_unref (rule);
1053
_dbus_list_remove_link (rules, *rules);
1058
rule_list_ptr_free (DBusList **list)
1060
/* We have to cope with NULL because the hash table frees the "existing"
1061
* value (which is NULL) when creating a new table entry...
1065
rule_list_free (list);
1029
1071
bus_matchmaker_new (void)
1031
1073
BusMatchmaker *matchmaker;
1033
1076
matchmaker = dbus_new0 (BusMatchmaker, 1);
1034
1077
if (matchmaker == NULL)
1037
1080
matchmaker->refcount = 1;
1082
for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1084
RulePool *p = matchmaker->rules_by_type + i;
1086
p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
1087
dbus_free, (DBusFreeFunction) rule_list_ptr_free);
1089
if (p->rules_by_iface == NULL)
1039
1093
return matchmaker;
1096
for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1098
RulePool *p = matchmaker->rules_by_type + i;
1100
if (p->rules_by_iface == NULL)
1103
_dbus_hash_table_unref (p->rules_by_iface);
1110
bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
1112
const char *interface,
1117
_dbus_assert (message_type >= 0);
1118
_dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
1120
_dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
1122
interface != NULL ? interface : "<null>");
1124
p = matchmaker->rules_by_type + message_type;
1126
if (interface == NULL)
1128
return &p->rules_without_iface;
1134
list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
1136
if (list == NULL && create)
1138
char *dupped_interface;
1140
list = dbus_new0 (DBusList *, 1);
1144
dupped_interface = _dbus_strdup (interface);
1145
if (dupped_interface == NULL)
1151
_dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
1154
if (!_dbus_hash_table_insert_string (p->rules_by_iface,
1155
dupped_interface, list))
1158
dbus_free (dupped_interface);
1168
bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
1170
const char *interface,
1175
if (interface == NULL)
1181
_dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
1182
message_type, interface);
1184
p = matchmaker->rules_by_type + message_type;
1186
_dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
1189
_dbus_hash_table_remove_string (p->rules_by_iface, interface);
1042
1192
BusMatchmaker *
1057
1207
matchmaker->refcount -= 1;
1058
1208
if (matchmaker->refcount == 0)
1060
while (matchmaker->all_rules != NULL)
1212
for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1214
RulePool *p = matchmaker->rules_by_type + i;
1064
rule = matchmaker->all_rules->data;
1065
bus_match_rule_unref (rule);
1066
_dbus_list_remove_link (&matchmaker->all_rules,
1067
matchmaker->all_rules);
1216
_dbus_hash_table_unref (p->rules_by_iface);
1217
rule_list_free (&p->rules_without_iface);
1070
1220
dbus_free (matchmaker);
1076
1226
bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
1077
1227
BusMatchRule *rule)
1079
1231
_dbus_assert (bus_connection_is_active (rule->matches_go_to));
1081
if (!_dbus_list_append (&matchmaker->all_rules, rule))
1233
_dbus_verbose ("Adding rule with message_type %d, interface %s\n",
1235
rule->interface != NULL ? rule->interface : "<null>");
1237
rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1238
rule->interface, TRUE);
1243
if (!_dbus_list_append (rules, rule))
1084
1246
if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
1086
_dbus_list_remove_last (&matchmaker->all_rules, rule);
1248
_dbus_list_remove_last (rules, rule);
1249
bus_matchmaker_gc_rules (matchmaker, rule->message_type,
1250
rule->interface, rules);
1090
1254
bus_match_rule_ref (rule);
1092
1256
#ifdef DBUS_ENABLE_VERBOSE_MODE
1174
bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
1338
bus_matchmaker_remove_rule_link (DBusList **rules,
1175
1339
DBusList *link)
1177
1341
BusMatchRule *rule = link->data;
1179
1343
bus_connection_remove_match_rule (rule->matches_go_to, rule);
1180
_dbus_list_remove_link (&matchmaker->all_rules, link);
1344
_dbus_list_remove_link (rules, link);
1182
1346
#ifdef DBUS_ENABLE_VERBOSE_MODE
1196
1360
bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
1197
1361
BusMatchRule *rule)
1365
_dbus_verbose ("Removing rule with message_type %d, interface %s\n",
1367
rule->interface != NULL ? rule->interface : "<null>");
1199
1369
bus_connection_remove_match_rule (rule->matches_go_to, rule);
1200
_dbus_list_remove (&matchmaker->all_rules, rule);
1371
rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
1372
rule->interface, FALSE);
1374
/* We should only be asked to remove a rule by identity right after it was
1375
* added, so there should be a list for it.
1377
_dbus_assert (rules != NULL);
1379
_dbus_list_remove (rules, rule);
1380
bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
1202
1383
#ifdef DBUS_ENABLE_VERBOSE_MODE
1218
1399
BusMatchRule *value,
1219
1400
DBusError *error)
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)
1403
DBusList *link = NULL;
1405
_dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
1406
value->message_type,
1407
value->interface != NULL ? value->interface : "<null>");
1409
rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
1410
value->interface, FALSE);
1235
prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
1237
if (match_rule_equal (rule, value))
1414
/* we traverse backward because bus_connection_remove_match_rule()
1415
* removes the most-recently-added rule
1417
link = _dbus_list_get_last_link (rules);
1418
while (link != NULL)
1239
bus_matchmaker_remove_rule_link (matchmaker, link);
1424
prev = _dbus_list_get_prev_link (rules, link);
1426
if (match_rule_equal (rule, value))
1428
bus_matchmaker_remove_rule_link (rules, link);
1246
1436
if (link == NULL)
1443
bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
1257
bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1258
DBusConnection *disconnected)
1450
rule_list_remove_by_connection (DBusList **rules,
1451
DBusConnection *connection)
1260
1453
DBusList *link;
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);
1455
link = _dbus_list_get_first_link (rules);
1274
1456
while (link != NULL)
1276
1458
BusMatchRule *rule;
1277
1459
DBusList *next;
1279
1461
rule = link->data;
1280
next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1462
next = _dbus_list_get_next_link (rules, link);
1282
if (rule->matches_go_to == disconnected)
1464
if (rule->matches_go_to == connection)
1284
bus_matchmaker_remove_rule_link (matchmaker, link);
1466
bus_matchmaker_remove_rule_link (rules, link);
1286
1468
else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1287
1469
((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1494
bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1495
DBusConnection *connection)
1501
* This scans all match rules on the bus. We could avoid that
1502
* for the rules belonging to the connection, since we keep
1503
* a list of those; but for the rules that just refer to
1504
* the connection we'd need to do something more elaborate.
1507
_dbus_assert (bus_connection_is_active (connection));
1509
_dbus_verbose ("Removing all rules for connection %p\n", connection);
1511
for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
1513
RulePool *p = matchmaker->rules_by_type + i;
1516
rule_list_remove_by_connection (&p->rules_without_iface, connection);
1518
_dbus_hash_iter_init (p->rules_by_iface, &iter);
1519
while (_dbus_hash_iter_next (&iter))
1521
DBusList **items = _dbus_hash_iter_get_value (&iter);
1523
rule_list_remove_by_connection (items, connection);
1526
_dbus_hash_iter_remove_entry (&iter);
1311
1531
static dbus_bool_t
1312
1532
connection_is_primary_owner (DBusConnection *connection,
1313
1533
const char *service_name)
1734
get_recipients_from_list (DBusList **rules,
1735
DBusConnection *sender,
1736
DBusConnection *addressed_recipient,
1737
DBusMessage *message,
1738
DBusList **recipients_p)
1745
link = _dbus_list_get_first_link (rules);
1746
while (link != NULL)
1752
#ifdef DBUS_ENABLE_VERBOSE_MODE
1754
char *s = match_rule_to_string (rule);
1756
_dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1757
s, rule->matches_go_to);
1762
if (match_rule_matches (rule,
1763
sender, addressed_recipient, message,
1764
BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
1766
_dbus_verbose ("Rule matched\n");
1768
/* Append to the list if we haven't already */
1769
if (bus_connection_mark_stamp (rule->matches_go_to))
1771
if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1774
#ifdef DBUS_ENABLE_VERBOSE_MODE
1777
_dbus_verbose ("Connection already receiving this message, so not adding again\n");
1779
#endif /* DBUS_ENABLE_VERBOSE_MODE */
1782
link = _dbus_list_get_next_link (rules, link);
1508
1789
bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1509
1790
BusConnections *connections,
1535
1812
if (addressed_recipient != NULL)
1536
1813
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);
1815
type = dbus_message_get_type (message);
1816
interface = dbus_message_get_interface (message);
1818
neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
1820
just_type = just_iface = both = NULL;
1822
if (interface != NULL)
1823
just_iface = bus_matchmaker_get_rules (matchmaker,
1824
DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
1826
if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
1828
just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
1830
if (interface != NULL)
1831
both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
1834
if (!(get_recipients_from_list (neither, sender, addressed_recipient,
1835
message, recipients_p) &&
1836
get_recipients_from_list (just_iface, sender, addressed_recipient,
1837
message, recipients_p) &&
1838
get_recipients_from_list (just_type, sender, addressed_recipient,
1839
message, recipients_p) &&
1840
get_recipients_from_list (both, sender, addressed_recipient,
1841
message, recipients_p)))
1843
_dbus_list_clear (recipients_p);
1580
_dbus_list_clear (recipients_p);
1584
1850
#ifdef DBUS_BUILD_TESTS