All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant
@ 2016-03-14  3:41 Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 02/20] dbus: Add _dbus_message_get_nth_string_argument Andrew Zaborowski
                   ` (19 more replies)
  0 siblings, 20 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2685 bytes --]

This will be used for the get_nth_string_argument function in
dbus-message.c.  There seems to be no other way to skip over an iterator
entry without knowing the data type.
---
 ell/dbus-private.h     |  1 +
 ell/dbus-util.c        | 16 ++++++++++++++++
 ell/gvariant-private.h |  1 +
 ell/gvariant-util.c    | 10 ++++++++++
 4 files changed, 28 insertions(+)

diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index 8322475..cfed4f7 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -77,6 +77,7 @@ bool _dbus1_iter_enter_variant(struct l_dbus_message_iter *iter,
 					struct l_dbus_message_iter *variant);
 bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter,
 					struct l_dbus_message_iter *array);
+bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter);
 
 struct dbus_builder *_dbus1_builder_new(void *body, size_t body_size);
 void _dbus1_builder_free(struct dbus_builder *builder);
diff --git a/ell/dbus-util.c b/ell/dbus-util.c
index 5ab4298..9d5b5af 100644
--- a/ell/dbus-util.c
+++ b/ell/dbus-util.c
@@ -805,6 +805,22 @@ bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter,
 	return true;
 }
 
+bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter)
+{
+	size_t len;
+	const char *sig_end;
+
+	sig_end = calc_len_next_item(iter->sig_start + iter->sig_pos,
+					iter->data, iter->pos, iter->len, &len);
+	if (!sig_end)
+		return false;
+
+	iter->pos += len;
+	iter->sig_pos = sig_end - iter->sig_start;
+
+	return true;
+}
+
 struct dbus_builder {
 	struct l_string *signature;
 	void *body;
diff --git a/ell/gvariant-private.h b/ell/gvariant-private.h
index 1acac74..2a20feb 100644
--- a/ell/gvariant-private.h
+++ b/ell/gvariant-private.h
@@ -35,6 +35,7 @@ bool _gvariant_iter_enter_variant(struct l_dbus_message_iter *iter,
 					struct l_dbus_message_iter *variant);
 bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter,
 					struct l_dbus_message_iter *array);
+bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter);
 
 bool _gvariant_valid_signature(const char *sig);
 int _gvariant_get_alignment(const char *signature);
diff --git a/ell/gvariant-util.c b/ell/gvariant-util.c
index 7534509..1aaddc3 100644
--- a/ell/gvariant-util.c
+++ b/ell/gvariant-util.c
@@ -731,6 +731,16 @@ bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter,
 						start, item_size);
 }
 
+bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter)
+{
+	size_t size;
+
+	if (!next_item(iter, &size))
+		return false;
+
+	return true;
+}
+
 struct dbus_builder {
 	struct l_string *signature;
 	void *body;
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/20] dbus: Add _dbus_message_get_nth_string_argument
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 03/20] dbus: Support 2+ arguments in l_dbus_message_get_error Andrew Zaborowski
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2467 bytes --]

We happen to need to access n-th argument specifically only if it is
of a string type in at least three places, so add this shortcut.
---
 ell/dbus-message.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 ell/dbus-private.h |  2 ++
 2 files changed, 47 insertions(+)

diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index c876863..f3557b8 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -392,6 +392,51 @@ LIB_EXPORT void l_dbus_message_unref(struct l_dbus_message *message)
 	l_free(message);
 }
 
+const char *_dbus_message_get_nth_string_argument(
+					struct l_dbus_message *message, int n)
+{
+	struct l_dbus_message_iter iter;
+	const char *signature, *value;
+	void *body;
+	size_t size;
+	char type;
+	bool (*skip_entry)(struct l_dbus_message_iter *);
+	bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
+
+	signature = l_dbus_message_get_signature(message);
+	body = _dbus_message_get_body(message, &size);
+
+	if (!signature)
+		return NULL;
+
+	if (_dbus_message_is_gvariant(message)) {
+		if (!_gvariant_iter_init(&iter, message, signature, NULL,
+						body, size))
+			return NULL;
+
+		skip_entry = _gvariant_iter_skip_entry;
+		get_basic = _gvariant_iter_next_entry_basic;
+	} else {
+		_dbus1_iter_init(&iter, message, signature, NULL, body, size);
+
+		skip_entry = _dbus1_iter_skip_entry;
+		get_basic = _dbus1_iter_next_entry_basic;
+	}
+
+	while (n--)
+		if (!skip_entry(&iter))
+			return NULL;
+
+	type = l_dbus_message_iter_get_type(&iter);
+	if (!strchr("sog", type))
+		return NULL;
+
+	if (!get_basic(&iter, type, &value))
+		return NULL;
+
+	return value;
+}
+
 static bool message_iter_next_entry_valist(struct l_dbus_message_iter *orig,
 						va_list args)
 {
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index cfed4f7..607fdf4 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -115,6 +115,8 @@ enum dbus_message_type _dbus_message_get_type(struct l_dbus_message *message);
 const char * _dbus_message_get_type_as_string(struct l_dbus_message *message);
 uint8_t _dbus_message_get_version(struct l_dbus_message *message);
 uint8_t _dbus_message_get_endian(struct l_dbus_message *message);
+const char *_dbus_message_get_nth_string_argument(
+					struct l_dbus_message *message, int n);
 
 struct l_dbus_message *_dbus_message_new_method_call(uint8_t version,
 							const char *destination,
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/20] dbus: Support 2+ arguments in l_dbus_message_get_error
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 02/20] dbus: Add _dbus_message_get_nth_string_argument Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments Andrew Zaborowski
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]

Error messages may have any number of arguments, the first one is still
error string if it's a string.
---
 ell/dbus-message.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index f3557b8..f223c70 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1101,7 +1101,6 @@ error:
 LIB_EXPORT bool l_dbus_message_get_error(struct l_dbus_message *message,
 					const char **name, const char **text)
 {
-	struct l_dbus_message_iter iter;
 	struct dbus_header *hdr;
 	const char *str;
 
@@ -1116,17 +1115,11 @@ LIB_EXPORT bool l_dbus_message_get_error(struct l_dbus_message *message,
 	if (!message->signature)
 		return false;
 
-	if (strcmp(message->signature, "s"))
+	if (message->signature[0] != 's')
 		return false;
 
-	if (_dbus_message_is_gvariant(message))
-		_gvariant_iter_init(&iter, message, message->signature, NULL,
-					message->body, message->body_size);
-	else
-		_dbus1_iter_init(&iter, message, message->signature, NULL,
-				message->body, message->body_size);
-
-	if (!message_iter_next_entry(&iter, &str))
+	str = _dbus_message_get_nth_string_argument(message, 0);
+	if (!str)
 		return false;
 
 	if (!message->error_name)
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 02/20] dbus: Add _dbus_message_get_nth_string_argument Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 03/20] dbus: Support 2+ arguments in l_dbus_message_get_error Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 16:49   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c Andrew Zaborowski
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2579 bytes --]

It seems that l_dbus_message_iter_get_type can't be used to get the
value of a single argument and be called repeatedly, it might crash if
the number and types of call arguments don't match the message arguments.
Also try to support the string arguments that come after non-string
arguments in the bloom filter.
---
 ell/dbus-message.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index f223c70..a123a8a 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1412,9 +1412,12 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
 	const char *signature;
 	void *body;
 	size_t body_size;
-	struct l_dbus_message_iter iter;
+	struct l_dbus_message_iter iter, tmp;
 	uint8_t argn;
 	char buf[256];
+	bool (*skip_entry)(struct l_dbus_message_iter *);
+	bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
+	char type;
 
 	/* The string "interface:" suffixed by the interface name */
 	attr = l_dbus_message_get_interface(message);
@@ -1458,17 +1461,32 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
 
 	body = _dbus_message_get_body(message, &body_size);
 
-	if (_dbus_message_is_gvariant(message))
-		_gvariant_iter_init(&iter, message, signature, NULL,
-					body, body_size);
-	else
+	if (_dbus_message_is_gvariant(message)) {
+		if (!_gvariant_iter_init(&iter, message, signature, NULL,
+						body, body_size))
+			return false;
+
+		skip_entry = _gvariant_iter_skip_entry;
+		get_basic = _gvariant_iter_next_entry_basic;
+	} else {
 		_dbus1_iter_init(&iter, message, signature, NULL,
-				body, body_size);
+					body, body_size);
+
+		skip_entry = _dbus1_iter_skip_entry;
+		get_basic = _dbus1_iter_next_entry_basic;
+	}
 
 	argn = 0;
 
-	while (*signature == 's' || *signature == 'o' || *signature == 'g') {
-		if (!message_iter_next_entry(&iter, &attr))
+	do {
+		type = l_dbus_message_iter_get_type(&iter);
+		if (!strchr("sog", type))
+			goto next;
+
+		/* Don't let get_basic move iter->pos without moving sig_pos */
+		memcpy(&tmp, &iter, sizeof(tmp));
+
+		if (!get_basic(&tmp, type, &attr))
 			return false;
 
 		sprintf(buf, "arg%hhu", argn);
@@ -1482,9 +1500,9 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
 		_dbus_kernel_bloom_add_parents(filter, f_size, num_hash, buf,
 						attr, '.');
 
+next:
 		argn += 1;
-		signature += 1;
-	}
+	} while (skip_entry(&iter));
 
 	return true;
 }
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 17:37   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 06/20] unit: Add dbus message filter tests Andrew Zaborowski
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 11814 bytes --]

This will be used for the public API for adding and removing signal
callbacks.
---
 Makefile.am        |   1 +
 ell/dbus-filter.c  | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dbus-private.h |  31 +++++
 ell/dbus.h         |  13 ++
 4 files changed, 403 insertions(+)
 create mode 100644 ell/dbus-filter.c

diff --git a/Makefile.am b/Makefile.am
index 256b163..7283a7e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -75,6 +75,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
 			ell/dbus-message.c \
 			ell/dbus-util.c \
 			ell/dbus-service.c \
+			ell/dbus-filter.c \
 			ell/gvariant-private.h \
 			ell/gvariant-util.c \
 			ell/siphash-private.h \
diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
new file mode 100644
index 0000000..2541374
--- /dev/null
+++ b/ell/dbus-filter.c
@@ -0,0 +1,358 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2011-2014  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "queue.h"
+#include "hashmap.h"
+#include "string.h"
+#include "dbus.h"
+#include "dbus-private.h"
+#include "gvariant-private.h"
+#include "private.h"
+
+#define NODE_TYPE_CALLBACK	L_DBUS_MATCH_NONE
+
+struct filter_node {
+	enum l_dbus_match_type type;
+	union {
+		struct {
+			char *value;
+			struct filter_node *children;
+			bool remote_rule;
+		} match;
+		struct {
+			l_dbus_message_func_t func;
+			void *user_data;
+		} callback;
+	};
+	unsigned int id;
+	struct filter_node *next;
+};
+
+struct _dbus_filter {
+	struct l_dbus *dbus;
+	struct filter_node *root;
+	unsigned int signal_id;
+	unsigned int last_id;
+	const struct _dbus_filter_ops *driver;
+};
+
+static void filter_subtree_free(struct filter_node *node)
+{
+	struct filter_node *child, *next;
+
+	if (node->type == NODE_TYPE_CALLBACK) {
+		l_free(node);
+		return;
+	}
+
+	next = node->match.children;
+
+	l_free(node->match.value);
+	l_free(node);
+
+	while (next) {
+		child = next;
+		next = child->next;
+
+		filter_subtree_free(child);
+	}
+}
+
+static void dbus_filter_destroy(void *data)
+{
+	struct _dbus_filter *filter = data;
+
+	if (filter->root)
+		filter_subtree_free(filter->root);
+
+	l_free(filter);
+}
+
+static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
+						struct filter_node *node,
+						struct l_dbus_message *message)
+{
+	const char *value = NULL;
+	struct filter_node *child;
+
+	switch ((int) node->type) {
+	case NODE_TYPE_CALLBACK:
+		node->callback.func(message, node->callback.user_data);
+		return;
+
+	case L_DBUS_MATCH_SENDER:
+		value = l_dbus_message_get_sender(message);
+		break;
+
+	case L_DBUS_MATCH_DESTINATION:
+		value = l_dbus_message_get_destination(message);
+		break;
+
+	case L_DBUS_MATCH_TYPE:
+		value = _dbus_message_get_type_as_string(message);
+		break;
+
+	case L_DBUS_MATCH_PATH:
+		value = l_dbus_message_get_path(message);
+		break;
+
+	case L_DBUS_MATCH_INTERFACE:
+		value = l_dbus_message_get_interface(message);
+		break;
+
+	case L_DBUS_MATCH_MEMBER:
+		value = l_dbus_message_get_member(message);
+		break;
+
+	case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
+		value = _dbus_message_get_nth_string_argument(message,
+						node->type - L_DBUS_MATCH_ARG0);
+		break;
+	}
+
+	if (!value)
+		return;
+
+	if (strcmp(value, node->match.value))
+		return;
+
+	for (child = node->match.children; child; child = child->next)
+		filter_dispatch_match_recurse(filter, child, message);
+}
+
+void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
+{
+	struct _dbus_filter *filter = user_data;
+
+	filter_dispatch_match_recurse(filter, filter->root, message);
+}
+
+struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
+					const struct _dbus_filter_ops *driver)
+{
+	struct _dbus_filter *filter;
+
+	filter = l_new(struct _dbus_filter, 1);
+
+	filter->dbus = dbus;
+	filter->driver = driver;
+
+	if (!filter->driver->skip_register)
+		filter->signal_id = l_dbus_register(dbus, _dbus_filter_dispatch,
+							filter,
+							dbus_filter_destroy);
+
+	return filter;
+}
+
+void _dbus_filter_free(struct _dbus_filter *filter)
+{
+	if (!filter)
+		return;
+
+	if (!filter->driver->skip_register)
+		l_dbus_unregister(filter->dbus, filter->signal_id);
+	else
+		dbus_filter_destroy(filter);
+}
+
+static int condition_compare(const void *a, const void *b)
+{
+	const struct _dbus_filter_condition *condition_a = a, *condition_b = b;
+
+	return condition_a->type - condition_b->type;
+}
+
+unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
+					struct _dbus_filter_condition *rule,
+					int rule_len,
+					l_dbus_message_func_t signal_func,
+					void *user_data)
+{
+	struct filter_node **node_ptr = &filter->root;
+	struct filter_node *node;
+	struct filter_node *parent = filter->root;
+	bool remote_rule = false;
+	struct _dbus_filter_condition *condition, *end = rule + rule_len;
+
+	qsort(rule, rule_len, sizeof(*rule), condition_compare);
+
+	for (condition = rule; condition < end; condition++) {
+		/* See if this condition is already a child of the node */
+		while (*node_ptr) {
+			node = *node_ptr;
+
+			if (node->type == condition->type &&
+					!strcmp(node->match.value,
+						condition->value))
+				break;
+
+			node_ptr = &node->next;
+		}
+
+		/* Add one */
+		if (!*node_ptr) {
+			node = l_new(struct filter_node, 1);
+			node->type = condition->type;
+			node->match.value = l_strdup(condition->value);
+
+			*node_ptr = node;
+		}
+
+		node_ptr = &node->match.children;
+
+		parent = node;
+
+		/*
+		 * Only have to call AddMatch if none of the parent nodes
+		 * have yet created an AddMatch rule on the server.
+		 */
+		remote_rule |= node->match.remote_rule;
+	}
+
+	node = l_new(struct filter_node, 1);
+	node->type = NODE_TYPE_CALLBACK;
+	node->callback.func = signal_func;
+	node->callback.user_data = user_data;
+	node->id = ++filter->last_id;
+	node->next = *node_ptr;
+
+	if (!remote_rule) {
+		if (!filter->driver->add_match(filter->dbus, node->id,
+						rule, rule_len)) {
+			l_free(node);
+			return 0;
+		}
+
+		parent->id = node->id;
+		parent->match.remote_rule = true;
+	}
+
+	*node_ptr = node;
+
+	return node->id;
+}
+
+static bool remove_recurse(struct _dbus_filter *filter,
+				struct filter_node **node, unsigned int id)
+{
+	struct filter_node *tmp;
+
+	for (; *node; node = &(*node)->next) {
+		if ((*node)->type == NODE_TYPE_CALLBACK && (*node)->id == id)
+			break;
+
+		if ((*node)->type != NODE_TYPE_CALLBACK &&
+				remove_recurse(filter, &(*node)->match.children,
+						id))
+			break;
+	}
+
+	if (!*node)
+		return false;
+
+	if ((*node)->type == NODE_TYPE_CALLBACK || !(*node)->match.children) {
+		tmp = *node;
+		*node = tmp->next;
+
+		if (tmp->match.remote_rule)
+			filter->driver->remove_match(filter->dbus, tmp->id);
+
+		filter_subtree_free(tmp);
+	}
+
+	return true;
+}
+
+bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id)
+{
+	return remove_recurse(filter, &filter->root, id);
+}
+
+char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
+				int rule_len)
+{
+	struct l_string *str = l_string_new(63);
+	char *key, arg_buf[6];
+	const char *value, *endp;
+
+	for (; rule_len; rule++, rule_len--) {
+		switch ((int) rule->type) {
+		case L_DBUS_MATCH_SENDER:
+			key = "sender";
+			break;
+		case L_DBUS_MATCH_DESTINATION:
+			key = "destination";
+			break;
+		case L_DBUS_MATCH_TYPE:
+			key = "type";
+			break;
+		case L_DBUS_MATCH_PATH:
+			key = "path";
+			break;
+		case L_DBUS_MATCH_INTERFACE:
+			key = "interface";
+			break;
+		case L_DBUS_MATCH_MEMBER:
+			key = "member";
+			break;
+		case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
+			key = arg_buf;
+			snprintf(arg_buf, sizeof(arg_buf), "arg%i",
+					rule->type - L_DBUS_MATCH_ARG0);
+			break;
+		default:
+			l_string_free(str, true);
+			return NULL;
+		}
+
+		l_string_append(str, key);
+		l_string_append(str, "='");
+
+		/* We only need to escape single-quotes in the values */
+		value = rule->value;
+
+		while ((endp = strchr(value, '\''))) {
+			l_string_append_fixed(str, value, endp - value);
+			l_string_append(str, "'\\''");
+
+			value = endp + 1;
+		}
+
+		l_string_append(str, value);
+		l_string_append_c(str, '\'');
+
+		if (rule_len > 1)
+			l_string_append_c(str, ',');
+	}
+
+	return l_string_free(str, false);
+}
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index 607fdf4..d4a4782 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -64,6 +64,9 @@ struct _dbus_property;
 struct l_dbus_message_iter;
 struct l_dbus_message;
 struct l_dbus;
+struct _dbus_filter;
+struct _dbus_filter_condition;
+struct _dbus_filter_ops;
 
 void _dbus1_iter_init(struct l_dbus_message_iter *iter,
 			struct l_dbus_message *message,
@@ -241,6 +244,34 @@ uint8_t _dbus_get_version(struct l_dbus *dbus);
 int _dbus_get_fd(struct l_dbus *dbus);
 struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus);
 
+struct _dbus_filter_condition {
+	enum l_dbus_match_type type;
+	const char *value;
+};
+
+struct _dbus_filter_ops {
+	bool skip_register;
+	bool (*add_match)(struct l_dbus *bus, unsigned int id,
+				const struct _dbus_filter_condition *rule,
+				int rule_len);
+	bool (*remove_match)(struct l_dbus *bus, unsigned int id);
+};
+
+struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
+					const struct _dbus_filter_ops *driver);
+void _dbus_filter_free(struct _dbus_filter *filter);
+
+unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
+					struct _dbus_filter_condition *rule,
+					int rule_len,
+					l_dbus_message_func_t signal_func,
+					void *user_data);
+bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id);
+
+char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
+				int rule_len);
+void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data);
+
 struct dbus1_filter_data;
 
 void _dbus1_filter_format_match(struct dbus1_filter_data *data, char *rule,
diff --git a/ell/dbus.h b/ell/dbus.h
index c8fdec1..24527e0 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -42,6 +42,19 @@ enum l_dbus_bus {
 	L_DBUS_SESSION_BUS,
 };
 
+enum l_dbus_match_type {
+	L_DBUS_MATCH_NONE = 0,
+	L_DBUS_MATCH_TYPE,
+	L_DBUS_MATCH_SENDER,
+	L_DBUS_MATCH_DESTINATION,
+	L_DBUS_MATCH_PATH,
+	L_DBUS_MATCH_INTERFACE,
+	L_DBUS_MATCH_MEMBER,
+	L_DBUS_MATCH_ARG0,
+};
+
+#define L_DBUS_MATCH_ARGUMENT(i)	(L_DBUS_MATCH_ARG0 + (i))
+
 struct l_dbus;
 struct l_dbus_interface;
 struct l_dbus_message_builder;
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/20] unit: Add dbus message filter tests.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (3 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 07/20] dbus-filter: Name owner change tracking support Andrew Zaborowski
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7714 bytes --]

---
 unit/test-dbus-watch.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 230 insertions(+)

diff --git a/unit/test-dbus-watch.c b/unit/test-dbus-watch.c
index 104f432..dce7c4b 100644
--- a/unit/test-dbus-watch.c
+++ b/unit/test-dbus-watch.c
@@ -33,6 +33,7 @@
 
 #include <ell/ell.h>
 #include "ell/dbus-private.h"
+#include "ell/private.h"
 
 #define DBUS_SERVICE_DBUS	"org.freedesktop.DBus"
 #define DBUS_PATH_DBUS		"/org/freedesktop/DBus"
@@ -245,6 +246,231 @@ static void test_disconnect_watch(const void *test_data)
 	_dbus1_filter_data_destroy(data);
 }
 
+static void test_rule_to_str(const void *test_data)
+{
+	static const struct _dbus_filter_condition rule1[] = {
+		{ L_DBUS_MATCH_TYPE, "signal" },
+		{ L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS },
+		{ L_DBUS_MATCH_PATH, DBUS_PATH_DBUS },
+		{ L_DBUS_MATCH_INTERFACE, DBUS_INTERFACE_DBUS },
+		{ L_DBUS_MATCH_MEMBER, "NameOwnerChanged" },
+		{ L_DBUS_MATCH_ARGUMENT(0), ":1.101" }
+	};
+	static const char *expected1 = "type='signal',"
+		"sender='org.freedesktop.DBus',"
+		"path='/org/freedesktop/DBus',"
+		"interface='org.freedesktop.DBus',"
+		"member='NameOwnerChanged',"
+		"arg0=':1.101'";
+	static const struct _dbus_filter_condition rule2[] = {
+		{ L_DBUS_MATCH_ARGUMENT(0), "'" },
+		{ L_DBUS_MATCH_ARGUMENT(1), "\\" },
+		{ L_DBUS_MATCH_ARGUMENT(2), "," },
+		{ L_DBUS_MATCH_ARGUMENT(3), "\\\\" }
+	};
+	static const char *expected2 =
+		"arg0=''\\''',arg1='\\',arg2=',',arg3='\\\\'";
+	char *str;
+
+	str = _dbus_filter_rule_to_str(rule1, L_ARRAY_SIZE(rule1));
+	assert(str && !strcmp(str, expected1));
+	l_free(str);
+
+	str = _dbus_filter_rule_to_str(rule2, L_ARRAY_SIZE(rule2));
+	assert(str && !strcmp(str, expected2));
+	l_free(str);
+}
+
+struct l_dbus {
+};
+
+struct filter_test_state {
+	struct l_dbus dbus;
+	const struct _dbus_filter_condition *expected_rule;
+	int expected_rule_len;
+	unsigned int expected_id, new_id;
+	int calls[4];
+};
+
+static void rule_compare(const struct _dbus_filter_condition *a, int len_a,
+			const struct _dbus_filter_condition *b, int len_b)
+{
+	int i, j;
+	bool matched[len_a];
+
+	assert(len_a == len_b);
+
+	for (i = 0; i < len_a; i++)
+		matched[i] = false;
+
+	for (i = 0; i < len_a; i++) {
+		for (j = 0; j < len_a; j++)
+			if (!matched[j] && a[i].type == b[j].type &&
+					!strcmp(a[i].value, b[j].value))
+				break;
+
+		assert(j < len_a);
+		matched[j] = true;
+	}
+}
+
+static bool test_add_match(struct l_dbus *dbus, unsigned int id,
+				const struct _dbus_filter_condition *rule,
+				int rule_len)
+{
+	struct filter_test_state *test =
+		container_of(dbus, struct filter_test_state, dbus);
+
+	assert(test->expected_rule);
+
+	rule_compare(test->expected_rule, test->expected_rule_len,
+			rule, rule_len);
+
+	test->new_id = id;
+	test->expected_rule = NULL;
+
+	return true;
+}
+
+static bool test_remove_match(struct l_dbus *dbus, unsigned int id)
+{
+	struct filter_test_state *test =
+		container_of(dbus, struct filter_test_state, dbus);
+
+	assert(test->expected_id == id && id);
+
+	test->expected_id = 0;
+
+	return true;
+}
+
+static void test_rule1_cb(struct l_dbus_message *message, void *user_data)
+{
+	struct filter_test_state *test = user_data;
+
+	test->calls[0]++;
+}
+
+static void test_rule2_cb(struct l_dbus_message *message, void *user_data)
+{
+	struct filter_test_state *test = user_data;
+
+	test->calls[1]++;
+}
+
+static void test_rule3_cb(struct l_dbus_message *message, void *user_data)
+{
+	struct filter_test_state *test = user_data;
+
+	test->calls[2]++;
+}
+
+static void test_rule4_cb(struct l_dbus_message *message, void *user_data)
+{
+	struct filter_test_state *test = user_data;
+
+	test->calls[3]++;
+}
+
+static void test_filter_tree(const void *test_data)
+{
+	struct _dbus_filter *filter;
+	struct filter_test_state test = { .calls = { 0, 0, 0, 0 } };
+	static const struct _dbus_filter_ops filter_ops = {
+		.track_name_owner_change = false,
+		.skip_register = true,
+		.add_match = test_add_match,
+		.remove_match = test_remove_match,
+	};
+	static struct _dbus_filter_condition rule123[] = {
+		{ L_DBUS_MATCH_TYPE, "signal" },
+		{ L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS },
+		{ L_DBUS_MATCH_PATH, DBUS_PATH_DBUS },
+		{ L_DBUS_MATCH_INTERFACE, DBUS_INTERFACE_DBUS },
+		{ L_DBUS_MATCH_MEMBER, "NameOwnerChanged" },
+		{ L_DBUS_MATCH_ARGUMENT(0), ":1.101" }
+	};
+	static struct _dbus_filter_condition rule4[] = {
+		{ L_DBUS_MATCH_TYPE, "signal" },
+		{ L_DBUS_MATCH_SENDER, "foo" },
+	};
+	unsigned int id1, id2, id3, id4, internal_id1, internal_id4;
+	struct l_dbus_message *message;
+
+	filter = _dbus_filter_new(&test.dbus, &filter_ops);
+	assert(filter);
+
+	test.expected_rule = rule123;
+	test.expected_rule_len = 2;
+	id1 = _dbus_filter_add_rule(filter, rule123, 2, test_rule1_cb, &test);
+	assert(id1);
+	assert(!test.expected_rule);
+	internal_id1 = test.new_id;
+
+	id2 = _dbus_filter_add_rule(filter, rule123, 4, test_rule2_cb, &test);
+	id3 = _dbus_filter_add_rule(filter, rule123, 6, test_rule3_cb, &test);
+	assert(id2 && id3 && id2 != id1 && id3 != id1 && id3 != id2);
+
+	test.expected_rule = rule4;
+	test.expected_rule_len = 2;
+	id4 = _dbus_filter_add_rule(filter, rule4, 2, test_rule4_cb, &test);
+	assert(id4 && id4 != id1 && id4 != id2 && id4 != id3);
+	assert(!test.expected_rule);
+	internal_id4 = test.new_id;
+
+	assert(test.calls[0] == 0 && test.calls[1] == 0 &&
+			test.calls[2] == 0 && test.calls[3] == 0);
+
+	message = _dbus_message_new_signal(2, DBUS_PATH_DBUS,
+						DBUS_INTERFACE_DBUS,
+						"NameOwnerChanged");
+	l_dbus_message_set_arguments(message, "sss", ":1.101", "", ":1.101");
+	_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
+	_dbus_filter_dispatch(message, filter);
+	l_dbus_message_unref(message);
+
+	message = _dbus_message_new_signal(2, DBUS_PATH_DBUS,
+						DBUS_INTERFACE_DBUS,
+						"NameOwnerChanged");
+	l_dbus_message_set_arguments(message, "");
+	_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
+	_dbus_filter_dispatch(message, filter);
+	l_dbus_message_unref(message);
+
+	message = _dbus_message_new_signal(2, DBUS_PATH_DBUS, "foo", "Bar");
+	l_dbus_message_set_arguments(message, "");
+	_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
+	_dbus_filter_dispatch(message, filter);
+
+	_dbus_message_set_sender(message, "foo");
+	_dbus_filter_dispatch(message, filter);
+
+	_dbus_message_set_sender(message, "bar");
+	_dbus_filter_dispatch(message, filter);
+	l_dbus_message_unref(message);
+
+	assert(test.calls[0] == 3 && test.calls[1] == 2 &&
+			test.calls[2] == 1 && test.calls[3] == 1);
+
+	test.expected_id = 0;
+	assert(_dbus_filter_remove_rule(filter, id2));
+
+	assert(_dbus_filter_remove_rule(filter, id1));
+
+	test.expected_id = internal_id4;
+	assert(_dbus_filter_remove_rule(filter, id4));
+	assert(!test.expected_id);
+
+	test.expected_id = internal_id1;
+	assert(_dbus_filter_remove_rule(filter, id3));
+	assert(!test.expected_id);
+
+	_dbus_filter_free(filter);
+
+	assert(test.calls[0] == 3 && test.calls[1] == 2 &&
+			test.calls[2] == 1 && test.calls[3] == 1);
+}
+
 int main(int argc, char *argv[])
 {
 	l_test_init(&argc, &argv);
@@ -264,5 +490,9 @@ int main(int argc, char *argv[])
 	l_test_add("DBus disconnect watch", test_disconnect_watch,
 						&disconnect_test);
 
+	l_test_add("_dbus_filter_rule_to_str", test_rule_to_str, NULL);
+
+	l_test_add("DBus filter tree", test_filter_tree, NULL);
+
 	return l_test_run();
 }
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/20] dbus-filter: Name owner change tracking support.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (4 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 06/20] unit: Add dbus message filter tests Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 18:03   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 08/20] dbus: Classic dbus filter_ops implementation Andrew Zaborowski
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 6360 bytes --]

This is needed because incoming message callbacks normally care what
Well-known Bus Name the message comes from but the sender field of the
message normally stores unique bus names in classic dbus.  The
Well-known names may be re-assigned to different unique names while the
rule is in place.
---
 ell/dbus-filter.c  | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ell/dbus-private.h |   5 +++
 2 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
index 2541374..f2cc023 100644
--- a/ell/dbus-filter.c
+++ b/ell/dbus-filter.c
@@ -62,6 +62,12 @@ struct _dbus_filter {
 	unsigned int signal_id;
 	unsigned int last_id;
 	const struct _dbus_filter_ops *driver;
+	struct l_hashmap *unique_names;
+};
+
+struct unique_name_record {
+	int ref_count;
+	char *unique_name;
 };
 
 static void filter_subtree_free(struct filter_node *node)
@@ -86,6 +92,14 @@ static void filter_subtree_free(struct filter_node *node)
 	}
 }
 
+static void unique_name_record_free(void *data)
+{
+	struct unique_name_record *name_rec = data;
+
+	l_free(name_rec->unique_name);
+	l_free(name_rec);
+}
+
 static void dbus_filter_destroy(void *data)
 {
 	struct _dbus_filter *filter = data;
@@ -93,6 +107,10 @@ static void dbus_filter_destroy(void *data)
 	if (filter->root)
 		filter_subtree_free(filter->root);
 
+	if (filter->unique_names)
+		l_hashmap_destroy(filter->unique_names,
+					unique_name_record_free);
+
 	l_free(filter);
 }
 
@@ -101,6 +119,8 @@ static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
 						struct l_dbus_message *message)
 {
 	const char *value = NULL;
+	const char *alt_value = NULL;
+	const struct unique_name_record *name_rec;
 	struct filter_node *child;
 
 	switch ((int) node->type) {
@@ -141,7 +161,18 @@ static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
 	if (!value)
 		return;
 
-	if (strcmp(value, node->match.value))
+	if ((node->type == L_DBUS_MATCH_SENDER ||
+				node->type == L_DBUS_MATCH_DESTINATION) &&
+			filter->unique_names) {
+		name_rec = l_hashmap_lookup(filter->unique_names,
+						node->match.value);
+
+		if (name_rec)
+			alt_value = name_rec->unique_name;
+	}
+
+	if (strcmp(value, node->match.value) &&
+			(!alt_value || strcmp(value, alt_value)))
 		return;
 
 	for (child = node->match.children; child; child = child->next)
@@ -155,6 +186,21 @@ void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
 	filter_dispatch_match_recurse(filter, filter->root, message);
 }
 
+void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
+					const char *name, const char *owner)
+{
+	if (_dbus_parse_unique_name(name, NULL))
+		return;
+
+	name_rec = l_hashmap_lookup(filter->unique_names, name);
+	if (!name_rec)
+		return;
+
+	l_free(name_rec->unique_name);
+
+	name_rec->unique_name = (owner && *owner) ? l_strdup(owner) : NULL;
+}
+
 struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
 					const struct _dbus_filter_ops *driver)
 {
@@ -170,6 +216,9 @@ struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
 							filter,
 							dbus_filter_destroy);
 
+	if (filter->driver->track_name_owner_change)
+		filter->unique_names = l_hashmap_string_new();
+
 	return filter;
 }
 
@@ -184,6 +233,49 @@ void _dbus_filter_free(struct _dbus_filter *filter)
 		dbus_filter_destroy(filter);
 }
 
+static void filter_add_bus_name(struct _dbus_filter *filter, const char *name)
+{
+	struct unique_name_record *name_rec;
+
+	if (!filter->unique_names)
+		return;
+
+	if (_dbus_parse_unique_name(name, NULL))
+		return;
+
+	name_rec = l_hashmap_lookup(filter->unique_names, name);
+	if (!name_rec) {
+		name_rec = l_new(struct unique_name_record, 1);
+
+		l_hashmap_insert(filter->unique_names, name, name_rec);
+
+		filter->driver->get_name_owner(filter->dbus, name);
+	}
+
+	name_rec->ref_count++;
+}
+
+static void filter_remove_bus_name(struct _dbus_filter *filter,
+					const char *name)
+{
+	struct unique_name_record *name_rec;
+
+	if (!filter->unique_names)
+		return;
+
+	if (_dbus_parse_unique_name(name, NULL))
+		return;
+
+	name_rec = l_hashmap_lookup(filter->unique_names, name);
+
+	if (--name_rec->ref_count)
+		return;
+
+	l_hashmap_remove(filter->unique_names, name);
+
+	unique_name_record_free(name_rec);
+}
+
 static int condition_compare(const void *a, const void *b)
 {
 	const struct _dbus_filter_condition *condition_a = a, *condition_b = b;
@@ -225,6 +317,10 @@ unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
 			node->match.value = l_strdup(condition->value);
 
 			*node_ptr = node;
+
+			if (node->type == L_DBUS_MATCH_SENDER ||
+					node->type == L_DBUS_MATCH_DESTINATION)
+				filter_add_bus_name(filter, node->match.value);
 		}
 
 		node_ptr = &node->match.children;
@@ -286,6 +382,10 @@ static bool remove_recurse(struct _dbus_filter *filter,
 		if (tmp->match.remote_rule)
 			filter->driver->remove_match(filter->dbus, tmp->id);
 
+		if (tmp->type == L_DBUS_MATCH_SENDER ||
+				tmp->type == L_DBUS_MATCH_DESTINATION)
+			filter_remove_bus_name(filter, tmp->match.value);
+
 		filter_subtree_free(tmp);
 	}
 
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index d4a4782..de4e706 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -250,11 +250,13 @@ struct _dbus_filter_condition {
 };
 
 struct _dbus_filter_ops {
+	bool track_name_owner_change;
 	bool skip_register;
 	bool (*add_match)(struct l_dbus *bus, unsigned int id,
 				const struct _dbus_filter_condition *rule,
 				int rule_len);
 	bool (*remove_match)(struct l_dbus *bus, unsigned int id);
+	bool (*get_name_owner)(struct l_dbus *bus, const char *name);
 };
 
 struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
@@ -270,7 +272,10 @@ bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id);
 
 char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
 				int rule_len);
+
 void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data);
+void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
+					const char *name, const char *owner);
 
 struct dbus1_filter_data;
 
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/20] dbus: Classic dbus filter_ops implementation.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (5 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 07/20] dbus-filter: Name owner change tracking support Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 18:18   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 09/20] dbus: kdbus " Andrew Zaborowski
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 6449 bytes --]

For the name owner tracking I decided to subscribe to all name
owner changes instead of adding separate rules for every name because
in some scenarios that saves us cycles/memory and we don't have
to hold a list of IDs of every such rule so that we could remove them
when no longer needed.
---
 ell/dbus-filter.c |   5 +++
 ell/dbus.c        | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)

diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
index f2cc023..47f2a0b 100644
--- a/ell/dbus-filter.c
+++ b/ell/dbus-filter.c
@@ -189,6 +189,11 @@ void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
 void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
 					const char *name, const char *owner)
 {
+	struct unique_name_record *name_rec;
+
+	if (!filter)
+		return;
+
 	if (_dbus_parse_unique_name(name, NULL))
 		return;
 
diff --git a/ell/dbus.c b/ell/dbus.c
index 2ac9e58..e9d3424 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -63,6 +63,7 @@ struct l_dbus_ops {
 				struct l_dbus_message *message);
 	struct l_dbus_message *(*recv_message)(struct l_dbus *bus);
 	void (*free)(struct l_dbus *bus);
+	struct _dbus_filter_ops filter_ops;
 };
 
 struct l_dbus {
@@ -87,6 +88,7 @@ struct l_dbus {
 	l_dbus_destroy_func_t debug_destroy;
 	void *debug_data;
 	struct _dbus_object_tree *tree;
+	struct _dbus_filter *filter;
 
 	const struct l_dbus_ops *driver;
 };
@@ -103,6 +105,7 @@ struct l_dbus_classic {
 	struct l_dbus super;
 	void *auth_command;
 	enum auth_state auth_state;
+	struct l_hashmap *match_strings;
 };
 
 struct message_callback {
@@ -553,6 +556,7 @@ static void classic_free(struct l_dbus *dbus)
 		container_of(dbus, struct l_dbus_classic, super);
 
 	l_free(classic->auth_command);
+	l_hashmap_destroy(classic->match_strings, l_free);
 	l_free(classic);
 }
 
@@ -664,13 +668,129 @@ cmsg_fail:
 	return NULL;
 }
 
+static bool classic_add_match(struct l_dbus *dbus, unsigned int id,
+				const struct _dbus_filter_condition *rule,
+				int rule_len)
+{
+	struct l_dbus_classic *classic =
+		container_of(dbus, struct l_dbus_classic, super);
+	char *match_str;
+	struct l_dbus_message *message;
+
+	match_str = _dbus_filter_rule_to_str(rule, rule_len);
+
+	l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id), match_str);
+
+	message = l_dbus_message_new_method_call(dbus,
+						DBUS_SERVICE_DBUS,
+						DBUS_PATH_DBUS,
+						L_DBUS_INTERFACE_DBUS,
+						"AddMatch");
+
+	l_dbus_message_set_arguments(message, "s", match_str);
+
+	send_message(dbus, false, message, NULL, NULL, NULL);
+
+	return true;
+}
+
+static bool classic_remove_match(struct l_dbus *dbus, unsigned int id)
+{
+	struct l_dbus_classic *classic =
+		container_of(dbus, struct l_dbus_classic, super);
+	char *match_str = l_hashmap_remove(classic->match_strings,
+						L_UINT_TO_PTR(id));
+	struct l_dbus_message *message;
+
+	if (!match_str)
+		return false;
+
+	message = l_dbus_message_new_method_call(dbus,
+						DBUS_SERVICE_DBUS,
+						DBUS_PATH_DBUS,
+						L_DBUS_INTERFACE_DBUS,
+						"RemoveMatch");
+
+	l_dbus_message_set_arguments(message, "s", match_str);
+
+	send_message(dbus, false, message, NULL, NULL, NULL);
+
+	l_free(match_str);
+
+	return true;
+}
+
+struct get_name_owner_request {
+	struct l_dbus_message *message;
+	struct l_dbus *dbus;
+};
+
+static void get_name_owner_reply_cb(struct l_dbus_message *reply,
+					void *user_data)
+{
+	struct get_name_owner_request *req = user_data;
+	const char *name, *owner;
+
+	/* No name owner yet */
+	if (l_dbus_message_is_error(reply))
+		return;
+
+	/* Shouldn't happen */
+	if (!l_dbus_message_get_arguments(reply, "s", &owner))
+		return;
+
+	/* Shouldn't happen */
+	if (!l_dbus_message_get_arguments(req->message, "s", &name))
+		return;
+
+	_dbus_filter_name_owner_notify(req->dbus->filter, name, owner);
+}
+
+static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
+{
+	struct get_name_owner_request *req;
+
+	req = l_new(struct get_name_owner_request, 1);
+	req->dbus = bus;
+	req->message = l_dbus_message_new_method_call(bus,
+							DBUS_SERVICE_DBUS,
+							DBUS_PATH_DBUS,
+							L_DBUS_INTERFACE_DBUS,
+							"GetNameOwner");
+
+	l_dbus_message_set_arguments(req->message, "s", name);
+
+	send_message(bus, false, req->message, get_name_owner_reply_cb,
+			req, l_free);
+
+	return true;
+}
+
 static const struct l_dbus_ops classic_ops = {
 	.version = 1,
 	.send_message = classic_send_message,
 	.recv_message = classic_recv_message,
 	.free = classic_free,
+	.filter_ops = {
+		.track_name_owner_change = true,
+		.add_match = classic_add_match,
+		.remove_match = classic_remove_match,
+		.get_name_owner = classic_get_name_owner,
+	},
 };
 
+static void name_owner_changed_cb(struct l_dbus_message *message,
+					void *user_data)
+{
+	struct l_dbus *dbus = user_data;
+	char *name, *old, *new;
+
+	if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new))
+		return;
+
+	_dbus_filter_name_owner_notify(dbus->filter, name, new);
+}
+
 static struct l_dbus *setup_dbus1(int fd, const char *guid)
 {
 	static const unsigned char creds = 0x00;
@@ -680,6 +800,13 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
 	ssize_t written;
 	unsigned int i;
 	long flags;
+	static struct _dbus_filter_condition rule[] = {
+		{ L_DBUS_MATCH_TYPE,		"signal" },
+		{ L_DBUS_MATCH_SENDER,		DBUS_SERVICE_DBUS },
+		{ L_DBUS_MATCH_PATH,		DBUS_PATH_DBUS },
+		{ L_DBUS_MATCH_INTERFACE,	L_DBUS_INTERFACE_DBUS },
+		{ L_DBUS_MATCH_MEMBER,		"NameOwnerChanged" },
+	};
 
 	if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) {
 		close(fd);
@@ -714,6 +841,8 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
 	dbus = &classic->super;
 	dbus->driver = &classic_ops;
 
+	classic->match_strings = l_hashmap_new();
+
 	dbus_init(dbus, fd);
 	dbus->guid = l_strdup(guid);
 
@@ -726,6 +855,9 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
 	l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL);
 	l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL);
 
+	_dbus_filter_add_rule(dbus->filter, rule, L_ARRAY_SIZE(rule),
+				name_owner_changed_cb, dbus);
+
 	return dbus;
 }
 
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/20] dbus: kdbus filter_ops implementation.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (6 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 08/20] dbus: Classic dbus filter_ops implementation Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 10/20] linux: Update kdbus.h to current github version Andrew Zaborowski
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 15544 bytes --]

For the name owner tracking I decided to subscribe to all name
owner changes instead of adding separate rules for every name because
in some scenarios that saves us cycles/memory and we don't have
to hold a list of IDs of every such rule so that we could remove them
when no longer needed.
---
 ell/dbus-kernel.c  | 205 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 ell/dbus-private.h |  17 ++++-
 ell/dbus.c         | 152 +++++++++++++++++++++++++++++----------
 3 files changed, 317 insertions(+), 57 deletions(-)

diff --git a/ell/dbus-kernel.c b/ell/dbus-kernel.c
index 6ce3e6f..25510ad 100644
--- a/ell/dbus-kernel.c
+++ b/ell/dbus-kernel.c
@@ -543,11 +543,16 @@ static int _dbus_kernel_make_message(struct kdbus_msg *kmsg,
 }
 
 int _dbus_kernel_recv(int fd, void *kdbus_pool,
-				struct l_dbus_message **out_message)
+			l_dbus_message_func_t message_func,
+			_dbus_name_owner_change_func_t name_owner_change_func,
+			void *user_data)
 {
 	struct kdbus_cmd_recv recv_cmd;
 	struct kdbus_msg *msg;
+	struct l_dbus_message *dbus_msg;
+	struct kdbus_item *item;
 	int r;
+	size_t min_size;
 
 	memset(&recv_cmd, 0, sizeof(recv_cmd));
 
@@ -559,9 +564,39 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 
 	switch (msg->payload_type) {
 	case KDBUS_PAYLOAD_DBUS:
-		r = _dbus_kernel_make_message(msg, out_message);
+		r = _dbus_kernel_make_message(msg, &dbus_msg);
+		if (!r)
+			message_func(dbus_msg, user_data);
 		break;
 	case KDBUS_PAYLOAD_KERNEL:
+		if (msg->size < sizeof(*msg) + KDBUS_ITEM_HEADER_SIZE) {
+			r = -EPROTONOSUPPORT;
+			break;
+		}
+
+		item = msg->items;
+
+		switch (item->type) {
+		case KDBUS_ITEM_NAME_ADD:
+		case KDBUS_ITEM_NAME_CHANGE:
+		case KDBUS_ITEM_NAME_REMOVE:
+			min_size = KDBUS_ITEM_SIZE(sizeof(item->name_change));
+			if (msg->size < sizeof(*msg) + min_size ||
+					item->size < min_size) {
+				r = -EPROTONOSUPPORT;
+				break;
+			}
+
+			name_owner_change_func(item->name_change.name,
+						item->name_change.old.id,
+						item->name_change.new.id,
+						user_data);
+			break;
+
+		default:
+			break;
+		}
+
 		break;
 	default:
 		r = -EPROTONOSUPPORT;
@@ -600,47 +635,107 @@ int _dbus_kernel_name_acquire(int fd, const char *name)
 }
 
 int _dbus_kernel_add_match(int fd, uint64_t bloom_size, uint64_t bloom_n_hash,
-				uint64_t *out_cookie)
+				const struct _dbus_filter_condition *rule,
+				int rule_len, unsigned int id)
 {
-	static uint64_t cookie = 1;
-	struct kdbus_item *item;
+	struct kdbus_item *bloom, *item;
 	struct kdbus_cmd_match *cmd;
 	size_t cmd_size;
-	int r;
+	const char *prefix;
+	char argstr[8];
+	int r, i;
+	uint64_t sender_id;
 
 	cmd_size = sizeof(struct kdbus_cmd_match);
 	cmd_size += KDBUS_ITEM_SIZE(bloom_size);
 
+	for (i = 0; i < rule_len; i++) {
+		switch (rule[i].type) {
+		case L_DBUS_MATCH_SENDER:
+			if (_dbus_parse_unique_name(rule->value, NULL))
+				cmd_size += KDBUS_ITEM_SIZE(sizeof(item->id));
+			else
+				cmd_size += KDBUS_ITEM_SIZE(
+						strlen(rule[i].value) + 1);
+			break;
+		default:
+			break;
+		}
+	}
+
 	cmd = alloca(cmd_size);
 	memset(cmd, 0, cmd_size);
 	cmd->size = cmd_size;
-	cmd->cookie = cookie++;
+	cmd->cookie = id;
 	item = cmd->items;
 
-	item->size = KDBUS_ITEM_HEADER_SIZE + bloom_size;
-	item->type = KDBUS_ITEM_BLOOM_MASK;
-	_dbus_kernel_bloom_add((uint64_t *) item->data64, bloom_size,
-				bloom_n_hash, "message-type", "signal");
+	bloom = item;
+	bloom->size = KDBUS_ITEM_HEADER_SIZE + bloom_size;
+	bloom->type = KDBUS_ITEM_BLOOM_MASK;
+
+	for (; rule_len; rule++, rule_len--) {
+		switch ((int) rule->type) {
+		case L_DBUS_MATCH_SENDER:
+			item = KDBUS_ITEM_NEXT(item);
+
+			if (_dbus_parse_unique_name(rule->value, &sender_id)) {
+				item->size = KDBUS_ITEM_HEADER_SIZE +
+					strlen(rule->value) + 1;
+				item->type = KDBUS_ITEM_ID;
+				item->id = id;
+			} else {
+				item->size = KDBUS_ITEM_HEADER_SIZE +
+					strlen(rule->value) + 1;
+				item->type = KDBUS_ITEM_NAME;
+				strcpy(item->str, rule->value);
+			}
+
+			continue;
+		case L_DBUS_MATCH_DESTINATION:
+			prefix = "destination";
+			break;
+		case L_DBUS_MATCH_TYPE:
+			prefix = "message-type";
+			break;
+		case L_DBUS_MATCH_PATH:
+			prefix = "path";
+			break;
+		case L_DBUS_MATCH_INTERFACE:
+			prefix = "interface";
+			break;
+		case L_DBUS_MATCH_MEMBER:
+			prefix = "member";
+			break;
+		case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
+			prefix = argstr;
+			snprintf(argstr, sizeof(argstr), "arg%i",
+					rule->type - L_DBUS_MATCH_ARG0);
+			break;
+		default:
+			return -ENOTSUP;
+		}
+
+		_dbus_kernel_bloom_add((uint64_t *) bloom->data64, bloom_size,
+					bloom_n_hash, prefix, rule->value);
+	}
+
 	item = KDBUS_ITEM_NEXT(item);
 
 	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, cmd);
 	if (r < 0)
 		return -errno;
 
-	if (out_cookie)
-		*out_cookie = cmd->cookie;
-
 	return 0;
 }
 
-int _dbus_kernel_remove_match(int fd, uint64_t cookie)
+int _dbus_kernel_remove_match(int fd, unsigned int id)
 {
 	struct kdbus_cmd_match cmd;
 	int r;
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.size = sizeof(cmd);
-	cmd.cookie = cookie;
+	cmd.cookie = id;
 
 	r = ioctl(fd, KDBUS_CMD_MATCH_REMOVE, &cmd);
 	if (r < 0)
@@ -648,3 +743,81 @@ int _dbus_kernel_remove_match(int fd, uint64_t cookie)
 
 	return 0;
 }
+
+int _dbus_kernel_enable_name_owner_notify(int fd)
+{
+	struct {
+		struct kdbus_cmd_match cmd;
+		uint8_t param[KDBUS_ITEM_SIZE(
+				sizeof(struct kdbus_notify_name_change))];
+	} cmd_match;
+	struct kdbus_item *item;
+	int r;
+
+	memset(&cmd_match, 0, sizeof(cmd_match));
+	item = cmd_match.cmd.items;
+	item->type = KDBUS_ITEM_NAME_ADD;
+	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
+	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
+
+	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
+	if (r < 0)
+		return -errno;
+
+	memset(&cmd_match, 0, sizeof(cmd_match));
+	item = cmd_match.cmd.items;
+	item->type = KDBUS_ITEM_NAME_CHANGE;
+	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
+	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
+
+	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
+	if (r < 0)
+		return -errno;
+
+	memset(&cmd_match, 0, sizeof(cmd_match));
+	item = cmd_match.cmd.items;
+	item->type = KDBUS_ITEM_NAME_REMOVE;
+	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
+	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
+
+	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
+	if (r < 0)
+		return -errno;
+
+	return 0;
+}
+
+uint64_t _dbus_kernel_get_name_owner(int fd, void *kdbus_pool,
+					const char *name)
+{
+	struct kdbus_cmd_name_list cmd;
+	struct kdbus_name_list *list;
+	const struct kdbus_cmd_name *entry, *end;
+	uint64_t owner_id = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.flags = KDBUS_NAME_LIST_NAMES;
+
+	if (ioctl(fd, KDBUS_CMD_NAME_LIST, &cmd) < 0)
+		return 0;
+
+	list = (struct kdbus_name_list *) (kdbus_pool + cmd.offset);
+	end = (void *) list + list->size;
+
+	for (entry = list->names; entry < end;
+			entry = (void *) entry + entry->size)
+		if (!strcmp(entry->name, name)) {
+			owner_id = entry->owner_id;
+			break;
+		}
+
+	ioctl(fd, KDBUS_CMD_FREE, cmd.offset);
+
+	return owner_id;
+}
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index de4e706..f210a3c 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -230,15 +230,26 @@ int _dbus_kernel_hello(int fd, const char *connection_name,
 			uint64_t *id, void **pool, char **guid);
 void _dbus_kernel_unmap_pool(void *pool);
 
+typedef void (*_dbus_name_owner_change_func_t)(const char *name,
+						uint64_t old_owner,
+						uint64_t new_owner,
+						void *user_data);
+
 int _dbus_kernel_send(int fd, size_t bloom_size, uint8_t n_bloom_hash,
 			struct l_dbus_message *message);
 int _dbus_kernel_recv(int fd, void *kdbus_pool,
-				struct l_dbus_message **out_message);
+			l_dbus_message_func_t message_func,
+			_dbus_name_owner_change_func_t name_owner_change_func,
+			void *user_data);
 
 int _dbus_kernel_name_acquire(int fd, const char *name);
 int _dbus_kernel_add_match(int fd, uint64_t bloom_size, uint64_t bloom_n_hash,
-				uint64_t *out_cookie);
-int _dbus_kernel_remove_match(int fd, uint64_t cookie);
+				const struct _dbus_filter_condition *rule,
+				int rule_len, unsigned int id);
+int _dbus_kernel_remove_match(int fd, unsigned int it);
+int _dbus_kernel_enable_name_owner_notify(int fd);
+uint64_t _dbus_kernel_get_name_owner(int fd, void *kdbus_pool,
+					const char *name);
 
 uint8_t _dbus_get_version(struct l_dbus *dbus);
 int _dbus_get_fd(struct l_dbus *dbus);
diff --git a/ell/dbus.c b/ell/dbus.c
index e9d3424..487208b 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -277,7 +277,7 @@ static bool message_read_handler(struct l_io *io, void *user_data)
 
 	message = dbus->driver->recv_message(dbus);
 	if (!message)
-		return false;
+		return true;
 
 	header = _dbus_message_get_header(message, &header_size);
 	body = _dbus_message_get_body(message, &body_size);
@@ -347,6 +347,22 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 	return callback->serial;
 }
 
+static void bus_ready(struct l_dbus *dbus)
+{
+	dbus->is_ready = true;
+
+	if (dbus->ready_handler)
+		dbus->ready_handler(dbus->ready_data);
+
+	l_io_set_read_handler(dbus->io, message_read_handler, dbus, NULL);
+
+	/* Check for messages added before the connection was ready */
+	if (l_queue_isempty(dbus->message_queue))
+		return;
+
+	l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL);
+}
+
 static void hello_callback(struct l_dbus_message *message, void *user_data)
 {
 	struct l_dbus *dbus = user_data;
@@ -366,16 +382,7 @@ static void hello_callback(struct l_dbus_message *message, void *user_data)
 
 	dbus->unique_name = l_strdup(unique_name);
 
-	dbus->is_ready = true;
-
-	if (dbus->ready_handler)
-		dbus->ready_handler(dbus->ready_data);
-
-	/* Check for messages added before the connection was ready */
-	if (l_queue_isempty(dbus->message_queue))
-		return;
-
-	l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL);
+	bus_ready(dbus);
 }
 
 static bool auth_write_handler(struct l_io *io, void *user_data)
@@ -934,29 +941,8 @@ static struct l_dbus *setup_unix(char *params)
 static void kdbus_ready(void *user_data)
 {
 	struct l_dbus *dbus = user_data;
-	struct l_dbus_kdbus *kdbus =
-		container_of(dbus, struct l_dbus_kdbus, super);
-	int fd = l_io_get_fd(dbus->io);
-	int r;
-
-	r = _dbus_kernel_add_match(fd, kdbus->bloom_size, kdbus->bloom_n_hash,
-					NULL);
-	if (r < 0)
-		l_util_debug(dbus->debug_handler,
-				dbus->debug_data, strerror(-r));
-
-	dbus->is_ready = true;
 
-	if (dbus->ready_handler)
-		dbus->ready_handler(dbus->ready_data);
-
-	l_io_set_read_handler(dbus->io, message_read_handler, dbus, NULL);
-
-	/* Check for messages added before the connection was ready */
-	if (l_queue_isempty(dbus->message_queue))
-		return;
-
-	l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL);
+	bus_ready(dbus);
 }
 
 static void kdbus_free(struct l_dbus *dbus)
@@ -989,25 +975,103 @@ static bool kdbus_send_message(struct l_dbus *dbus,
 	return true;
 }
 
+struct kdbus_message_recv_data {
+	struct l_dbus_message *message;
+	struct l_dbus *dbus;
+};
+
+static void kdbus_message_func(struct l_dbus_message *message, void *user_data)
+{
+	struct kdbus_message_recv_data *recv_data = user_data;
+
+	recv_data->message = message;
+
+	l_util_debug(recv_data->dbus->debug_handler,
+			recv_data->dbus->debug_data, "Read KDBUS Message");
+}
+
+static void kdbus_name_owner_change_func(const char *name, uint64_t old_owner,
+						uint64_t new_owner,
+						void *user_data)
+{
+	struct kdbus_message_recv_data *recv_data = user_data;
+	char owner[32];
+
+	snprintf(owner, sizeof(owner), ":1.%" PRIu64, new_owner);
+
+	_dbus_filter_name_owner_notify(recv_data->dbus->filter, name, owner);
+}
+
 static struct l_dbus_message *kdbus_recv_message(struct l_dbus *dbus)
 {
 	struct l_dbus_kdbus *kdbus =
 			container_of(dbus, struct l_dbus_kdbus, super);
 	int fd = l_io_get_fd(dbus->io);
-	struct l_dbus_message *message = NULL;
+	struct kdbus_message_recv_data recv_data = { NULL, dbus };
 	int r;
 
-	r = _dbus_kernel_recv(fd, kdbus->kdbus_pool, &message);
+	r = _dbus_kernel_recv(fd, kdbus->kdbus_pool, kdbus_message_func,
+				kdbus_name_owner_change_func, &recv_data);
 	if (r < 0) {
 		l_util_debug(dbus->debug_handler,
 				dbus->debug_data, strerror(-r));
 		return NULL;
 	}
 
-	l_util_debug(dbus->debug_handler, dbus->debug_data,
-			"Read KDBUS Message");
+	return recv_data.message;
+}
+
+static bool kdbus_add_match(struct l_dbus *dbus, unsigned int id,
+				const struct _dbus_filter_condition *rule,
+				int rule_len)
+{
+	struct l_dbus_kdbus *kdbus =
+		container_of(dbus, struct l_dbus_kdbus, super);
+	int fd = l_io_get_fd(dbus->io);
+	int r;
+
+	r = _dbus_kernel_add_match(fd, kdbus->bloom_size, kdbus->bloom_n_hash,
+					rule, rule_len, id);
+	if (r < 0)
+		l_util_debug(dbus->debug_handler,
+				dbus->debug_data, strerror(-r));
+
+	return !r;
+}
+
+static bool kdbus_remove_match(struct l_dbus *dbus, unsigned int id)
+{
+	int fd = l_io_get_fd(dbus->io);
+	int r;
+
+	r = _dbus_kernel_remove_match(fd, id);
+	if (r < 0)
+		l_util_debug(dbus->debug_handler,
+				dbus->debug_data, strerror(-r));
+
+	return !r;
+}
+
+static bool kdbus_get_name_owner(struct l_dbus *dbus, const char *name)
+{
+	struct l_dbus_kdbus *kdbus =
+		container_of(dbus, struct l_dbus_kdbus, super);
+	int fd = l_io_get_fd(dbus->io);
+	uint64_t owner_id;
+	char owner[32];
+
+	owner_id = _dbus_kernel_get_name_owner(fd, kdbus->kdbus_pool, name);
+	if (!owner_id) {
+		l_util_debug(dbus->debug_handler,
+				dbus->debug_data, "Error getting name owner");
+		return false;
+	}
+
+	snprintf(owner, sizeof(owner), ":1.%" PRIu64, owner_id);
+
+	_dbus_filter_name_owner_notify(dbus->filter, name, owner);
 
-	return message;
+	return true;
 }
 
 static const struct l_dbus_ops kdbus_ops = {
@@ -1015,12 +1079,19 @@ static const struct l_dbus_ops kdbus_ops = {
 	.free = kdbus_free,
 	.send_message = kdbus_send_message,
 	.recv_message = kdbus_recv_message,
+	.filter_ops = {
+		.track_name_owner_change = true,
+		.add_match = kdbus_add_match,
+		.remove_match = kdbus_remove_match,
+		.get_name_owner = kdbus_get_name_owner,
+	},
 };
 
 static struct l_dbus *setup_kdbus(int fd)
 {
 	struct l_dbus *dbus;
 	struct l_dbus_kdbus *kdbus;
+	int r;
 
 	kdbus = l_new(struct l_dbus_kdbus, 1);
 	dbus = &kdbus->super;
@@ -1041,6 +1112,11 @@ static struct l_dbus *setup_kdbus(int fd)
 
 	l_idle_oneshot(kdbus_ready, dbus, NULL);
 
+	r = _dbus_kernel_enable_name_owner_notify(fd);
+	if (r < 0)
+		l_util_debug(dbus->debug_handler,
+				dbus->debug_data, strerror(-r));
+
 	return dbus;
 }
 
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/20] linux: Update kdbus.h to current github version.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (7 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 09/20] dbus: kdbus " Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 11/20] dbus-kernel: Update with kdbus API changes Andrew Zaborowski
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 53426 bytes --]

---
 linux/kdbus.h | 1061 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 547 insertions(+), 514 deletions(-)

diff --git a/linux/kdbus.h b/linux/kdbus.h
index 8f98396..4fc44cb 100644
--- a/linux/kdbus.h
+++ b/linux/kdbus.h
@@ -1,33 +1,22 @@
 /*
- * Copyright (C) 2013 Kay Sievers
- * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- * Copyright (C) 2013 Linux Foundation
- * Copyright (C) 2013 Lennart Poettering
- * Copyright (C) 2013 Daniel Mack <daniel@zonque.org>
- *
  * kdbus is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the
  * Free Software Foundation; either version 2.1 of the License, or (at
  * your option) any later version.
- *
- * "Everything should be made as simple as possible, but not simpler."
- *   -- Albert Einstein
  */
 
-#ifndef _KDBUS_H_
-#define _KDBUS_H_
+#ifndef _UAPI_KDBUS_H_
+#define _UAPI_KDBUS_H_
 
-#ifndef __KERNEL__
-#include <sys/ioctl.h>
-#include <sys/types.h>
+#include <linux/ioctl.h>
 #include <linux/types.h>
-#endif
 
 #define KDBUS_IOCTL_MAGIC		0x95
 #define KDBUS_SRC_ID_KERNEL		(0)
 #define KDBUS_DST_ID_NAME		(0)
 #define KDBUS_MATCH_ID_ANY		(~0ULL)
 #define KDBUS_DST_ID_BROADCAST		(~0ULL)
+#define KDBUS_FLAG_NEGOTIATE		(1ULL << 63)
 
 /**
  * struct kdbus_notify_id_change - name registry change message
@@ -44,12 +33,12 @@
 struct kdbus_notify_id_change {
 	__u64 id;
 	__u64 flags;
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_notify_name_change - name registry change message
- * @old:		ID and flags of former owner of a name
- * @new:		ID and flags of new owner of a name
+ * @old_id:		ID and flags of former owner of a name
+ * @new_id:		ID and flags of new owner of a name
  * @name:		Well-known name
  *
  * Sent from kernel to userspace when the owner or activator of
@@ -61,34 +50,67 @@ struct kdbus_notify_id_change {
  *   KDBUS_ITEM_NAME_CHANGE
  */
 struct kdbus_notify_name_change {
-	struct kdbus_notify_id_change old;
-	struct kdbus_notify_id_change new;
+	struct kdbus_notify_id_change old_id;
+	struct kdbus_notify_id_change new_id;
 	char name[0];
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_creds - process credentials
  * @uid:		User ID
+ * @euid:		Effective UID
+ * @suid:		Saved UID
+ * @fsuid:		Filesystem UID
  * @gid:		Group ID
- * @pid:		Process ID
- * @tid:		Thread ID
- * @starttime:		Starttime of the process
- *
- * The starttime of the process PID. This is useful to detect PID overruns
- * from the client side. i.e. if you use the PID to look something up in
- * /proc/$PID/ you can afterwards check the starttime field of it, to ensure
- * you didn't run into a PID overrun.
+ * @egid:		Effective GID
+ * @sgid:		Saved GID
+ * @fsgid:		Filesystem GID
  *
  * Attached to:
  *   KDBUS_ITEM_CREDS
  */
 struct kdbus_creds {
 	__u64 uid;
+	__u64 euid;
+	__u64 suid;
+	__u64 fsuid;
 	__u64 gid;
+	__u64 egid;
+	__u64 sgid;
+	__u64 fsgid;
+} __attribute__((__aligned__(8)));
+
+/**
+ * struct kdbus_pids - process identifiers
+ * @pid:		Process ID
+ * @tid:		Thread ID
+ * @ppid:		Parent process ID
+ *
+ * The PID and TID of a process.
+ *
+ * Attached to:
+ *   KDBUS_ITEM_PIDS
+ */
+struct kdbus_pids {
 	__u64 pid;
 	__u64 tid;
-	__u64 starttime;
-};
+	__u64 ppid;
+} __attribute__((__aligned__(8)));
+
+/**
+ * struct kdbus_caps - process capabilities
+ * @last_cap:	Highest currently known capability bit
+ * @caps:	Variable number of 32-bit capabilities flags
+ *
+ * Contains a variable number of 32-bit capabilities flags.
+ *
+ * Attached to:
+ *   KDBUS_ITEM_CAPS
+ */
+struct kdbus_caps {
+	__u32 last_cap;
+	__u32 caps[0];
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_audit - audit information
@@ -99,9 +121,9 @@ struct kdbus_creds {
  *   KDBUS_ITEM_AUDIT
  */
 struct kdbus_audit {
-	__u64 sessionid;
-	__u64 loginuid;
-};
+	__u32 sessionid;
+	__u32 loginuid;
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_timestamp
@@ -116,17 +138,17 @@ struct kdbus_timestamp {
 	__u64 seqnum;
 	__u64 monotonic_ns;
 	__u64 realtime_ns;
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_vec - I/O vector for kdbus payload items
  * @size:		The size of the vector
- * @address:		Memory address for memory addresses
+ * @address:		Memory address of data buffer
  * @offset:		Offset in the in-message payload memory,
  *			relative to the message head
  *
  * Attached to:
- *   KDBUS_ITEM_PAYLOAD_VEC
+ *   KDBUS_ITEM_PAYLOAD_VEC, KDBUS_ITEM_PAYLOAD_OFF
  */
 struct kdbus_vec {
 	__u64 size;
@@ -134,7 +156,7 @@ struct kdbus_vec {
 		__u64 address;
 		__u64 offset;
 	};
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_bloom_parameter - bus-wide bloom parameters
@@ -144,7 +166,7 @@ struct kdbus_vec {
 struct kdbus_bloom_parameter {
 	__u64 size;
 	__u64 n_hash;
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_bloom_filter - bloom filter containing n elements
@@ -154,22 +176,24 @@ struct kdbus_bloom_parameter {
 struct kdbus_bloom_filter {
 	__u64 generation;
 	__u64 data[0];
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_memfd - a kdbus memfd
- * @size:		The memfd's size
+ * @start:		The offset into the memfd where the segment starts
+ * @size:		The size of the memfd segment
  * @fd:			The file descriptor number
- * @__pad:		Padding to ensure proper alignement and size
+ * @__pad:		Padding to ensure proper alignment and size
  *
  * Attached to:
  *   KDBUS_ITEM_PAYLOAD_MEMFD
  */
 struct kdbus_memfd {
+	__u64 start;
 	__u64 size;
 	int fd;
 	__u32 __pad;
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * struct kdbus_name - a registered well-known name with its flags
@@ -177,11 +201,39 @@ struct kdbus_memfd {
  * @name:		Well-known name
  *
  * Attached to:
- *   KDBUS_ITEM_NAME
+ *   KDBUS_ITEM_OWNED_NAME
  */
 struct kdbus_name {
 	__u64 flags;
 	char name[0];
+} __attribute__((__aligned__(8)));
+
+/**
+ * enum kdbus_policy_access_type - permissions of a policy record
+ * @_KDBUS_POLICY_ACCESS_NULL:	Uninitialized/invalid
+ * @KDBUS_POLICY_ACCESS_USER:	Grant access to a uid
+ * @KDBUS_POLICY_ACCESS_GROUP:	Grant access to gid
+ * @KDBUS_POLICY_ACCESS_WORLD:	World-accessible
+ */
+enum kdbus_policy_access_type {
+	_KDBUS_POLICY_ACCESS_NULL,
+	KDBUS_POLICY_ACCESS_USER,
+	KDBUS_POLICY_ACCESS_GROUP,
+	KDBUS_POLICY_ACCESS_WORLD,
+};
+
+/**
+ * enum kdbus_policy_access_flags - mode flags
+ * @KDBUS_POLICY_OWN:		Allow to own a well-known name
+ *				Implies KDBUS_POLICY_TALK and KDBUS_POLICY_SEE
+ * @KDBUS_POLICY_TALK:		Allow communication to a well-known name
+ *				Implies KDBUS_POLICY_SEE
+ * @KDBUS_POLICY_SEE:		Allow to see a well-known name
+ */
+enum kdbus_policy_type {
+	KDBUS_POLICY_SEE	= 0,
+	KDBUS_POLICY_TALK,
+	KDBUS_POLICY_OWN,
 };
 
 /**
@@ -195,83 +247,151 @@ struct kdbus_policy_access {
 	__u64 type;	/* USER, GROUP, WORLD */
 	__u64 access;	/* OWN, TALK, SEE */
 	__u64 id;	/* uid, gid, 0 */
+} __attribute__((__aligned__(8)));
+
+/**
+ * enum kdbus_attach_flags - flags for metadata attachments
+ * @KDBUS_ATTACH_TIMESTAMP:		Timestamp
+ * @KDBUS_ATTACH_CREDS:			Credentials
+ * @KDBUS_ATTACH_PIDS:			PIDs
+ * @KDBUS_ATTACH_AUXGROUPS:		Auxiliary groups
+ * @KDBUS_ATTACH_NAMES:			Well-known names
+ * @KDBUS_ATTACH_TID_COMM:		The "comm" process identifier of the TID
+ * @KDBUS_ATTACH_PID_COMM:		The "comm" process identifier of the PID
+ * @KDBUS_ATTACH_EXE:			The path of the executable
+ * @KDBUS_ATTACH_CMDLINE:		The process command line
+ * @KDBUS_ATTACH_CGROUP:		The croup membership
+ * @KDBUS_ATTACH_CAPS:			The process capabilities
+ * @KDBUS_ATTACH_SECLABEL:		The security label
+ * @KDBUS_ATTACH_AUDIT:			The audit IDs
+ * @KDBUS_ATTACH_CONN_DESCRIPTION:	The human-readable connection name
+ * @_KDBUS_ATTACH_ALL:			All of the above
+ * @_KDBUS_ATTACH_ANY:			Wildcard match to enable any kind of
+ *					metatdata.
+ */
+enum kdbus_attach_flags {
+	KDBUS_ATTACH_TIMESTAMP		=  1ULL <<  0,
+	KDBUS_ATTACH_CREDS		=  1ULL <<  1,
+	KDBUS_ATTACH_PIDS		=  1ULL <<  2,
+	KDBUS_ATTACH_AUXGROUPS		=  1ULL <<  3,
+	KDBUS_ATTACH_NAMES		=  1ULL <<  4,
+	KDBUS_ATTACH_TID_COMM		=  1ULL <<  5,
+	KDBUS_ATTACH_PID_COMM		=  1ULL <<  6,
+	KDBUS_ATTACH_EXE		=  1ULL <<  7,
+	KDBUS_ATTACH_CMDLINE		=  1ULL <<  8,
+	KDBUS_ATTACH_CGROUP		=  1ULL <<  9,
+	KDBUS_ATTACH_CAPS		=  1ULL << 10,
+	KDBUS_ATTACH_SECLABEL		=  1ULL << 11,
+	KDBUS_ATTACH_AUDIT		=  1ULL << 12,
+	KDBUS_ATTACH_CONN_DESCRIPTION	=  1ULL << 13,
+	_KDBUS_ATTACH_ALL		=  (1ULL << 14) - 1,
+	_KDBUS_ATTACH_ANY		=  ~0ULL
 };
 
 /**
  * enum kdbus_item_type - item types to chain data in a list
- * @_KDBUS_ITEM_NULL:		Uninitialized/invalid
- * @_KDBUS_ITEM_USER_BASE:	Start of user items
- * @KDBUS_ITEM_PAYLOAD_VEC:	Vector to data
- * @KDBUS_ITEM_PAYLOAD_OFF:	Data at returned offset to message head
- * @KDBUS_ITEM_PAYLOAD_MEMFD:	Data as sealed memfd
- * @KDBUS_ITEM_FDS:		Attached file descriptors
- * @KDBUS_ITEM_BLOOM_PARAMETER:	Bus-wide bloom parameters, used with
- *				KDBUS_CMD_BUS_MAKE, carries a
- *				struct kdbus_bloom_parameter
- * @KDBUS_ITEM_BLOOM_FILTER:	Bloom filter carried with a message, used to
- *				match against a bloom mask of a connection,
- *				carries a struct kdbus_bloom_filter
- * @KDBUS_ITEM_BLOOM_MASK:	Bloom mask used to match against a message's
- *				bloom filter
- * @KDBUS_ITEM_DST_NAME:	Destination's well-known name
- * @KDBUS_ITEM_MAKE_NAME:	Name of domain, bus, endpoint
- * @KDBUS_ITEM_MEMFD_NAME:	The human readable name of a memfd (debugging)
- * @KDBUS_ITEM_ATTACH_FLAGS:	Attach-flags, used for updating which metadata
- *				a connection subscribes to
- * @_KDBUS_ITEM_ATTACH_BASE:	Start of metadata attach items
- * @KDBUS_ITEM_NAME:		Well-know name with flags
- * @KDBUS_ITEM_ID:		Connection ID
- * @KDBUS_ITEM_TIMESTAMP:	Timestamp
- * @KDBUS_ITEM_CREDS:		Process credential
- * @KDBUS_ITEM_PID_COMM:	Process ID "comm" identifier
- * @KDBUS_ITEM_TID_COMM:	Thread ID "comm" identifier
- * @KDBUS_ITEM_EXE:		The path of the executable
- * @KDBUS_ITEM_CMDLINE:		The process command line
- * @KDBUS_ITEM_CGROUP:		The croup membership
- * @KDBUS_ITEM_CAPS:		The process capabilities
- * @KDBUS_ITEM_SECLABEL:	The security label
- * @KDBUS_ITEM_AUDIT:		The audit IDs
- * @KDBUS_ITEM_CONN_NAME:	The connection's human-readable name (debugging)
- * @_KDBUS_ITEM_POLICY_BASE:	Start of policy items
- * @KDBUS_ITEM_POLICY_ACCESS:	Policy access block
- * @_KDBUS_ITEM_KERNEL_BASE:	Start of kernel-generated message items
- * @KDBUS_ITEM_NAME_ADD:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_REMOVE:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_CHANGE:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_ID_ADD:		Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_ID_REMOVE:	Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_REPLY_TIMEOUT:	Timeout has been reached
- * @KDBUS_ITEM_REPLY_DEAD:	Destination died
+ * @_KDBUS_ITEM_NULL:			Uninitialized/invalid
+ * @_KDBUS_ITEM_USER_BASE:		Start of user items
+ * @KDBUS_ITEM_NEGOTIATE:		Negotiate supported items
+ * @KDBUS_ITEM_PAYLOAD_VEC:		Vector to data
+ * @KDBUS_ITEM_PAYLOAD_OFF:		Data at returned offset to message head
+ * @KDBUS_ITEM_PAYLOAD_MEMFD:		Data as sealed memfd
+ * @KDBUS_ITEM_FDS:			Attached file descriptors
+ * @KDBUS_ITEM_CANCEL_FD:		FD used to cancel a synchronous
+ *					operation by writing to it from
+ *					userspace
+ * @KDBUS_ITEM_BLOOM_PARAMETER:		Bus-wide bloom parameters, used with
+ *					KDBUS_CMD_BUS_MAKE, carries a
+ *					struct kdbus_bloom_parameter
+ * @KDBUS_ITEM_BLOOM_FILTER:		Bloom filter carried with a message,
+ *					used to match against a bloom mask of a
+ *					connection, carries a struct
+ *					kdbus_bloom_filter
+ * @KDBUS_ITEM_BLOOM_MASK:		Bloom mask used to match against a
+ *					message'sbloom filter
+ * @KDBUS_ITEM_DST_NAME:		Destination's well-known name
+ * @KDBUS_ITEM_MAKE_NAME:		Name of domain, bus, endpoint
+ * @KDBUS_ITEM_ATTACH_FLAGS_SEND:	Attach-flags, used for updating which
+ *					metadata a connection opts in to send
+ * @KDBUS_ITEM_ATTACH_FLAGS_RECV:	Attach-flags, used for updating which
+ *					metadata a connection requests to
+ *					receive for each reeceived message
+ * @KDBUS_ITEM_ID:			Connection ID
+ * @KDBUS_ITEM_NAME:			Well-know name with flags
+ * @_KDBUS_ITEM_ATTACH_BASE:		Start of metadata attach items
+ * @KDBUS_ITEM_TIMESTAMP:		Timestamp
+ * @KDBUS_ITEM_CREDS:			Process credentials
+ * @KDBUS_ITEM_PIDS:			Process identifiers
+ * @KDBUS_ITEM_AUXGROUPS:		Auxiliary process groups
+ * @KDBUS_ITEM_OWNED_NAME:		A name owned by the associated
+ *					connection
+ * @KDBUS_ITEM_TID_COMM:		Thread ID "comm" identifier
+ *					(Don't trust this, see below.)
+ * @KDBUS_ITEM_PID_COMM:		Process ID "comm" identifier
+ *					(Don't trust this, see below.)
+ * @KDBUS_ITEM_EXE:			The path of the executable
+ *					(Don't trust this, see below.)
+ * @KDBUS_ITEM_CMDLINE:			The process command line
+ *					(Don't trust this, see below.)
+ * @KDBUS_ITEM_CGROUP:			The croup membership
+ * @KDBUS_ITEM_CAPS:			The process capabilities
+ * @KDBUS_ITEM_SECLABEL:		The security label
+ * @KDBUS_ITEM_AUDIT:			The audit IDs
+ * @KDBUS_ITEM_CONN_DESCRIPTION:	The connection's human-readable name
+ *					(debugging)
+ * @_KDBUS_ITEM_POLICY_BASE:		Start of policy items
+ * @KDBUS_ITEM_POLICY_ACCESS:		Policy access block
+ * @_KDBUS_ITEM_KERNEL_BASE:		Start of kernel-generated message items
+ * @KDBUS_ITEM_NAME_ADD:		Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_REMOVE:		Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_CHANGE:		Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_ID_ADD:			Notification in kdbus_notify_id_change
+ * @KDBUS_ITEM_ID_REMOVE:		Notification in kdbus_notify_id_change
+ * @KDBUS_ITEM_REPLY_TIMEOUT:		Timeout has been reached
+ * @KDBUS_ITEM_REPLY_DEAD:		Destination died
+ *
+ * N.B: The process and thread COMM fields, as well as the CMDLINE and
+ * EXE fields may be altered by unprivileged processes und should
+ * hence *not* used for security decisions. Peers should make use of
+ * these items only for informational purposes, such as generating log
+ * records.
  */
 enum kdbus_item_type {
 	_KDBUS_ITEM_NULL,
 	_KDBUS_ITEM_USER_BASE,
-	KDBUS_ITEM_PAYLOAD_VEC	= _KDBUS_ITEM_USER_BASE,
+	KDBUS_ITEM_NEGOTIATE	= _KDBUS_ITEM_USER_BASE,
+	KDBUS_ITEM_PAYLOAD_VEC,
 	KDBUS_ITEM_PAYLOAD_OFF,
 	KDBUS_ITEM_PAYLOAD_MEMFD,
 	KDBUS_ITEM_FDS,
+	KDBUS_ITEM_CANCEL_FD,
 	KDBUS_ITEM_BLOOM_PARAMETER,
 	KDBUS_ITEM_BLOOM_FILTER,
 	KDBUS_ITEM_BLOOM_MASK,
 	KDBUS_ITEM_DST_NAME,
 	KDBUS_ITEM_MAKE_NAME,
-	KDBUS_ITEM_MEMFD_NAME,
-	KDBUS_ITEM_ATTACH_FLAGS,
+	KDBUS_ITEM_ATTACH_FLAGS_SEND,
+	KDBUS_ITEM_ATTACH_FLAGS_RECV,
+	KDBUS_ITEM_ID,
+	KDBUS_ITEM_NAME,
+	KDBUS_ITEM_DST_ID,
 
+	/* keep these item types in sync with KDBUS_ATTACH_* flags */
 	_KDBUS_ITEM_ATTACH_BASE	= 0x1000,
-	KDBUS_ITEM_NAME		= _KDBUS_ITEM_ATTACH_BASE,
-	KDBUS_ITEM_ID,
-	KDBUS_ITEM_TIMESTAMP,
+	KDBUS_ITEM_TIMESTAMP	= _KDBUS_ITEM_ATTACH_BASE,
 	KDBUS_ITEM_CREDS,
-	KDBUS_ITEM_PID_COMM,
+	KDBUS_ITEM_PIDS,
+	KDBUS_ITEM_AUXGROUPS,
+	KDBUS_ITEM_OWNED_NAME,
 	KDBUS_ITEM_TID_COMM,
+	KDBUS_ITEM_PID_COMM,
 	KDBUS_ITEM_EXE,
 	KDBUS_ITEM_CMDLINE,
 	KDBUS_ITEM_CGROUP,
 	KDBUS_ITEM_CAPS,
 	KDBUS_ITEM_SECLABEL,
 	KDBUS_ITEM_AUDIT,
-	KDBUS_ITEM_CONN_NAME,
+	KDBUS_ITEM_CONN_DESCRIPTION,
 
 	_KDBUS_ITEM_POLICY_BASE	= 0x2000,
 	KDBUS_ITEM_POLICY_ACCESS = _KDBUS_ITEM_POLICY_BASE,
@@ -322,7 +442,9 @@ struct kdbus_item {
 		__u64 id;
 		struct kdbus_vec vec;
 		struct kdbus_creds creds;
+		struct kdbus_pids pids;
 		struct kdbus_audit audit;
+		struct kdbus_caps caps;
 		struct kdbus_timestamp timestamp;
 		struct kdbus_name name;
 		struct kdbus_bloom_parameter bloom_parameter;
@@ -333,38 +455,34 @@ struct kdbus_item {
 		struct kdbus_notify_id_change id_change;
 		struct kdbus_policy_access policy_access;
 	};
-};
+} __attribute__((__aligned__(8)));
 
 /**
  * enum kdbus_msg_flags - type of message
- * @KDBUS_MSG_FLAGS_EXPECT_REPLY:	Expect a reply message, used for
- *					method calls. The userspace-supplied
- *					cookie identifies the message and the
- *					respective reply carries the cookie
- *					in cookie_reply
- * @KDBUS_MSG_FLAGS_SYNC_REPLY:		Wait for destination connection to
- *					reply to this message. The
- *					KDBUS_CMD_MSG_SEND ioctl() will block
- *					until the reply is received, and
- *					offset_reply in struct kdbus_msg will
- *					yield the offset in the sender's pool
- *					where the reply can be found.
- *					This flag is only valid if
- *					@KDBUS_MSG_FLAGS_EXPECT_REPLY is set as
- *					well.
- * @KDBUS_MSG_FLAGS_NO_AUTO_START:	Do not start a service, if the addressed
- *					name is not currently active
+ * @KDBUS_MSG_EXPECT_REPLY:	Expect a reply message, used for
+ *				method calls. The userspace-supplied
+ *				cookie identifies the message and the
+ *				respective reply carries the cookie
+ *				in cookie_reply
+ * @KDBUS_MSG_NO_AUTO_START:	Do not start a service if the addressed
+ *				name is not currently active. This flag is
+ *				not looked at by the kernel but only
+ *				serves as hint for userspace implementations.
+ * @KDBUS_MSG_SIGNAL:		Treat this message as signal
  */
 enum kdbus_msg_flags {
-	KDBUS_MSG_FLAGS_EXPECT_REPLY	= 1 << 0,
-	KDBUS_MSG_FLAGS_SYNC_REPLY	= 1 << 1,
-	KDBUS_MSG_FLAGS_NO_AUTO_START	= 1 << 2,
+	KDBUS_MSG_EXPECT_REPLY	= 1ULL << 0,
+	KDBUS_MSG_NO_AUTO_START	= 1ULL << 1,
+	KDBUS_MSG_SIGNAL	= 1ULL << 2,
 };
 
 /**
  * enum kdbus_payload_type - type of payload carried by message
  * @KDBUS_PAYLOAD_KERNEL:	Kernel-generated simple message
  * @KDBUS_PAYLOAD_DBUS:		D-Bus marshalling "DBusDBus"
+ *
+ * Any payload-type is accepted. Common types will get added here once
+ * established.
  */
 enum kdbus_payload_type {
 	KDBUS_PAYLOAD_KERNEL,
@@ -374,7 +492,7 @@ enum kdbus_payload_type {
 /**
  * struct kdbus_msg - the representation of a kdbus message
  * @size:		Total size of the message
- * @flags:		Message flags (KDBUS_MSG_FLAGS_*)
+ * @flags:		Message flags (KDBUS_MSG_*), userspace → kernel
  * @priority:		Message queue priority value
  * @dst_id:		64-bit ID of the destination connection
  * @src_id:		64-bit ID of the source connection
@@ -382,15 +500,16 @@ enum kdbus_payload_type {
  * @cookie:		Userspace-supplied cookie, for the connection
  *			to identify its messages
  * @timeout_ns:		The time to wait for a message reply from the peer.
- *			If there is no reply, a kernel-generated message
+ *			If there is no reply, and the send command is
+ *			executed asynchronously, a kernel-generated message
  *			with an attached KDBUS_ITEM_REPLY_TIMEOUT item
- *			is sent to @src_id.
+ *			is sent to @src_id. For synchronously executed send
+ *			command, the value denotes the maximum time the call
+ *			blocks to wait for a reply. The timeout is expected in
+ *			nanoseconds and as absolute CLOCK_MONOTONIC value.
  * @cookie_reply:	A reply to the requesting message with the same
  *			cookie. The requesting connection can match its
  *			request and the reply with this value
- * @offset_reply:	If KDBUS_MSG_FLAGS_EXPECT_REPLY, this field will
- *			contain the offset in the sender's pool where the
- *			reply is stored.
  * @items:		A list of kdbus_items containing the message payload
  */
 struct kdbus_msg {
@@ -404,10 +523,56 @@ struct kdbus_msg {
 	union {
 		__u64 timeout_ns;
 		__u64 cookie_reply;
-		__u64 offset_reply;
 	};
 	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+} __attribute__((__aligned__(8)));
+
+/**
+ * struct kdbus_msg_info - returned message container
+ * @offset:		Offset of kdbus_msg slice in pool
+ * @msg_size:		Copy of the kdbus_msg.size field
+ * @return_flags:	Command return flags, kernel → userspace
+ */
+struct kdbus_msg_info {
+	__u64 offset;
+	__u64 msg_size;
+	__u64 return_flags;
+} __attribute__((__aligned__(8)));
+
+/**
+ * enum kdbus_send_flags - flags for sending messages
+ * @KDBUS_SEND_SYNC_REPLY:	Wait for destination connection to
+ *				reply to this message. The
+ *				KDBUS_CMD_SEND ioctl() will block
+ *				until the reply is received, and
+ *				reply in struct kdbus_cmd_send will
+ *				yield the offset in the sender's pool
+ *				where the reply can be found.
+ *				This flag is only valid if
+ *				@KDBUS_MSG_EXPECT_REPLY is set as well.
+ */
+enum kdbus_send_flags {
+	KDBUS_SEND_SYNC_REPLY		= 1ULL << 0,
+};
+
+/**
+ * struct kdbus_cmd_send - send message
+ * @size:		Overall size of this structure
+ * @flags:		Flags to change send behavior (KDBUS_SEND_*)
+ * @return_flags:	Command return flags, kernel → userspace
+ * @msg_address:	Storage address of the kdbus_msg to send
+ * @reply:		Storage for message reply if KDBUS_SEND_SYNC_REPLY
+ *			was given
+ * @items:		Additional items for this command
+ */
+struct kdbus_cmd_send {
+	__u64 size;
+	__u64 flags;
+	__u64 return_flags;
+	__u64 msg_address;
+	struct kdbus_msg_info reply;
+	struct kdbus_item items[0];
+} __attribute__((__aligned__(8)));
 
 /**
  * enum kdbus_recv_flags - flags for de-queuing messages
@@ -423,59 +588,77 @@ struct kdbus_msg {
  *				the priority value is ignored.
  */
 enum kdbus_recv_flags {
-	KDBUS_RECV_PEEK		= 1 <<  0,
-	KDBUS_RECV_DROP		= 1 <<  1,
-	KDBUS_RECV_USE_PRIORITY	= 1 <<  2,
+	KDBUS_RECV_PEEK		= 1ULL <<  0,
+	KDBUS_RECV_DROP		= 1ULL <<  1,
+	KDBUS_RECV_USE_PRIORITY	= 1ULL <<  2,
+};
+
+/**
+ * enum kdbus_recv_return_flags - return flags for message receive commands
+ * @KDBUS_RECV_RETURN_INCOMPLETE_FDS:	One or more file descriptors could not
+ *					be installed. These descriptors in
+ *					KDBUS_ITEM_FDS will carry the value -1.
+ * @KDBUS_RECV_RETURN_DROPPED_MSGS:	There have been dropped messages since
+ *					the last time a message was received.
+ *					The 'dropped_msgs' counter contains the
+ *					number of messages dropped pool
+ *					overflows or other missed broadcasts.
+ */
+enum kdbus_recv_return_flags {
+	KDBUS_RECV_RETURN_INCOMPLETE_FDS	= 1ULL <<  0,
+	KDBUS_RECV_RETURN_DROPPED_MSGS		= 1ULL <<  1,
 };
 
 /**
  * struct kdbus_cmd_recv - struct to de-queue a buffered message
- * @flags:		KDBUS_RECV_* flags
+ * @size:		Overall size of this object
+ * @flags:		KDBUS_RECV_* flags, userspace → kernel
+ * @return_flags:	Command return flags, kernel → userspace
  * @priority:		Minimum priority of the messages to de-queue. Lowest
  *			values have the highest priority.
- * @offset:		Returned offset in the pool where the message is
- *			stored. The user must use KDBUS_CMD_FREE to free
- *			the allocated memory.
+ * @dropped_msgs:	In case there were any dropped messages since the last
+ *			time a message was received, this will be set to the
+ *			number of lost messages and
+ *			KDBUS_RECV_RETURN_DROPPED_MSGS will be set in
+ *			'return_flags'. This can only happen if the ioctl
+ *			returns 0 or EAGAIN.
+ * @msg:		Return storage for received message.
+ * @items:		Additional items for this command.
  *
- * This struct is used with the KDBUS_CMD_MSG_RECV ioctl.
+ * This struct is used with the KDBUS_CMD_RECV ioctl.
  */
 struct kdbus_cmd_recv {
+	__u64 size;
 	__u64 flags;
+	__u64 return_flags;
 	__s64 priority;
-	__u64 offset;
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_policy_access_type - permissions of a policy record
- * @_KDBUS_POLICY_ACCESS_NULL:	Uninitialized/invalid
- * @KDBUS_POLICY_ACCESS_USER:	Grant access to a uid
- * @KDBUS_POLICY_ACCESS_GROUP:	Grant access to gid
- * @KDBUS_POLICY_ACCESS_WORLD:	World-accessible
- */
-enum kdbus_policy_access_type {
-	_KDBUS_POLICY_ACCESS_NULL,
-	KDBUS_POLICY_ACCESS_USER,
-	KDBUS_POLICY_ACCESS_GROUP,
-	KDBUS_POLICY_ACCESS_WORLD,
-};
+	__u64 dropped_msgs;
+	struct kdbus_msg_info msg;
+	struct kdbus_item items[0];
+} __attribute__((__aligned__(8)));
 
 /**
- * enum kdbus_policy_access_flags - mode flags
- * @KDBUS_POLICY_OWN:		Allow to own a well-known name
- *				Implies KDBUS_POLICY_TALK and KDBUS_POLICY_SEE
- * @KDBUS_POLICY_TALK:		Allow communication to a well-known name
- *				Implies KDBUS_POLICY_SEE
- * @KDBUS_POLICY_SEE:		Allow to see a well-known name
+ * struct kdbus_cmd_free - struct to free a slice of memory in the pool
+ * @size:		Overall size of this structure
+ * @flags:		Flags for the free command, userspace → kernel
+ * @return_flags:	Command return flags, kernel → userspace
+ * @offset:		The offset of the memory slice, as returned by other
+ *			ioctls
+ * @items:		Additional items to modify the behavior
+ *
+ * This struct is used with the KDBUS_CMD_FREE ioctl.
  */
-enum kdbus_policy_type {
-	KDBUS_POLICY_SEE	= 0,
-	KDBUS_POLICY_TALK,
-	KDBUS_POLICY_OWN,
-};
+struct kdbus_cmd_free {
+	__u64 size;
+	__u64 flags;
+	__u64 return_flags;
+	__u64 offset;
+	struct kdbus_item items[0];
+} __attribute__((__aligned__(8)));
 
 /**
  * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
- * @KDBUS_HELLO_ACCEPT_FD:	The connection allows the receiving of
+ * @KDBUS_HELLO_ACCEPT_FD:	The connection allows the reception of
  *				any passed file descriptors
  * @KDBUS_HELLO_ACTIVATOR:	Special-purpose connection which registers
  *				a well-know name for a process to be started
@@ -484,55 +667,27 @@ enum kdbus_policy_type {
  *				policy entries for a name. The provided name
  *				is not activated and not registered with the
  *				name database, it only allows unprivileged
- *				connections to aquire a name, talk or discover
+ *				connections to acquire a name, talk or discover
  *				a service
  * @KDBUS_HELLO_MONITOR:	Special-purpose connection to monitor
  *				bus traffic
  */
 enum kdbus_hello_flags {
-	KDBUS_HELLO_ACCEPT_FD		=  1 <<  0,
-	KDBUS_HELLO_ACTIVATOR		=  1 <<  1,
-	KDBUS_HELLO_POLICY_HOLDER	=  1 <<  2,
-	KDBUS_HELLO_MONITOR		=  1 <<  3,
-};
-
-/**
- * enum kdbus_attach_flags - flags for metadata attachments
- * @KDBUS_ATTACH_TIMESTAMP:	Timestamp
- * @KDBUS_ATTACH_CREDS:		Credentials
- * @KDBUS_ATTACH_NAMES:		Well-known names
- * @KDBUS_ATTACH_COMM:		The "comm" process identifier
- * @KDBUS_ATTACH_EXE:		The path of the executable
- * @KDBUS_ATTACH_CMDLINE:	The process command line
- * @KDBUS_ATTACH_CGROUP:	The croup membership
- * @KDBUS_ATTACH_CAPS:		The process capabilities
- * @KDBUS_ATTACH_SECLABEL:	The security label
- * @KDBUS_ATTACH_AUDIT:		The audit IDs
- * @KDBUS_ATTACH_CONN_NAME:	The human-readable connection name
- * @_KDBUS_ATTACH_ALL:		All of the above
- */
-enum kdbus_attach_flags {
-	KDBUS_ATTACH_TIMESTAMP		=  1 <<  0,
-	KDBUS_ATTACH_CREDS		=  1 <<  1,
-	KDBUS_ATTACH_NAMES		=  1 <<  2,
-	KDBUS_ATTACH_COMM		=  1 <<  3,
-	KDBUS_ATTACH_EXE		=  1 <<  4,
-	KDBUS_ATTACH_CMDLINE		=  1 <<  5,
-	KDBUS_ATTACH_CGROUP		=  1 <<  6,
-	KDBUS_ATTACH_CAPS		=  1 <<  7,
-	KDBUS_ATTACH_SECLABEL		=  1 <<  8,
-	KDBUS_ATTACH_AUDIT		=  1 <<  9,
-	KDBUS_ATTACH_CONN_NAME		=  1 << 10,
-	_KDBUS_ATTACH_ALL		=  (1 << 11) - 1,
+	KDBUS_HELLO_ACCEPT_FD		=  1ULL <<  0,
+	KDBUS_HELLO_ACTIVATOR		=  1ULL <<  1,
+	KDBUS_HELLO_POLICY_HOLDER	=  1ULL <<  2,
+	KDBUS_HELLO_MONITOR		=  1ULL <<  3,
 };
 
 /**
  * struct kdbus_cmd_hello - struct to say hello to kdbus
  * @size:		The total size of the structure
- * @conn_flags:		Connection flags (KDBUS_HELLO_*). The kernel will
- *			return its capabilities in that field.
- * @attach_flags:	Mask of metadata to attach to each message sent
- *			(KDBUS_ATTACH_*)
+ * @flags:		Connection flags (KDBUS_HELLO_*), userspace → kernel
+ * @return_flags:	Command return flags, kernel → userspace
+ * @attach_flags_send:	Mask of metadata to attach to each message sent
+ *			off by this connection (KDBUS_ATTACH_*)
+ * @attach_flags_recv:	Mask of metadata to attach to each message receieved
+ *			by the new connection (KDBUS_ATTACH_*)
  * @bus_flags:		The flags field copied verbatim from the original
  *			KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful
  *			to do negotiation of features of the payload that is
@@ -540,8 +695,10 @@ enum kdbus_attach_flags {
  * @id:			The ID of this connection (kernel → userspace)
  * @pool_size:		Size of the connection's buffer where the received
  *			messages are placed
- * @bloom:		The bloom properties of the bus, specified
- *			by the bus creator (kernel → userspace)
+ * @offset:		Pool offset where items are returned to report
+ *			additional information about the bus and the newly
+ *			created connection.
+ * @items_size:		Size of buffer returned in the pool slice at @offset.
  * @id128:		Unique 128-bit ID of the bus (kernel → userspace)
  * @items:		A list of items
  *
@@ -549,403 +706,279 @@ enum kdbus_attach_flags {
  */
 struct kdbus_cmd_hello {
 	__u64 size;
-	__u64 conn_flags;
-	__u64 attach_flags;
+	__u64 flags;
+	__u64 return_flags;
+	__u64 attach_flags_send;
+	__u64 attach_flags_recv;
 	__u64 bus_flags;
 	__u64 id;
 	__u64 pool_size;
-	struct kdbus_bloom_parameter bloom;
+	__u64 offset;
+	__u64 items_size;
 	__u8 id128[16];
 	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+} __attribute__((__aligned__(8)));
 
 /**
- * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE
- * @KDBUS_MAKE_ACCESS_GROUP:	Make the device node group-accessible
- * @KDBUS_MAKE_ACCESS_WORLD:	Make the device node world-accessible
- */
-enum kdbus_make_flags {
-	KDBUS_MAKE_ACCESS_GROUP		= 1 <<  0,
-	KDBUS_MAKE_ACCESS_WORLD		= 1 <<  1,
-};
-
-/**
- * struct kdbus_cmd_make - struct to make a bus, an endpoint or a domain
- * @size:		The total size of the struct
- * @flags:		Properties for the bus/ep/domain to create
- * @items:		Items describing details
+ * struct kdbus_info - connection information
+ * @size:		total size of the struct
+ * @id:			64bit object ID
+ * @flags:		object creation flags
+ * @items:		list of items
  *
- * This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_EP_MAKE and
- * KDBUS_CMD_DOMAIN_MAKE ioctls.
+ * Note that the user is responsible for freeing the allocated memory with
+ * the KDBUS_CMD_FREE ioctl.
  */
-struct kdbus_cmd_make {
+struct kdbus_info {
 	__u64 size;
+	__u64 id;
 	__u64 flags;
 	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+} __attribute__((__aligned__(8)));
 
 /**
- * enum kdbus_name_flags - properties of a well-known name
- * @KDBUS_NAME_REPLACE_EXISTING:	Try to replace name of other connections
- * @KDBUS_NAME_ALLOW_REPLACEMENT:	Allow the replacement of the name
- * @KDBUS_NAME_QUEUE:			Name should be queued if busy
- * @KDBUS_NAME_IN_QUEUE:		Name is queued
- * @KDBUS_NAME_ACTIVATOR:		Name is owned by a activator connection
+ * enum kdbus_list_flags - what to include into the returned list
+ * @KDBUS_LIST_UNIQUE:		active connections
+ * @KDBUS_LIST_ACTIVATORS:	activator connections
+ * @KDBUS_LIST_NAMES:		known well-known names
+ * @KDBUS_LIST_QUEUED:		queued-up names
  */
-enum kdbus_name_flags {
-	KDBUS_NAME_REPLACE_EXISTING	= 1 <<  0,
-	KDBUS_NAME_ALLOW_REPLACEMENT	= 1 <<  1,
-	KDBUS_NAME_QUEUE		= 1 <<  2,
-	KDBUS_NAME_IN_QUEUE		= 1 <<  3,
-	KDBUS_NAME_ACTIVATOR		= 1 <<  4,
+enum kdbus_list_flags {
+	KDBUS_LIST_UNIQUE		= 1ULL <<  0,
+	KDBUS_LIST_NAMES		= 1ULL <<  1,
+	KDBUS_LIST_ACTIVATORS		= 1ULL <<  2,
+	KDBUS_LIST_QUEUED		= 1ULL <<  3,
 };
 
 /**
- * struct kdbus_cmd_name - struct to describe a well-known name
- * @size:		The total size of the struct
- * @flags:		Flags for a name entry (KDBUS_NAME_*)
- * @owner_id:		The current owner of the name.
- * @conn_flags:		The flags of the owning connection (KDBUS_HELLO_*)
- * @name:		The well-known name
- *
- * This structure is used with the KDBUS_CMD_NAME_ACQUIRE ioctl.
- */
-struct kdbus_cmd_name {
-	__u64 size;
-	__u64 flags;
-	__u64 owner_id;
-	__u64 conn_flags;
-	char name[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_name_list_flags - what to include into the returned list
- * @KDBUS_NAME_LIST_UNIQUE:	All active connections
- * @KDBUS_NAME_LIST_NAMES:	All known well-known names
- * @KDBUS_NAME_LIST_ACTIVATORS:	All activator connections
- * @KDBUS_NAME_LIST_QUEUED:	All queued-up names
- */
-enum kdbus_name_list_flags {
-	KDBUS_NAME_LIST_UNIQUE		= 1 <<  0,
-	KDBUS_NAME_LIST_NAMES		= 1 <<  1,
-	KDBUS_NAME_LIST_ACTIVATORS	= 1 <<  2,
-	KDBUS_NAME_LIST_QUEUED		= 1 <<  3,
-};
-
-/**
- * struct kdbus_cmd_name_list - request a list of name entries
- * @flags:		Flags for the query (KDBUS_NAME_LIST_*)
- * @offset:		The returned offset in the caller's pool buffer.
+ * struct kdbus_cmd_list - list connections
+ * @size:		overall size of this object
+ * @flags:		flags for the query (KDBUS_LIST_*), userspace → kernel
+ * @return_flags:	command return flags, kernel → userspace
+ * @offset:		Offset in the caller's pool buffer where an array of
+ *			kdbus_info objects is stored.
  *			The user must use KDBUS_CMD_FREE to free the
  *			allocated memory.
+ * @list_size:		size of returned list in bytes
+ * @items:		Items for the command. Reserved for future use.
  *
- * This structure is used with the KDBUS_CMD_NAME_LIST ioctl.
+ * This structure is used with the KDBUS_CMD_LIST ioctl.
  */
-struct kdbus_cmd_name_list {
+struct kdbus_cmd_list {
+	__u64 size;
 	__u64 flags;
+	__u64 return_flags;
 	__u64 offset;
-} __attribute__((aligned(8)));
-
-/**
- * struct kdbus_name_list - information returned by KDBUS_CMD_NAME_LIST
- * @size:		The total size of the structure
- * @names:		A list of names
- *
- * Note that the user is responsible for freeing the allocated memory with
- * the KDBUS_CMD_FREE ioctl.
- */
-struct kdbus_name_list {
-	__u64 size;
-	struct kdbus_cmd_name names[0];
-};
+	__u64 list_size;
+	struct kdbus_item items[0];
+} __attribute__((__aligned__(8)));
 
 /**
- * struct kdbus_cmd_conn_info - struct used for KDBUS_CMD_CONN_INFO ioctl
+ * struct kdbus_cmd_info - struct used for KDBUS_CMD_CONN_INFO ioctl
  * @size:		The total size of the struct
- * @flags:		KDBUS_ATTACH_* flags
+ * @flags:		Flags for this ioctl, userspace → kernel
+ * @return_flags:	Command return flags, kernel → userspace
  * @id:			The 64-bit ID of the connection. If set to zero, passing
  *			@name is required. kdbus will look up the name to
  *			determine the ID in this case.
+ * @attach_flags:	Set of attach flags to specify the set of information
+ *			to receive, userspace → kernel
  * @offset:		Returned offset in the caller's pool buffer where the
- *			kdbus_conn_info struct result is stored. The user must
+ *			kdbus_info struct result is stored. The user must
  *			use KDBUS_CMD_FREE to free the allocated memory.
- * @name:		The optional well-known name to look up. Only needed in
- *			case @id is zero.
+ * @info_size:		Output buffer to report size of data at @offset.
+ * @items:		The optional item list, containing the
+ *			well-known name to look up as a KDBUS_ITEM_NAME.
+ *			Only needed in case @id is zero.
  *
  * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will
  * tell the user the offset in the connection pool buffer at which to find the
- * result in a struct kdbus_conn_info.
+ * result in a struct kdbus_info.
  */
-struct kdbus_cmd_conn_info {
+struct kdbus_cmd_info {
 	__u64 size;
 	__u64 flags;
+	__u64 return_flags;
 	__u64 id;
+	__u64 attach_flags;
 	__u64 offset;
-	char name[0];
-} __attribute__((aligned(8)));
-
-/**
- * struct kdbus_conn_info - information returned by KDBUS_CMD_CONN_INFO
- * @size:		The total size of the struct
- * @id:			The connection's 64-bit ID
- * @flags:		The connection's flags
- * @items:		A list of struct kdbus_item
- *
- * Note that the user is responsible for freeing the allocated memory with
- * the KDBUS_CMD_FREE ioctl.
- */
-struct kdbus_conn_info {
-	__u64 size;
-	__u64 id;
-	__u64 flags;
+	__u64 info_size;
 	struct kdbus_item items[0];
-};
+} __attribute__((__aligned__(8)));
 
 /**
- * struct kdbus_cmd_update - update flags of a connection
- * @size:		The total size of the struct
- * @items:		A list of struct kdbus_item
- *
- * This struct is used with the KDBUS_CMD_CONN_UPDATE ioctl.
+ * enum kdbus_cmd_match_flags - flags to control the KDBUS_CMD_MATCH_ADD ioctl
+ * @KDBUS_MATCH_REPLACE:	If entries with the supplied cookie already
+ *				exists, remove them before installing the new
+ *				matches.
  */
-struct kdbus_cmd_update {
-	__u64 size;
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+enum kdbus_cmd_match_flags {
+	KDBUS_MATCH_REPLACE	= 1ULL <<  0,
+};
 
 /**
  * struct kdbus_cmd_match - struct to add or remove matches
  * @size:		The total size of the struct
+ * @flags:		Flags for match command (KDBUS_MATCH_*),
+ *			userspace → kernel
+ * @return_flags:	Command return flags, kernel → userspace
  * @cookie:		Userspace supplied cookie. When removing, the cookie
  *			identifies the match to remove
  * @items:		A list of items for additional information
  *
- * This structure is used with the KDBUS_CMD_ADD_MATCH and
- * KDBUS_CMD_REMOVE_MATCH ioctl.
+ * This structure is used with the KDBUS_CMD_MATCH_ADD and
+ * KDBUS_CMD_MATCH_REMOVE ioctl.
  */
 struct kdbus_cmd_match {
 	__u64 size;
+	__u64 flags;
+	__u64 return_flags;
 	__u64 cookie;
 	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+} __attribute__((__aligned__(8)));
 
 /**
- * struct kdbus_cmd_memfd_make - create a kdbus memfd
- * @size:		The total size of the struct
- * @file_size:		The initial file size
- * @fd:			The returned file descriptor number
- * @__pad:		Padding to ensure proper alignement
- * @items:		A list of items for additional information
+ * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,ENDPOINT}_MAKE
+ * @KDBUS_MAKE_ACCESS_GROUP:	Make the bus or endpoint node group-accessible
+ * @KDBUS_MAKE_ACCESS_WORLD:	Make the bus or endpoint node world-accessible
+ */
+enum kdbus_make_flags {
+	KDBUS_MAKE_ACCESS_GROUP		= 1ULL <<  0,
+	KDBUS_MAKE_ACCESS_WORLD		= 1ULL <<  1,
+};
+
+/**
+ * enum kdbus_name_flags - flags for KDBUS_CMD_NAME_ACQUIRE
+ * @KDBUS_NAME_REPLACE_EXISTING:	Try to replace name of other connections
+ * @KDBUS_NAME_ALLOW_REPLACEMENT:	Allow the replacement of the name
+ * @KDBUS_NAME_QUEUE:			Name should be queued if busy
+ * @KDBUS_NAME_IN_QUEUE:		Name is queued
+ * @KDBUS_NAME_ACTIVATOR:		Name is owned by a activator connection
+ * @KDBUS_NAME_PRIMARY:			Primary owner of the name
+ * @KDBUS_NAME_ACQUIRED:		Name was acquired/queued _now_
+ */
+enum kdbus_name_flags {
+	KDBUS_NAME_REPLACE_EXISTING	= 1ULL <<  0,
+	KDBUS_NAME_ALLOW_REPLACEMENT	= 1ULL <<  1,
+	KDBUS_NAME_QUEUE		= 1ULL <<  2,
+	KDBUS_NAME_IN_QUEUE		= 1ULL <<  3,
+	KDBUS_NAME_ACTIVATOR		= 1ULL <<  4,
+	KDBUS_NAME_PRIMARY		= 1ULL <<  5,
+	KDBUS_NAME_ACQUIRED		= 1ULL <<  6,
+};
+
+/**
+ * struct kdbus_cmd - generic ioctl payload
+ * @size:		Overall size of this structure
+ * @flags:		Flags for this ioctl, userspace → kernel
+ * @return_flags:	Ioctl return flags, kernel → userspace
+ * @items:		Additional items to modify the behavior
  *
- * This structure is used with the KDBUS_CMD_MEMFD_NEW ioctl.
+ * This is a generic ioctl payload object. It's used by all ioctls that only
+ * take flags and items as input.
  */
-struct kdbus_cmd_memfd_make {
+struct kdbus_cmd {
 	__u64 size;
-	__u64 file_size;
-	int fd;
-	__u32 __pad;
+	__u64 flags;
+	__u64 return_flags;
 	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
+} __attribute__((__aligned__(8)));
 
 /**
- * enum kdbus_ioctl_type - Ioctl API
- * @KDBUS_CMD_BUS_MAKE:		After opening the "control" device node, this
- *				command creates a new bus with the specified
+ * Ioctl API
+ *
+ * KDBUS_CMD_BUS_MAKE:		After opening the "control" node, this command
+ *				creates a new bus with the specified
  *				name. The bus is immediately shut down and
- *				cleaned up when the opened "control" device node
- *				is closed.
- * @KDBUS_CMD_DOMAIN_MAKE:	Similar to KDBUS_CMD_BUS_MAKE, but it creates a
- *				new kdbus domain.
- * @KDBUS_CMD_EP_MAKE:		Creates a new named special endpoint to talk to
+ *				cleaned up when the opened file descriptor is
+ *				closed.
+ *
+ * KDBUS_CMD_ENDPOINT_MAKE:	Creates a new named special endpoint to talk to
  *				the bus. Such endpoints usually carry a more
  *				restrictive policy and grant restricted access
  *				to specific applications.
- * @KDBUS_CMD_HELLO:		By opening the bus device node a connection is
+ * KDBUS_CMD_ENDPOINT_UPDATE:	Update the properties of a custom enpoint. Used
+ *				to update the policy.
+ *
+ * KDBUS_CMD_HELLO:		By opening the bus node, a connection is
  *				created. After a HELLO the opened connection
  *				becomes an active peer on the bus.
- * @KDBUS_CMD_BYEBYE:		Disconnect a connection. If the connection's
- *				message list is empty, the calls succeeds, and
- *				the handle is rendered unusable. Otherwise,
- *				-EAGAIN is returned without any further side-
- *				effects.
- * @KDBUS_CMD_MSG_SEND:		Send a message and pass data from userspace to
+ * KDBUS_CMD_UPDATE:		Update the properties of a connection. Used to
+ *				update the metadata subscription mask and
+ *				policy.
+ * KDBUS_CMD_BYEBYE:		Disconnect a connection. If there are no
+ *				messages queued up in the connection's pool,
+ *				the call succeeds, and the handle is rendered
+ *				unusable. Otherwise, -EBUSY is returned without
+ *				any further side-effects.
+ * KDBUS_CMD_FREE:		Release the allocated memory in the receiver's
+ *				pool.
+ * KDBUS_CMD_CONN_INFO:		Retrieve credentials and properties of the
+ *				initial creator of the connection. The data was
+ *				stored at registration time and does not
+ *				necessarily represent the connected process or
+ *				the actual state of the process.
+ * KDBUS_CMD_BUS_CREATOR_INFO:	Retrieve information of the creator of the bus
+ *				a connection is attached to.
+ *
+ * KDBUS_CMD_SEND:		Send a message and pass data from userspace to
  *				the kernel.
- * @KDBUS_CMD_MSG_RECV:		Receive a message from the kernel which is
+ * KDBUS_CMD_RECV:		Receive a message from the kernel which is
  *				placed in the receiver's pool.
- * @KDBUS_CMD_MSG_CANCEL:	Cancel a pending request of a message that
- *				blocks while waiting for a reply. The parameter
- *				denotes the cookie of the message in flight.
- * @KDBUS_CMD_FREE:		Release the allocated memory in the receiver's
- *				pool.
- * @KDBUS_CMD_NAME_ACQUIRE:	Request a well-known bus name to associate with
+ *
+ * KDBUS_CMD_NAME_ACQUIRE:	Request a well-known bus name to associate with
  *				the connection. Well-known names are used to
  *				address a peer on the bus.
- * @KDBUS_CMD_NAME_RELEASE:	Release a well-known name the connection
+ * KDBUS_CMD_NAME_RELEASE:	Release a well-known name the connection
  *				currently owns.
- * @KDBUS_CMD_NAME_LIST:	Retrieve the list of all currently registered
+ * KDBUS_CMD_LIST:		Retrieve the list of all currently registered
  *				well-known and unique names.
- * @KDBUS_CMD_CONN_INFO:	Retrieve credentials and properties of the
- *				initial creator of the connection. The data was
- *				stored at registration time and does not
- *				necessarily represent the connected process or
- *				the actual state of the process.
- * @KDBUS_CMD_CONN_UPDATE:	Update the properties of a connection. Used to
- *				update the metadata subscription mask and
- *				policy.
- * @KDBUS_CMD_EP_UPDATE:	Update the properties of a custom enpoint. Used
- *				to update the policy.
- * @KDBUS_CMD_MATCH_ADD:	Install a match which broadcast messages should
+ *
+ * KDBUS_CMD_MATCH_ADD:		Install a match which broadcast messages should
  *				be delivered to the connection.
- * @KDBUS_CMD_MATCH_REMOVE:	Remove a current match for broadcast messages.
- * @KDBUS_CMD_MEMFD_NEW:	Return a new file descriptor which provides an
- *				anonymous shared memory file and which can be
- *				used to pass around larger chunks of data.
- *				Kdbus memfd files can be sealed, which allows
- *				the receiver to trust the data it has received.
- *				Kdbus memfd files expose only very limited
- *				operations, they can be mmap()ed, seek()ed,
- *				(p)read(v)() and (p)write(v)(); most other
- *				common file operations are not implemented.
- *				Special caution needs to be taken with
- *				read(v)()/write(v)() on a shared file; the
- *				underlying file position is always shared
- *				between all users of the file and race against
- *				each other, pread(v)()/pwrite(v)() avoid these
- *				issues.
- * @KDBUS_CMD_MEMFD_SIZE_GET:	Return the size of the underlying file, which
- *				changes with write().
- * @KDBUS_CMD_MEMFD_SIZE_SET:	Truncate the underlying file to the specified
- *				size.
- * @KDBUS_CMD_MEMFD_SEAL_GET:	Return the state of the file sealing.
- * @KDBUS_CMD_MEMFD_SEAL_SET:	Seal or break a seal of the file. Only files
- *				which are not shared with other processes and
- *				which are currently not mapped can be sealed.
- *				The current process needs to be the one and
- *				single owner of the file, the sealing cannot
- *				be changed as long as the file is shared.
+ * KDBUS_CMD_MATCH_REMOVE:	Remove a current match for broadcast messages.
  */
 enum kdbus_ioctl_type {
+	/* bus owner (00-0f) */
 	KDBUS_CMD_BUS_MAKE =		_IOW(KDBUS_IOCTL_MAGIC, 0x00,
-					     struct kdbus_cmd_make),
-	KDBUS_CMD_DOMAIN_MAKE =		_IOW(KDBUS_IOCTL_MAGIC, 0x10,
-					     struct kdbus_cmd_make),
-	KDBUS_CMD_EP_MAKE =		_IOW(KDBUS_IOCTL_MAGIC, 0x20,
-					     struct kdbus_cmd_make),
+					     struct kdbus_cmd),
 
-	KDBUS_CMD_HELLO =		_IOWR(KDBUS_IOCTL_MAGIC, 0x30,
+	/* endpoint owner (10-1f) */
+	KDBUS_CMD_ENDPOINT_MAKE =	_IOW(KDBUS_IOCTL_MAGIC, 0x10,
+					     struct kdbus_cmd),
+	KDBUS_CMD_ENDPOINT_UPDATE =	_IOW(KDBUS_IOCTL_MAGIC, 0x11,
+					     struct kdbus_cmd),
+
+	/* connection owner (80-ff) */
+	KDBUS_CMD_HELLO =		_IOWR(KDBUS_IOCTL_MAGIC, 0x80,
 					      struct kdbus_cmd_hello),
-	KDBUS_CMD_BYEBYE =		_IO(KDBUS_IOCTL_MAGIC, 0x31),
-
-	KDBUS_CMD_MSG_SEND =		_IOWR(KDBUS_IOCTL_MAGIC, 0x40,
-					      struct kdbus_msg),
-	KDBUS_CMD_MSG_RECV =		_IOWR(KDBUS_IOCTL_MAGIC, 0x41,
-					      struct kdbus_cmd_recv),
-	KDBUS_CMD_MSG_CANCEL =		_IOW(KDBUS_IOCTL_MAGIC, 0x42, __u64 *),
-	KDBUS_CMD_FREE =		_IOW(KDBUS_IOCTL_MAGIC, 0x43, __u64 *),
-
-	KDBUS_CMD_NAME_ACQUIRE =	_IOWR(KDBUS_IOCTL_MAGIC, 0x50,
-					      struct kdbus_cmd_name),
-	KDBUS_CMD_NAME_RELEASE =	_IOW(KDBUS_IOCTL_MAGIC, 0x51,
-					     struct kdbus_cmd_name),
-	KDBUS_CMD_NAME_LIST =		_IOWR(KDBUS_IOCTL_MAGIC, 0x52,
-					     struct kdbus_cmd_name_list),
-
-	KDBUS_CMD_CONN_INFO =		_IOWR(KDBUS_IOCTL_MAGIC, 0x60,
-					      struct kdbus_cmd_conn_info),
-	KDBUS_CMD_CONN_UPDATE =		_IOW(KDBUS_IOCTL_MAGIC, 0x61,
-					     struct kdbus_cmd_update),
-
-	KDBUS_CMD_EP_UPDATE =		_IOW(KDBUS_IOCTL_MAGIC, 0x71,
-					     struct kdbus_cmd_update),
-
-	KDBUS_CMD_MATCH_ADD =		_IOW(KDBUS_IOCTL_MAGIC, 0x80,
+	KDBUS_CMD_UPDATE =		_IOW(KDBUS_IOCTL_MAGIC, 0x81,
+					     struct kdbus_cmd),
+	KDBUS_CMD_BYEBYE =		_IOW(KDBUS_IOCTL_MAGIC, 0x82,
+					     struct kdbus_cmd),
+	KDBUS_CMD_FREE =		_IOW(KDBUS_IOCTL_MAGIC, 0x83,
+					     struct kdbus_cmd_free),
+	KDBUS_CMD_CONN_INFO =		_IOR(KDBUS_IOCTL_MAGIC, 0x84,
+					     struct kdbus_cmd_info),
+	KDBUS_CMD_BUS_CREATOR_INFO =	_IOR(KDBUS_IOCTL_MAGIC, 0x85,
+					     struct kdbus_cmd_info),
+	KDBUS_CMD_LIST =		_IOR(KDBUS_IOCTL_MAGIC, 0x86,
+					     struct kdbus_cmd_list),
+
+	KDBUS_CMD_SEND =		_IOW(KDBUS_IOCTL_MAGIC, 0x90,
+					     struct kdbus_cmd_send),
+	KDBUS_CMD_RECV =		_IOR(KDBUS_IOCTL_MAGIC, 0x91,
+					     struct kdbus_cmd_recv),
+
+	KDBUS_CMD_NAME_ACQUIRE =	_IOW(KDBUS_IOCTL_MAGIC, 0xa0,
+					     struct kdbus_cmd),
+	KDBUS_CMD_NAME_RELEASE =	_IOW(KDBUS_IOCTL_MAGIC, 0xa1,
+					     struct kdbus_cmd),
+
+	KDBUS_CMD_MATCH_ADD =		_IOW(KDBUS_IOCTL_MAGIC, 0xb0,
 					     struct kdbus_cmd_match),
-	KDBUS_CMD_MATCH_REMOVE =	_IOW(KDBUS_IOCTL_MAGIC, 0x81,
+	KDBUS_CMD_MATCH_REMOVE =	_IOW(KDBUS_IOCTL_MAGIC, 0xb1,
 					     struct kdbus_cmd_match),
-
-	KDBUS_CMD_MEMFD_NEW =		_IOWR(KDBUS_IOCTL_MAGIC, 0xc0,
-					      struct kdbus_cmd_memfd_make),
-	KDBUS_CMD_MEMFD_SIZE_GET =	_IOR(KDBUS_IOCTL_MAGIC, 0xc1, __u64 *),
-	KDBUS_CMD_MEMFD_SIZE_SET =	_IOW(KDBUS_IOCTL_MAGIC, 0xc2, __u64 *),
-	KDBUS_CMD_MEMFD_SEAL_GET =	_IOR(KDBUS_IOCTL_MAGIC, 0xc3, int *),
-	KDBUS_CMD_MEMFD_SEAL_SET =	_IO(KDBUS_IOCTL_MAGIC, 0xc4),
 };
 
-/*
- * errno - api error codes
- * @E2BIG:		A message contains too many records or items.
- * @EADDRINUSE:		A well-known bus name is already taken by another
- *			connection.
- * @EADDRNOTAVAIL:	A message flagged not to activate a service, addressed
- *			a service which is not currently running.
- * @EAGAIN:		No messages are queued@the moment.
- * @EALREADY:		A requested name is already owned by the connection,
- *			a connection is already disconnected, memfd is already
- *			sealed or has the requested size.
- * @EBADF:		File descriptors passed with the message are not valid.
- * @EBADFD:		A bus connection is in a corrupted state.
- * @EBADMSG:		Passed data contains a combination of conflicting or
- *			inconsistent types.
- * @EBUSY:		The user tried to say BYEBYE to a connection, but the
- *			connection had a non-empty message list.
- * @ECANCELED:		A synchronous message sending was cancelled.
- * @ECONNRESET:		A connection is shut down, no further operations are
- *			possible.
- * @ECOMM:		A peer does not accept the file descriptors addressed
- *			to it.
- * @EDESTADDRREQ:	The well-known bus name is required but missing.
- * @EDOM:		The size of data does not match the expectations. Used
- *			for bloom bit field sizes.
- * @EEXIST:		A requested domain, bus or endpoint with the same
- *			name already exists.  A specific data type, which is
- *			only expected once, is provided multiple times.
- * @EFAULT:		The supplied memory could not be accessed, or the data
- *			is not properly aligned.
- * @EINVAL:		The provided data does not match its type or other
- *			expectations, like a string which is not NUL terminated,
- *			or a string length that points behind the first
- *			\0-byte in the string.
- * @EMEDIUMTYPE:	A file descriptor which is not a kdbus memfd was
- *			refused to send as KDBUS_MSG_PAYLOAD_MEMFD.
- * @EMFILE:		Too many file descriptors have been supplied with a
- *			message.
- *			Too many connections or buses are created for a given
- *			user.
- * @EMLINK:		Too many requests from this connection to other peers
- *			are queued and waiting for a reply
- * @EMSGSIZE:		The supplied data is larger than the allowed maximum
- *			size.
- * @ENAMETOOLONG:	The requested name is larger than the allowed maximum
- *			size.
- * @ENOBUFS:		There is no space left for the submitted data to fit
- *			into the receiver's pool.
- * @ENOENT:		The to be cancelled message was not found.
- * @ENOMEM:		Out of memory.
- * @ENOMSG:		The queue is not empty, but no message with a matching
- *			priority is currently queued.
- * @ENOSYS:		The requested functionality is not available.
- * @ENOTTY:		An unknown ioctl command was received.
- * @ENOTUNIQ:		A specific data type was addressed to a broadcast
- *			address, but only direct addresses support this kind of
- *			data.
- * @ENXIO:		A unique address does not exist, or an offset in the
- *			receiver's pool does not represent a queued message.
- * @EOPNOTSUPP:		The feature negotiation failed, a not supported feature
- *			was requested, or an unknown item type was received.
- * @EPERM:		The policy prevented an operation. The requested
- *			resource is owned by another entity.
- * @EPIPE:		When sending a message, a synchronous reply from the
- *			receiving connection was expected but the connection
- *			died before answering.
- * @ESHUTDOWN:		A domain, bus or endpoint is currently shutting down;
- *			no further operations will be possible.
- * @ESRCH:		A requested well-known bus name is not found.
- * @ETIMEDOUT:		A synchronous wait for a message reply did not arrive
- *			within the specified time frame.
- * @ETXTBSY:		A kdbus memfd file cannot be sealed or the seal removed,
- *			because it is shared with other processes or still
- *			mmap()ed.
- * @EXFULL:		The size limits in the pool are reached, no data of
- *			the size tried to submit can be queued.
- */
-#endif
+#endif /* _UAPI_KDBUS_H_ */
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/20] dbus-kernel: Update with kdbus API changes.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (8 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 10/20] linux: Update kdbus.h to current github version Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 12/20] dbus: Add message filter public API Andrew Zaborowski
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 9534 bytes --]

---
 ell/dbus-kernel.c | 105 ++++++++++++++++++++++++++++++++++--------------------
 ell/dbus.c        |   4 +++
 2 files changed, 70 insertions(+), 39 deletions(-)

diff --git a/ell/dbus-kernel.c b/ell/dbus-kernel.c
index 25510ad..54d7d4d 100644
--- a/ell/dbus-kernel.c
+++ b/ell/dbus-kernel.c
@@ -33,6 +33,7 @@
 #include <alloca.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/ioctl.h>
 
 #include "linux/kdbus.h"
 
@@ -180,7 +181,7 @@ void _dbus_kernel_bloom_add_parents(uint64_t filter[], size_t size,
 int _dbus_kernel_create_bus(const char *name)
 {
 	struct {
-		struct kdbus_cmd_make head;
+		struct kdbus_cmd head;
 		/* bloom size item */
 		uint64_t bloom_size;
 		uint64_t bloom_type;
@@ -244,13 +245,14 @@ int _dbus_kernel_hello(int fd, const char *connection_name,
 	memset(hello, 0, size);
 
 	hello->size = size;
-	hello->conn_flags |= KDBUS_HELLO_ACCEPT_FD;
-	hello->attach_flags |= KDBUS_ATTACH_NAMES;
+	hello->flags |= KDBUS_HELLO_ACCEPT_FD;
+	hello->attach_flags_send |= KDBUS_ATTACH_NAMES;
+	hello->attach_flags_recv |= KDBUS_ATTACH_NAMES;
 	hello->pool_size = KDBUS_POOL_SIZE;
 
 	item = hello->items;
 	item->size = KDBUS_ITEM_HEADER_SIZE + len + 1;
-	item->type = KDBUS_ITEM_CONN_NAME;
+	item->type = KDBUS_ITEM_CONN_DESCRIPTION;
 	strcpy(item->str, connection_name);
 
 	ret = ioctl(fd, KDBUS_CMD_HELLO, hello);
@@ -259,7 +261,7 @@ int _dbus_kernel_hello(int fd, const char *connection_name,
 
         /* Check for incompatible flags (upper 32 bits) */
         if (hello->bus_flags > 0xFFFFFFFFULL ||
-			hello->conn_flags > 0xFFFFFFFFULL)
+			hello->flags > 0xFFFFFFFFULL)
                 return -ENOTSUP;
 
 	*pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0);
@@ -268,8 +270,9 @@ int _dbus_kernel_hello(int fd, const char *connection_name,
 		return -errno;
 	}
 
-	*bloom_size = hello->bloom.size;
-	*bloom_n_hash = hello->bloom.n_hash;
+	*bloom_size = DEFAULT_BLOOM_SIZE;
+	*bloom_n_hash = DEFAULT_BLOOM_N_HASH;
+
 	*id = hello->id;
 	*guid = l_strdup_printf("%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 				"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
@@ -300,6 +303,7 @@ int _dbus_kernel_send(int fd, size_t bloom_size, uint8_t bloom_n_hash,
 	void *body;
 	size_t body_size;
 	int ret;
+	struct kdbus_cmd_send cmd;
 	L_AUTO_FREE_VAR(struct kdbus_msg *, kmsg);
 
 	dest = l_dbus_message_get_destination(message);
@@ -337,10 +341,10 @@ int _dbus_kernel_send(int fd, size_t bloom_size, uint8_t bloom_n_hash,
 	kmsg->cookie = _dbus_message_get_serial(message);
 
 	if (l_dbus_message_get_no_autostart(message))
-		kmsg->flags |= KDBUS_MSG_FLAGS_NO_AUTO_START;
+		kmsg->flags |= KDBUS_MSG_NO_AUTO_START;
 
 	if (!l_dbus_message_get_no_reply(message))
-		kmsg->flags |= KDBUS_MSG_FLAGS_EXPECT_REPLY;
+		kmsg->flags |= KDBUS_MSG_EXPECT_REPLY;
 
 	if (!unique && dest) {
 		kmsg->dst_id = KDBUS_DST_ID_NAME;
@@ -366,9 +370,12 @@ int _dbus_kernel_send(int fd, size_t bloom_size, uint8_t bloom_n_hash,
 		break;
 	}
 	case DBUS_MESSAGE_TYPE_METHOD_CALL:
-		kmsg->timeout_ns = 30000 * 1000ULL;
+		if (!l_dbus_message_get_no_reply(message))
+			kmsg->timeout_ns = 30000 * 1000ULL;
 		break;
 	case DBUS_MESSAGE_TYPE_SIGNAL:
+		kmsg->flags |= KDBUS_MSG_SIGNAL;
+
 		item->size = KDBUS_ITEM_HEADER_SIZE +
 				sizeof(struct kdbus_bloom_filter) + bloom_size;
 		item->type = KDBUS_ITEM_BLOOM_FILTER;
@@ -400,7 +407,11 @@ int _dbus_kernel_send(int fd, size_t bloom_size, uint8_t bloom_n_hash,
 
 	kmsg->size = (void *)item - (void *)kmsg;
 
-	ret = ioctl(fd, KDBUS_CMD_MSG_SEND, kmsg);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.size = sizeof(cmd);
+	cmd.msg_address = (uint64_t) kmsg;
+
+	ret = ioctl(fd, KDBUS_CMD_SEND, &cmd);
 	if (ret < 0)
 		return -errno;
 
@@ -556,11 +567,13 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 
 	memset(&recv_cmd, 0, sizeof(recv_cmd));
 
-	r = ioctl(fd, KDBUS_CMD_MSG_RECV, &recv_cmd);
+	recv_cmd.size = sizeof(recv_cmd);
+
+	r = ioctl(fd, KDBUS_CMD_RECV, &recv_cmd);
 	if (r < 0)
 		return -errno;
 
-	msg = (struct kdbus_msg *)(kdbus_pool + recv_cmd.offset);
+	msg = (struct kdbus_msg *)(kdbus_pool + recv_cmd.msg.offset);
 
 	switch (msg->payload_type) {
 	case KDBUS_PAYLOAD_DBUS:
@@ -588,8 +601,8 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 			}
 
 			name_owner_change_func(item->name_change.name,
-						item->name_change.old.id,
-						item->name_change.new.id,
+						item->name_change.old_id.id,
+						item->name_change.new_id.id,
 						user_data);
 			break;
 
@@ -603,7 +616,7 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 		break;
 	}
 
-	ioctl(fd, KDBUS_CMD_FREE, &recv_cmd.offset);
+	ioctl(fd, KDBUS_CMD_FREE, &recv_cmd.msg.offset);
 
 	return r;
 }
@@ -611,22 +624,27 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 int _dbus_kernel_name_acquire(int fd, const char *name)
 {
 	struct {
-		struct kdbus_cmd_name head;
+		struct kdbus_cmd head;
 		char param[64];
 	} cmd_name;
+	struct kdbus_item *item;
 	size_t nlen;
 
 	if (!name)
 		return false;
 
 	nlen = strlen(name) + 1;
-	if (nlen > sizeof(cmd_name.param))
+	if (KDBUS_ITEM_SIZE(nlen) > sizeof(cmd_name.param))
 		return false;
 
 	memset(&cmd_name, 0, sizeof(cmd_name));
 
-	strcpy(cmd_name.param, name);
-	cmd_name.head.size = sizeof(cmd_name.head) + nlen;
+	cmd_name.head.size = sizeof(cmd_name.head) + KDBUS_ITEM_SIZE(nlen);
+
+	item = cmd_name.head.items;
+	item->size = KDBUS_ITEM_HEADER_SIZE + nlen;
+	item->type = KDBUS_ITEM_NAME;
+	strcpy(item->str, name);
 
 	if (ioctl(fd, KDBUS_CMD_NAME_ACQUIRE, &cmd_name) < 0)
 		return -errno;
@@ -719,8 +737,6 @@ int _dbus_kernel_add_match(int fd, uint64_t bloom_size, uint64_t bloom_n_hash,
 					bloom_n_hash, prefix, rule->value);
 	}
 
-	item = KDBUS_ITEM_NEXT(item);
-
 	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, cmd);
 	if (r < 0)
 		return -errno;
@@ -758,8 +774,8 @@ int _dbus_kernel_enable_name_owner_notify(int fd)
 	item = cmd_match.cmd.items;
 	item->type = KDBUS_ITEM_NAME_ADD;
 	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
-	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
-	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
 	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
 
 	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
@@ -770,8 +786,8 @@ int _dbus_kernel_enable_name_owner_notify(int fd)
 	item = cmd_match.cmd.items;
 	item->type = KDBUS_ITEM_NAME_CHANGE;
 	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
-	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
-	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
 	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
 
 	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
@@ -782,8 +798,8 @@ int _dbus_kernel_enable_name_owner_notify(int fd)
 	item = cmd_match.cmd.items;
 	item->type = KDBUS_ITEM_NAME_REMOVE;
 	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->name_change);
-	item->name_change.old.id = KDBUS_MATCH_ID_ANY;
-	item->name_change.new.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+	item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
 	cmd_match.cmd.size = sizeof(cmd_match.cmd) + item->size;
 
 	r = ioctl(fd, KDBUS_CMD_MATCH_ADD, &cmd_match);
@@ -796,26 +812,37 @@ int _dbus_kernel_enable_name_owner_notify(int fd)
 uint64_t _dbus_kernel_get_name_owner(int fd, void *kdbus_pool,
 					const char *name)
 {
-	struct kdbus_cmd_name_list cmd;
-	struct kdbus_name_list *list;
-	const struct kdbus_cmd_name *entry, *end;
+	struct kdbus_cmd_list cmd;
+	struct kdbus_info *entry, *end;
+	struct kdbus_item *item;
+	const char *entry_name;
 	uint64_t owner_id = 0;
 
 	memset(&cmd, 0, sizeof(cmd));
-	cmd.flags = KDBUS_NAME_LIST_NAMES;
+	cmd.size = sizeof(cmd);
+	cmd.flags = KDBUS_LIST_NAMES;
 
-	if (ioctl(fd, KDBUS_CMD_NAME_LIST, &cmd) < 0)
+	if (ioctl(fd, KDBUS_CMD_LIST, &cmd) < 0)
 		return 0;
 
-	list = (struct kdbus_name_list *) (kdbus_pool + cmd.offset);
-	end = (void *) list + list->size;
+	entry = kdbus_pool + cmd.offset;
+	end = (void *) entry + cmd.list_size;
 
-	for (entry = list->names; entry < end;
-			entry = (void *) entry + entry->size)
-		if (!strcmp(entry->name, name)) {
-			owner_id = entry->owner_id;
+	for (; entry < end; entry = (void *) entry + entry->size) {
+		entry_name = NULL;
+
+		KDBUS_ITEM_FOREACH(item, entry, items) {
+			if (item->type == KDBUS_ITEM_OWNED_NAME) {
+				entry_name = item->name.name;
+				break;
+			}
+		}
+
+		if (entry_name && !strcmp(entry_name, name)) {
+			owner_id = entry->id;
 			break;
 		}
+	}
 
 	ioctl(fd, KDBUS_CMD_FREE, cmd.offset);
 
diff --git a/ell/dbus.c b/ell/dbus.c
index 487208b..dbfa1be 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -997,6 +997,10 @@ static void kdbus_name_owner_change_func(const char *name, uint64_t old_owner,
 	struct kdbus_message_recv_data *recv_data = user_data;
 	char owner[32];
 
+	l_util_debug(recv_data->dbus->debug_handler,
+			recv_data->dbus->debug_data,
+			"Read KDBUS Name Owner Change notification");
+
 	snprintf(owner, sizeof(owner), ":1.%" PRIu64, new_owner);
 
 	_dbus_filter_name_owner_notify(recv_data->dbus->filter, name, owner);
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 12/20] dbus: Add message filter public API.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (9 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 11/20] dbus-kernel: Update with kdbus API changes Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 13/20] unit: Use the message filter API in dbus tests Andrew Zaborowski
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5265 bytes --]

A do-it-all single method to add a signal filter, an alternative would
be to add a bunch of functions for specific use cases.
---
 ell/dbus.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dbus.h |   7 ++++
 2 files changed, 130 insertions(+)

diff --git a/ell/dbus.c b/ell/dbus.c
index dbfa1be..362b1f5 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -555,6 +555,8 @@ static void dbus_init(struct l_dbus *dbus, int fd)
 	dbus->signal_list = l_hashmap_new();
 
 	dbus->tree = _dbus_object_tree_new();
+
+	dbus->filter = _dbus_filter_new(dbus, &dbus->driver->filter_ops);
 }
 
 static void classic_free(struct l_dbus *dbus)
@@ -1226,6 +1228,8 @@ LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus)
 	if (dbus->ready_destroy)
 		dbus->ready_destroy(dbus->ready_data);
 
+	_dbus_filter_free(dbus->filter);
+
 	l_hashmap_destroy(dbus->signal_list, signal_list_destroy);
 	l_hashmap_destroy(dbus->message_list, message_list_destroy);
 	l_queue_destroy(dbus->message_queue, message_queue_destroy);
@@ -1886,3 +1890,122 @@ LIB_EXPORT bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id)
 {
 	return l_dbus_unregister(dbus, id);
 }
+
+/**
+ * l_dbus_add_signal_watch:
+ * @dbus: D-Bus connection
+ * @sender: bus name to match the signal sender against or NULL to
+ *          match any sender
+ * @path: object path to match the signal path against or NULL to
+ *        match any path
+ * @interface: interface name to match the signal interface against
+ *             or NULL to match any interface
+ * @member: name to match the signal name against or NULL to match any
+ *          signal
+ * @...: a list of further conditions to be met by the signal followed
+ *       by three more mandatory parameters:
+ *       enum l_dbus_match_type list_end_marker,
+ *       l_dbus_message_func callback,
+ *       void *user_data,
+ *       The value L_DBUS_MATCH_NONE must be passed as the end of list
+ *       marker, followed by the signal match callback and user_data.
+ *       In the list, every condition is a pair of parameters:
+ *       enum l_dbus_match_type match_type, const char *value.
+ *
+ * Subscribe to a group of signals based on a set of conditions that
+ * compare the signal's header fields and string arguments against given
+ * values.  For example:
+ * 	signal_id = l_dbus_add_signal_watch(bus, "org.example", "/"
+ * 						"org.example.Manager",
+ * 						"PropertyChanged",
+ * 						L_DBUS_MATCH_ARGUMENT(0),
+ * 						"ExampleProperty",
+ * 						L_DBUS_MATCH_NONE
+ * 						manager_property_change_cb,
+ * 						NULL);
+  *
+ * Returns: a non-zero signal filter identifier that can be passed to
+ *          l_dbus_remove_signal_watch to remove this filter rule, or
+ *          zero on failure.
+ **/
+LIB_EXPORT unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus,
+						const char *sender,
+						const char *path,
+						const char *interface,
+						const char *member, ...)
+{
+	struct _dbus_filter_condition *rule;
+	int rule_len;
+	va_list args;
+	const char *value;
+	l_dbus_message_func_t signal_func;
+	enum l_dbus_match_type type;
+	void *user_data;
+	unsigned int id;
+
+	va_start(args, member);
+
+	rule_len = 0;
+	while ((type = va_arg(args, enum l_dbus_match_type)) !=
+			L_DBUS_MATCH_NONE)
+		rule_len++;
+
+	va_end(args);
+
+	rule = l_new(struct _dbus_filter_condition, rule_len + 5);
+
+	rule_len = 0;
+
+	rule[rule_len].type = L_DBUS_MATCH_TYPE;
+	rule[rule_len++].value = "signal";
+
+	if (sender) {
+		rule[rule_len].type = L_DBUS_MATCH_SENDER;
+		rule[rule_len++].value = sender;
+	}
+
+	if (path) {
+		rule[rule_len].type = L_DBUS_MATCH_PATH;
+		rule[rule_len++].value = path;
+	}
+
+	if (interface) {
+		rule[rule_len].type = L_DBUS_MATCH_INTERFACE;
+		rule[rule_len++].value = interface;
+	}
+
+	if (member) {
+		rule[rule_len].type = L_DBUS_MATCH_MEMBER;
+		rule[rule_len++].value = member;
+	}
+
+	va_start(args, member);
+
+	while (true) {
+		type = va_arg(args, enum l_dbus_match_type);
+		if (type == L_DBUS_MATCH_NONE)
+			break;
+
+		value = va_arg(args, const char *);
+
+		rule[rule_len].type = type;
+		rule[rule_len++].value = value;
+	}
+
+	signal_func = va_arg(args, l_dbus_message_func_t);
+	user_data = va_arg(args, void *);
+
+	va_end(args);
+
+	id = _dbus_filter_add_rule(dbus->filter, rule, rule_len,
+					signal_func, user_data);
+
+	l_free(rule);
+
+	return id;
+}
+
+LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id)
+{
+	return _dbus_filter_remove_rule(dbus->filter, id);
+}
diff --git a/ell/dbus.h b/ell/dbus.h
index 24527e0..c527058 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -246,6 +246,13 @@ unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus,
 					l_dbus_destroy_func_t destroy);
 bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id);
 
+unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus,
+					const char *sender,
+					const char *path,
+					const char *interface,
+					const char *member, ...);
+bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 13/20] unit: Use the message filter API in dbus tests.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (10 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 12/20] dbus: Add message filter public API Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 14/20] dbus: Don't send replies to messages with no reply flag Andrew Zaborowski
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7478 bytes --]

---
 unit/test-dbus-properties.c | 142 +++++++++++++++++++++-----------------------
 unit/test-kdbus.c           |   3 +-
 2 files changed, 69 insertions(+), 76 deletions(-)

diff --git a/unit/test-dbus-properties.c b/unit/test-dbus-properties.c
index f1aa406..be91dd3 100644
--- a/unit/test-dbus-properties.c
+++ b/unit/test-dbus-properties.c
@@ -665,56 +665,10 @@ static void signal_timeout_callback(struct l_timeout *timeout, void *user_data)
 static bool old_signal_received, new_signal_received;
 static bool signal_success;
 
-static void test_signal_callback(struct l_dbus_message *message)
+static void test_check_signal_success(void)
 {
-	const char *interface, *member, *property, *value;
-	struct l_dbus_message_iter variant, changed, invalidated;
 	struct l_dbus_message *call;
 
-	if (!signal_timeout)
-		return;
-
-	interface = l_dbus_message_get_interface(message);
-	member = l_dbus_message_get_member(message);
-
-	if (!strcmp(interface, "org.test") &&
-			!strcmp(member, "PropertyChanged")) {
-		test_assert(l_dbus_message_get_arguments(message, "sv",
-								&property,
-								&variant));
-		test_assert(!strcmp(property, "String"));
-		test_assert(l_dbus_message_iter_get_variant(&variant, "s",
-								&value));
-		test_assert(!strcmp(value, "foo"));
-
-		test_assert(!old_signal_received);
-		old_signal_received = true;
-	}
-
-	if (!strcmp(interface, "org.freedesktop.DBus.Properties") &&
-			!strcmp(member, "PropertiesChanged")) {
-		test_assert(l_dbus_message_get_arguments(message, "sa{sv}as",
-								&interface,
-								&changed,
-								&invalidated));
-		test_assert(!strcmp(interface, "org.test"));
-
-		test_assert(l_dbus_message_iter_next_entry(&changed, &property,
-								&variant));
-		test_assert(!strcmp(property, "String"));
-		test_assert(l_dbus_message_iter_get_variant(&variant, "s",
-								&value));
-		test_assert(!strcmp(value, "foo"));
-
-		test_assert(!l_dbus_message_iter_next_entry(&changed, &property,
-								&variant));
-		test_assert(!l_dbus_message_iter_next_entry(&invalidated,
-								&property));
-
-		test_assert(!new_signal_received);
-		new_signal_received = true;
-	}
-
 	if (!old_signal_received || !new_signal_received)
 		return;
 
@@ -751,6 +705,57 @@ static void test_signal_callback(struct l_dbus_message *message)
 	}
 }
 
+static void test_old_signal_callback(struct l_dbus_message *message,
+					void *user_data)
+{
+	const char *property, *value;
+	struct l_dbus_message_iter variant;
+
+	if (!signal_timeout)
+		return;
+
+	test_assert(l_dbus_message_get_arguments(message, "sv",
+							&property, &variant));
+	test_assert(!strcmp(property, "String"));
+	test_assert(l_dbus_message_iter_get_variant(&variant, "s", &value));
+	test_assert(!strcmp(value, "foo"));
+
+	test_assert(!old_signal_received);
+	old_signal_received = true;
+
+	test_check_signal_success();
+}
+
+static void test_new_signal_callback(struct l_dbus_message *message,
+					void *user_data)
+{
+	const char *interface, *property, *value;
+	struct l_dbus_message_iter variant, changed, invalidated;
+
+	if (!signal_timeout)
+		return;
+
+	test_assert(l_dbus_message_get_arguments(message, "sa{sv}as",
+							&interface, &changed,
+							&invalidated));
+
+	test_assert(l_dbus_message_iter_next_entry(&changed, &property,
+							&variant));
+	test_assert(!strcmp(property, "String"));
+	test_assert(l_dbus_message_iter_get_variant(&variant, "s", &value));
+	test_assert(!strcmp(value, "foo"));
+
+	test_assert(!l_dbus_message_iter_next_entry(&changed, &property,
+							&variant));
+	test_assert(!l_dbus_message_iter_next_entry(&invalidated,
+							&property));
+
+	test_assert(!new_signal_received);
+	new_signal_received = true;
+
+	test_check_signal_success();
+}
+
 static void test_property_signals(struct l_dbus *dbus, void *test_data)
 {
 	old_signal_received = false;
@@ -837,7 +842,7 @@ static void om_signal_timeout_callback(struct l_timeout *timeout,
 
 static bool expect_interfaces_added;
 
-static void root_signal_callback(struct l_dbus_message *message)
+static void om_signal_callback(struct l_dbus_message *message, void *user_data)
 {
 	const char *path, *interface, *member;
 	struct l_dbus_message_iter interfaces, properties;
@@ -845,12 +850,8 @@ static void root_signal_callback(struct l_dbus_message *message)
 	if (!om_signal_timeout)
 		return;
 
-	interface = l_dbus_message_get_interface(message);
 	member = l_dbus_message_get_member(message);
 
-	if (strcmp(interface, "org.freedesktop.DBus.ObjectManager"))
-		return;
-
 	if (!strcmp(member, "InterfacesAdded"))
 		test_assert(expect_interfaces_added);
 	else if (!strcmp(member, "InterfacesRemoved"))
@@ -909,25 +910,11 @@ static void test_object_manager_signals(struct l_dbus *dbus, void *test_data)
 						NULL));
 }
 
-static void signal_message(struct l_dbus_message *message, void *user_data)
-{
-	const char *path;
-
-	path = l_dbus_message_get_path(message);
-
-	if (!strcmp(path, "/test"))
-		test_signal_callback(message);
-
-	if (!strcmp(path, "/"))
-		root_signal_callback(message);
-}
-
 int main(int argc, char *argv[])
 {
 	struct l_signal *signal;
 	sigset_t mask;
 	int i;
-	struct l_dbus_message *call;
 
 	sigemptyset(&mask);
 	sigaddset(&mask, SIGINT);
@@ -951,15 +938,6 @@ int main(int argc, char *argv[])
 	l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
 	l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
 
-	l_dbus_register(dbus, signal_message, NULL, NULL);
-
-	call = l_dbus_message_new_method_call(dbus, "org.freedesktop.DBus",
-						"/org/freedesktop/DBus",
-						"org.freedesktop.DBus",
-						"AddMatch");
-	l_dbus_message_set_arguments(call, "s", "type=signal,sender=org.test");
-	l_dbus_send(dbus, call);
-
 	l_dbus_method_call(dbus, "org.freedesktop.DBus",
 				"/org/freedesktop/DBus",
 				"org.freedesktop.DBus", "RequestName",
@@ -983,11 +961,25 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
+	l_dbus_add_signal_watch(dbus, "org.test", "/test", "org.test",
+				"PropertyChanged", L_DBUS_MATCH_NONE,
+				test_old_signal_callback, NULL);
+	l_dbus_add_signal_watch(dbus, "org.test", "/test",
+				"org.freedesktop.DBus.Properties",
+				"PropertiesChanged", L_DBUS_MATCH_ARGUMENT(0),
+				"org.test", L_DBUS_MATCH_NONE,
+				test_new_signal_callback, NULL);
+
 	if (!l_dbus_object_manager_enable(dbus)) {
 		l_info("Unable to enable Object Manager");
 		goto done;
 	}
 
+	l_dbus_add_signal_watch(dbus, "org.test", "/",
+				"org.freedesktop.DBus.ObjectManager",
+				NULL, L_DBUS_MATCH_NONE,
+				om_signal_callback, NULL);
+
 	test_add("Legacy properties get", test_old_get, NULL);
 	test_add("Legacy properties set", test_old_set, NULL);
 	test_add("Legacy optional property", test_old_optional_get, NULL);
diff --git a/unit/test-kdbus.c b/unit/test-kdbus.c
index 3a6af3e..dde2596 100644
--- a/unit/test-kdbus.c
+++ b/unit/test-kdbus.c
@@ -174,7 +174,8 @@ int main(int argc, char *argv[])
 
 	l_dbus_set_debug(client, do_debug, "[CLIENT] ", NULL);
 	l_dbus_set_ready_handler(client, client_ready_callback, client, NULL);
-	l_dbus_register(client, signal_message, NULL, NULL);
+	l_dbus_add_signal_watch(client, "org.test", NULL, NULL, NULL,
+				L_DBUS_MATCH_NONE, signal_message, NULL);
 
 	l_main_run();
 
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 14/20] dbus: Don't send replies to messages with no reply flag.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (11 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 13/20] unit: Use the message filter API in dbus tests Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 17:11   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 15/20] dbus: Rewrite service/disconnect watch APIs on top of filter API Andrew Zaborowski
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 977 bytes --]

Kdbus doesn't store the cookies for messages that have the no reply flag
and throws error when a reply is sent with reply_cookie that it doesn't
know.  It's not fatal, but we also save some cycles by not sending the
message.  A further change could be made to not even let users create a
message as a return from a method call but that may be confusing.
---
 ell/dbus-service.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/ell/dbus-service.c b/ell/dbus-service.c
index b4e0b60..c1ed9ec 100644
--- a/ell/dbus-service.c
+++ b/ell/dbus-service.c
@@ -1624,8 +1624,12 @@ bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree,
 		return false;
 
 	reply = method->cb(dbus, message, instance->user_data);
-	if (reply)
-		l_dbus_send(dbus, reply);
+	if (reply) {
+		if (l_dbus_message_get_no_reply(message))
+			l_dbus_message_unref(reply);
+		else
+			l_dbus_send(dbus, reply);
+	}
 
 	return true;
 }
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 15/20] dbus: Rewrite service/disconnect watch APIs on top of filter API
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (12 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 14/20] dbus: Don't send replies to messages with no reply flag Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 16/20] dbus: Remove now unused filter functions Andrew Zaborowski
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 9333 bytes --]

The two advantages are that this should now work on top of kdbus and
that the full list of watches is not traversed on every notification.
---
 ell/dbus.c | 194 +++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 125 insertions(+), 69 deletions(-)

diff --git a/ell/dbus.c b/ell/dbus.c
index 362b1f5..38b6705 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -89,6 +89,9 @@ struct l_dbus {
 	void *debug_data;
 	struct _dbus_object_tree *tree;
 	struct _dbus_filter *filter;
+	struct l_hashmap *services_watched;
+	struct service_watch_data *service_watch_head;
+	unsigned int last_service_watch_id;
 
 	const struct l_dbus_ops *driver;
 };
@@ -123,6 +126,17 @@ struct signal_callback {
 	void *user_data;
 };
 
+struct service_watch_data {
+	char *bus_name;
+	l_dbus_destroy_func_t destroy_func;
+	l_dbus_watch_func_t connect_func;
+	l_dbus_watch_func_t disconnect_func;
+	void *user_data;
+	unsigned int id;
+	bool pending_get_name_owner;
+	struct service_watch_data *next;
+};
+
 struct dbus1_filter_data {
 	struct l_dbus *dbus;
 	char *sender;
@@ -363,6 +377,34 @@ static void bus_ready(struct l_dbus *dbus)
 	l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL);
 }
 
+static void name_owner_notify(struct l_dbus *dbus, const char *name,
+				const char *old, const char *new)
+{
+	struct service_watch_data *watch, *next;
+	bool connect = old && new && !*old && *new;
+	bool disconnect = old && new && *old && !*new;
+
+	_dbus_filter_name_owner_notify(dbus->filter, name, new);
+
+	watch = l_hashmap_lookup(dbus->services_watched, name);
+
+	while (watch && !strcmp(watch->bus_name, name)) {
+		/* Save next in case watch is freed from within the callback */
+		next = watch->next;
+
+		if (watch->pending_get_name_owner) {
+			watch->pending_get_name_owner = false;
+			if (new && *new)
+				watch->connect_func(dbus, watch->user_data);
+		} else if (connect && watch->connect_func)
+			watch->connect_func(dbus, watch->user_data);
+		else if (disconnect && watch->disconnect_func)
+			watch->disconnect_func(dbus, watch->user_data);
+
+		watch = next;
+	}
+}
+
 static void hello_callback(struct l_dbus_message *message, void *user_data)
 {
 	struct l_dbus *dbus = user_data;
@@ -752,7 +794,7 @@ static void get_name_owner_reply_cb(struct l_dbus_message *reply,
 	if (!l_dbus_message_get_arguments(req->message, "s", &name))
 		return;
 
-	_dbus_filter_name_owner_notify(req->dbus->filter, name, owner);
+	name_owner_notify(req->dbus, name, NULL, owner);
 }
 
 static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
@@ -797,7 +839,7 @@ static void name_owner_changed_cb(struct l_dbus_message *message,
 	if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new))
 		return;
 
-	_dbus_filter_name_owner_notify(dbus->filter, name, new);
+	name_owner_notify(dbus, name, old, new);
 }
 
 static struct l_dbus *setup_dbus1(int fd, const char *guid)
@@ -997,15 +1039,22 @@ static void kdbus_name_owner_change_func(const char *name, uint64_t old_owner,
 						void *user_data)
 {
 	struct kdbus_message_recv_data *recv_data = user_data;
-	char owner[32];
+	char old[32], new[32];
 
 	l_util_debug(recv_data->dbus->debug_handler,
 			recv_data->dbus->debug_data,
 			"Read KDBUS Name Owner Change notification");
 
-	snprintf(owner, sizeof(owner), ":1.%" PRIu64, new_owner);
+	if (old_owner)
+		snprintf(old, sizeof(old), ":1.%" PRIu64, new_owner);
+	else
+		*old = '\0';
+	if (new_owner)
+		snprintf(new, sizeof(new), ":1.%" PRIu64, new_owner);
+	else
+		*new = '\0';
 
-	_dbus_filter_name_owner_notify(recv_data->dbus->filter, name, owner);
+	name_owner_notify(recv_data->dbus, name, old, new);
 }
 
 static struct l_dbus_message *kdbus_recv_message(struct l_dbus *dbus)
@@ -1067,15 +1116,13 @@ static bool kdbus_get_name_owner(struct l_dbus *dbus, const char *name)
 	char owner[32];
 
 	owner_id = _dbus_kernel_get_name_owner(fd, kdbus->kdbus_pool, name);
-	if (!owner_id) {
-		l_util_debug(dbus->debug_handler,
-				dbus->debug_data, "Error getting name owner");
-		return false;
-	}
 
-	snprintf(owner, sizeof(owner), ":1.%" PRIu64, owner_id);
+	if (owner_id)
+		snprintf(owner, sizeof(owner), ":1.%" PRIu64, owner_id);
+	else
+		*owner = '\0';
 
-	_dbus_filter_name_owner_notify(dbus->filter, name, owner);
+	name_owner_notify(dbus, name, NULL, owner);
 
 	return true;
 }
@@ -1220,6 +1267,17 @@ LIB_EXPORT struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus)
 	return setup_address(address);
 }
 
+static void service_watch_data_free(void *data)
+{
+	struct service_watch_data *watch = data;
+
+	if (watch->destroy_func)
+		watch->destroy_func(watch->user_data);
+
+	l_free(watch->bus_name);
+	l_free(watch);
+}
+
 LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus)
 {
 	if (unlikely(!dbus))
@@ -1234,6 +1292,8 @@ LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus)
 	l_hashmap_destroy(dbus->message_list, message_list_destroy);
 	l_queue_destroy(dbus->message_queue, message_queue_destroy);
 
+	l_hashmap_destroy(dbus->services_watched, service_watch_data_free);
+
 	l_io_destroy(dbus->io);
 
 	if (dbus->disconnect_destroy)
@@ -1802,33 +1862,6 @@ void _dbus1_name_owner_changed_filter(struct l_dbus_message *message,
 	}
 }
 
-static void _dbus1_get_name_owner_reply(struct l_dbus_message *message,
-							void *user_data)
-{
-	struct dbus1_filter_data *data = user_data;
-	const char *name;
-
-	data->get_name_owner_id = 0;
-
-	/* No name owner yet */
-	if (l_dbus_message_is_error(message))
-		return;
-
-	/* Shouldn't happen */
-	if (!l_dbus_message_get_arguments(message, "s", &name))
-		return;
-
-	/* If the signal arrived before the reply, don't do anything */
-	if (data->owner && !strcmp(data->owner, name))
-		return;
-
-	l_free(data->owner);
-	data->owner = l_strdup(name);
-
-	if (data->connect_func)
-		data->connect_func(data->dbus, data->user_data);
-}
-
 LIB_EXPORT unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus,
 					const char *name,
 					l_dbus_watch_func_t disconnect_func,
@@ -1839,56 +1872,79 @@ LIB_EXPORT unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus,
 					user_data, destroy);
 }
 
-unsigned int l_dbus_add_service_watch(struct l_dbus *dbus,
+LIB_EXPORT unsigned int l_dbus_add_service_watch(struct l_dbus *dbus,
 					const char *name,
 					l_dbus_watch_func_t connect_func,
 					l_dbus_watch_func_t disconnect_func,
 					void *user_data,
 					l_dbus_destroy_func_t destroy)
 {
-	struct dbus1_filter_data *data;
+	struct service_watch_data *watch, *first;
 
 	if (!name)
 		return 0;
 
-	data = _dbus1_filter_data_get(dbus, _dbus1_name_owner_changed_filter,
-				DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-				L_DBUS_INTERFACE_DBUS, "NameOwnerChanged",
-				name,
-				disconnect_func,
-				user_data,
-				destroy);
-	if (!data)
-		return 0;
+	if (!dbus->services_watched)
+		dbus->services_watched = l_hashmap_string_new();
+
+	watch = l_new(struct service_watch_data, 1);
+	watch->bus_name = l_strdup(name);
+	watch->id = ++dbus->last_service_watch_id;
+	watch->connect_func = connect_func;
+	watch->disconnect_func = disconnect_func;
+	watch->destroy_func = destroy;
+
+	/*
+	 * Make sure that all the entries for the same bus name are
+	 * grouped together on the list and that the first entry on the
+	 * list is in the hashmap for easy lookups.
+	 */
+	first = l_hashmap_lookup(dbus->services_watched, name);
+	if (first) {
+		watch->next = first->next;
+		first->next = watch;
+	} else {
+		l_hashmap_insert(dbus->services_watched, name, watch);
 
-	add_match(data);
+		watch->next = dbus->service_watch_head;
+		dbus->service_watch_head = watch;
+	}
 
 	if (connect_func) {
-		struct l_dbus_message *message;
-
-		data->connect_func = connect_func;
+		watch->pending_get_name_owner = true;
 
-		message = l_dbus_message_new_method_call(dbus,
-							DBUS_SERVICE_DBUS,
-							DBUS_PATH_DBUS,
-							L_DBUS_INTERFACE_DBUS,
-							"GetNameOwner");
-
-		l_dbus_message_set_arguments(message, "s", name);
-
-		data->get_name_owner_id =
-			l_dbus_send_with_reply(dbus, message,
-						_dbus1_get_name_owner_reply,
-						data, NULL);
+		dbus->driver->filter_ops.get_name_owner(dbus, name);
 	}
 
-	return l_dbus_register(dbus, _dbus1_signal_dispatcher, data,
-							filter_data_destroy);
+	return watch->id;
 }
 
 LIB_EXPORT bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id)
 {
-	return l_dbus_unregister(dbus, id);
+	struct service_watch_data **watch, *tmp;
+
+	for (watch = &dbus->service_watch_head; *watch; watch = &(*watch)->next)
+		if ((*watch)->id == id)
+			break;
+
+	if (!*watch)
+		return false;
+
+	tmp = *watch;
+	*watch = tmp->next;
+
+	/* Check if this was the first entry for the bus name */
+	if (l_hashmap_lookup(dbus->services_watched, tmp->bus_name) == tmp) {
+		l_hashmap_remove(dbus->services_watched, tmp->bus_name);
+
+		if (tmp->next && !strcmp(tmp->bus_name, tmp->next->bus_name))
+			l_hashmap_insert(dbus->services_watched,
+						tmp->bus_name, tmp->next);
+	}
+
+	service_watch_data_free(tmp);
+
+	return true;
 }
 
 /**
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 16/20] dbus: Remove now unused filter functions.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (13 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 15/20] dbus: Rewrite service/disconnect watch APIs on top of filter API Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 19:12   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 17/20] dbus: kdbus driver->name_acquire implementation Andrew Zaborowski
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1712 bytes --]

---
 ell/dbus.c | 51 ---------------------------------------------------
 1 file changed, 51 deletions(-)

diff --git a/ell/dbus.c b/ell/dbus.c
index 38b6705..35afd1f 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -1745,57 +1745,6 @@ void _dbus1_filter_data_destroy(void *user_data)
 	l_free(data);
 }
 
-static void dbus1_send_match(struct l_dbus *dbus, const char *rule,
-						const char *method)
-{
-	struct l_dbus_message *message;
-
-	message = l_dbus_message_new_method_call(dbus,
-						DBUS_SERVICE_DBUS,
-						DBUS_PATH_DBUS,
-						L_DBUS_INTERFACE_DBUS,
-						method);
-
-	l_dbus_message_set_arguments(message, "s", rule);
-
-	send_message(dbus, false, message, NULL, NULL, NULL);
-}
-
-static void dbus1_bus_add_match(struct l_dbus *dbus, const char *rule)
-{
-	dbus1_send_match(dbus, rule, "AddMatch");
-}
-
-static void dbus1_bus_remove_match(struct l_dbus *dbus, const char *rule)
-{
-	dbus1_send_match(dbus, rule, "RemoveMatch");
-}
-
-static void add_match(struct dbus1_filter_data *data)
-{
-	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
-
-	_dbus1_filter_format_match(data, rule, sizeof(rule));
-
-	dbus1_bus_add_match(data->dbus, rule);
-}
-
-static void remove_match(struct dbus1_filter_data *data)
-{
-	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
-
-	_dbus1_filter_format_match(data, rule, sizeof(rule));
-
-	dbus1_bus_remove_match(data->dbus, rule);
-}
-
-static void filter_data_destroy(void *user_data)
-{
-	remove_match(user_data);
-
-	_dbus1_filter_data_destroy(user_data);
-}
-
 void _dbus1_signal_dispatcher(struct l_dbus_message *message, void *user_data)
 {
 	struct dbus1_filter_data *data = user_data;
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 17/20] dbus: kdbus driver->name_acquire implementation.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (14 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 16/20] dbus: Remove now unused filter functions Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API Andrew Zaborowski
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4263 bytes --]

---
 ell/dbus-kernel.c  | 13 ++++++++++++-
 ell/dbus-private.h |  4 +++-
 ell/dbus.c         | 34 ++++++++++++++++++++++++++++++++++
 ell/dbus.h         |  3 +++
 4 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/ell/dbus-kernel.c b/ell/dbus-kernel.c
index 54d7d4d..e054863 100644
--- a/ell/dbus-kernel.c
+++ b/ell/dbus-kernel.c
@@ -621,7 +621,8 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 	return r;
 }
 
-int _dbus_kernel_name_acquire(int fd, const char *name)
+int _dbus_kernel_name_acquire(int fd, const char *name, bool allow_replacement,
+				bool replace_existing, bool queue, bool *queued)
 {
 	struct {
 		struct kdbus_cmd head;
@@ -646,9 +647,19 @@ int _dbus_kernel_name_acquire(int fd, const char *name)
 	item->type = KDBUS_ITEM_NAME;
 	strcpy(item->str, name);
 
+	if (replace_existing)
+		cmd_name.head.flags |= KDBUS_NAME_REPLACE_EXISTING;
+	if (allow_replacement)
+		cmd_name.head.flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
+	if (queue)
+		cmd_name.head.flags |= KDBUS_NAME_QUEUE;
+
 	if (ioctl(fd, KDBUS_CMD_NAME_ACQUIRE, &cmd_name) < 0)
 		return -errno;
 
+	if (queued)
+		*queued = !!(cmd_name.head.flags & KDBUS_NAME_IN_QUEUE);
+
 	return 0;
 }
 
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index f210a3c..0dfdc82 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -242,7 +242,9 @@ int _dbus_kernel_recv(int fd, void *kdbus_pool,
 			_dbus_name_owner_change_func_t name_owner_change_func,
 			void *user_data);
 
-int _dbus_kernel_name_acquire(int fd, const char *name);
+int _dbus_kernel_name_acquire(int fd, const char *name, bool allow_replacement,
+				bool replace_existing, bool queue,
+				bool *queued);
 int _dbus_kernel_add_match(int fd, uint64_t bloom_size, uint64_t bloom_n_hash,
 				const struct _dbus_filter_condition *rule,
 				int rule_len, unsigned int id);
diff --git a/ell/dbus.c b/ell/dbus.c
index 35afd1f..c5cc1fc 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <errno.h>
 
 #include "util.h"
 #include "io.h"
@@ -64,6 +65,10 @@ struct l_dbus_ops {
 	struct l_dbus_message *(*recv_message)(struct l_dbus *bus);
 	void (*free)(struct l_dbus *bus);
 	struct _dbus_filter_ops filter_ops;
+	uint32_t (*name_acquire)(struct l_dbus *dbus, const char *name,
+				bool allow_replacement, bool replace_existing,
+				bool queue, l_dbus_name_acquire_func_t callback,
+				void *user_data);
 };
 
 struct l_dbus {
@@ -1127,6 +1132,34 @@ static bool kdbus_get_name_owner(struct l_dbus *dbus, const char *name)
 	return true;
 }
 
+static uint32_t kdbus_name_acquire(struct l_dbus *dbus, const char *name,
+					bool allow_replacement,
+					bool replace_existing, bool queue,
+					l_dbus_name_acquire_func_t callback,
+					void *user_data)
+{
+	int fd = l_io_get_fd(dbus->io);
+	bool queued = false;
+	int r;
+
+	r = _dbus_kernel_name_acquire(fd, name, allow_replacement,
+					replace_existing, queue, &queued);
+	if (r < 0 && r != -EALREADY) {
+		l_util_debug(dbus->debug_handler,
+				dbus->debug_data, strerror(-r));
+
+		if (callback)
+			callback(dbus, false, false, user_data);
+
+		return 0;
+	}
+
+	if (callback)
+		callback(dbus, true, queued, user_data);
+
+	return 0;
+}
+
 static const struct l_dbus_ops kdbus_ops = {
 	.version  = 2,
 	.free = kdbus_free,
@@ -1138,6 +1171,7 @@ static const struct l_dbus_ops kdbus_ops = {
 		.remove_match = kdbus_remove_match,
 		.get_name_owner = kdbus_get_name_owner,
 	},
+	.name_acquire = kdbus_name_acquire,
 };
 
 static struct l_dbus *setup_kdbus(int fd)
diff --git a/ell/dbus.h b/ell/dbus.h
index c527058..0b82899 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -68,6 +68,9 @@ typedef void (*l_dbus_interface_setup_func_t) (struct l_dbus_interface *);
 
 typedef void (*l_dbus_watch_func_t) (struct l_dbus *dbus, void *user_data);
 
+typedef void (*l_dbus_name_acquire_func_t) (struct l_dbus *dbus, bool success,
+						bool queued, void *user_data);
+
 struct l_dbus *l_dbus_new(const char *address);
 struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus);
 void l_dbus_destroy(struct l_dbus *dbus);
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (15 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 17/20] dbus: kdbus driver->name_acquire implementation Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 19:18   ` Denis Kenzior
  2016-03-14  3:41 ` [PATCH 19/20] unit: Use l_dbus_name_acquire to acquire well-known name Andrew Zaborowski
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3998 bytes --]

---
 ell/dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dbus.h |  5 ++++
 2 files changed, 94 insertions(+)

diff --git a/ell/dbus.c b/ell/dbus.c
index c5cc1fc..6c267ae 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -822,6 +822,84 @@ static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
 	return true;
 }
 
+struct name_request {
+	l_dbus_name_acquire_func_t callback;
+	void *user_data;
+	struct l_dbus *dbus;
+};
+
+enum dbus_name_flag {
+	DBUS_NAME_FLAG_ALLOW_REPLACEMENT	= 0x1,
+	DBUS_NAME_FLAG_REPLACE_EXISTING		= 0x2,
+	DBUS_NAME_FLAG_DO_NOT_QUEUE		= 0x4,
+};
+
+enum dbus_name_reply {
+	DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER	= 1,
+	DBUS_REQUEST_NAME_REPLY_IN_QUEUE	= 2,
+	DBUS_REQUEST_NAME_REPLY_EXISTS		= 3,
+	DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER	= 4,
+};
+
+static void request_name_reply_cb(struct l_dbus_message *reply, void *user_data)
+{
+	struct name_request *req = user_data;
+	bool success = false, queued = false;
+	uint32_t retval;
+
+	if (!req->callback)
+		return;
+
+	/* No name owner yet */
+	if (l_dbus_message_is_error(reply))
+		goto call_back;
+
+	/* Shouldn't happen */
+	if (!l_dbus_message_get_arguments(reply, "u", &retval))
+		goto call_back;
+
+	success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) ||
+		(retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) ||
+		(retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
+	queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
+
+call_back:
+	req->callback(req->dbus, success, queued, req->user_data);
+}
+
+static uint32_t classic_name_acquire(struct l_dbus *dbus, const char *name,
+					bool allow_replacement,
+					bool replace_existing, bool queue,
+					l_dbus_name_acquire_func_t callback,
+					void *user_data)
+{
+	struct name_request *req;
+	struct l_dbus_message *message;
+	uint32_t flags = 0;
+
+	req = l_new(struct name_request, 1);
+	req->dbus = dbus;
+	req->user_data = user_data;
+	req->callback = callback;
+
+	message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS,
+							DBUS_PATH_DBUS,
+							L_DBUS_INTERFACE_DBUS,
+							"RequestName");
+
+	if (allow_replacement)
+		flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
+	if (replace_existing)
+		flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
+	if (!queue)
+		flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
+
+	l_dbus_message_set_arguments(message, "su", name, flags);
+
+	return send_message(dbus, false, message, request_name_reply_cb,
+				req, free);
+}
+
 static const struct l_dbus_ops classic_ops = {
 	.version = 1,
 	.send_message = classic_send_message,
@@ -833,6 +911,7 @@ static const struct l_dbus_ops classic_ops = {
 		.remove_match = classic_remove_match,
 		.get_name_owner = classic_get_name_owner,
 	},
+	.name_acquire = classic_name_acquire,
 };
 
 static void name_owner_changed_cb(struct l_dbus_message *message,
@@ -2048,3 +2127,13 @@ LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id)
 {
 	return _dbus_filter_remove_rule(dbus->filter, id);
 }
+
+LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
+				bool allow_replacement, bool replace_existing,
+				bool queue, l_dbus_name_acquire_func_t callback,
+				void *user_data)
+{
+	return dbus->driver->name_acquire(dbus, name, allow_replacement,
+						replace_existing, queue,
+						callback, user_data);
+}
diff --git a/ell/dbus.h b/ell/dbus.h
index 0b82899..f4b2527 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -256,6 +256,11 @@ unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus,
 					const char *member, ...);
 bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id);
 
+uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
+				bool allow_replacement, bool replace_existing,
+				bool queue, l_dbus_name_acquire_func_t callback,
+				void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 19/20] unit: Use l_dbus_name_acquire to acquire well-known name.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (16 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14  3:41 ` [PATCH 20/20] examples: " Andrew Zaborowski
  2016-03-14 16:50 ` [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Denis Kenzior
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2754 bytes --]

---
 unit/test-dbus-properties.c | 36 ++++++------------------------------
 unit/test-kdbus.c           | 14 +++++++++-----
 2 files changed, 15 insertions(+), 35 deletions(-)

diff --git a/unit/test-dbus-properties.c b/unit/test-dbus-properties.c
index be91dd3..c7ed384 100644
--- a/unit/test-dbus-properties.c
+++ b/unit/test-dbus-properties.c
@@ -152,32 +152,11 @@ static void test_next()
 		}	\
 	} while (0)
 
-static void request_name_setup(struct l_dbus_message *message, void *user_data)
+static void request_name_callback(struct l_dbus *dbus, bool success,
+					bool queued, void *user_data)
 {
-	const char *name = "org.test";
-
-	l_dbus_message_set_arguments(message, "su", name, 0);
-}
-
-static void request_name_callback(struct l_dbus_message *message,
-					void *user_data)
-{
-	const char *error, *text;
-	uint32_t result;
-
-	if (l_dbus_message_get_error(message, &error, &text)) {
-		l_error("error=%s", error);
-		l_error("message=%s", text);
-		l_main_quit();
-		return;
-	}
-
-	if (!l_dbus_message_get_arguments(message, "u", &result)) {
-		l_main_quit();
-		return;
-	}
-
-	l_info("request name result=%d", result);
+	l_info("request name result=%s",
+		success ? (queued ? "queued" : "success") : "failed");
 
 	test_next();
 }
@@ -938,11 +917,8 @@ int main(int argc, char *argv[])
 	l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
 	l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
 
-	l_dbus_method_call(dbus, "org.freedesktop.DBus",
-				"/org/freedesktop/DBus",
-				"org.freedesktop.DBus", "RequestName",
-				request_name_setup,
-				request_name_callback, NULL, NULL);
+	l_dbus_name_acquire(dbus, "org.test", false, false, false,
+				request_name_callback, NULL);
 
 	if (!l_dbus_register_interface(dbus, "org.test", setup_test_interface,
 					NULL, true)) {
diff --git a/unit/test-kdbus.c b/unit/test-kdbus.c
index dde2596..8cac761 100644
--- a/unit/test-kdbus.c
+++ b/unit/test-kdbus.c
@@ -97,16 +97,20 @@ static void client_ready_callback(void *user_data)
 				NULL, NULL, NULL);
 }
 
+static void service_name_acquire_callback(struct l_dbus *dbus, bool success,
+						bool queued, void *user_data)
+{
+	if (!success)
+		l_info("Failed to acquire name");
+}
+
 static void service_ready_callback(void *user_data)
 {
 	struct l_dbus *dbus = user_data;
 	struct l_dbus_message *message;
-	int fd = _dbus_get_fd(dbus);
-	int r;
 
-	r = _dbus_kernel_name_acquire(fd, "org.test");
-	if (r < 0)
-		l_info("Failed to acquire name: %s", strerror(-r));
+	l_dbus_name_acquire(dbus, "org.test", false, false, false,
+				service_name_acquire_callback, NULL);
 
 	l_info("service ready");
 
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 20/20] examples: Use l_dbus_name_acquire to acquire well-known name.
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (17 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 19/20] unit: Use l_dbus_name_acquire to acquire well-known name Andrew Zaborowski
@ 2016-03-14  3:41 ` Andrew Zaborowski
  2016-03-14 16:50 ` [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Denis Kenzior
  19 siblings, 0 replies; 40+ messages in thread
From: Andrew Zaborowski @ 2016-03-14  3:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1836 bytes --]

---
 examples/dbus-service.c | 33 ++++++---------------------------
 1 file changed, 6 insertions(+), 27 deletions(-)

diff --git a/examples/dbus-service.c b/examples/dbus-service.c
index 347faae..51b7e4f 100644
--- a/examples/dbus-service.c
+++ b/examples/dbus-service.c
@@ -50,29 +50,11 @@ static void signal_handler(struct l_signal *signal, uint32_t signo,
 	}
 }
 
-static void request_name_setup(struct l_dbus_message *message, void *user_data)
+static void request_name_callback(struct l_dbus *dbus, bool success,
+					bool queued, void *user_data)
 {
-	const char *name = "org.test";
-
-	l_dbus_message_set_arguments(message, "su", name, 0);
-}
-
-static void request_name_callback(struct l_dbus_message *message,
-							void *user_data)
-{
-	const char *error, *text;
-	uint32_t result;
-
-	if (l_dbus_message_get_error(message, &error, &text)) {
-		l_error("error=%s", error);
-		l_error("message=%s", text);
-		return;
-	}
-
-	if (!l_dbus_message_get_arguments(message, "u", &result))
-		return;
-
-	l_info("request name result=%d", result);
+	l_info("request name result=%s",
+		success ? (queued ? "queued" : "success") : "failed");
 }
 
 static void ready_callback(void *user_data)
@@ -211,11 +193,8 @@ int main(int argc, char *argv[])
 	l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
 	l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
 
-	l_dbus_method_call(dbus, "org.freedesktop.DBus",
-				"/org/freedesktop/DBus",
-				L_DBUS_INTERFACE_DBUS, "RequestName",
-				request_name_setup,
-				request_name_callback, NULL, NULL);
+	l_dbus_name_acquire(dbus, "org.test", false, false, false,
+				request_name_callback, NULL);
 
 	if (!l_dbus_object_manager_enable(dbus)) {
 		l_info("Unable to enable Object Manager");
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-14  3:41 ` [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments Andrew Zaborowski
@ 2016-03-14 16:49   ` Denis Kenzior
  2016-03-14 22:11     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 16:49 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3233 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> It seems that l_dbus_message_iter_get_type can't be used to get the
> value of a single argument and be called repeatedly, it might crash if

Looking at l_dbus_message_iter_get_type, it just returns 
iter->sig_start[iter->sig_pos].  Is there something deeper going on here 
that is not readily apparent?

> the number and types of call arguments don't match the message arguments.
> Also try to support the string arguments that come after non-string
> arguments in the bloom filter.

 From my reading of systemd code, I didn't think this was possible.  But 
I could be wrong...

> ---
>   ell/dbus-message.c | 38 ++++++++++++++++++++++++++++----------
>   1 file changed, 28 insertions(+), 10 deletions(-)
>
> diff --git a/ell/dbus-message.c b/ell/dbus-message.c
> index f223c70..a123a8a 100644
> --- a/ell/dbus-message.c
> +++ b/ell/dbus-message.c
> @@ -1412,9 +1412,12 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
>   	const char *signature;
>   	void *body;
>   	size_t body_size;
> -	struct l_dbus_message_iter iter;
> +	struct l_dbus_message_iter iter, tmp;
>   	uint8_t argn;
>   	char buf[256];
> +	bool (*skip_entry)(struct l_dbus_message_iter *);
> +	bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
> +	char type;
>
>   	/* The string "interface:" suffixed by the interface name */
>   	attr = l_dbus_message_get_interface(message);
> @@ -1458,17 +1461,32 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
>
>   	body = _dbus_message_get_body(message, &body_size);
>
> -	if (_dbus_message_is_gvariant(message))
> -		_gvariant_iter_init(&iter, message, signature, NULL,
> -					body, body_size);
> -	else
> +	if (_dbus_message_is_gvariant(message)) {
> +		if (!_gvariant_iter_init(&iter, message, signature, NULL,
> +						body, body_size))
> +			return false;
> +
> +		skip_entry = _gvariant_iter_skip_entry;
> +		get_basic = _gvariant_iter_next_entry_basic;
> +	} else {
>   		_dbus1_iter_init(&iter, message, signature, NULL,
> -				body, body_size);
> +					body, body_size);
> +
> +		skip_entry = _dbus1_iter_skip_entry;
> +		get_basic = _dbus1_iter_next_entry_basic;
> +	}
>
>   	argn = 0;
>
> -	while (*signature == 's' || *signature == 'o' || *signature == 'g') {
> -		if (!message_iter_next_entry(&iter, &attr))
> +	do {
> +		type = l_dbus_message_iter_get_type(&iter);
> +		if (!strchr("sog", type))
> +			goto next;
> +
> +		/* Don't let get_basic move iter->pos without moving sig_pos */
> +		memcpy(&tmp, &iter, sizeof(tmp));
> +
> +		if (!get_basic(&tmp, type, &attr))
>   			return false;

Is this to avoid double skipping this entry?  Can we find a less hacky 
way to do this?  Perhaps peek_basic, or restructure the loop in some way?

>
>   		sprintf(buf, "arg%hhu", argn);
> @@ -1482,9 +1500,9 @@ bool _dbus_kernel_calculate_bloom(struct l_dbus_message *message,
>   		_dbus_kernel_bloom_add_parents(filter, f_size, num_hash, buf,
>   						attr, '.');
>
> +next:
>   		argn += 1;
> -		signature += 1;
> -	}
> +	} while (skip_entry(&iter));
>
>   	return true;
>   }
>

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant
  2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
                   ` (18 preceding siblings ...)
  2016-03-14  3:41 ` [PATCH 20/20] examples: " Andrew Zaborowski
@ 2016-03-14 16:50 ` Denis Kenzior
  19 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 16:50 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> This will be used for the get_nth_string_argument function in
> dbus-message.c.  There seems to be no other way to skip over an iterator
> entry without knowing the data type.
> ---
>   ell/dbus-private.h     |  1 +
>   ell/dbus-util.c        | 16 ++++++++++++++++
>   ell/gvariant-private.h |  1 +
>   ell/gvariant-util.c    | 10 ++++++++++
>   4 files changed, 28 insertions(+)
>

This just screams to be separated into two patches :)

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 14/20] dbus: Don't send replies to messages with no reply flag.
  2016-03-14  3:41 ` [PATCH 14/20] dbus: Don't send replies to messages with no reply flag Andrew Zaborowski
@ 2016-03-14 17:11   ` Denis Kenzior
  2016-03-14 22:15     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 17:11 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1295 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> Kdbus doesn't store the cookies for messages that have the no reply flag
> and throws error when a reply is sent with reply_cookie that it doesn't
> know.  It's not fatal, but we also save some cycles by not sending the
> message.  A further change could be made to not even let users create a
> message as a return from a method call but that may be confusing.
> ---
>   ell/dbus-service.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/ell/dbus-service.c b/ell/dbus-service.c
> index b4e0b60..c1ed9ec 100644
> --- a/ell/dbus-service.c
> +++ b/ell/dbus-service.c
> @@ -1624,8 +1624,12 @@ bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree,
>   		return false;
>
>   	reply = method->cb(dbus, message, instance->user_data);
> -	if (reply)
> -		l_dbus_send(dbus, reply);
> +	if (reply) {
> +		if (l_dbus_message_get_no_reply(message))
> +			l_dbus_message_unref(reply);
> +		else
> +			l_dbus_send(dbus, reply);
> +	}

Okay, but this doesn't solve the issue for async method returns.  Should 
we save the no_reply flag inside l_dbus_message_new_method_return & 
l_dbus_message_new_error and then take care of this inside l_dbus_send?

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c
  2016-03-14  3:41 ` [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c Andrew Zaborowski
@ 2016-03-14 17:37   ` Denis Kenzior
  2016-03-14 22:25     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 17:37 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 13145 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> This will be used for the public API for adding and removing signal
> callbacks.
> ---
>   Makefile.am        |   1 +
>   ell/dbus-filter.c  | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>   ell/dbus-private.h |  31 +++++
>   ell/dbus.h         |  13 ++
>   4 files changed, 403 insertions(+)
>   create mode 100644 ell/dbus-filter.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 256b163..7283a7e 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -75,6 +75,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
>   			ell/dbus-message.c \
>   			ell/dbus-util.c \
>   			ell/dbus-service.c \
> +			ell/dbus-filter.c \
>   			ell/gvariant-private.h \
>   			ell/gvariant-util.c \
>   			ell/siphash-private.h \
> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
> new file mode 100644
> index 0000000..2541374
> --- /dev/null
> +++ b/ell/dbus-filter.c
> @@ -0,0 +1,358 @@
> +/*
> + *
> + *  Embedded Linux library
> + *
> + *  Copyright (C) 2011-2014  Intel Corporation. All rights reserved.

Please make sure you update the header when copy-pasting the files :)

> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "util.h"
> +#include "queue.h"
> +#include "hashmap.h"
> +#include "string.h"
> +#include "dbus.h"
> +#include "dbus-private.h"
> +#include "gvariant-private.h"
> +#include "private.h"
> +
> +#define NODE_TYPE_CALLBACK	L_DBUS_MATCH_NONE
> +
> +struct filter_node {
> +	enum l_dbus_match_type type;
> +	union {
> +		struct {
> +			char *value;
> +			struct filter_node *children;
> +			bool remote_rule;
> +		} match;
> +		struct {
> +			l_dbus_message_func_t func;
> +			void *user_data;
> +		} callback;
> +	};
> +	unsigned int id;
> +	struct filter_node *next;
> +};
> +
> +struct _dbus_filter {
> +	struct l_dbus *dbus;
> +	struct filter_node *root;
> +	unsigned int signal_id;
> +	unsigned int last_id;
> +	const struct _dbus_filter_ops *driver;
> +};
> +
> +static void filter_subtree_free(struct filter_node *node)
> +{
> +	struct filter_node *child, *next;
> +
> +	if (node->type == NODE_TYPE_CALLBACK) {
> +		l_free(node);
> +		return;
> +	}
> +
> +	next = node->match.children;
> +
> +	l_free(node->match.value);
> +	l_free(node);
> +
> +	while (next) {
> +		child = next;
> +		next = child->next;
> +
> +		filter_subtree_free(child);
> +	}
> +}
> +
> +static void dbus_filter_destroy(void *data)
> +{
> +	struct _dbus_filter *filter = data;
> +
> +	if (filter->root)
> +		filter_subtree_free(filter->root);
> +
> +	l_free(filter);
> +}
> +
> +static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
> +						struct filter_node *node,
> +						struct l_dbus_message *message)
> +{
> +	const char *value = NULL;
> +	struct filter_node *child;
> +
> +	switch ((int) node->type) {
> +	case NODE_TYPE_CALLBACK:
> +		node->callback.func(message, node->callback.user_data);
> +		return;
> +
> +	case L_DBUS_MATCH_SENDER:
> +		value = l_dbus_message_get_sender(message);
> +		break;
> +
> +	case L_DBUS_MATCH_DESTINATION:
> +		value = l_dbus_message_get_destination(message);
> +		break;
> +
> +	case L_DBUS_MATCH_TYPE:
> +		value = _dbus_message_get_type_as_string(message);
> +		break;
> +
> +	case L_DBUS_MATCH_PATH:
> +		value = l_dbus_message_get_path(message);
> +		break;
> +
> +	case L_DBUS_MATCH_INTERFACE:
> +		value = l_dbus_message_get_interface(message);
> +		break;
> +
> +	case L_DBUS_MATCH_MEMBER:
> +		value = l_dbus_message_get_member(message);
> +		break;
> +
> +	case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
> +		value = _dbus_message_get_nth_string_argument(message,
> +						node->type - L_DBUS_MATCH_ARG0);
> +		break;
> +	}
> +
> +	if (!value)
> +		return;
> +
> +	if (strcmp(value, node->match.value))
> +		return;
> +
> +	for (child = node->match.children; child; child = child->next)
> +		filter_dispatch_match_recurse(filter, child, message);
> +}
> +
> +void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
> +{
> +	struct _dbus_filter *filter = user_data;
> +
> +	filter_dispatch_match_recurse(filter, filter->root, message);
> +}
> +
> +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
> +					const struct _dbus_filter_ops *driver)
> +{
> +	struct _dbus_filter *filter;
> +
> +	filter = l_new(struct _dbus_filter, 1);
> +
> +	filter->dbus = dbus;
> +	filter->driver = driver;
> +
> +	if (!filter->driver->skip_register)
> +		filter->signal_id = l_dbus_register(dbus, _dbus_filter_dispatch,
> +							filter,
> +							dbus_filter_destroy);
> +
> +	return filter;
> +}
> +
> +void _dbus_filter_free(struct _dbus_filter *filter)
> +{
> +	if (!filter)
> +		return;
> +
> +	if (!filter->driver->skip_register)
> +		l_dbus_unregister(filter->dbus, filter->signal_id);
> +	else
> +		dbus_filter_destroy(filter);
> +}
> +
> +static int condition_compare(const void *a, const void *b)
> +{
> +	const struct _dbus_filter_condition *condition_a = a, *condition_b = b;
> +
> +	return condition_a->type - condition_b->type;
> +}
> +
> +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
> +					struct _dbus_filter_condition *rule,
> +					int rule_len,
> +					l_dbus_message_func_t signal_func,
> +					void *user_data)
> +{
> +	struct filter_node **node_ptr = &filter->root;
> +	struct filter_node *node;
> +	struct filter_node *parent = filter->root;
> +	bool remote_rule = false;
> +	struct _dbus_filter_condition *condition, *end = rule + rule_len;
> +
> +	qsort(rule, rule_len, sizeof(*rule), condition_compare);
> +
> +	for (condition = rule; condition < end; condition++) {
> +		/* See if this condition is already a child of the node */
> +		while (*node_ptr) {
> +			node = *node_ptr;
> +
> +			if (node->type == condition->type &&
> +					!strcmp(node->match.value,
> +						condition->value))
> +				break;
> +
> +			node_ptr = &node->next;
> +		}
> +
> +		/* Add one */
> +		if (!*node_ptr) {
> +			node = l_new(struct filter_node, 1);
> +			node->type = condition->type;
> +			node->match.value = l_strdup(condition->value);
> +
> +			*node_ptr = node;
> +		}
> +
> +		node_ptr = &node->match.children;
> +
> +		parent = node;
> +
> +		/*
> +		 * Only have to call AddMatch if none of the parent nodes
> +		 * have yet created an AddMatch rule on the server.
> +		 */
> +		remote_rule |= node->match.remote_rule;
> +	}
> +
> +	node = l_new(struct filter_node, 1);
> +	node->type = NODE_TYPE_CALLBACK;
> +	node->callback.func = signal_func;
> +	node->callback.user_data = user_data;
> +	node->id = ++filter->last_id;
> +	node->next = *node_ptr;
> +
> +	if (!remote_rule) {
> +		if (!filter->driver->add_match(filter->dbus, node->id,
> +						rule, rule_len)) {
> +			l_free(node);
> +			return 0;
> +		}
> +
> +		parent->id = node->id;
> +		parent->match.remote_rule = true;
> +	}
> +
> +	*node_ptr = node;
> +
> +	return node->id;
> +}
> +
> +static bool remove_recurse(struct _dbus_filter *filter,
> +				struct filter_node **node, unsigned int id)
> +{
> +	struct filter_node *tmp;
> +
> +	for (; *node; node = &(*node)->next) {
> +		if ((*node)->type == NODE_TYPE_CALLBACK && (*node)->id == id)
> +			break;
> +
> +		if ((*node)->type != NODE_TYPE_CALLBACK &&
> +				remove_recurse(filter, &(*node)->match.children,
> +						id))
> +			break;
> +	}
> +
> +	if (!*node)
> +		return false;
> +
> +	if ((*node)->type == NODE_TYPE_CALLBACK || !(*node)->match.children) {
> +		tmp = *node;
> +		*node = tmp->next;
> +
> +		if (tmp->match.remote_rule)
> +			filter->driver->remove_match(filter->dbus, tmp->id);
> +
> +		filter_subtree_free(tmp);
> +	}
> +
> +	return true;
> +}
> +
> +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id)
> +{
> +	return remove_recurse(filter, &filter->root, id);
> +}
> +
> +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
> +				int rule_len)
> +{
> +	struct l_string *str = l_string_new(63);
> +	char *key, arg_buf[6];
> +	const char *value, *endp;
> +
> +	for (; rule_len; rule++, rule_len--) {
> +		switch ((int) rule->type) {
> +		case L_DBUS_MATCH_SENDER:
> +			key = "sender";
> +			break;
> +		case L_DBUS_MATCH_DESTINATION:
> +			key = "destination";
> +			break;
> +		case L_DBUS_MATCH_TYPE:
> +			key = "type";
> +			break;
> +		case L_DBUS_MATCH_PATH:
> +			key = "path";
> +			break;
> +		case L_DBUS_MATCH_INTERFACE:
> +			key = "interface";
> +			break;
> +		case L_DBUS_MATCH_MEMBER:
> +			key = "member";
> +			break;
> +		case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
> +			key = arg_buf;
> +			snprintf(arg_buf, sizeof(arg_buf), "arg%i",
> +					rule->type - L_DBUS_MATCH_ARG0);
> +			break;
> +		default:
> +			l_string_free(str, true);
> +			return NULL;
> +		}
> +
> +		l_string_append(str, key);
> +		l_string_append(str, "='");
> +
> +		/* We only need to escape single-quotes in the values */
> +		value = rule->value;
> +
> +		while ((endp = strchr(value, '\''))) {
> +			l_string_append_fixed(str, value, endp - value);
> +			l_string_append(str, "'\\''");
> +
> +			value = endp + 1;
> +		}
> +
> +		l_string_append(str, value);
> +		l_string_append_c(str, '\'');
> +
> +		if (rule_len > 1)
> +			l_string_append_c(str, ',');
> +	}
> +
> +	return l_string_free(str, false);
> +}
> diff --git a/ell/dbus-private.h b/ell/dbus-private.h
> index 607fdf4..d4a4782 100644
> --- a/ell/dbus-private.h
> +++ b/ell/dbus-private.h
> @@ -64,6 +64,9 @@ struct _dbus_property;
>   struct l_dbus_message_iter;
>   struct l_dbus_message;
>   struct l_dbus;
> +struct _dbus_filter;
> +struct _dbus_filter_condition;
> +struct _dbus_filter_ops;
>
>   void _dbus1_iter_init(struct l_dbus_message_iter *iter,
>   			struct l_dbus_message *message,
> @@ -241,6 +244,34 @@ uint8_t _dbus_get_version(struct l_dbus *dbus);
>   int _dbus_get_fd(struct l_dbus *dbus);
>   struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus);
>
> +struct _dbus_filter_condition {
> +	enum l_dbus_match_type type;
> +	const char *value;
> +};
> +
> +struct _dbus_filter_ops {
> +	bool skip_register;
> +	bool (*add_match)(struct l_dbus *bus, unsigned int id,
> +				const struct _dbus_filter_condition *rule,
> +				int rule_len);
> +	bool (*remove_match)(struct l_dbus *bus, unsigned int id);
> +};
> +
> +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
> +					const struct _dbus_filter_ops *driver);
> +void _dbus_filter_free(struct _dbus_filter *filter);
> +
> +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
> +					struct _dbus_filter_condition *rule,
> +					int rule_len,
> +					l_dbus_message_func_t signal_func,
> +					void *user_data);
> +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id);
> +
> +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
> +				int rule_len);
> +void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data);
> +
>   struct dbus1_filter_data;
>
>   void _dbus1_filter_format_match(struct dbus1_filter_data *data, char *rule,
> diff --git a/ell/dbus.h b/ell/dbus.h
> index c8fdec1..24527e0 100644
> --- a/ell/dbus.h
> +++ b/ell/dbus.h
> @@ -42,6 +42,19 @@ enum l_dbus_bus {
>   	L_DBUS_SESSION_BUS,
>   };
>
> +enum l_dbus_match_type {
> +	L_DBUS_MATCH_NONE = 0,
> +	L_DBUS_MATCH_TYPE,
> +	L_DBUS_MATCH_SENDER,
> +	L_DBUS_MATCH_DESTINATION,

This is for eavesdropping?  Do we need this?

> +	L_DBUS_MATCH_PATH,
> +	L_DBUS_MATCH_INTERFACE,
> +	L_DBUS_MATCH_MEMBER,
> +	L_DBUS_MATCH_ARG0,
> +};
> +

Can we make this private in some way?

> +#define L_DBUS_MATCH_ARGUMENT(i)	(L_DBUS_MATCH_ARG0 + (i))
> +

It seems that l_dbus_match_type is only exposed for the sake of 
L_DBUS_MATCH_ARGUMENT() and L_DBUS_MATCH_NONE.

>   struct l_dbus;
>   struct l_dbus_interface;
>   struct l_dbus_message_builder;
>

Otherwise, this looks fine to me.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 07/20] dbus-filter: Name owner change tracking support.
  2016-03-14  3:41 ` [PATCH 07/20] dbus-filter: Name owner change tracking support Andrew Zaborowski
@ 2016-03-14 18:03   ` Denis Kenzior
  2016-03-14 22:32     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 18:03 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7439 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> This is needed because incoming message callbacks normally care what
> Well-known Bus Name the message comes from but the sender field of the
> message normally stores unique bus names in classic dbus.  The
> Well-known names may be re-assigned to different unique names while the
> rule is in place.
> ---
>   ell/dbus-filter.c  | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>   ell/dbus-private.h |   5 +++
>   2 files changed, 106 insertions(+), 1 deletion(-)
>
> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
> index 2541374..f2cc023 100644
> --- a/ell/dbus-filter.c
> +++ b/ell/dbus-filter.c
> @@ -62,6 +62,12 @@ struct _dbus_filter {
>   	unsigned int signal_id;
>   	unsigned int last_id;
>   	const struct _dbus_filter_ops *driver;
> +	struct l_hashmap *unique_names;
> +};
> +
> +struct unique_name_record {
> +	int ref_count;
> +	char *unique_name;
>   };
>
>   static void filter_subtree_free(struct filter_node *node)
> @@ -86,6 +92,14 @@ static void filter_subtree_free(struct filter_node *node)
>   	}
>   }
>
> +static void unique_name_record_free(void *data)
> +{
> +	struct unique_name_record *name_rec = data;
> +
> +	l_free(name_rec->unique_name);
> +	l_free(name_rec);
> +}
> +
>   static void dbus_filter_destroy(void *data)
>   {
>   	struct _dbus_filter *filter = data;
> @@ -93,6 +107,10 @@ static void dbus_filter_destroy(void *data)
>   	if (filter->root)
>   		filter_subtree_free(filter->root);
>
> +	if (filter->unique_names)
> +		l_hashmap_destroy(filter->unique_names,
> +					unique_name_record_free);
> +
>   	l_free(filter);
>   }
>
> @@ -101,6 +119,8 @@ static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
>   						struct l_dbus_message *message)
>   {
>   	const char *value = NULL;
> +	const char *alt_value = NULL;
> +	const struct unique_name_record *name_rec;
>   	struct filter_node *child;
>
>   	switch ((int) node->type) {
> @@ -141,7 +161,18 @@ static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
>   	if (!value)
>   		return;
>
> -	if (strcmp(value, node->match.value))
> +	if ((node->type == L_DBUS_MATCH_SENDER ||
> +				node->type == L_DBUS_MATCH_DESTINATION) &&

According to DBus specification, destination matches only match the 
unique name:
"Matches messages which are being sent to the given unique name. An 
example of a destination match is destination=':1.0'"

> +			filter->unique_names) {
> +		name_rec = l_hashmap_lookup(filter->unique_names,
> +						node->match.value);
> +
> +		if (name_rec)
> +			alt_value = name_rec->unique_name;
> +	}
> +
> +	if (strcmp(value, node->match.value) &&
> +			(!alt_value || strcmp(value, alt_value)))
>   		return;
>
>   	for (child = node->match.children; child; child = child->next)
> @@ -155,6 +186,21 @@ void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
>   	filter_dispatch_match_recurse(filter, filter->root, message);
>   }
>
> +void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
> +					const char *name, const char *owner)
> +{
> +	if (_dbus_parse_unique_name(name, NULL))
> +		return;
> +
> +	name_rec = l_hashmap_lookup(filter->unique_names, name);
> +	if (!name_rec)
> +		return;
> +
> +	l_free(name_rec->unique_name);
> +
> +	name_rec->unique_name = (owner && *owner) ? l_strdup(owner) : NULL;
> +}
> +
>   struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
>   					const struct _dbus_filter_ops *driver)
>   {
> @@ -170,6 +216,9 @@ struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
>   							filter,
>   							dbus_filter_destroy);
>
> +	if (filter->driver->track_name_owner_change)

Is this ever going to be false?

> +		filter->unique_names = l_hashmap_string_new();
> +
>   	return filter;
>   }
>
> @@ -184,6 +233,49 @@ void _dbus_filter_free(struct _dbus_filter *filter)
>   		dbus_filter_destroy(filter);
>   }
>
> +static void filter_add_bus_name(struct _dbus_filter *filter, const char *name)
> +{
> +	struct unique_name_record *name_rec;
> +
> +	if (!filter->unique_names)
> +		return;
> +
> +	if (_dbus_parse_unique_name(name, NULL))
> +		return;

Do you need to add a check for valid_bus_name?

Should this function return something?

> +
> +	name_rec = l_hashmap_lookup(filter->unique_names, name);
> +	if (!name_rec) {
> +		name_rec = l_new(struct unique_name_record, 1);
> +
> +		l_hashmap_insert(filter->unique_names, name, name_rec);
> +
> +		filter->driver->get_name_owner(filter->dbus, name);
> +	}
> +
> +	name_rec->ref_count++;
> +}
> +
> +static void filter_remove_bus_name(struct _dbus_filter *filter,
> +					const char *name)
> +{
> +	struct unique_name_record *name_rec;
> +
> +	if (!filter->unique_names)
> +		return;
> +
> +	if (_dbus_parse_unique_name(name, NULL))
> +		return;
> +
> +	name_rec = l_hashmap_lookup(filter->unique_names, name);
> +
> +	if (--name_rec->ref_count)
> +		return;
> +
> +	l_hashmap_remove(filter->unique_names, name);
> +
> +	unique_name_record_free(name_rec);
> +}
> +
>   static int condition_compare(const void *a, const void *b)
>   {
>   	const struct _dbus_filter_condition *condition_a = a, *condition_b = b;
> @@ -225,6 +317,10 @@ unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
>   			node->match.value = l_strdup(condition->value);
>
>   			*node_ptr = node;
> +
> +			if (node->type == L_DBUS_MATCH_SENDER ||
> +					node->type == L_DBUS_MATCH_DESTINATION)
> +				filter_add_bus_name(filter, node->match.value);

As mentioned before, L_DBUS_MATCH_DESTINATION does not seem to be 
relevant here.

>   		}
>
>   		node_ptr = &node->match.children;
> @@ -286,6 +382,10 @@ static bool remove_recurse(struct _dbus_filter *filter,
>   		if (tmp->match.remote_rule)
>   			filter->driver->remove_match(filter->dbus, tmp->id);
>
> +		if (tmp->type == L_DBUS_MATCH_SENDER ||
> +				tmp->type == L_DBUS_MATCH_DESTINATION)
> +			filter_remove_bus_name(filter, tmp->match.value);
> +
>   		filter_subtree_free(tmp);
>   	}
>
> diff --git a/ell/dbus-private.h b/ell/dbus-private.h
> index d4a4782..de4e706 100644
> --- a/ell/dbus-private.h
> +++ b/ell/dbus-private.h
> @@ -250,11 +250,13 @@ struct _dbus_filter_condition {
>   };
>
>   struct _dbus_filter_ops {
> +	bool track_name_owner_change;

Do we really need this? I think we can safely assume that this is true 
if get_name_owner implementation is provided.

>   	bool skip_register;
>   	bool (*add_match)(struct l_dbus *bus, unsigned int id,
>   				const struct _dbus_filter_condition *rule,
>   				int rule_len);
>   	bool (*remove_match)(struct l_dbus *bus, unsigned int id);
> +	bool (*get_name_owner)(struct l_dbus *bus, const char *name);
>   };
>
>   struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
> @@ -270,7 +272,10 @@ bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id);
>
>   char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
>   				int rule_len);
> +
>   void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data);
> +void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
> +					const char *name, const char *owner);
>
>   struct dbus1_filter_data;
>
>

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/20] dbus: Classic dbus filter_ops implementation.
  2016-03-14  3:41 ` [PATCH 08/20] dbus: Classic dbus filter_ops implementation Andrew Zaborowski
@ 2016-03-14 18:18   ` Denis Kenzior
  2016-03-14 22:36     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 18:18 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7163 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> For the name owner tracking I decided to subscribe to all name
> owner changes instead of adding separate rules for every name because
> in some scenarios that saves us cycles/memory and we don't have
> to hold a list of IDs of every such rule so that we could remove them
> when no longer needed.
> ---
>   ell/dbus-filter.c |   5 +++
>   ell/dbus.c        | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 137 insertions(+)
>
> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
> index f2cc023..47f2a0b 100644
> --- a/ell/dbus-filter.c
> +++ b/ell/dbus-filter.c
> @@ -189,6 +189,11 @@ void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data)
>   void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
>   					const char *name, const char *owner)
>   {
> +	struct unique_name_record *name_rec;
> +
> +	if (!filter)
> +		return;
> +
>   	if (_dbus_parse_unique_name(name, NULL))
>   		return;

Does this belong in a different patch?

>
> diff --git a/ell/dbus.c b/ell/dbus.c
> index 2ac9e58..e9d3424 100644
> --- a/ell/dbus.c
> +++ b/ell/dbus.c
> @@ -63,6 +63,7 @@ struct l_dbus_ops {
>   				struct l_dbus_message *message);
>   	struct l_dbus_message *(*recv_message)(struct l_dbus *bus);
>   	void (*free)(struct l_dbus *bus);
> +	struct _dbus_filter_ops filter_ops;
>   };
>
>   struct l_dbus {
> @@ -87,6 +88,7 @@ struct l_dbus {
>   	l_dbus_destroy_func_t debug_destroy;
>   	void *debug_data;
>   	struct _dbus_object_tree *tree;
> +	struct _dbus_filter *filter;
>
>   	const struct l_dbus_ops *driver;
>   };
> @@ -103,6 +105,7 @@ struct l_dbus_classic {
>   	struct l_dbus super;
>   	void *auth_command;
>   	enum auth_state auth_state;
> +	struct l_hashmap *match_strings;
>   };
>
>   struct message_callback {
> @@ -553,6 +556,7 @@ static void classic_free(struct l_dbus *dbus)
>   		container_of(dbus, struct l_dbus_classic, super);
>
>   	l_free(classic->auth_command);
> +	l_hashmap_destroy(classic->match_strings, l_free);
>   	l_free(classic);
>   }
>
> @@ -664,13 +668,129 @@ cmsg_fail:
>   	return NULL;
>   }
>
> +static bool classic_add_match(struct l_dbus *dbus, unsigned int id,
> +				const struct _dbus_filter_condition *rule,
> +				int rule_len)
> +{
> +	struct l_dbus_classic *classic =
> +		container_of(dbus, struct l_dbus_classic, super);
> +	char *match_str;
> +	struct l_dbus_message *message;
> +
> +	match_str = _dbus_filter_rule_to_str(rule, rule_len);
> +
> +	l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id), match_str);
> +
> +	message = l_dbus_message_new_method_call(dbus,
> +						DBUS_SERVICE_DBUS,
> +						DBUS_PATH_DBUS,
> +						L_DBUS_INTERFACE_DBUS,
> +						"AddMatch");
> +
> +	l_dbus_message_set_arguments(message, "s", match_str);
> +
> +	send_message(dbus, false, message, NULL, NULL, NULL);
> +
> +	return true;
> +}
> +
> +static bool classic_remove_match(struct l_dbus *dbus, unsigned int id)
> +{
> +	struct l_dbus_classic *classic =
> +		container_of(dbus, struct l_dbus_classic, super);
> +	char *match_str = l_hashmap_remove(classic->match_strings,
> +						L_UINT_TO_PTR(id));
> +	struct l_dbus_message *message;
> +
> +	if (!match_str)
> +		return false;
> +
> +	message = l_dbus_message_new_method_call(dbus,
> +						DBUS_SERVICE_DBUS,
> +						DBUS_PATH_DBUS,
> +						L_DBUS_INTERFACE_DBUS,
> +						"RemoveMatch");
> +
> +	l_dbus_message_set_arguments(message, "s", match_str);
> +
> +	send_message(dbus, false, message, NULL, NULL, NULL);
> +
> +	l_free(match_str);
> +
> +	return true;
> +}
> +
> +struct get_name_owner_request {
> +	struct l_dbus_message *message;
> +	struct l_dbus *dbus;
> +};
> +
> +static void get_name_owner_reply_cb(struct l_dbus_message *reply,
> +					void *user_data)
> +{
> +	struct get_name_owner_request *req = user_data;
> +	const char *name, *owner;
> +
> +	/* No name owner yet */
> +	if (l_dbus_message_is_error(reply))
> +		return;
> +
> +	/* Shouldn't happen */
> +	if (!l_dbus_message_get_arguments(reply, "s", &owner))
> +		return;
> +
> +	/* Shouldn't happen */
> +	if (!l_dbus_message_get_arguments(req->message, "s", &name))
> +		return;
> +
> +	_dbus_filter_name_owner_notify(req->dbus->filter, name, owner);
> +}
> +
> +static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
> +{
> +	struct get_name_owner_request *req;
> +
> +	req = l_new(struct get_name_owner_request, 1);
> +	req->dbus = bus;
> +	req->message = l_dbus_message_new_method_call(bus,
> +							DBUS_SERVICE_DBUS,
> +							DBUS_PATH_DBUS,
> +							L_DBUS_INTERFACE_DBUS,
> +							"GetNameOwner");
> +
> +	l_dbus_message_set_arguments(req->message, "s", name);
> +
> +	send_message(bus, false, req->message, get_name_owner_reply_cb,
> +			req, l_free);
> +
> +	return true;
> +}
> +
>   static const struct l_dbus_ops classic_ops = {
>   	.version = 1,
>   	.send_message = classic_send_message,
>   	.recv_message = classic_recv_message,
>   	.free = classic_free,
> +	.filter_ops = {
> +		.track_name_owner_change = true,
> +		.add_match = classic_add_match,
> +		.remove_match = classic_remove_match,
> +		.get_name_owner = classic_get_name_owner,
> +	},
>   };
>
> +static void name_owner_changed_cb(struct l_dbus_message *message,
> +					void *user_data)
> +{
> +	struct l_dbus *dbus = user_data;
> +	char *name, *old, *new;
> +
> +	if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new))
> +		return;
> +
> +	_dbus_filter_name_owner_notify(dbus->filter, name, new);
> +}
> +
>   static struct l_dbus *setup_dbus1(int fd, const char *guid)
>   {
>   	static const unsigned char creds = 0x00;
> @@ -680,6 +800,13 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
>   	ssize_t written;
>   	unsigned int i;
>   	long flags;
> +	static struct _dbus_filter_condition rule[] = {
> +		{ L_DBUS_MATCH_TYPE,		"signal" },
> +		{ L_DBUS_MATCH_SENDER,		DBUS_SERVICE_DBUS },
> +		{ L_DBUS_MATCH_PATH,		DBUS_PATH_DBUS },
> +		{ L_DBUS_MATCH_INTERFACE,	L_DBUS_INTERFACE_DBUS },
> +		{ L_DBUS_MATCH_MEMBER,		"NameOwnerChanged" },
> +	};
>
>   	if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) {
>   		close(fd);
> @@ -714,6 +841,8 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
>   	dbus = &classic->super;
>   	dbus->driver = &classic_ops;
>
> +	classic->match_strings = l_hashmap_new();
> +
>   	dbus_init(dbus, fd);
>   	dbus->guid = l_strdup(guid);
>
> @@ -726,6 +855,9 @@ static struct l_dbus *setup_dbus1(int fd, const char *guid)
>   	l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL);
>   	l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL);
>
> +	_dbus_filter_add_rule(dbus->filter, rule, L_ARRAY_SIZE(rule),
> +				name_owner_changed_cb, dbus);
> +

Do we need to treat DBUS_SERVICE_DBUS conditions specially since this 
one is not subject to unique name resolution?

>   	return dbus;
>   }
>
>

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 16/20] dbus: Remove now unused filter functions.
  2016-03-14  3:41 ` [PATCH 16/20] dbus: Remove now unused filter functions Andrew Zaborowski
@ 2016-03-14 19:12   ` Denis Kenzior
  0 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 19:12 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 293 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> ---
>   ell/dbus.c | 51 ---------------------------------------------------
>   1 file changed, 51 deletions(-)
>

Do we also want to remove struct dbus1_filter_data and also the various 
unit tests?

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API.
  2016-03-14  3:41 ` [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API Andrew Zaborowski
@ 2016-03-14 19:18   ` Denis Kenzior
  2016-03-14 22:39     ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-14 19:18 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4534 bytes --]

Hi Andrew,

On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
> ---
>   ell/dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   ell/dbus.h |  5 ++++
>   2 files changed, 94 insertions(+)

I'd reflow this patch and one preceding it like this:

1. kdbus name_acquire variant
2. dbus1 name acquire variant
3. public API + driver method definitions

>
> diff --git a/ell/dbus.c b/ell/dbus.c
> index c5cc1fc..6c267ae 100644
> --- a/ell/dbus.c
> +++ b/ell/dbus.c
> @@ -822,6 +822,84 @@ static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
>   	return true;
>   }
>
> +struct name_request {
> +	l_dbus_name_acquire_func_t callback;
> +	void *user_data;
> +	struct l_dbus *dbus;
> +};
> +
> +enum dbus_name_flag {
> +	DBUS_NAME_FLAG_ALLOW_REPLACEMENT	= 0x1,
> +	DBUS_NAME_FLAG_REPLACE_EXISTING		= 0x2,
> +	DBUS_NAME_FLAG_DO_NOT_QUEUE		= 0x4,
> +};
> +
> +enum dbus_name_reply {
> +	DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER	= 1,
> +	DBUS_REQUEST_NAME_REPLY_IN_QUEUE	= 2,
> +	DBUS_REQUEST_NAME_REPLY_EXISTS		= 3,
> +	DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER	= 4,
> +};
> +
> +static void request_name_reply_cb(struct l_dbus_message *reply, void *user_data)
> +{
> +	struct name_request *req = user_data;
> +	bool success = false, queued = false;
> +	uint32_t retval;
> +
> +	if (!req->callback)
> +		return;
> +
> +	/* No name owner yet */
> +	if (l_dbus_message_is_error(reply))
> +		goto call_back;
> +
> +	/* Shouldn't happen */
> +	if (!l_dbus_message_get_arguments(reply, "u", &retval))
> +		goto call_back;
> +
> +	success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) ||
> +		(retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) ||
> +		(retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
> +	queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
> +
> +call_back:
> +	req->callback(req->dbus, success, queued, req->user_data);
> +}
> +
> +static uint32_t classic_name_acquire(struct l_dbus *dbus, const char *name,
> +					bool allow_replacement,
> +					bool replace_existing, bool queue,
> +					l_dbus_name_acquire_func_t callback,
> +					void *user_data)
> +{
> +	struct name_request *req;
> +	struct l_dbus_message *message;
> +	uint32_t flags = 0;
> +
> +	req = l_new(struct name_request, 1);
> +	req->dbus = dbus;
> +	req->user_data = user_data;
> +	req->callback = callback;
> +
> +	message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS,
> +							DBUS_PATH_DBUS,
> +							L_DBUS_INTERFACE_DBUS,
> +							"RequestName");
> +
> +	if (allow_replacement)
> +		flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
> +	if (replace_existing)
> +		flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
> +	if (!queue)
> +		flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
> +
> +	l_dbus_message_set_arguments(message, "su", name, flags);
> +
> +	return send_message(dbus, false, message, request_name_reply_cb,
> +				req, free);
> +}
> +
>   static const struct l_dbus_ops classic_ops = {
>   	.version = 1,
>   	.send_message = classic_send_message,
> @@ -833,6 +911,7 @@ static const struct l_dbus_ops classic_ops = {
>   		.remove_match = classic_remove_match,
>   		.get_name_owner = classic_get_name_owner,
>   	},
> +	.name_acquire = classic_name_acquire,
>   };
>
>   static void name_owner_changed_cb(struct l_dbus_message *message,
> @@ -2048,3 +2127,13 @@ LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id)
>   {
>   	return _dbus_filter_remove_rule(dbus->filter, id);
>   }
> +
> +LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
> +				bool allow_replacement, bool replace_existing,
> +				bool queue, l_dbus_name_acquire_func_t callback,
> +				void *user_data)
> +{
> +	return dbus->driver->name_acquire(dbus, name, allow_replacement,
> +						replace_existing, queue,
> +						callback, user_data);
> +}
> diff --git a/ell/dbus.h b/ell/dbus.h
> index 0b82899..f4b2527 100644
> --- a/ell/dbus.h
> +++ b/ell/dbus.h
> @@ -256,6 +256,11 @@ unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus,
>   					const char *member, ...);
>   bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id);
>
> +uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
> +				bool allow_replacement, bool replace_existing,
> +				bool queue, l_dbus_name_acquire_func_t callback,
> +				void *user_data);
> +

What's the uint32_t return for?

>   #ifdef __cplusplus
>   }
>   #endif
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-14 16:49   ` Denis Kenzior
@ 2016-03-14 22:11     ` Andrzej Zaborowski
  2016-03-15 16:27       ` Denis Kenzior
  0 siblings, 1 reply; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:11 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4360 bytes --]

 Hi Denis,

On 14 March 2016 at 17:49, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> It seems that l_dbus_message_iter_get_type can't be used to get the
>> value of a single argument and be called repeatedly, it might crash if
>
>
> Looking at l_dbus_message_iter_get_type, it just returns
> iter->sig_start[iter->sig_pos].  Is there something deeper going on here
> that is not readily apparent?

Sorry, l_dbus_message_iter_get_type is a typo, I wanted to say
message_iter_next_entry here.  This function calls it with a fixed
number of parameters and sooner or later it will receive a message
with more arguments and by my reading will segfault.

>
>> the number and types of call arguments don't match the message arguments.
>> Also try to support the string arguments that come after non-string
>> arguments in the bloom filter.
>
>
> From my reading of systemd code, I didn't think this was possible.  But I
> could be wrong...

I see no problem with the bloom filter containing, say, arg3="hello",
even though arguments 1 and 2 are integers.  I don't know if systemd
supports that but if for example a client adds a match with this kind
of filter, the service must also support that or the signal won't pass
through the filter.

>
>
>> ---
>>   ell/dbus-message.c | 38 ++++++++++++++++++++++++++++----------
>>   1 file changed, 28 insertions(+), 10 deletions(-)
>>
>> diff --git a/ell/dbus-message.c b/ell/dbus-message.c
>> index f223c70..a123a8a 100644
>> --- a/ell/dbus-message.c
>> +++ b/ell/dbus-message.c
>> @@ -1412,9 +1412,12 @@ bool _dbus_kernel_calculate_bloom(struct
>> l_dbus_message *message,
>>         const char *signature;
>>         void *body;
>>         size_t body_size;
>> -       struct l_dbus_message_iter iter;
>> +       struct l_dbus_message_iter iter, tmp;
>>         uint8_t argn;
>>         char buf[256];
>> +       bool (*skip_entry)(struct l_dbus_message_iter *);
>> +       bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
>> +       char type;
>>
>>         /* The string "interface:" suffixed by the interface name */
>>         attr = l_dbus_message_get_interface(message);
>> @@ -1458,17 +1461,32 @@ bool _dbus_kernel_calculate_bloom(struct
>> l_dbus_message *message,
>>
>>         body = _dbus_message_get_body(message, &body_size);
>>
>> -       if (_dbus_message_is_gvariant(message))
>> -               _gvariant_iter_init(&iter, message, signature, NULL,
>> -                                       body, body_size);
>> -       else
>> +       if (_dbus_message_is_gvariant(message)) {
>> +               if (!_gvariant_iter_init(&iter, message, signature, NULL,
>> +                                               body, body_size))
>> +                       return false;
>> +
>> +               skip_entry = _gvariant_iter_skip_entry;
>> +               get_basic = _gvariant_iter_next_entry_basic;
>> +       } else {
>>                 _dbus1_iter_init(&iter, message, signature, NULL,
>> -                               body, body_size);
>> +                                       body, body_size);
>> +
>> +               skip_entry = _dbus1_iter_skip_entry;
>> +               get_basic = _dbus1_iter_next_entry_basic;
>> +       }
>>
>>         argn = 0;
>>
>> -       while (*signature == 's' || *signature == 'o' || *signature ==
>> 'g') {
>> -               if (!message_iter_next_entry(&iter, &attr))
>> +       do {
>> +               type = l_dbus_message_iter_get_type(&iter);
>> +               if (!strchr("sog", type))
>> +                       goto next;
>> +
>> +               /* Don't let get_basic move iter->pos without moving
>> sig_pos */
>> +               memcpy(&tmp, &iter, sizeof(tmp));
>> +
>> +               if (!get_basic(&tmp, type, &attr))
>>                         return false;
>
>
> Is this to avoid double skipping this entry?  Can we find a less hacky way
> to do this?  Perhaps peek_basic, or restructure the loop in some way?

The problem is that get_basic moves the data position (iter->pos) but
doesn't move the iter->sig_pos, as fas as I can see.  Maybe instead we
should just do iter->sig_pos += 1, similarly to what
message_iter_next_entry_valist does?

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 14/20] dbus: Don't send replies to messages with no reply flag.
  2016-03-14 17:11   ` Denis Kenzior
@ 2016-03-14 22:15     ` Andrzej Zaborowski
  2016-03-15 16:35       ` Denis Kenzior
  0 siblings, 1 reply; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:15 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1694 bytes --]

Hi Denis,

On 14 March 2016 at 18:11, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> Kdbus doesn't store the cookies for messages that have the no reply flag
>> and throws error when a reply is sent with reply_cookie that it doesn't
>> know.  It's not fatal, but we also save some cycles by not sending the
>> message.  A further change could be made to not even let users create a
>> message as a return from a method call but that may be confusing.
>> ---
>>   ell/dbus-service.c | 8 ++++++--
>>   1 file changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/ell/dbus-service.c b/ell/dbus-service.c
>> index b4e0b60..c1ed9ec 100644
>> --- a/ell/dbus-service.c
>> +++ b/ell/dbus-service.c
>> @@ -1624,8 +1624,12 @@ bool _dbus_object_tree_dispatch(struct
>> _dbus_object_tree *tree,
>>                 return false;
>>
>>         reply = method->cb(dbus, message, instance->user_data);
>> -       if (reply)
>> -               l_dbus_send(dbus, reply);
>> +       if (reply) {
>> +               if (l_dbus_message_get_no_reply(message))
>> +                       l_dbus_message_unref(reply);
>> +               else
>> +                       l_dbus_send(dbus, reply);
>> +       }
>
>
> Okay, but this doesn't solve the issue for async method returns.
>

True, I forgot about that.

> Should we
> save the no_reply flag inside l_dbus_message_new_method_return &
> l_dbus_message_new_error and then take care of this inside l_dbus_send?

I was thinking of modifying l_dbus_message_new_method_return to set
message->destination to NULL or returning an error.

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c
  2016-03-14 17:37   ` Denis Kenzior
@ 2016-03-14 22:25     ` Andrzej Zaborowski
  0 siblings, 0 replies; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:25 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 17446 bytes --]

Hi Denis,

On 14 March 2016 at 18:37, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> This will be used for the public API for adding and removing signal
>> callbacks.
>> ---
>>   Makefile.am        |   1 +
>>   ell/dbus-filter.c  | 358
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   ell/dbus-private.h |  31 +++++
>>   ell/dbus.h         |  13 ++
>>   4 files changed, 403 insertions(+)
>>   create mode 100644 ell/dbus-filter.c
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 256b163..7283a7e 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -75,6 +75,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
>>                         ell/dbus-message.c \
>>                         ell/dbus-util.c \
>>                         ell/dbus-service.c \
>> +                       ell/dbus-filter.c \
>>                         ell/gvariant-private.h \
>>                         ell/gvariant-util.c \
>>                         ell/siphash-private.h \
>> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
>> new file mode 100644
>> index 0000000..2541374
>> --- /dev/null
>> +++ b/ell/dbus-filter.c
>> @@ -0,0 +1,358 @@
>> +/*
>> + *
>> + *  Embedded Linux library
>> + *
>> + *  Copyright (C) 2011-2014  Intel Corporation. All rights reserved.
>
>
> Please make sure you update the header when copy-pasting the files :)

Good point..

>
>
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
>> USA
>> + *
>> + */
>> +
>> +#ifdef HAVE_CONFIG_H
>> +#include <config.h>
>> +#endif
>> +
>> +#define _GNU_SOURCE
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +
>> +#include "util.h"
>> +#include "queue.h"
>> +#include "hashmap.h"
>> +#include "string.h"
>> +#include "dbus.h"
>> +#include "dbus-private.h"
>> +#include "gvariant-private.h"
>> +#include "private.h"
>> +
>> +#define NODE_TYPE_CALLBACK     L_DBUS_MATCH_NONE
>> +
>> +struct filter_node {
>> +       enum l_dbus_match_type type;
>> +       union {
>> +               struct {
>> +                       char *value;
>> +                       struct filter_node *children;
>> +                       bool remote_rule;
>> +               } match;
>> +               struct {
>> +                       l_dbus_message_func_t func;
>> +                       void *user_data;
>> +               } callback;
>> +       };
>> +       unsigned int id;
>> +       struct filter_node *next;
>> +};
>> +
>> +struct _dbus_filter {
>> +       struct l_dbus *dbus;
>> +       struct filter_node *root;
>> +       unsigned int signal_id;
>> +       unsigned int last_id;
>> +       const struct _dbus_filter_ops *driver;
>> +};
>> +
>> +static void filter_subtree_free(struct filter_node *node)
>> +{
>> +       struct filter_node *child, *next;
>> +
>> +       if (node->type == NODE_TYPE_CALLBACK) {
>> +               l_free(node);
>> +               return;
>> +       }
>> +
>> +       next = node->match.children;
>> +
>> +       l_free(node->match.value);
>> +       l_free(node);
>> +
>> +       while (next) {
>> +               child = next;
>> +               next = child->next;
>> +
>> +               filter_subtree_free(child);
>> +       }
>> +}
>> +
>> +static void dbus_filter_destroy(void *data)
>> +{
>> +       struct _dbus_filter *filter = data;
>> +
>> +       if (filter->root)
>> +               filter_subtree_free(filter->root);
>> +
>> +       l_free(filter);
>> +}
>> +
>> +static void filter_dispatch_match_recurse(struct _dbus_filter *filter,
>> +                                               struct filter_node *node,
>> +                                               struct l_dbus_message
>> *message)
>> +{
>> +       const char *value = NULL;
>> +       struct filter_node *child;
>> +
>> +       switch ((int) node->type) {
>> +       case NODE_TYPE_CALLBACK:
>> +               node->callback.func(message, node->callback.user_data);
>> +               return;
>> +
>> +       case L_DBUS_MATCH_SENDER:
>> +               value = l_dbus_message_get_sender(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_DESTINATION:
>> +               value = l_dbus_message_get_destination(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_TYPE:
>> +               value = _dbus_message_get_type_as_string(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_PATH:
>> +               value = l_dbus_message_get_path(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_INTERFACE:
>> +               value = l_dbus_message_get_interface(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_MEMBER:
>> +               value = l_dbus_message_get_member(message);
>> +               break;
>> +
>> +       case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
>> +               value = _dbus_message_get_nth_string_argument(message,
>> +                                               node->type -
>> L_DBUS_MATCH_ARG0);
>> +               break;
>> +       }
>> +
>> +       if (!value)
>> +               return;
>> +
>> +       if (strcmp(value, node->match.value))
>> +               return;
>> +
>> +       for (child = node->match.children; child; child = child->next)
>> +               filter_dispatch_match_recurse(filter, child, message);
>> +}
>> +
>> +void _dbus_filter_dispatch(struct l_dbus_message *message, void
>> *user_data)
>> +{
>> +       struct _dbus_filter *filter = user_data;
>> +
>> +       filter_dispatch_match_recurse(filter, filter->root, message);
>> +}
>> +
>> +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
>> +                                       const struct _dbus_filter_ops
>> *driver)
>> +{
>> +       struct _dbus_filter *filter;
>> +
>> +       filter = l_new(struct _dbus_filter, 1);
>> +
>> +       filter->dbus = dbus;
>> +       filter->driver = driver;
>> +
>> +       if (!filter->driver->skip_register)
>> +               filter->signal_id = l_dbus_register(dbus,
>> _dbus_filter_dispatch,
>> +                                                       filter,
>> +
>> dbus_filter_destroy);
>> +
>> +       return filter;
>> +}
>> +
>> +void _dbus_filter_free(struct _dbus_filter *filter)
>> +{
>> +       if (!filter)
>> +               return;
>> +
>> +       if (!filter->driver->skip_register)
>> +               l_dbus_unregister(filter->dbus, filter->signal_id);
>> +       else
>> +               dbus_filter_destroy(filter);
>> +}
>> +
>> +static int condition_compare(const void *a, const void *b)
>> +{
>> +       const struct _dbus_filter_condition *condition_a = a, *condition_b
>> = b;
>> +
>> +       return condition_a->type - condition_b->type;
>> +}
>> +
>> +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
>> +                                       struct _dbus_filter_condition
>> *rule,
>> +                                       int rule_len,
>> +                                       l_dbus_message_func_t signal_func,
>> +                                       void *user_data)
>> +{
>> +       struct filter_node **node_ptr = &filter->root;
>> +       struct filter_node *node;
>> +       struct filter_node *parent = filter->root;
>> +       bool remote_rule = false;
>> +       struct _dbus_filter_condition *condition, *end = rule + rule_len;
>> +
>> +       qsort(rule, rule_len, sizeof(*rule), condition_compare);
>> +
>> +       for (condition = rule; condition < end; condition++) {
>> +               /* See if this condition is already a child of the node */
>> +               while (*node_ptr) {
>> +                       node = *node_ptr;
>> +
>> +                       if (node->type == condition->type &&
>> +                                       !strcmp(node->match.value,
>> +                                               condition->value))
>> +                               break;
>> +
>> +                       node_ptr = &node->next;
>> +               }
>> +
>> +               /* Add one */
>> +               if (!*node_ptr) {
>> +                       node = l_new(struct filter_node, 1);
>> +                       node->type = condition->type;
>> +                       node->match.value = l_strdup(condition->value);
>> +
>> +                       *node_ptr = node;
>> +               }
>> +
>> +               node_ptr = &node->match.children;
>> +
>> +               parent = node;
>> +
>> +               /*
>> +                * Only have to call AddMatch if none of the parent nodes
>> +                * have yet created an AddMatch rule on the server.
>> +                */
>> +               remote_rule |= node->match.remote_rule;
>> +       }
>> +
>> +       node = l_new(struct filter_node, 1);
>> +       node->type = NODE_TYPE_CALLBACK;
>> +       node->callback.func = signal_func;
>> +       node->callback.user_data = user_data;
>> +       node->id = ++filter->last_id;
>> +       node->next = *node_ptr;
>> +
>> +       if (!remote_rule) {
>> +               if (!filter->driver->add_match(filter->dbus, node->id,
>> +                                               rule, rule_len)) {
>> +                       l_free(node);
>> +                       return 0;
>> +               }
>> +
>> +               parent->id = node->id;
>> +               parent->match.remote_rule = true;
>> +       }
>> +
>> +       *node_ptr = node;
>> +
>> +       return node->id;
>> +}
>> +
>> +static bool remove_recurse(struct _dbus_filter *filter,
>> +                               struct filter_node **node, unsigned int
>> id)
>> +{
>> +       struct filter_node *tmp;
>> +
>> +       for (; *node; node = &(*node)->next) {
>> +               if ((*node)->type == NODE_TYPE_CALLBACK && (*node)->id ==
>> id)
>> +                       break;
>> +
>> +               if ((*node)->type != NODE_TYPE_CALLBACK &&
>> +                               remove_recurse(filter,
>> &(*node)->match.children,
>> +                                               id))
>> +                       break;
>> +       }
>> +
>> +       if (!*node)
>> +               return false;
>> +
>> +       if ((*node)->type == NODE_TYPE_CALLBACK ||
>> !(*node)->match.children) {
>> +               tmp = *node;
>> +               *node = tmp->next;
>> +
>> +               if (tmp->match.remote_rule)
>> +                       filter->driver->remove_match(filter->dbus,
>> tmp->id);
>> +
>> +               filter_subtree_free(tmp);
>> +       }
>> +
>> +       return true;
>> +}
>> +
>> +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int
>> id)
>> +{
>> +       return remove_recurse(filter, &filter->root, id);
>> +}
>> +
>> +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
>> +                               int rule_len)
>> +{
>> +       struct l_string *str = l_string_new(63);
>> +       char *key, arg_buf[6];
>> +       const char *value, *endp;
>> +
>> +       for (; rule_len; rule++, rule_len--) {
>> +               switch ((int) rule->type) {
>> +               case L_DBUS_MATCH_SENDER:
>> +                       key = "sender";
>> +                       break;
>> +               case L_DBUS_MATCH_DESTINATION:
>> +                       key = "destination";
>> +                       break;
>> +               case L_DBUS_MATCH_TYPE:
>> +                       key = "type";
>> +                       break;
>> +               case L_DBUS_MATCH_PATH:
>> +                       key = "path";
>> +                       break;
>> +               case L_DBUS_MATCH_INTERFACE:
>> +                       key = "interface";
>> +                       break;
>> +               case L_DBUS_MATCH_MEMBER:
>> +                       key = "member";
>> +                       break;
>> +               case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63):
>> +                       key = arg_buf;
>> +                       snprintf(arg_buf, sizeof(arg_buf), "arg%i",
>> +                                       rule->type - L_DBUS_MATCH_ARG0);
>> +                       break;
>> +               default:
>> +                       l_string_free(str, true);
>> +                       return NULL;
>> +               }
>> +
>> +               l_string_append(str, key);
>> +               l_string_append(str, "='");
>> +
>> +               /* We only need to escape single-quotes in the values */
>> +               value = rule->value;
>> +
>> +               while ((endp = strchr(value, '\''))) {
>> +                       l_string_append_fixed(str, value, endp - value);
>> +                       l_string_append(str, "'\\''");
>> +
>> +                       value = endp + 1;
>> +               }
>> +
>> +               l_string_append(str, value);
>> +               l_string_append_c(str, '\'');
>> +
>> +               if (rule_len > 1)
>> +                       l_string_append_c(str, ',');
>> +       }
>> +
>> +       return l_string_free(str, false);
>> +}
>> diff --git a/ell/dbus-private.h b/ell/dbus-private.h
>> index 607fdf4..d4a4782 100644
>> --- a/ell/dbus-private.h
>> +++ b/ell/dbus-private.h
>> @@ -64,6 +64,9 @@ struct _dbus_property;
>>   struct l_dbus_message_iter;
>>   struct l_dbus_message;
>>   struct l_dbus;
>> +struct _dbus_filter;
>> +struct _dbus_filter_condition;
>> +struct _dbus_filter_ops;
>>
>>   void _dbus1_iter_init(struct l_dbus_message_iter *iter,
>>                         struct l_dbus_message *message,
>> @@ -241,6 +244,34 @@ uint8_t _dbus_get_version(struct l_dbus *dbus);
>>   int _dbus_get_fd(struct l_dbus *dbus);
>>   struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus);
>>
>> +struct _dbus_filter_condition {
>> +       enum l_dbus_match_type type;
>> +       const char *value;
>> +};
>> +
>> +struct _dbus_filter_ops {
>> +       bool skip_register;
>> +       bool (*add_match)(struct l_dbus *bus, unsigned int id,
>> +                               const struct _dbus_filter_condition *rule,
>> +                               int rule_len);
>> +       bool (*remove_match)(struct l_dbus *bus, unsigned int id);
>> +};
>> +
>> +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
>> +                                       const struct _dbus_filter_ops
>> *driver);
>> +void _dbus_filter_free(struct _dbus_filter *filter);
>> +
>> +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
>> +                                       struct _dbus_filter_condition
>> *rule,
>> +                                       int rule_len,
>> +                                       l_dbus_message_func_t signal_func,
>> +                                       void *user_data);
>> +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int
>> id);
>> +
>> +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
>> +                               int rule_len);
>> +void _dbus_filter_dispatch(struct l_dbus_message *message, void
>> *user_data);
>> +
>>   struct dbus1_filter_data;
>>
>>   void _dbus1_filter_format_match(struct dbus1_filter_data *data, char
>> *rule,
>> diff --git a/ell/dbus.h b/ell/dbus.h
>> index c8fdec1..24527e0 100644
>> --- a/ell/dbus.h
>> +++ b/ell/dbus.h
>> @@ -42,6 +42,19 @@ enum l_dbus_bus {
>>         L_DBUS_SESSION_BUS,
>>   };
>>
>> +enum l_dbus_match_type {
>> +       L_DBUS_MATCH_NONE = 0,
>> +       L_DBUS_MATCH_TYPE,
>> +       L_DBUS_MATCH_SENDER,
>> +       L_DBUS_MATCH_DESTINATION,
>
>
> This is for eavesdropping?  Do we need this?

Yes, we could drop this.  I'd like to eventually add also the
"namespace" style conditions and "path" style conditions, I thought it
might be a good idea to support everything that dbus supports.

>
>> +       L_DBUS_MATCH_PATH,
>> +       L_DBUS_MATCH_INTERFACE,
>> +       L_DBUS_MATCH_MEMBER,
>> +       L_DBUS_MATCH_ARG0,
>> +};
>> +
>
>
> Can we make this private in some way?
>
>> +#define L_DBUS_MATCH_ARGUMENT(i)       (L_DBUS_MATCH_ARG0 + (i))
>> +
>
>
> It seems that l_dbus_match_type is only exposed for the sake of
> L_DBUS_MATCH_ARGUMENT() and L_DBUS_MATCH_NONE.

Those are all supposed to be used by the users of
l_dbus_add_signal_watch (later patch) and potential other xxx_watch
functions so that the user can create any filter they like.

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 07/20] dbus-filter: Name owner change tracking support.
  2016-03-14 18:03   ` Denis Kenzior
@ 2016-03-14 22:32     ` Andrzej Zaborowski
  0 siblings, 0 replies; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:32 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 8439 bytes --]

On 14 March 2016 at 19:03, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> This is needed because incoming message callbacks normally care what
>> Well-known Bus Name the message comes from but the sender field of the
>> message normally stores unique bus names in classic dbus.  The
>> Well-known names may be re-assigned to different unique names while the
>> rule is in place.
>> ---
>>   ell/dbus-filter.c  | 102
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   ell/dbus-private.h |   5 +++
>>   2 files changed, 106 insertions(+), 1 deletion(-)
>>
>> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
>> index 2541374..f2cc023 100644
>> --- a/ell/dbus-filter.c
>> +++ b/ell/dbus-filter.c
>> @@ -62,6 +62,12 @@ struct _dbus_filter {
>>         unsigned int signal_id;
>>         unsigned int last_id;
>>         const struct _dbus_filter_ops *driver;
>> +       struct l_hashmap *unique_names;
>> +};
>> +
>> +struct unique_name_record {
>> +       int ref_count;
>> +       char *unique_name;
>>   };
>>
>>   static void filter_subtree_free(struct filter_node *node)
>> @@ -86,6 +92,14 @@ static void filter_subtree_free(struct filter_node
>> *node)
>>         }
>>   }
>>
>> +static void unique_name_record_free(void *data)
>> +{
>> +       struct unique_name_record *name_rec = data;
>> +
>> +       l_free(name_rec->unique_name);
>> +       l_free(name_rec);
>> +}
>> +
>>   static void dbus_filter_destroy(void *data)
>>   {
>>         struct _dbus_filter *filter = data;
>> @@ -93,6 +107,10 @@ static void dbus_filter_destroy(void *data)
>>         if (filter->root)
>>                 filter_subtree_free(filter->root);
>>
>> +       if (filter->unique_names)
>> +               l_hashmap_destroy(filter->unique_names,
>> +                                       unique_name_record_free);
>> +
>>         l_free(filter);
>>   }
>>
>> @@ -101,6 +119,8 @@ static void filter_dispatch_match_recurse(struct
>> _dbus_filter *filter,
>>                                                 struct l_dbus_message
>> *message)
>>   {
>>         const char *value = NULL;
>> +       const char *alt_value = NULL;
>> +       const struct unique_name_record *name_rec;
>>         struct filter_node *child;
>>
>>         switch ((int) node->type) {
>> @@ -141,7 +161,18 @@ static void filter_dispatch_match_recurse(struct
>> _dbus_filter *filter,
>>         if (!value)
>>                 return;
>>
>> -       if (strcmp(value, node->match.value))
>> +       if ((node->type == L_DBUS_MATCH_SENDER ||
>> +                               node->type == L_DBUS_MATCH_DESTINATION) &&
>
>
> According to DBus specification, destination matches only match the unique
> name:
> "Matches messages which are being sent to the given unique name. An example
> of a destination match is destination=':1.0'"

Okay, good point.
>
>
>> +                       filter->unique_names) {
>> +               name_rec = l_hashmap_lookup(filter->unique_names,
>> +                                               node->match.value);
>> +
>> +               if (name_rec)
>> +                       alt_value = name_rec->unique_name;
>> +       }
>> +
>> +       if (strcmp(value, node->match.value) &&
>> +                       (!alt_value || strcmp(value, alt_value)))
>>                 return;
>>
>>         for (child = node->match.children; child; child = child->next)
>> @@ -155,6 +186,21 @@ void _dbus_filter_dispatch(struct l_dbus_message
>> *message, void *user_data)
>>         filter_dispatch_match_recurse(filter, filter->root, message);
>>   }
>>
>> +void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
>> +                                       const char *name, const char
>> *owner)
>> +{
>> +       if (_dbus_parse_unique_name(name, NULL))
>> +               return;
>> +
>> +       name_rec = l_hashmap_lookup(filter->unique_names, name);
>> +       if (!name_rec)
>> +               return;
>> +
>> +       l_free(name_rec->unique_name);
>> +
>> +       name_rec->unique_name = (owner && *owner) ? l_strdup(owner) :
>> NULL;
>> +}
>> +
>>   struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
>>                                         const struct _dbus_filter_ops
>> *driver)
>>   {
>> @@ -170,6 +216,9 @@ struct _dbus_filter *_dbus_filter_new(struct l_dbus
>> *dbus,
>>                                                         filter,
>>
>> dbus_filter_destroy);
>>
>> +       if (filter->driver->track_name_owner_change)
>
>
> Is this ever going to be false?
>
>> +               filter->unique_names = l_hashmap_string_new();
>> +
>>         return filter;
>>   }
>>
>> @@ -184,6 +233,49 @@ void _dbus_filter_free(struct _dbus_filter *filter)
>>                 dbus_filter_destroy(filter);
>>   }
>>
>> +static void filter_add_bus_name(struct _dbus_filter *filter, const char
>> *name)
>> +{
>> +       struct unique_name_record *name_rec;
>> +
>> +       if (!filter->unique_names)
>> +               return;
>> +
>> +       if (_dbus_parse_unique_name(name, NULL))
>> +               return;
>
>
> Do you need to add a check for valid_bus_name?
>
> Should this function return something?

Maybe we should have a check in _dbus_filter_add_rule but I'd rather
let the user submit rules even for names that we think are wrong and
have the D-Bus implementation handle that.

>
>
>> +
>> +       name_rec = l_hashmap_lookup(filter->unique_names, name);
>> +       if (!name_rec) {
>> +               name_rec = l_new(struct unique_name_record, 1);
>> +
>> +               l_hashmap_insert(filter->unique_names, name, name_rec);
>> +
>> +               filter->driver->get_name_owner(filter->dbus, name);
>> +       }
>> +
>> +       name_rec->ref_count++;
>> +}
>> +
>> +static void filter_remove_bus_name(struct _dbus_filter *filter,
>> +                                       const char *name)
>> +{
>> +       struct unique_name_record *name_rec;
>> +
>> +       if (!filter->unique_names)
>> +               return;
>> +
>> +       if (_dbus_parse_unique_name(name, NULL))
>> +               return;
>> +
>> +       name_rec = l_hashmap_lookup(filter->unique_names, name);
>> +
>> +       if (--name_rec->ref_count)
>> +               return;
>> +
>> +       l_hashmap_remove(filter->unique_names, name);
>> +
>> +       unique_name_record_free(name_rec);
>> +}
>> +
>>   static int condition_compare(const void *a, const void *b)
>>   {
>>         const struct _dbus_filter_condition *condition_a = a, *condition_b
>> = b;
>> @@ -225,6 +317,10 @@ unsigned int _dbus_filter_add_rule(struct
>> _dbus_filter *filter,
>>                         node->match.value = l_strdup(condition->value);
>>
>>                         *node_ptr = node;
>> +
>> +                       if (node->type == L_DBUS_MATCH_SENDER ||
>> +                                       node->type ==
>> L_DBUS_MATCH_DESTINATION)
>> +                               filter_add_bus_name(filter,
>> node->match.value);
>
>
> As mentioned before, L_DBUS_MATCH_DESTINATION does not seem to be relevant
> here.

Yes.

>
>>                 }
>>
>>                 node_ptr = &node->match.children;
>> @@ -286,6 +382,10 @@ static bool remove_recurse(struct _dbus_filter
>> *filter,
>>                 if (tmp->match.remote_rule)
>>                         filter->driver->remove_match(filter->dbus,
>> tmp->id);
>>
>> +               if (tmp->type == L_DBUS_MATCH_SENDER ||
>> +                               tmp->type == L_DBUS_MATCH_DESTINATION)
>> +                       filter_remove_bus_name(filter, tmp->match.value);
>> +
>>                 filter_subtree_free(tmp);
>>         }
>>
>> diff --git a/ell/dbus-private.h b/ell/dbus-private.h
>> index d4a4782..de4e706 100644
>> --- a/ell/dbus-private.h
>> +++ b/ell/dbus-private.h
>> @@ -250,11 +250,13 @@ struct _dbus_filter_condition {
>>   };
>>
>>   struct _dbus_filter_ops {
>> +       bool track_name_owner_change;
>
>
> Do we really need this? I think we can safely assume that this is true if
> get_name_owner implementation is provided.

Yes, let's do that.  The reason for this is that my earlier
implementation didn't have a get_name_owner.

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/20] dbus: Classic dbus filter_ops implementation.
  2016-03-14 18:18   ` Denis Kenzior
@ 2016-03-14 22:36     ` Andrzej Zaborowski
  2016-03-15 16:32       ` Denis Kenzior
  0 siblings, 1 reply; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:36 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 9175 bytes --]

On 14 March 2016 at 19:18, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> For the name owner tracking I decided to subscribe to all name
>> owner changes instead of adding separate rules for every name because
>> in some scenarios that saves us cycles/memory and we don't have
>> to hold a list of IDs of every such rule so that we could remove them
>> when no longer needed.
>> ---
>>   ell/dbus-filter.c |   5 +++
>>   ell/dbus.c        | 132
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 137 insertions(+)
>>
>> diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
>> index f2cc023..47f2a0b 100644
>> --- a/ell/dbus-filter.c
>> +++ b/ell/dbus-filter.c
>> @@ -189,6 +189,11 @@ void _dbus_filter_dispatch(struct l_dbus_message
>> *message, void *user_data)
>>   void _dbus_filter_name_owner_notify(struct _dbus_filter *filter,
>>                                         const char *name, const char
>> *owner)
>>   {
>> +       struct unique_name_record *name_rec;
>> +
>> +       if (!filter)
>> +               return;
>> +
>>         if (_dbus_parse_unique_name(name, NULL))
>>                 return;
>
>
> Does this belong in a different patch?

Yep, sorry, rebasing error.
>
>
>>
>> diff --git a/ell/dbus.c b/ell/dbus.c
>> index 2ac9e58..e9d3424 100644
>> --- a/ell/dbus.c
>> +++ b/ell/dbus.c
>> @@ -63,6 +63,7 @@ struct l_dbus_ops {
>>                                 struct l_dbus_message *message);
>>         struct l_dbus_message *(*recv_message)(struct l_dbus *bus);
>>         void (*free)(struct l_dbus *bus);
>> +       struct _dbus_filter_ops filter_ops;
>>   };
>>
>>   struct l_dbus {
>> @@ -87,6 +88,7 @@ struct l_dbus {
>>         l_dbus_destroy_func_t debug_destroy;
>>         void *debug_data;
>>         struct _dbus_object_tree *tree;
>> +       struct _dbus_filter *filter;
>>
>>         const struct l_dbus_ops *driver;
>>   };
>> @@ -103,6 +105,7 @@ struct l_dbus_classic {
>>         struct l_dbus super;
>>         void *auth_command;
>>         enum auth_state auth_state;
>> +       struct l_hashmap *match_strings;
>>   };
>>
>>   struct message_callback {
>> @@ -553,6 +556,7 @@ static void classic_free(struct l_dbus *dbus)
>>                 container_of(dbus, struct l_dbus_classic, super);
>>
>>         l_free(classic->auth_command);
>> +       l_hashmap_destroy(classic->match_strings, l_free);
>>         l_free(classic);
>>   }
>>
>> @@ -664,13 +668,129 @@ cmsg_fail:
>>         return NULL;
>>   }
>>
>> +static bool classic_add_match(struct l_dbus *dbus, unsigned int id,
>> +                               const struct _dbus_filter_condition *rule,
>> +                               int rule_len)
>> +{
>> +       struct l_dbus_classic *classic =
>> +               container_of(dbus, struct l_dbus_classic, super);
>> +       char *match_str;
>> +       struct l_dbus_message *message;
>> +
>> +       match_str = _dbus_filter_rule_to_str(rule, rule_len);
>> +
>> +       l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id),
>> match_str);
>> +
>> +       message = l_dbus_message_new_method_call(dbus,
>> +                                               DBUS_SERVICE_DBUS,
>> +                                               DBUS_PATH_DBUS,
>> +                                               L_DBUS_INTERFACE_DBUS,
>> +                                               "AddMatch");
>> +
>> +       l_dbus_message_set_arguments(message, "s", match_str);
>> +
>> +       send_message(dbus, false, message, NULL, NULL, NULL);
>> +
>> +       return true;
>> +}
>> +
>> +static bool classic_remove_match(struct l_dbus *dbus, unsigned int id)
>> +{
>> +       struct l_dbus_classic *classic =
>> +               container_of(dbus, struct l_dbus_classic, super);
>> +       char *match_str = l_hashmap_remove(classic->match_strings,
>> +                                               L_UINT_TO_PTR(id));
>> +       struct l_dbus_message *message;
>> +
>> +       if (!match_str)
>> +               return false;
>> +
>> +       message = l_dbus_message_new_method_call(dbus,
>> +                                               DBUS_SERVICE_DBUS,
>> +                                               DBUS_PATH_DBUS,
>> +                                               L_DBUS_INTERFACE_DBUS,
>> +                                               "RemoveMatch");
>> +
>> +       l_dbus_message_set_arguments(message, "s", match_str);
>> +
>> +       send_message(dbus, false, message, NULL, NULL, NULL);
>> +
>> +       l_free(match_str);
>> +
>> +       return true;
>> +}
>> +
>> +struct get_name_owner_request {
>> +       struct l_dbus_message *message;
>> +       struct l_dbus *dbus;
>> +};
>> +
>> +static void get_name_owner_reply_cb(struct l_dbus_message *reply,
>> +                                       void *user_data)
>> +{
>> +       struct get_name_owner_request *req = user_data;
>> +       const char *name, *owner;
>> +
>> +       /* No name owner yet */
>> +       if (l_dbus_message_is_error(reply))
>> +               return;
>> +
>> +       /* Shouldn't happen */
>> +       if (!l_dbus_message_get_arguments(reply, "s", &owner))
>> +               return;
>> +
>> +       /* Shouldn't happen */
>> +       if (!l_dbus_message_get_arguments(req->message, "s", &name))
>> +               return;
>> +
>> +       _dbus_filter_name_owner_notify(req->dbus->filter, name, owner);
>> +}
>> +
>> +static bool classic_get_name_owner(struct l_dbus *bus, const char *name)
>> +{
>> +       struct get_name_owner_request *req;
>> +
>> +       req = l_new(struct get_name_owner_request, 1);
>> +       req->dbus = bus;
>> +       req->message = l_dbus_message_new_method_call(bus,
>> +                                                       DBUS_SERVICE_DBUS,
>> +                                                       DBUS_PATH_DBUS,
>> +
>> L_DBUS_INTERFACE_DBUS,
>> +                                                       "GetNameOwner");
>> +
>> +       l_dbus_message_set_arguments(req->message, "s", name);
>> +
>> +       send_message(bus, false, req->message, get_name_owner_reply_cb,
>> +                       req, l_free);
>> +
>> +       return true;
>> +}
>> +
>>   static const struct l_dbus_ops classic_ops = {
>>         .version = 1,
>>         .send_message = classic_send_message,
>>         .recv_message = classic_recv_message,
>>         .free = classic_free,
>> +       .filter_ops = {
>> +               .track_name_owner_change = true,
>> +               .add_match = classic_add_match,
>> +               .remove_match = classic_remove_match,
>> +               .get_name_owner = classic_get_name_owner,
>> +       },
>>   };
>>
>> +static void name_owner_changed_cb(struct l_dbus_message *message,
>> +                                       void *user_data)
>> +{
>> +       struct l_dbus *dbus = user_data;
>> +       char *name, *old, *new;
>> +
>> +       if (!l_dbus_message_get_arguments(message, "sss", &name, &old,
>> &new))
>> +               return;
>> +
>> +       _dbus_filter_name_owner_notify(dbus->filter, name, new);
>> +}
>> +
>>   static struct l_dbus *setup_dbus1(int fd, const char *guid)
>>   {
>>         static const unsigned char creds = 0x00;
>> @@ -680,6 +800,13 @@ static struct l_dbus *setup_dbus1(int fd, const char
>> *guid)
>>         ssize_t written;
>>         unsigned int i;
>>         long flags;
>> +       static struct _dbus_filter_condition rule[] = {
>> +               { L_DBUS_MATCH_TYPE,            "signal" },
>> +               { L_DBUS_MATCH_SENDER,          DBUS_SERVICE_DBUS },
>> +               { L_DBUS_MATCH_PATH,            DBUS_PATH_DBUS },
>> +               { L_DBUS_MATCH_INTERFACE,       L_DBUS_INTERFACE_DBUS },
>> +               { L_DBUS_MATCH_MEMBER,          "NameOwnerChanged" },
>> +       };
>>
>>         if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) {
>>                 close(fd);
>> @@ -714,6 +841,8 @@ static struct l_dbus *setup_dbus1(int fd, const char
>> *guid)
>>         dbus = &classic->super;
>>         dbus->driver = &classic_ops;
>>
>> +       classic->match_strings = l_hashmap_new();
>> +
>>         dbus_init(dbus, fd);
>>         dbus->guid = l_strdup(guid);
>>
>> @@ -726,6 +855,9 @@ static struct l_dbus *setup_dbus1(int fd, const char
>> *guid)
>>         l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL);
>>         l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL);
>>
>> +       _dbus_filter_add_rule(dbus->filter, rule, L_ARRAY_SIZE(rule),
>> +                               name_owner_changed_cb, dbus);
>> +
>
>
> Do we need to treat DBUS_SERVICE_DBUS conditions specially since this one is
> not subject to unique name resolution?

Good point, we don't *need* to, but we can save a GetNameOwner call if
we do that.  Possibly we can just return "org.freedesktop.Dbus"
immediately from classic_get_name_owner.

Best regard

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API.
  2016-03-14 19:18   ` Denis Kenzior
@ 2016-03-14 22:39     ` Andrzej Zaborowski
  2016-03-15 16:38       ` Denis Kenzior
  0 siblings, 1 reply; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-14 22:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5901 bytes --]

