diff options
| author | Ryan Lortie <desrt@desrt.ca> | 2007-09-20 13:04:38 -0400 | 
|---|---|---|
| committer | Ryan Lortie <desrt@desrt.ca> | 2007-09-20 13:04:38 -0400 | 
| commit | f6ec4a80abbfd4e4f4969747c39e625b2689df08 (patch) | |
| tree | 1500ff660a14b0ffd1d5f797d42e8fc322e1933c | |
| parent | 8c6b0ab3f7e437362112eeaf83a566475b85d27c (diff) | |
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.
| -rw-r--r-- | ChangeLog | 18 | ||||
| -rw-r--r-- | bus/signals.c | 119 | ||||
| -rw-r--r-- | bus/signals.h | 31 | ||||
| -rw-r--r-- | dbus/dbus-bus.c | 7 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 14 | 
5 files changed, 152 insertions, 37 deletions
| @@ -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. diff --git a/bus/signals.c b/bus/signals.c index d0845b1a..c90149b2 100644 --- a/bus/signals.c +++ b/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) diff --git a/bus/signals.h b/bus/signals.h index ca74dc99..ab3c33aa 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -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, diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index fd569c2b..c7f43e8c 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -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 diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 39bb7723..9e33944c 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -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> | 
