*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+
+#include <config.h>
#include "signals.h"
#include "services.h"
#include "utils.h"
char *destination;
char *path;
+ unsigned int *arg_lens;
char **args;
int args_len;
};
+#define BUS_MATCH_ARG_IS_PATH 0x8000000u
+
BusMatchRule*
bus_match_rule_new (DBusConnection *matches_go_to)
{
dbus_free (rule->sender);
dbus_free (rule->destination);
dbus_free (rule->path);
+ dbus_free (rule->arg_lens);
/* can't use dbus_free_string_array() since there
* are embedded NULL
{
if (rule->args[i] != NULL)
{
+ dbus_bool_t is_path;
+
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
+
+ is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
if (!_dbus_string_append_printf (&str,
- "arg%d='%s'",
- i,
+ "arg%d%s='%s'",
+ i, is_path ? "path" : "",
rule->args[i]))
goto nomem;
}
}
dbus_bool_t
-bus_match_rule_set_arg (BusMatchRule *rule,
- int arg,
- const char *value)
+bus_match_rule_set_arg (BusMatchRule *rule,
+ int arg,
+ const DBusString *value,
+ dbus_bool_t is_path)
{
+ int length;
char *new;
_dbus_assert (value != NULL);
- new = _dbus_strdup (value);
- if (new == NULL)
- return FALSE;
-
/* args_len is the number of args not including null termination
* in the char**
*/
if (arg >= rule->args_len)
{
+ unsigned int *new_arg_lens;
char **new_args;
int new_args_len;
int i;
/* add another + 1 here for null termination */
new_args = dbus_realloc (rule->args,
- sizeof(rule->args[0]) * (new_args_len + 1));
+ sizeof (char *) * (new_args_len + 1));
if (new_args == NULL)
- {
- dbus_free (new);
- return FALSE;
- }
+ return FALSE;
/* NULL the new slots */
i = rule->args_len;
}
rule->args = new_args;
+
+ /* and now add to the lengths */
+ new_arg_lens = dbus_realloc (rule->arg_lens,
+ sizeof (int) * (new_args_len + 1));
+
+ if (new_arg_lens == NULL)
+ return FALSE;
+
+ /* zero the new slots */
+ i = rule->args_len;
+ while (i <= new_args_len) /* <= for null termination */
+ {
+ new_arg_lens[i] = 0;
+ ++i;
+ }
+
+ rule->arg_lens = new_arg_lens;
rule->args_len = new_args_len;
}
+ length = _dbus_string_get_length (value);
+ if (!_dbus_string_copy_data (value, &new))
+ return FALSE;
+
rule->flags |= BUS_MATCH_ARGS;
dbus_free (rule->args[arg]);
+ rule->arg_lens[arg] = length;
rule->args[arg] = new;
+ if (is_path)
+ rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
+
/* NULL termination didn't get busted */
_dbus_assert (rule->args[rule->args_len] == NULL);
+ _dbus_assert (rule->arg_lens[rule->args_len] == 0);
return TRUE;
}
const DBusString *value,
DBusError *error)
{
+ dbus_bool_t is_path;
DBusString key_str;
unsigned long arg;
+ int length;
int end;
/* For now, arg0='foo' always implies that 'foo' is a
/* First we need to parse arg0 = 0, arg27 = 27 */
_dbus_string_init_const (&key_str, key);
+ length = _dbus_string_get_length (&key_str);
if (_dbus_string_get_length (&key_str) < 4)
{
goto failed;
}
- if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end) ||
- end != _dbus_string_get_length (&key_str))
+ if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
{
dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
"Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
goto failed;
}
+ if (end != length &&
+ ((end + 4) != length ||
+ !_dbus_string_ends_with_c_str (&key_str, "path")))
+ {
+ dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+ "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key);
+ goto failed;
+ }
+
+ is_path = end != length;
+
/* If we didn't check this we could allocate a huge amount of RAM */
if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
{
rule->args[arg] != NULL)
{
dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
- "Key '%s' specified twice in match rule\n", key);
+ "Argument %d matched more than once in match rule\n", key);
goto failed;
}
- if (!bus_match_rule_set_arg (rule, arg,
- _dbus_string_get_const_data (value)))
+ if (!bus_match_rule_set_arg (rule, arg, value, is_path))
{
BUS_SET_OOM (error);
goto failed;
return rule;
}
+typedef struct RulePool RulePool;
+struct RulePool
+{
+ /* Maps non-NULL interface names to non-NULL (DBusList **)s */
+ DBusHashTable *rules_by_iface;
+
+ /* List of BusMatchRules which don't specify an interface */
+ DBusList *rules_without_iface;
+};
+
struct BusMatchmaker
{
int refcount;
- DBusList *all_rules;
+ /* Pools of rules, grouped by the type of message they match. 0
+ * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
+ * type.
+ */
+ RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
};
+static void
+rule_list_free (DBusList **rules)
+{
+ while (*rules != NULL)
+ {
+ BusMatchRule *rule;
+
+ rule = (*rules)->data;
+ bus_match_rule_unref (rule);
+ _dbus_list_remove_link (rules, *rules);
+ }
+}
+
+static void
+rule_list_ptr_free (DBusList **list)
+{
+ /* We have to cope with NULL because the hash table frees the "existing"
+ * value (which is NULL) when creating a new table entry...
+ */
+ if (list != NULL)
+ {
+ rule_list_free (list);
+ dbus_free (list);
+ }
+}
+
BusMatchmaker*
bus_matchmaker_new (void)
{
BusMatchmaker *matchmaker;
+ int i;
matchmaker = dbus_new0 (BusMatchmaker, 1);
if (matchmaker == NULL)
return NULL;
matchmaker->refcount = 1;
-
+
+ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+ {
+ RulePool *p = matchmaker->rules_by_type + i;
+
+ p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
+ dbus_free, (DBusFreeFunction) rule_list_ptr_free);
+
+ if (p->rules_by_iface == NULL)
+ goto nomem;
+ }
+
return matchmaker;
+
+ nomem:
+ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+ {
+ RulePool *p = matchmaker->rules_by_type + i;
+
+ if (p->rules_by_iface == NULL)
+ break;
+ else
+ _dbus_hash_table_unref (p->rules_by_iface);
+ }
+
+ return NULL;
+}
+
+static DBusList **
+bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
+ int message_type,
+ const char *interface,
+ dbus_bool_t create)
+{
+ RulePool *p;
+
+ _dbus_assert (message_type >= 0);
+ _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
+
+ _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
+ message_type,
+ interface != NULL ? interface : "<null>");
+
+ p = matchmaker->rules_by_type + message_type;
+
+ if (interface == NULL)
+ {
+ return &p->rules_without_iface;
+ }
+ else
+ {
+ DBusList **list;
+
+ list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
+
+ if (list == NULL && create)
+ {
+ char *dupped_interface;
+
+ list = dbus_new0 (DBusList *, 1);
+ if (list == NULL)
+ return NULL;
+
+ dupped_interface = _dbus_strdup (interface);
+ if (dupped_interface == NULL)
+ {
+ dbus_free (list);
+ return NULL;
+ }
+
+ _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
+ interface);
+
+ if (!_dbus_hash_table_insert_string (p->rules_by_iface,
+ dupped_interface, list))
+ {
+ dbus_free (list);
+ dbus_free (dupped_interface);
+ return NULL;
+ }
+ }
+
+ return list;
+ }
+}
+
+static void
+bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
+ int message_type,
+ const char *interface,
+ DBusList **rules)
+{
+ RulePool *p;
+
+ if (interface == NULL)
+ return;
+
+ if (*rules != NULL)
+ return;
+
+ _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
+ message_type, interface);
+
+ p = matchmaker->rules_by_type + message_type;
+
+ _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
+ == rules);
+
+ _dbus_hash_table_remove_string (p->rules_by_iface, interface);
}
BusMatchmaker *
matchmaker->refcount -= 1;
if (matchmaker->refcount == 0)
{
- while (matchmaker->all_rules != NULL)
+ int i;
+
+ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
{
- BusMatchRule *rule;
+ RulePool *p = matchmaker->rules_by_type + i;
- rule = matchmaker->all_rules->data;
- bus_match_rule_unref (rule);
- _dbus_list_remove_link (&matchmaker->all_rules,
- matchmaker->all_rules);
+ _dbus_hash_table_unref (p->rules_by_iface);
+ rule_list_free (&p->rules_without_iface);
}
dbus_free (matchmaker);
bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule)
{
+ DBusList **rules;
+
_dbus_assert (bus_connection_is_active (rule->matches_go_to));
- if (!_dbus_list_append (&matchmaker->all_rules, rule))
+ _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
+ rule->message_type,
+ rule->interface != NULL ? rule->interface : "<null>");
+
+ rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
+ rule->interface, TRUE);
+
+ if (rules == NULL)
+ return FALSE;
+
+ if (!_dbus_list_append (rules, rule))
return FALSE;
if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
{
- _dbus_list_remove_last (&matchmaker->all_rules, rule);
+ _dbus_list_remove_last (rules, rule);
+ bus_matchmaker_gc_rules (matchmaker, rule->message_type,
+ rule->interface, rules);
return FALSE;
}
-
+
bus_match_rule_ref (rule);
#ifdef DBUS_ENABLE_VERBOSE_MODE
i = 0;
while (i < a->args_len)
{
+ int length;
+
if ((a->args[i] != NULL) != (b->args[i] != NULL))
return FALSE;
+ if (a->arg_lens[i] != b->arg_lens[i])
+ return FALSE;
+
+ length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
+
if (a->args[i] != NULL)
{
_dbus_assert (b->args[i] != NULL);
- if (strcmp (a->args[i], b->args[i]) != 0)
+ if (memcmp (a->args[i], b->args[i], length) != 0)
return FALSE;
}
}
static void
-bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
+bus_matchmaker_remove_rule_link (DBusList **rules,
DBusList *link)
{
BusMatchRule *rule = link->data;
bus_connection_remove_match_rule (rule->matches_go_to, rule);
- _dbus_list_remove_link (&matchmaker->all_rules, link);
+ _dbus_list_remove_link (rules, link);
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule)
{
+ DBusList **rules;
+
+ _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
+ rule->message_type,
+ rule->interface != NULL ? rule->interface : "<null>");
+
bus_connection_remove_match_rule (rule->matches_go_to, rule);
- _dbus_list_remove (&matchmaker->all_rules, rule);
+
+ rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
+ rule->interface, FALSE);
+
+ /* We should only be asked to remove a rule by identity right after it was
+ * added, so there should be a list for it.
+ */
+ _dbus_assert (rules != NULL);
+
+ _dbus_list_remove (rules, rule);
+ bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
+ rules);
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
BusMatchRule *value,
DBusError *error)
{
- /* FIXME this is an unoptimized linear scan */
+ DBusList **rules;
+ DBusList *link = NULL;
- DBusList *link;
+ _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
+ value->message_type,
+ value->interface != NULL ? value->interface : "<null>");
- /* we traverse backward because bus_connection_remove_match_rule()
- * removes the most-recently-added rule
- */
- link = _dbus_list_get_last_link (&matchmaker->all_rules);
- while (link != NULL)
+ rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
+ value->interface, FALSE);
+
+ if (rules != NULL)
{
- BusMatchRule *rule;
- DBusList *prev;
+ /* we traverse backward because bus_connection_remove_match_rule()
+ * removes the most-recently-added rule
+ */
+ link = _dbus_list_get_last_link (rules);
+ while (link != NULL)
+ {
+ BusMatchRule *rule;
+ DBusList *prev;
- rule = link->data;
- prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
+ rule = link->data;
+ prev = _dbus_list_get_prev_link (rules, link);
- if (match_rule_equal (rule, value))
- {
- bus_matchmaker_remove_rule_link (matchmaker, link);
- break;
- }
+ if (match_rule_equal (rule, value))
+ {
+ bus_matchmaker_remove_rule_link (rules, link);
+ break;
+ }
- link = prev;
+ link = prev;
+ }
}
if (link == NULL)
return FALSE;
}
+ bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
+ rules);
+
return TRUE;
}
-void
-bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
- DBusConnection *disconnected)
+static void
+rule_list_remove_by_connection (DBusList **rules,
+ DBusConnection *connection)
{
DBusList *link;
- /* FIXME
- *
- * This scans all match rules on the bus. We could avoid that
- * for the rules belonging to the connection, since we keep
- * a list of those; but for the rules that just refer to
- * the connection we'd need to do something more elaborate.
- *
- */
-
- _dbus_assert (bus_connection_is_active (disconnected));
-
- link = _dbus_list_get_first_link (&matchmaker->all_rules);
+ link = _dbus_list_get_first_link (rules);
while (link != NULL)
{
BusMatchRule *rule;
DBusList *next;
rule = link->data;
- next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
+ next = _dbus_list_get_next_link (rules, link);
- if (rule->matches_go_to == disconnected)
+ if (rule->matches_go_to == connection)
{
- bus_matchmaker_remove_rule_link (matchmaker, link);
+ bus_matchmaker_remove_rule_link (rules, link);
}
else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
*/
const char *name;
- name = bus_connection_get_name (disconnected);
+ name = bus_connection_get_name (connection);
_dbus_assert (name != NULL); /* because we're an active connection */
if (((rule->flags & BUS_MATCH_SENDER) &&
((rule->flags & BUS_MATCH_DESTINATION) &&
strcmp (rule->destination, name) == 0))
{
- bus_matchmaker_remove_rule_link (matchmaker, link);
+ bus_matchmaker_remove_rule_link (rules, link);
}
}
}
}
+void
+bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
+ DBusConnection *connection)
+{
+ int i;
+
+ /* FIXME
+ *
+ * This scans all match rules on the bus. We could avoid that
+ * for the rules belonging to the connection, since we keep
+ * a list of those; but for the rules that just refer to
+ * the connection we'd need to do something more elaborate.
+ */
+
+ _dbus_assert (bus_connection_is_active (connection));
+
+ _dbus_verbose ("Removing all rules for connection %p\n", connection);
+
+ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+ {
+ RulePool *p = matchmaker->rules_by_type + i;
+ DBusHashIter iter;
+
+ rule_list_remove_by_connection (&p->rules_without_iface, connection);
+
+ _dbus_hash_iter_init (p->rules_by_iface, &iter);
+ while (_dbus_hash_iter_next (&iter))
+ {
+ DBusList **items = _dbus_hash_iter_get_value (&iter);
+
+ rule_list_remove_by_connection (items, connection);
+
+ if (*items == NULL)
+ _dbus_hash_iter_remove_entry (&iter);
+ }
+ }
+}
+
static dbus_bool_t
connection_is_primary_owner (DBusConnection *connection,
const char *service_name)
match_rule_matches (BusMatchRule *rule,
DBusConnection *sender,
DBusConnection *addressed_recipient,
- DBusMessage *message)
+ DBusMessage *message,
+ BusMatchFlags already_matched)
{
+ int flags;
+
/* All features of the match rule are AND'd together,
* so FALSE if any of them don't match.
*/
* or for addressed_recipient may mean a message with no
* specific recipient (i.e. a signal)
*/
-
- if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
+
+ /* Don't bother re-matching features we've already checked implicitly. */
+ flags = rule->flags & (~already_matched);
+
+ if (flags & BUS_MATCH_MESSAGE_TYPE)
{
_dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
return FALSE;
}
- if (rule->flags & BUS_MATCH_INTERFACE)
+ if (flags & BUS_MATCH_INTERFACE)
{
const char *iface;
return FALSE;
}
- if (rule->flags & BUS_MATCH_MEMBER)
+ if (flags & BUS_MATCH_MEMBER)
{
const char *member;
return FALSE;
}
- if (rule->flags & BUS_MATCH_SENDER)
+ if (flags & BUS_MATCH_SENDER)
{
_dbus_assert (rule->sender != NULL);
}
}
- if (rule->flags & BUS_MATCH_DESTINATION)
+ if (flags & BUS_MATCH_DESTINATION)
{
const char *destination;
}
}
- if (rule->flags & BUS_MATCH_PATH)
+ if (flags & BUS_MATCH_PATH)
{
const char *path;
return FALSE;
}
- if (rule->flags & BUS_MATCH_ARGS)
+ if (flags & BUS_MATCH_ARGS)
{
int i;
DBusMessageIter iter;
{
int current_type;
const char *expected_arg;
+ int expected_length;
+ dbus_bool_t is_path;
expected_arg = rule->args[i];
+ expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
+ is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
current_type = dbus_message_iter_get_arg_type (&iter);
if (expected_arg != NULL)
{
const char *actual_arg;
+ int actual_length;
if (current_type != DBUS_TYPE_STRING)
return FALSE;
dbus_message_iter_get_basic (&iter, &actual_arg);
_dbus_assert (actual_arg != NULL);
- if (strcmp (expected_arg, actual_arg) != 0)
- return FALSE;
+ actual_length = strlen (actual_arg);
+
+ if (is_path)
+ {
+ if (actual_length < expected_length &&
+ actual_arg[actual_length - 1] != '/')
+ return FALSE;
+
+ if (expected_length < actual_length &&
+ expected_arg[expected_length - 1] != '/')
+ return FALSE;
+
+ if (memcmp (actual_arg, expected_arg,
+ MIN (actual_length, expected_length)) != 0)
+ return FALSE;
+ }
+ else
+ {
+ if (expected_length != actual_length ||
+ memcmp (expected_arg, actual_arg, expected_length) != 0)
+ return FALSE;
+ }
+
}
if (current_type != DBUS_TYPE_INVALID)
return TRUE;
}
-dbus_bool_t
-bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
- BusConnections *connections,
- DBusConnection *sender,
- DBusConnection *addressed_recipient,
- DBusMessage *message,
- DBusList **recipients_p)
+static dbus_bool_t
+get_recipients_from_list (DBusList **rules,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ DBusList **recipients_p)
{
- /* FIXME for now this is a wholly unoptimized linear search */
- /* Guessing the important optimization is to skip the signal-related
- * match lists when processing method call and exception messages.
- * So separate match rule lists for signals?
- */
-
DBusList *link;
- _dbus_assert (*recipients_p == NULL);
+ if (rules == NULL)
+ return TRUE;
- /* This avoids sending same message to the same connection twice.
- * Purpose of the stamp instead of a bool is to avoid iterating over
- * all connections resetting the bool each time.
- */
- bus_connections_increment_stamp (connections);
-
- /* addressed_recipient is already receiving the message, don't add to list.
- * NULL addressed_recipient means either bus driver, or this is a signal
- * and thus lacks a specific addressed_recipient.
- */
- if (addressed_recipient != NULL)
- bus_connection_mark_stamp (addressed_recipient);
-
- link = _dbus_list_get_first_link (&matchmaker->all_rules);
+ link = _dbus_list_get_first_link (rules);
while (link != NULL)
{
BusMatchRule *rule;
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
char *s = match_rule_to_string (rule);
-
+
_dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
s, rule->matches_go_to);
dbus_free (s);
}
#endif
-
+
if (match_rule_matches (rule,
- sender, addressed_recipient, message))
+ sender, addressed_recipient, message,
+ BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
{
_dbus_verbose ("Rule matched\n");
-
+
/* Append to the list if we haven't already */
if (bus_connection_mark_stamp (rule->matches_go_to))
{
if (!_dbus_list_append (recipients_p, rule->matches_go_to))
- goto nomem;
+ return FALSE;
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
else
#endif /* DBUS_ENABLE_VERBOSE_MODE */
}
- link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
+ link = _dbus_list_get_next_link (rules, link);
}
return TRUE;
+}
- nomem:
- _dbus_list_clear (recipients_p);
- return FALSE;
+dbus_bool_t
+bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
+ BusConnections *connections,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ DBusList **recipients_p)
+{
+ int type;
+ const char *interface;
+ DBusList **neither, **just_type, **just_iface, **both;
+
+ _dbus_assert (*recipients_p == NULL);
+
+ /* This avoids sending same message to the same connection twice.
+ * Purpose of the stamp instead of a bool is to avoid iterating over
+ * all connections resetting the bool each time.
+ */
+ bus_connections_increment_stamp (connections);
+
+ /* addressed_recipient is already receiving the message, don't add to list.
+ * NULL addressed_recipient means either bus driver, or this is a signal
+ * and thus lacks a specific addressed_recipient.
+ */
+ if (addressed_recipient != NULL)
+ bus_connection_mark_stamp (addressed_recipient);
+
+ type = dbus_message_get_type (message);
+ interface = dbus_message_get_interface (message);
+
+ neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
+ NULL, FALSE);
+ just_type = just_iface = both = NULL;
+
+ if (interface != NULL)
+ just_iface = bus_matchmaker_get_rules (matchmaker,
+ DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
+
+ if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
+ {
+ just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
+
+ if (interface != NULL)
+ both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
+ }
+
+ if (!(get_recipients_from_list (neither, sender, addressed_recipient,
+ message, recipients_p) &&
+ get_recipients_from_list (just_iface, sender, addressed_recipient,
+ message, recipients_p) &&
+ get_recipients_from_list (just_type, sender, addressed_recipient,
+ message, recipients_p) &&
+ get_recipients_from_list (both, sender, addressed_recipient,
+ message, recipients_p)))
+ {
+ _dbus_list_clear (recipients_p);
+ return FALSE;
+ }
+
+ return TRUE;
}
#ifdef DBUS_BUILD_TESTS
_dbus_assert (rule != NULL);
/* We can't test sender/destination rules since we pass NULL here */
- matched = match_rule_matches (rule, NULL, NULL, message);
+ matched = match_rule_matches (rule, NULL, NULL, message, 0);
if (matched != expected_to_match)
{