summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2015-11-06 17:36:31 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2015-11-06 17:37:29 +0100
commitd8fd6b8bd2fbe52a715b2ad79166e970e850c956 (patch)
tree506ee738b9acf2f6501a672060c0d2dacab215a7
parentf690775e74614d5711a7a671e0eee9a003ab8aa2 (diff)
signals: add support for arg0has keywordarg0has-91755
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=91755 Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r--bus/signals.c259
-rw-r--r--bus/signals.h5
2 files changed, 235 insertions, 29 deletions
diff --git a/bus/signals.c b/bus/signals.c
index f2843558..cde30a2d 100644
--- a/bus/signals.c
+++ b/bus/signals.c
@@ -45,15 +45,23 @@ struct BusMatchRule
char *destination;
char *path;
+ /* The low bits of each integer are the actual length; the high bits
+ * are flags. We can assume that the max length is less than
+ * DBUS_MAXIMUM_MATCH_RULE_LENGTH, which is 1024, so we only need 10 bits
+ * for the actual length. */
unsigned int *arg_lens;
+
char **args;
int args_len;
};
+#define BUS_MATCH_ARG_IS_HAS 0x2000000u
#define BUS_MATCH_ARG_NAMESPACE 0x4000000u
#define BUS_MATCH_ARG_IS_PATH 0x8000000u
-#define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
+#define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | \
+ BUS_MATCH_ARG_IS_PATH | \
+ BUS_MATCH_ARG_IS_HAS)
BusMatchRule*
bus_match_rule_new (DBusConnection *matches_go_to)
@@ -276,7 +284,7 @@ match_rule_to_string (BusMatchRule *rule)
{
if (rule->args[i] != NULL)
{
- dbus_bool_t is_path, is_namespace;
+ const char *flag = "";
if (_dbus_string_get_length (&str) > 0)
{
@@ -284,14 +292,17 @@ match_rule_to_string (BusMatchRule *rule)
goto nomem;
}
- is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
- is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
-
+ if (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH)
+ flag = "path";
+ else if (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE)
+ flag = "namespace";
+ else if (rule->arg_lens[i] & BUS_MATCH_ARG_IS_HAS)
+ flag = "has";
+
if (!_dbus_string_append_printf (&str,
"arg%d%s",
i,
- is_path ? "path" :
- is_namespace ? "namespace" : ""))
+ flag))
goto nomem;
if (!append_key_and_escaped_value (&str, "", rule->args[i]))
goto nomem;
@@ -445,12 +456,11 @@ bus_match_rule_set_path (BusMatchRule *rule,
return TRUE;
}
-dbus_bool_t
+static dbus_bool_t
bus_match_rule_set_arg (BusMatchRule *rule,
int arg,
const DBusString *value,
- dbus_bool_t is_path,
- dbus_bool_t is_namespace)
+ unsigned int flag)
{
int length;
char *new;
@@ -514,11 +524,7 @@ bus_match_rule_set_arg (BusMatchRule *rule,
rule->arg_lens[arg] = length;
rule->args[arg] = new;
- if (is_path)
- rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
-
- if (is_namespace)
- rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
+ rule->arg_lens[arg] |= flag;
/* NULL termination didn't get busted */
_dbus_assert (rule->args[rule->args_len] == NULL);
@@ -814,8 +820,7 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
const DBusString *value,
DBusError *error)
{
- dbus_bool_t is_path = FALSE;
- dbus_bool_t is_namespace = FALSE;
+ unsigned int flag = 0;
DBusString key_str;
unsigned long arg;
int length;
@@ -848,17 +853,16 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
if (end != length)
{
- int len1 = strlen ("path");
- if ((end + len1) == length &&
+ if ((end + (int) strlen ("path")) == length &&
_dbus_string_ends_with_c_str (&key_str, "path"))
{
- is_path = TRUE;
+ flag = BUS_MATCH_ARG_IS_PATH;
}
else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
{
int value_len = _dbus_string_get_length (value);
- is_namespace = TRUE;
+ flag = BUS_MATCH_ARG_NAMESPACE;
if (!_dbus_validate_bus_namespace (value, 0, value_len))
{
@@ -868,6 +872,11 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
goto failed;
}
}
+ else if ((end + (int) strlen ("has")) == length &&
+ _dbus_string_ends_with_c_str (&key_str, "has"))
+ {
+ flag = BUS_MATCH_ARG_IS_HAS;
+ }
else
{
dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
@@ -892,8 +901,8 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule,
"Argument %d matched more than once in match rule\n", key);
goto failed;
}
-
- if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
+
+ if (!bus_match_rule_set_arg (rule, arg, value, flag))
{
BUS_SET_OOM (error);
goto failed;
@@ -1775,6 +1784,26 @@ str_has_prefix (const char *str, const char *prefix)
}
static dbus_bool_t
+match_rule_matches_has (const char *expected_arg,
+ DBusMessageIter *array_iter,
+ unsigned int flags)
+{
+ while (dbus_message_iter_get_arg_type (array_iter) != DBUS_TYPE_INVALID)
+ {
+ const char *next_string;
+
+ dbus_message_iter_get_basic (array_iter, &next_string);
+
+ if (strcmp (next_string, expected_arg) == 0)
+ return TRUE;
+
+ dbus_message_iter_next (array_iter);
+ }
+
+ return FALSE;
+}
+
+static dbus_bool_t
match_rule_matches_string_arg (const char *expected_arg,
int expected_length,
const char *actual_arg,
@@ -2039,7 +2068,23 @@ match_rule_matches (BusMatchRule *rule,
current_type = dbus_message_iter_get_arg_type (&iter);
- if (expected_arg != NULL)
+ if (expected_arg != NULL && (flags & BUS_MATCH_ARG_IS_HAS) != 0)
+ {
+ DBusMessageIter array_iter;
+
+ if (current_type != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse (&iter, &array_iter);
+
+ if (dbus_message_iter_get_arg_type (&array_iter) !=
+ DBUS_TYPE_STRING)
+ return FALSE;
+
+ if (!match_rule_matches_has (expected_arg, &array_iter, flags))
+ return FALSE;
+ }
+ else if (expected_arg != NULL)
{
const char *actual_arg;
@@ -2963,6 +3008,171 @@ test_matching_path_namespace (void)
dbus_message_unref (message1);
}
+static const char * const contains_keyword1[] = {
+ "keyword", NULL
+};
+static const char * const contains_keyword2[] = {
+ "first", "keyword", NULL
+};
+static const char * const contains_keyword3[] = {
+ "keyword", "last", NULL
+};
+static const char * const contains_keyword4[] = {
+ "first", "keyword", "last", NULL
+};
+static const char * const contains_keyword5[] = {
+ "keyword", "keyword", NULL
+};
+static const char * const * const contains_keyword[] = {
+ contains_keyword1,
+ contains_keyword2,
+ contains_keyword3,
+ contains_keyword4,
+ contains_keyword5
+};
+
+static const char * const contains_empty1[] = {
+ "", NULL
+};
+static const char * const contains_empty2[] = {
+ "first", "", NULL
+};
+static const char * const contains_empty3[] = {
+ "", "last", NULL
+};
+static const char * const contains_empty4[] = {
+ "first", "", "last", NULL
+};
+static const char * const contains_empty5[] = {
+ "", "", NULL
+};
+static const char * const * const contains_empty[] = {
+ contains_empty1,
+ contains_empty2,
+ contains_empty3,
+ contains_empty4,
+ contains_empty5
+};
+
+static const char * const doesnt_contain_empty1[] = {
+ "a", NULL
+};
+static const char * const doesnt_contain_empty2[] = {
+ "a", "b", "c", NULL
+};
+static const char * const doesnt_contain_empty3[] = {
+ NULL
+};
+const char * const * const doesnt_contain_empty[] = {
+ doesnt_contain_empty1,
+ doesnt_contain_empty2,
+ doesnt_contain_empty3
+};
+
+static const char * const doesnt_contain_keyword1[] = {
+ "", NULL
+};
+static const char * const doesnt_contain_keyword2[] = {
+ "keywords", NULL
+};
+static const char * const doesnt_contain_keyword3[] = {
+ "notmykeywords", "last", NULL
+};
+static const char * const doesnt_contain_keyword4[] = {
+ "first", "notmykeyword", NULL
+};
+static const char * const doesnt_contain_keyword5[] = {
+ "first", "keywords", "last", NULL
+};
+static const char * const doesnt_contain_keyword6[] = {
+ NULL
+};
+const char * const * const doesnt_contain_keyword[] = {
+ doesnt_contain_keyword1,
+ doesnt_contain_keyword2,
+ doesnt_contain_keyword3,
+ doesnt_contain_keyword4,
+ doesnt_contain_keyword5,
+ doesnt_contain_keyword6
+};
+
+static void
+test_arr_match (const char *rule_text,
+ BusMatchRule *rule,
+ int which,
+ const char * const * keywords,
+ dbus_bool_t should_match)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ const char * const *keyword_iter;
+ dbus_bool_t matched;
+
+ message = dbus_message_new_signal ("/", "com.example.Foo", "Foo");
+ _dbus_assert (message != NULL);
+
+ dbus_message_iter_init_append (message, &iter);
+
+ if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
+ &array_iter))
+ _dbus_assert_not_reached ("OOM");
+
+ for (keyword_iter = keywords; *keyword_iter != NULL; keyword_iter++)
+ {
+ if (!dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING,
+ keyword_iter))
+ _dbus_assert_not_reached ("OOM");
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &array_iter))
+ _dbus_assert_not_reached ("OOM");
+
+ matched = match_rule_matches (rule, NULL, NULL, message, 0);
+
+ if (matched != should_match)
+ {
+ _dbus_warn ("Expected rule %s to %s in test #%d",
+ rule_text,
+ should_match ? "match" : "not match",
+ which);
+ exit (1);
+ }
+
+ dbus_message_unref (message);
+}
+
+static void
+test_matching_has (void)
+{
+ const char *rule_text = "arg0has='keyword'";
+ BusMatchRule *rule;
+ int i;
+
+ rule = check_parse (TRUE, rule_text);
+ _dbus_assert (rule != NULL);
+
+ for (i = 0; i < _DBUS_N_ELEMENTS (contains_keyword); i++)
+ test_arr_match (rule_text, rule, i, contains_keyword[i], TRUE);
+
+ for (i = 0; i < _DBUS_N_ELEMENTS (doesnt_contain_keyword); i++)
+ test_arr_match (rule_text, rule, i, doesnt_contain_keyword[i], FALSE);
+
+ bus_match_rule_unref (rule);
+
+ rule_text = "arg0has=''";
+ rule = check_parse (TRUE, rule_text);
+ _dbus_assert (rule != NULL);
+
+ for (i = 0; i < _DBUS_N_ELEMENTS (contains_empty); i++)
+ test_arr_match (rule_text, rule, i, contains_empty[i], TRUE);
+
+ for (i = 0; i < _DBUS_N_ELEMENTS (doesnt_contain_empty); i++)
+ test_arr_match (rule_text, rule, i, doesnt_contain_empty[i], FALSE);
+
+ bus_match_rule_unref (rule);
+}
+
dbus_bool_t
bus_signals_test (const DBusString *test_data_dir)
{
@@ -2980,6 +3190,7 @@ bus_signals_test (const DBusString *test_data_dir)
test_matching ();
test_path_matching ();
test_matching_path_namespace ();
+ test_matching_has ();
return TRUE;
}
diff --git a/bus/signals.h b/bus/signals.h
index 0edfb07e..b16f2ee5 100644
--- a/bus/signals.h
+++ b/bus/signals.h
@@ -59,11 +59,6 @@ dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule,
dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule,
const char *path,
dbus_bool_t is_namespace);
-dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule,
- int arg,
- const DBusString *value,
- dbus_bool_t is_path,
- dbus_bool_t is_namespace);
/* Calling this methods a client declares that it is creating a rule which
* needs to eavesdrop (e.g., dbus-monitor), any other created rules not