mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-04 06:10:16 +01:00
Add argument path matching support. Bug #11066.
2007-09-20 Ryan Lortie <desrt@desrt.ca>
* dbus/signals.c (struct DBusMatchRule, bus_match_rule_new,
bus_match_rule_set_arg, bus_match_rule_parse_arg_match,
match_rule_matches): Add support for parsing and matching on
arg0path='/some/path' type rules.
* dbus/signals.h (bus_match_rule_set_arg): change to take const
DBusString instead of const char * for the string to match against.
* dbus/dbus-bus.c: add a quick note to dbus_bus_add_match
documentation about the path matching.
* doc/dbus-specification.xml: add a more detailed description of the
changes here.
This commit is contained in:
parent
8c6b0ab3f7
commit
f6ec4a80ab
5 changed files with 152 additions and 37 deletions
18
ChangeLog
18
ChangeLog
|
|
@ -1,3 +1,21 @@
|
|||
2007-09-20 Ryan Lortie <desrt@desrt.ca>
|
||||
|
||||
Add argument path matching support. Bug #11066.
|
||||
|
||||
* dbus/signals.c (struct DBusMatchRule, bus_match_rule_new,
|
||||
bus_match_rule_set_arg, bus_match_rule_parse_arg_match,
|
||||
match_rule_matches): Add support for parsing and matching on
|
||||
arg0path='/some/path' type rules.
|
||||
|
||||
* dbus/signals.h (bus_match_rule_set_arg): change to take const
|
||||
DBusString instead of const char * for the string to match against.
|
||||
|
||||
* dbus/dbus-bus.c: add a quick note to dbus_bus_add_match
|
||||
documentation about the path matching.
|
||||
|
||||
* doc/dbus-specification.xml: add a more detailed description of the
|
||||
changes here.
|
||||
|
||||
2007-09-19 Ryan Lortie <desrt@desrt.ca>
|
||||
|
||||
Add support for compacting DBusStrings to release wasted memory.
|
||||
|
|
|
|||
119
bus/signals.c
119
bus/signals.c
|
|
@ -40,10 +40,13 @@ struct BusMatchRule
|
|||
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)
|
||||
{
|
||||
|
|
@ -86,6 +89,7 @@ bus_match_rule_unref (BusMatchRule *rule)
|
|||
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
|
||||
|
|
@ -205,15 +209,19 @@ match_rule_to_string (BusMatchRule *rule)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
@ -346,23 +354,22 @@ bus_match_rule_set_path (BusMatchRule *rule,
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
@ -371,12 +378,9 @@ bus_match_rule_set_arg (BusMatchRule *rule,
|
|||
|
||||
/* 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;
|
||||
|
|
@ -387,16 +391,42 @@ bus_match_rule_set_arg (BusMatchRule *rule,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -688,8 +718,10 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
|
|||
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
|
||||
|
|
@ -701,6 +733,7 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
|
|||
/* 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)
|
||||
{
|
||||
|
|
@ -709,14 +742,24 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
|
|||
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)
|
||||
{
|
||||
|
|
@ -730,12 +773,11 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
|
|||
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;
|
||||
|
|
@ -1104,13 +1146,20 @@ match_rule_equal (BusMatchRule *a,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -1399,14 +1448,19 @@ match_rule_matches (BusMatchRule *rule,
|
|||
{
|
||||
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;
|
||||
|
|
@ -1415,8 +1469,29 @@ match_rule_matches (BusMatchRule *rule,
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -44,21 +44,22 @@ BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to);
|
|||
BusMatchRule* bus_match_rule_ref (BusMatchRule *rule);
|
||||
void bus_match_rule_unref (BusMatchRule *rule);
|
||||
|
||||
dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule,
|
||||
int type);
|
||||
dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule,
|
||||
const char *interface);
|
||||
dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule,
|
||||
const char *member);
|
||||
dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule,
|
||||
const char *sender);
|
||||
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_arg (BusMatchRule *rule,
|
||||
int arg,
|
||||
const char *value);
|
||||
dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule,
|
||||
int type);
|
||||
dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule,
|
||||
const char *interface);
|
||||
dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule,
|
||||
const char *member);
|
||||
dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule,
|
||||
const char *sender);
|
||||
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_arg (BusMatchRule *rule,
|
||||
int arg,
|
||||
const DBusString *value,
|
||||
dbus_bool_t is_path);
|
||||
|
||||
BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to,
|
||||
const DBusString *rule_text,
|
||||
|
|
|
|||
|
|
@ -1424,6 +1424,13 @@ send_no_return_values (DBusConnection *connection,
|
|||
*
|
||||
* Currently there is no way to match against non-string arguments.
|
||||
*
|
||||
* A specialised form of wildcard matching on arguments is
|
||||
* supported for path-like namespaces. If your argument match has
|
||||
* a 'path' suffix (eg: "arg0path='/some/path/'") then it is
|
||||
* considered a match if the argument exactly matches the given
|
||||
* string or if one of them ends in a '/' and is a prefix of the
|
||||
* other.
|
||||
*
|
||||
* Matching on interface is tricky because method call
|
||||
* messages only optionally specify the interface.
|
||||
* If a message omits the interface, then it will NOT match
|
||||
|
|
|
|||
|
|
@ -3136,6 +3136,20 @@
|
|||
would be arg3='Foo'. Only argument indexes from 0 to 63 should be
|
||||
accepted.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>arg[0, 1, 2, 3, ...]path</literal></entry>
|
||||
<entry>Any string</entry>
|
||||
<entry>Argument path matches provide a specialised form of wildcard
|
||||
matching for path-like namespaces. As with normal argument matches,
|
||||
if the argument is exactly equal to the string given in the match
|
||||
rule then the rule is satisfied. Additionally, there is also a
|
||||
match when either the string given in the match rule or the
|
||||
appropriate message argument ends with '/' and is a prefix of the
|
||||
other. An example argument path match is arg0path='/aa/bb/'. This
|
||||
would match messages with first arguments of '/', '/aa/',
|
||||
'/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match
|
||||
messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue