From 5cf22aabbace6b706523ed2613b35ae1c5fd35ab Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 8 Mar 2011 10:32:34 -0500 Subject: [PATCH] Add path_prefix match rule Add a new path_prefix match rule that can be used for efficient implementations of the org.freedesktop.DBus.ObjectManager interface (see bug 34869). https://bugs.freedesktop.org/show_bug.cgi?id=34870 Signed-off-by: David Zeuthen --- bus/signals.c | 168 ++++++++++++++++++++++++++++++++++++++++++++ bus/signals.h | 5 +- doc/dbus-specification.xml | 20 +++++ 3 files changed, 192 insertions(+), 1 deletions(-) diff --git a/bus/signals.c b/bus/signals.c index c85a88d..7f7bab0 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -41,6 +41,7 @@ struct BusMatchRule char *sender; char *destination; char *path; + char *path_prefix; unsigned int *arg_lens; char **args; @@ -91,6 +92,7 @@ bus_match_rule_unref (BusMatchRule *rule) dbus_free (rule->sender); dbus_free (rule->destination); dbus_free (rule->path); + dbus_free (rule->path_prefix); dbus_free (rule->arg_lens); /* can't use dbus_free_string_array() since there @@ -203,6 +205,18 @@ match_rule_to_string (BusMatchRule *rule) goto nomem; } + if (rule->flags & BUS_MATCH_PATH_PREFIX) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "path_prefix='%s'", rule->path_prefix)) + goto nomem; + } + if (rule->flags & BUS_MATCH_SENDER) { if (_dbus_string_get_length (&str) > 0) @@ -383,6 +397,25 @@ bus_match_rule_set_path (BusMatchRule *rule, } dbus_bool_t +bus_match_rule_set_path_prefix (BusMatchRule *rule, + const char *path_prefix) +{ + char *new; + + _dbus_assert (path_prefix != NULL); + + new = _dbus_strdup (path_prefix); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_PATH_PREFIX; + dbus_free (rule->path_prefix); + rule->path_prefix = new; + + return TRUE; +} + +dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, @@ -984,6 +1017,34 @@ bus_match_rule_parse (DBusConnection *matches_go_to, goto failed; } } + else if (strcmp (key, "path_prefix") == 0) + { + int path_prefix_len; + + if (rule->flags & BUS_MATCH_PATH_PREFIX) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + path_prefix_len = len; + if (_dbus_string_ends_with_c_str (&tmp_str, "/")) + path_prefix_len--; + + if (!_dbus_validate_path (&tmp_str, 0, path_prefix_len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Path prefix '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_path_prefix (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } else if (strcmp (key, "destination") == 0) { if (rule->flags & BUS_MATCH_DESTINATION) @@ -1315,6 +1376,10 @@ match_rule_equal (BusMatchRule *a, if ((a->flags & BUS_MATCH_PATH) && strcmp (a->path, b->path) != 0) return FALSE; + + if ((a->flags & BUS_MATCH_PATH_PREFIX) && + strcmp (a->path_prefix, b->path_prefix) != 0) + return FALSE; if ((a->flags & BUS_MATCH_INTERFACE) && strcmp (a->interface, b->interface) != 0) @@ -1578,6 +1643,17 @@ connection_is_primary_owner (DBusConnection *connection, } static dbus_bool_t +str_has_prefix (const char *str, const char *prefix) +{ + size_t prefix_len; + prefix_len = strlen (prefix); + if (strncmp (str, prefix, prefix_len) == 0) + return TRUE; + else + return FALSE; +} + +static dbus_bool_t match_rule_matches (BusMatchRule *rule, DBusConnection *sender, DBusConnection *addressed_recipient, @@ -1688,6 +1764,20 @@ match_rule_matches (BusMatchRule *rule, return FALSE; } + if (flags & BUS_MATCH_PATH_PREFIX) + { + const char *path; + + _dbus_assert (rule->path_prefix != NULL); + + path = dbus_message_get_path (message); + if (path == NULL) + return FALSE; + + if (!str_has_prefix (path, rule->path_prefix)) + return FALSE; + } + if (flags & BUS_MATCH_ARGS) { int i; @@ -2300,6 +2390,83 @@ test_matching (void) dbus_message_unref (message1); } +static const char* +path_prefix_should_match_message_1[] = { + "type='signal',path_prefix='/foo'", + "type='signal',path_prefix='/foo/'", + "type='signal',path_prefix='/foo/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_1[] = { + "type='signal',path_prefix='/bar'", + "type='signal',path_prefix='/bar/'", + "type='signal',path_prefix='/bar/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_match_message_2[] = { + "type='signal',path_prefix='/foo/TheObjectManager'", + "type='signal',path_prefix='/foo/TheObjectManager/'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_2[] = { + NULL +}; + +static const char* +path_prefix_should_match_message_3[] = { + "type='signal',path_prefix='/foo/TheObjectManager'", + NULL +}; + +static const char* +path_prefix_should_not_match_message_3[] = { + "type='signal',path_prefix='/foo/TheObjectManager/'", + NULL +}; + +static void +test_matching_path_prefix (void) +{ + DBusMessage *message1; + DBusMessage *message2; + DBusMessage *message3; + + message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message1 != NULL); + if (!dbus_message_set_path (message1, "/foo/TheObjectManager")) + _dbus_assert_not_reached ("oom"); + + message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message2 != NULL); + if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object")) + _dbus_assert_not_reached ("oom"); + + message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message3 != NULL); + if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther")) + _dbus_assert_not_reached ("oom"); + + check_matching (message1, 1, + path_prefix_should_match_message_1, + path_prefix_should_not_match_message_1); + check_matching (message2, 2, + path_prefix_should_match_message_2, + path_prefix_should_not_match_message_2); + check_matching (message3, 3, + path_prefix_should_match_message_3, + path_prefix_should_not_match_message_3); + + dbus_message_unref (message3); + dbus_message_unref (message2); + dbus_message_unref (message1); +} + dbus_bool_t bus_signals_test (const DBusString *test_data_dir) { @@ -2316,6 +2483,7 @@ bus_signals_test (const DBusString *test_data_dir) test_equality (); test_matching (); + test_matching_path_prefix (); return TRUE; } diff --git a/bus/signals.h b/bus/signals.h index eeb1d2d..f39f644 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -37,7 +37,8 @@ typedef enum BUS_MATCH_SENDER = 1 << 3, BUS_MATCH_DESTINATION = 1 << 4, BUS_MATCH_PATH = 1 << 5, - BUS_MATCH_ARGS = 1 << 6 + BUS_MATCH_ARGS = 1 << 6, + BUS_MATCH_PATH_PREFIX = 1 << 7 } BusMatchFlags; BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to); @@ -56,6 +57,8 @@ dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule, const char *destination); dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, const char *path); +dbus_bool_t bus_match_rule_set_path_prefix (BusMatchRule *rule, + const char *path_prefix); dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, int arg, const DBusString *value, diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index ee5aac5..bd35909 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3722,6 +3722,26 @@ path match is path='/org/freedesktop/Hal/Manager' + path_prefix + An object path optionally ending in a slash + + + Matches messages which are sent from or to an + object for which the object path is a prefix of + the given value. Examples of matches are + path_prefix='/org/Application/ObjectManager' or + path_prefix='/org/Application/ContactObjects/'. + + + + This match key was added in version 0.15 of the + D-Bus specification and implemented by the bus + daemon in dbus 1.4.7 and later. + + + + + destination A unique name (see ) Matches messages which are being sent to the given unique name. An -- 1.7.4.1