Hi Denis,

On 14 March 2016 at 20:18, Denis Kenzior <denkenz@gmail.com> wrote:
> Hi Andrew,
>
> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>
>> ---
>>   ell/dbus.c | 89
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   ell/dbus.h |  5 ++++
>>   2 files changed, 94 insertions(+)
>
>
> I'd reflow this patch and one preceding it like this:
>
> 1. kdbus name_acquire variant
> 2. dbus1 name acquire variant
> 3. public API + driver method definitions

Ok.

>
>
>>
>> diff --git a/ell/dbus.c b/ell/dbus.c
>> index c5cc1fc..6c267ae 100644
>> --- a/ell/dbus.c
>> +++ b/ell/dbus.c
>> @@ -822,6 +822,84 @@ static bool classic_get_name_owner(struct l_dbus
>> *bus, const char *name)
>>         return true;
>>   }
>>
>> +struct name_request {
>> +       l_dbus_name_acquire_func_t callback;
>> +       void *user_data;
>> +       struct l_dbus *dbus;
>> +};
>> +
>> +enum dbus_name_flag {
>> +       DBUS_NAME_FLAG_ALLOW_REPLACEMENT        = 0x1,
>> +       DBUS_NAME_FLAG_REPLACE_EXISTING         = 0x2,
>> +       DBUS_NAME_FLAG_DO_NOT_QUEUE             = 0x4,
>> +};
>> +
>> +enum dbus_name_reply {
>> +       DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER   = 1,
>> +       DBUS_REQUEST_NAME_REPLY_IN_QUEUE        = 2,
>> +       DBUS_REQUEST_NAME_REPLY_EXISTS          = 3,
>> +       DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER   = 4,
>> +};
>> +
>> +static void request_name_reply_cb(struct l_dbus_message *reply, void
>> *user_data)
>> +{
>> +       struct name_request *req = user_data;
>> +       bool success = false, queued = false;
>> +       uint32_t retval;
>> +
>> +       if (!req->callback)
>> +               return;
>> +
>> +       /* No name owner yet */
>> +       if (l_dbus_message_is_error(reply))
>> +               goto call_back;
>> +
>> +       /* Shouldn't happen */
>> +       if (!l_dbus_message_get_arguments(reply, "u", &retval))
>> +               goto call_back;
>> +
>> +       success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) ||
>> +               (retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) ||
>> +               (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
>> +       queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
>> +
>> +call_back:
>> +       req->callback(req->dbus, success, queued, req->user_data);
>> +}
>> +
>> +static uint32_t classic_name_acquire(struct l_dbus *dbus, const char
>> *name,
>> +                                       bool allow_replacement,
>> +                                       bool replace_existing, bool queue,
>> +                                       l_dbus_name_acquire_func_t
>> callback,
>> +                                       void *user_data)
>> +{
>> +       struct name_request *req;
>> +       struct l_dbus_message *message;
>> +       uint32_t flags = 0;
>> +
>> +       req = l_new(struct name_request, 1);
>> +       req->dbus = dbus;
>> +       req->user_data = user_data;
>> +       req->callback = callback;
>> +
>> +       message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS,
>> +                                                       DBUS_PATH_DBUS,
>> +
>> L_DBUS_INTERFACE_DBUS,
>> +                                                       "RequestName");
>> +
>> +       if (allow_replacement)
>> +               flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
>> +       if (replace_existing)
>> +               flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
>> +       if (!queue)
>> +               flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
>> +
>> +       l_dbus_message_set_arguments(message, "su", name, flags);
>> +
>> +       return send_message(dbus, false, message, request_name_reply_cb,
>> +                               req, free);
>> +}
>> +
>>   static const struct l_dbus_ops classic_ops = {
>>         .version = 1,
>>         .send_message = classic_send_message,
>> @@ -833,6 +911,7 @@ static const struct l_dbus_ops classic_ops = {
>>                 .remove_match = classic_remove_match,
>>                 .get_name_owner = classic_get_name_owner,
>>         },
>> +       .name_acquire = classic_name_acquire,
>>   };
>>
>>   static void name_owner_changed_cb(struct l_dbus_message *message,
>> @@ -2048,3 +2127,13 @@ LIB_EXPORT bool l_dbus_remove_signal_watch(struct
>> l_dbus *dbus, unsigned int id)
>>   {
>>         return _dbus_filter_remove_rule(dbus->filter, id);
>>   }
>> +
>> +LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char
>> *name,
>> +                               bool allow_replacement, bool
>> replace_existing,
>> +                               bool queue, l_dbus_name_acquire_func_t
>> callback,
>> +                               void *user_data)
>> +{
>> +       return dbus->driver->name_acquire(dbus, name, allow_replacement,
>> +                                               replace_existing, queue,
>> +                                               callback, user_data);
>> +}
>> diff --git a/ell/dbus.h b/ell/dbus.h
>> index 0b82899..f4b2527 100644
>> --- a/ell/dbus.h
>> +++ b/ell/dbus.h
>> @@ -256,6 +256,11 @@ unsigned int l_dbus_add_signal_watch(struct l_dbus
>> *dbus,
>>                                         const char *member, ...);
>>   bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id);
>>
>> +uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
>> +                               bool allow_replacement, bool
>> replace_existing,
>> +                               bool queue, l_dbus_name_acquire_func_t
>> callback,
>> +                               void *user_data);
>> +
>
>
> What's the uint32_t return for?

So that the call can be cancelled with l_dbus_cancel if the user no
longer needs the name and it is still waiting for the callback (should
be rare).

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-14 22:11     ` Andrzej Zaborowski
@ 2016-03-15 16:27       ` Denis Kenzior
  2016-03-15 22:08         ` Andrzej Zaborowski
  0 siblings, 1 reply; 40+ messages in thread
From: Denis Kenzior @ 2016-03-15 16:27 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5817 bytes --]

Hi Andrew,

On 03/14/2016 05:11 PM, Andrzej Zaborowski wrote:
>   Hi Denis,
>
> On 14 March 2016 at 17:49, Denis Kenzior <denkenz@gmail.com> wrote:
>> Hi Andrew,
>>
>> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>>
>>> It seems that l_dbus_message_iter_get_type can't be used to get the
>>> value of a single argument and be called repeatedly, it might crash if
>>
>>
>> Looking at l_dbus_message_iter_get_type, it just returns
>> iter->sig_start[iter->sig_pos].  Is there something deeper going on here
>> that is not readily apparent?
>
> Sorry, l_dbus_message_iter_get_type is a typo, I wanted to say
> message_iter_next_entry here.  This function calls it with a fixed
> number of parameters and sooner or later it will receive a message
> with more arguments and by my reading will segfault.
>

So l_dbus_message_iter_next_entry is assuming that the programmer knows 
the signature of the next parameter and passes in a variable meant to 
hold that parameter.  If there's a mismatch, then yes, it might crash. 
However, that is why we check the signature ahead of time.

I guess I'm still not quite sure what you're trying to say here :)

>>
>>> the number and types of call arguments don't match the message arguments.
>>> Also try to support the string arguments that come after non-string
>>> arguments in the bloom filter.
>>
>>
>>  From my reading of systemd code, I didn't think this was possible.  But I
>> could be wrong...
>
> I see no problem with the bloom filter containing, say, arg3="hello",
> even though arguments 1 and 2 are integers.  I don't know if systemd
> supports that but if for example a client adds a match with this kind
> of filter, the service must also support that or the signal won't pass
> through the filter.
>

That is the problem with systemd, it does not explicitly document what 
is and what is not supported.  Having glanced at their bloom filter code 
again, I'm pretty sure only string arguments are currently supported and 
non-string arguments in between are not skipped.  This is why our code 
looks the way it does.

Can you also take a look and confirm?  We are stuck supporting only what 
systemd supports.

>>
>>
>>> ---
>>>    ell/dbus-message.c | 38 ++++++++++++++++++++++++++++----------
>>>    1 file changed, 28 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/ell/dbus-message.c b/ell/dbus-message.c
>>> index f223c70..a123a8a 100644
>>> --- a/ell/dbus-message.c
>>> +++ b/ell/dbus-message.c
>>> @@ -1412,9 +1412,12 @@ bool _dbus_kernel_calculate_bloom(struct
>>> l_dbus_message *message,
>>>          const char *signature;
>>>          void *body;
>>>          size_t body_size;
>>> -       struct l_dbus_message_iter iter;
>>> +       struct l_dbus_message_iter iter, tmp;
>>>          uint8_t argn;
>>>          char buf[256];
>>> +       bool (*skip_entry)(struct l_dbus_message_iter *);
>>> +       bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
>>> +       char type;
>>>
>>>          /* The string "interface:" suffixed by the interface name */
>>>          attr = l_dbus_message_get_interface(message);
>>> @@ -1458,17 +1461,32 @@ bool _dbus_kernel_calculate_bloom(struct
>>> l_dbus_message *message,
>>>
>>>          body = _dbus_message_get_body(message, &body_size);
>>>
>>> -       if (_dbus_message_is_gvariant(message))
>>> -               _gvariant_iter_init(&iter, message, signature, NULL,
>>> -                                       body, body_size);
>>> -       else
>>> +       if (_dbus_message_is_gvariant(message)) {
>>> +               if (!_gvariant_iter_init(&iter, message, signature, NULL,
>>> +                                               body, body_size))
>>> +                       return false;
>>> +
>>> +               skip_entry = _gvariant_iter_skip_entry;
>>> +               get_basic = _gvariant_iter_next_entry_basic;
>>> +       } else {
>>>                  _dbus1_iter_init(&iter, message, signature, NULL,
>>> -                               body, body_size);
>>> +                                       body, body_size);
>>> +
>>> +               skip_entry = _dbus1_iter_skip_entry;
>>> +               get_basic = _dbus1_iter_next_entry_basic;
>>> +       }
>>>
>>>          argn = 0;
>>>
>>> -       while (*signature == 's' || *signature == 'o' || *signature ==
>>> 'g') {
>>> -               if (!message_iter_next_entry(&iter, &attr))
>>> +       do {
>>> +               type = l_dbus_message_iter_get_type(&iter);
>>> +               if (!strchr("sog", type))
>>> +                       goto next;
>>> +
>>> +               /* Don't let get_basic move iter->pos without moving
>>> sig_pos */
>>> +               memcpy(&tmp, &iter, sizeof(tmp));
>>> +
>>> +               if (!get_basic(&tmp, type, &attr))
>>>                          return false;
>>
>>
>> Is this to avoid double skipping this entry?  Can we find a less hacky way
>> to do this?  Perhaps peek_basic, or restructure the loop in some way?
>
> The problem is that get_basic moves the data position (iter->pos) but
> doesn't move the iter->sig_pos, as fas as I can see.  Maybe instead we

I'm pretty sure it does.  See bottom of _dbus1_iter_next_entry_basic() 
for example.  However, the signature handling is full of nasty details. 
  See below.

> should just do iter->sig_pos += 1, similarly to what
> message_iter_next_entry_valist does?

It is really bad form to mess with iterator's internal data structures 
outside its core functions.  If you need it to do something specific, 
lets introduce an iterator method specific to your usecase.

Hence my suggestion to restructure the loop or introduce new operations.

Regards,
-Denis

>
> Best regards
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/20] dbus: Classic dbus filter_ops implementation.
  2016-03-14 22:36     ` Andrzej Zaborowski
@ 2016-03-15 16:32       ` Denis Kenzior
  0 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-15 16:32 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 676 bytes --]

Hi Andrew,

 >>> +       _dbus_filter_add_rule(dbus->filter, rule, L_ARRAY_SIZE(rule),
>>> +                               name_owner_changed_cb, dbus);
>>> +
>>
>>
>> Do we need to treat DBUS_SERVICE_DBUS conditions specially since this one is
>> not subject to unique name resolution?
>
> Good point, we don't *need* to, but we can save a GetNameOwner call if
> we do that.  Possibly we can just return "org.freedesktop.Dbus"
> immediately from classic_get_name_owner.
>

That could work, or alternatively notify the filtering code that name 
resolution should not be performed.  Saves us the alternative 
computation and comparison.

Regards,
-Denis


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 14/20] dbus: Don't send replies to messages with no reply flag.
  2016-03-14 22:15     ` Andrzej Zaborowski
@ 2016-03-15 16:35       ` Denis Kenzior
  0 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-15 16:35 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2341 bytes --]

Hi Andrew,

On 03/14/2016 05:15 PM, Andrzej Zaborowski wrote:
> Hi Denis,
>
> On 14 March 2016 at 18:11, Denis Kenzior <denkenz@gmail.com> wrote:
>> Hi Andrew,
>>
>> On 03/13/2016 10:41 PM, Andrew Zaborowski wrote:
>>>
>>> Kdbus doesn't store the cookies for messages that have the no reply flag
>>> and throws error when a reply is sent with reply_cookie that it doesn't
>>> know.  It's not fatal, but we also save some cycles by not sending the
>>> message.  A further change could be made to not even let users create a
>>> message as a return from a method call but that may be confusing.
>>> ---
>>>    ell/dbus-service.c | 8 ++++++--
>>>    1 file changed, 6 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/ell/dbus-service.c b/ell/dbus-service.c
>>> index b4e0b60..c1ed9ec 100644
>>> --- a/ell/dbus-service.c
>>> +++ b/ell/dbus-service.c
>>> @@ -1624,8 +1624,12 @@ bool _dbus_object_tree_dispatch(struct
>>> _dbus_object_tree *tree,
>>>                  return false;
>>>
>>>          reply = method->cb(dbus, message, instance->user_data);
>>> -       if (reply)
>>> -               l_dbus_send(dbus, reply);
>>> +       if (reply) {
>>> +               if (l_dbus_message_get_no_reply(message))
>>> +                       l_dbus_message_unref(reply);
>>> +               else
>>> +                       l_dbus_send(dbus, reply);
>>> +       }
>>
>>
>> Okay, but this doesn't solve the issue for async method returns.
>>
>
> True, I forgot about that.
>
>> Should we
>> save the no_reply flag inside l_dbus_message_new_method_return &
>> l_dbus_message_new_error and then take care of this inside l_dbus_send?
>
> I was thinking of modifying l_dbus_message_new_method_return to set
> message->destination to NULL or returning an error.
>

Returning an error is bad, since the code might not be setup to handle 
noreply messages.  Any client can call any method call on the service 
and just randomly set the noreply flag.  If we return an error, then 
half our method handlers might crash.  And I don't necessarily want to 
check for the noreply flag in every method handler.

I think the easiest way would be to just add a noreply flag inside 
l_dbus_message (similar to bool sealed) and just not put the message on 
the wire if that flag is set.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API.
  2016-03-14 22:39     ` Andrzej Zaborowski
@ 2016-03-15 16:38       ` Denis Kenzior
  0 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-15 16:38 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 841 bytes --]

Hi Andrew,

 >>>
>>> +uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name,
>>> +                               bool allow_replacement, bool
>>> replace_existing,
>>> +                               bool queue, l_dbus_name_acquire_func_t
>>> callback,
>>> +                               void *user_data);
>>> +
>>
>>
>> What's the uint32_t return for?
>
> So that the call can be cancelled with l_dbus_cancel if the user no
> longer needs the name and it is still waiting for the callback (should
> be rare).
>

The semantics are a bit weird here though.  You have kdbus version that 
simply returns 0.  dbus1 version returns a uint32 or 0 depending on 
success / failure.

How does the client application know what is what?  Perhaps a straight 
true/false might be better here?

Regards,
-Denis


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-15 16:27       ` Denis Kenzior
@ 2016-03-15 22:08         ` Andrzej Zaborowski
  2016-03-16  2:06           ` Denis Kenzior
  0 siblings, 1 reply; 40+ messages in thread
From: Andrzej Zaborowski @ 2016-03-15 22:08 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 6720 bytes --]

Hi Denis,

On 15 March 2016 at 17:27, Denis Kenzior <denkenz@gmail.com> wrote:
> On 03/14/2016 05:11 PM, Andrzej Zaborowski wrote:
>> Sorry, l_dbus_message_iter_get_type is a typo, I wanted to say
>> message_iter_next_entry here.  This function calls it with a fixed
>> number of parameters and sooner or later it will receive a message
>> with more arguments and by my reading will segfault.
>>
>
> So l_dbus_message_iter_next_entry is assuming that the programmer knows the
> signature of the next parameter and passes in a variable meant to hold that
> parameter.  If there's a mismatch, then yes, it might crash. However, that
> is why we check the signature ahead of time.

So i've looked at l_dbus_message_iter_next_entry many times and it
seems it won't stop at the next parameter, although the name could
suggest that.  It is expecting that the arguments list has a pointer
for every remaining item in the iterator and it doesn't check for
NULLs either.  So you can't just pass a single parameter without
knowing how many items are in the message. and you can't call it
multiple times on the same iterator except with arrays (I think...).

>
> I guess I'm still not quite sure what you're trying to say here :)
>
>>>
>>>> the number and types of call arguments don't match the message
>>>> arguments.
>>>> Also try to support the string arguments that come after non-string
>>>> arguments in the bloom filter.
>>>
>>>
>>>
>>>  From my reading of systemd code, I didn't think this was possible.  But
>>> I
>>> could be wrong...
>>
>>
>> I see no problem with the bloom filter containing, say, arg3="hello",
>> even though arguments 1 and 2 are integers.  I don't know if systemd
>> supports that but if for example a client adds a match with this kind
>> of filter, the service must also support that or the signal won't pass
>> through the filter.
>>
>
> That is the problem with systemd, it does not explicitly document what is
> and what is not supported.  Having glanced at their bloom filter code again,
> I'm pretty sure only string arguments are currently supported and non-string
> arguments in between are not skipped.  This is why our code looks the way it
> does.
>
> Can you also take a look and confirm?  We are stuck supporting only what
> systemd supports.

I'm going to look at the systemd code although I'd like to think kdbus
is not systemd.  Could we do what seems correct and submit a bug
report against systemd?

I'm pretty sure it is a bug if a message with "foo" as the 3rd
argument doesn't match a filter which includes arg2="foo" (2 because
0-based..), and there's not even a warning issued when you create such
a filter, or in the docs.

>
>>>
>>>
>>>> ---
>>>>    ell/dbus-message.c | 38 ++++++++++++++++++++++++++++----------
>>>>    1 file changed, 28 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/ell/dbus-message.c b/ell/dbus-message.c
>>>> index f223c70..a123a8a 100644
>>>> --- a/ell/dbus-message.c
>>>> +++ b/ell/dbus-message.c
>>>> @@ -1412,9 +1412,12 @@ bool _dbus_kernel_calculate_bloom(struct
>>>> l_dbus_message *message,
>>>>          const char *signature;
>>>>          void *body;
>>>>          size_t body_size;
>>>> -       struct l_dbus_message_iter iter;
>>>> +       struct l_dbus_message_iter iter, tmp;
>>>>          uint8_t argn;
>>>>          char buf[256];
>>>> +       bool (*skip_entry)(struct l_dbus_message_iter *);
>>>> +       bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
>>>> +       char type;
>>>>
>>>>          /* The string "interface:" suffixed by the interface name */
>>>>          attr = l_dbus_message_get_interface(message);
>>>> @@ -1458,17 +1461,32 @@ bool _dbus_kernel_calculate_bloom(struct
>>>> l_dbus_message *message,
>>>>
>>>>          body = _dbus_message_get_body(message, &body_size);
>>>>
>>>> -       if (_dbus_message_is_gvariant(message))
>>>> -               _gvariant_iter_init(&iter, message, signature, NULL,
>>>> -                                       body, body_size);
>>>> -       else
>>>> +       if (_dbus_message_is_gvariant(message)) {
>>>> +               if (!_gvariant_iter_init(&iter, message, signature,
>>>> NULL,
>>>> +                                               body, body_size))
>>>> +                       return false;
>>>> +
>>>> +               skip_entry = _gvariant_iter_skip_entry;
>>>> +               get_basic = _gvariant_iter_next_entry_basic;
>>>> +       } else {
>>>>                  _dbus1_iter_init(&iter, message, signature, NULL,
>>>> -                               body, body_size);
>>>> +                                       body, body_size);
>>>> +
>>>> +               skip_entry = _dbus1_iter_skip_entry;
>>>> +               get_basic = _dbus1_iter_next_entry_basic;
>>>> +       }
>>>>
>>>>          argn = 0;
>>>>
>>>> -       while (*signature == 's' || *signature == 'o' || *signature ==
>>>> 'g') {
>>>> -               if (!message_iter_next_entry(&iter, &attr))
>>>> +       do {
>>>> +               type = l_dbus_message_iter_get_type(&iter);
>>>> +               if (!strchr("sog", type))
>>>> +                       goto next;
>>>> +
>>>> +               /* Don't let get_basic move iter->pos without moving
>>>> sig_pos */
>>>> +               memcpy(&tmp, &iter, sizeof(tmp));
>>>> +
>>>> +               if (!get_basic(&tmp, type, &attr))
>>>>                          return false;
>>>
>>>
>>>
>>> Is this to avoid double skipping this entry?  Can we find a less hacky
>>> way
>>> to do this?  Perhaps peek_basic, or restructure the loop in some way?
>>
>>
>> The problem is that get_basic moves the data position (iter->pos) but
>> doesn't move the iter->sig_pos, as fas as I can see.  Maybe instead we
>
>
> I'm pretty sure it does.  See bottom of _dbus1_iter_next_entry_basic() for
> example.  However, the signature handling is full of nasty details.  See
> below.

Ah, yes, it does.  I apparently just read up to the first switch case
and forgot there could be more code.

In that case we can just "continue" the loop and not use skip_entry.

>
>> should just do iter->sig_pos += 1, similarly to what
>> message_iter_next_entry_valist does?
>
>
> It is really bad form to mess with iterator's internal data structures
> outside its core functions.

Yep.

> If you need it to do something specific, lets
> introduce an iterator method specific to your usecase.
>
> Hence my suggestion to restructure the loop or introduce new operations.

It seems there's no need for that, it was just my wrong assumption
about _dbus1_iter_next_entry_basic.

Best regards

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments.
  2016-03-15 22:08         ` Andrzej Zaborowski
@ 2016-03-16  2:06           ` Denis Kenzior
  0 siblings, 0 replies; 40+ messages in thread
From: Denis Kenzior @ 2016-03-16  2:06 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4126 bytes --]

Hi Andrew,

On 03/15/2016 05:08 PM, Andrzej Zaborowski wrote:
> Hi Denis,
>
> On 15 March 2016 at 17:27, Denis Kenzior <denkenz@gmail.com> wrote:
>> On 03/14/2016 05:11 PM, Andrzej Zaborowski wrote:
>>> Sorry, l_dbus_message_iter_get_type is a typo, I wanted to say
>>> message_iter_next_entry here.  This function calls it with a fixed
>>> number of parameters and sooner or later it will receive a message
>>> with more arguments and by my reading will segfault.
>>>
>>
>> So l_dbus_message_iter_next_entry is assuming that the programmer knows the
>> signature of the next parameter and passes in a variable meant to hold that
>> parameter.  If there's a mismatch, then yes, it might crash. However, that
>> is why we check the signature ahead of time.
>
> So i've looked at l_dbus_message_iter_next_entry many times and it
> seems it won't stop at the next parameter, although the name could
> suggest that.  It is expecting that the arguments list has a pointer
> for every remaining item in the iterator and it doesn't check for
> NULLs either.  So you can't just pass a single parameter without
> knowing how many items are in the message. and you can't call it
> multiple times on the same iterator except with arrays (I think...).
>

Ah, now I understand.  Yes, you are correct.

l_dbus_message_iter_next_entry wants you to consume everything in the 
enclosing structure.  It is not meant to be used like the traditional 
reference dbus_iter API that iterates over a single item at a time.

Our setup uses get_arguments to parse/validate the top level structure 
and the iterators obtained must then match the signature that the 
programmer expected.

I'm not quite sure why _dbus_kernel_calculate_bloom attempts to use 
message_iter_next_entry.  Don't recall whether the behavior of 
next_entry changed afterward or it was just never tested.  Either way, 
its a bug now.

>>
>> I guess I'm still not quite sure what you're trying to say here :)
>>
>>>>
>>>>> the number and types of call arguments don't match the message
>>>>> arguments.
>>>>> Also try to support the string arguments that come after non-string
>>>>> arguments in the bloom filter.
>>>>
>>>>
>>>>
>>>>   From my reading of systemd code, I didn't think this was possible.  But
>>>> I
>>>> could be wrong...
>>>
>>>
>>> I see no problem with the bloom filter containing, say, arg3="hello",
>>> even though arguments 1 and 2 are integers.  I don't know if systemd
>>> supports that but if for example a client adds a match with this kind
>>> of filter, the service must also support that or the signal won't pass
>>> through the filter.
>>>
>>
>> That is the problem with systemd, it does not explicitly document what is
>> and what is not supported.  Having glanced at their bloom filter code again,
>> I'm pretty sure only string arguments are currently supported and non-string
>> arguments in between are not skipped.  This is why our code looks the way it
>> does.
>>
>> Can you also take a look and confirm?  We are stuck supporting only what
>> systemd supports.
>
> I'm going to look at the systemd code although I'd like to think kdbus
> is not systemd.  Could we do what seems correct and submit a bug
> report against systemd?
>

You'd like to think that, but in reality this is not true :)  systemd 
contains the only kdbus implementation in existence.  So what systemd 
does is the reference behavior.  I'm not aware of any attempts to 
document how argument filters work over kdbus.

> I'm pretty sure it is a bug if a message with "foo" as the 3rd
> argument doesn't match a filter which includes arg2="foo" (2 because
> 0-based..), and there's not even a warning issued when you create such
> a filter, or in the docs.
>

*Shrug* Welcome to open source :)  Don't get me wrong, I do agree with 
you and have submitted patches to systemd in the past.  But that project 
is a very deep rabbit hole.

However, in reality, nobody actually uses arg filtering, outside of 
maybe filtering by arg0.  So its no big loss anyway.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2016-03-16  2:06 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-14  3:41 [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 02/20] dbus: Add _dbus_message_get_nth_string_argument Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 03/20] dbus: Support 2+ arguments in l_dbus_message_get_error Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 04/20] dbus: Fix _dbus_kernel_calculate_bloom for multiple arguments Andrew Zaborowski
2016-03-14 16:49   ` Denis Kenzior
2016-03-14 22:11     ` Andrzej Zaborowski
2016-03-15 16:27       ` Denis Kenzior
2016-03-15 22:08         ` Andrzej Zaborowski
2016-03-16  2:06           ` Denis Kenzior
2016-03-14  3:41 ` [PATCH 05/20] dbus: Add message filter logic in dbus-filter.c Andrew Zaborowski
2016-03-14 17:37   ` Denis Kenzior
2016-03-14 22:25     ` Andrzej Zaborowski
2016-03-14  3:41 ` [PATCH 06/20] unit: Add dbus message filter tests Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 07/20] dbus-filter: Name owner change tracking support Andrew Zaborowski
2016-03-14 18:03   ` Denis Kenzior
2016-03-14 22:32     ` Andrzej Zaborowski
2016-03-14  3:41 ` [PATCH 08/20] dbus: Classic dbus filter_ops implementation Andrew Zaborowski
2016-03-14 18:18   ` Denis Kenzior
2016-03-14 22:36     ` Andrzej Zaborowski
2016-03-15 16:32       ` Denis Kenzior
2016-03-14  3:41 ` [PATCH 09/20] dbus: kdbus " Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 10/20] linux: Update kdbus.h to current github version Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 11/20] dbus-kernel: Update with kdbus API changes Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 12/20] dbus: Add message filter public API Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 13/20] unit: Use the message filter API in dbus tests Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 14/20] dbus: Don't send replies to messages with no reply flag Andrew Zaborowski
2016-03-14 17:11   ` Denis Kenzior
2016-03-14 22:15     ` Andrzej Zaborowski
2016-03-15 16:35       ` Denis Kenzior
2016-03-14  3:41 ` [PATCH 15/20] dbus: Rewrite service/disconnect watch APIs on top of filter API Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 16/20] dbus: Remove now unused filter functions Andrew Zaborowski
2016-03-14 19:12   ` Denis Kenzior
2016-03-14  3:41 ` [PATCH 17/20] dbus: kdbus driver->name_acquire implementation Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 18/20] dbus: Classic dbus driver->name_acquire and public API Andrew Zaborowski
2016-03-14 19:18   ` Denis Kenzior
2016-03-14 22:39     ` Andrzej Zaborowski
2016-03-15 16:38       ` Denis Kenzior
2016-03-14  3:41 ` [PATCH 19/20] unit: Use l_dbus_name_acquire to acquire well-known name Andrew Zaborowski
2016-03-14  3:41 ` [PATCH 20/20] examples: " Andrew Zaborowski
2016-03-14 16:50 ` [PATCH 01/20] dbus: Add _dbus1_message_iter_skip_entry and gvariant variant Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.