All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Zaborowski <andrew.zaborowski@intel.com>
To: ell@lists.01.org
Subject: [PATCH 8/8] dbus: Implement org.freedesktop.DBus.Properties
Date: Mon, 01 Feb 2016 15:07:24 +0100	[thread overview]
Message-ID: <1454335644-17088-8-git-send-email-andrew.zaborowski@intel.com> (raw)
In-Reply-To: <1454335644-17088-1-git-send-email-andrew.zaborowski@intel.com>

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

---
 ell/dbus-service.c      | 287 ++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dbus.c              |   1 -
 examples/dbus-service.c |   7 ++
 3 files changed, 294 insertions(+), 1 deletion(-)

diff --git a/ell/dbus-service.c b/ell/dbus-service.c
index 93aeb60..962bbaf 100644
--- a/ell/dbus-service.c
+++ b/ell/dbus-service.c
@@ -47,6 +47,8 @@ static const char *static_introspectable =
 		"\t\t\t<arg name=\"xml\" type=\"s\" direction=\"out\"/>\n"
 		"\t\t</method>\n\t</interface>\n";
 
+#define DBUS_INTERFACE_PROPERTIES	"org.freedesktop.DBus.Properties"
+
 struct _dbus_method {
 	l_dbus_interface_method_cb_t cb;
 	uint32_t flags;
@@ -510,6 +512,8 @@ static bool match_interface_instance(const void *a, const void *b)
 	return false;
 }
 
+static void properties_setup_func(struct l_dbus_interface *);
+
 struct _dbus_object_tree *_dbus_object_tree_new()
 {
 	struct _dbus_object_tree *tree;
@@ -527,6 +531,10 @@ struct _dbus_object_tree *_dbus_object_tree_new()
 
 	tree->root = l_new(struct object_node, 1);
 
+	_dbus_object_tree_register_interface(tree, DBUS_INTERFACE_PROPERTIES,
+						properties_setup_func, NULL,
+						false);
+
 	return tree;
 }
 
@@ -725,6 +733,7 @@ bool _dbus_object_tree_prune_node(struct _dbus_object_tree *tree,
 	return true;
 }
 
+/* Send the signals associated with a property value change */
 void _dbus_object_tree_property_changed(struct l_dbus *dbus,
 					const char *path,
 					const char *interface_name,
@@ -735,6 +744,7 @@ void _dbus_object_tree_property_changed(struct l_dbus *dbus,
 	struct l_dbus_message_builder *builder;
 	char signature[256];
 	struct l_dbus_interface *interface;
+	struct object_node *object;
 	struct l_dbus_message_iter value;
 	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
 
@@ -762,6 +772,37 @@ void _dbus_object_tree_property_changed(struct l_dbus *dbus,
 		l_dbus_message_builder_destroy(builder);
 		l_dbus_send(dbus, signal);
 	}
+
+	object = l_hashmap_lookup(tree->objects, path);
+
+	if (l_queue_find(object->instances, match_interface_instance,
+				DBUS_INTERFACE_PROPERTIES)) {
+		memcpy(&value, variant, sizeof(value));
+
+		signal = l_dbus_message_new_signal(dbus, path,
+						DBUS_INTERFACE_PROPERTIES,
+						"PropertiesChanged");
+
+		builder = l_dbus_message_builder_new(signal);
+
+		l_dbus_message_builder_append_basic(builder, 's',
+							interface_name);
+		l_dbus_message_builder_enter_array(builder, "{sv}");
+		l_dbus_message_builder_enter_dict(builder, "sv");
+		l_dbus_message_builder_append_basic(builder, 's',
+							property_name);
+		l_dbus_message_builder_enter_variant(builder, signature);
+		l_dbus_message_builder_append_from_iter(builder, &value);
+		l_dbus_message_builder_leave_variant(builder);
+		l_dbus_message_builder_leave_dict(builder);
+		l_dbus_message_builder_leave_array(builder);
+		l_dbus_message_builder_enter_array(builder, "s");
+		l_dbus_message_builder_leave_array(builder);
+
+		l_dbus_message_builder_finalize(builder);
+		l_dbus_message_builder_destroy(builder);
+		l_dbus_send(dbus, signal);
+	}
 }
 
 static void set_property_complete(struct l_dbus *dbus,
@@ -1224,3 +1265,249 @@ bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree,
 
 	return true;
 }
+
+static void properties_get_complete(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message *error)
+{
+	struct get_properties_state *state;
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+
+	state = l_hashmap_lookup(tree->property_requests, message);
+
+	l_dbus_message_builder_leave_variant(state->builder);
+
+	get_properties_done(dbus, state, error);
+}
+
+static struct l_dbus_message *properties_get(struct l_dbus *dbus,
+						struct l_dbus_message *message,
+						void *user_data)
+{
+	struct l_dbus_interface *interface;
+	struct interface_instance *instance;
+	const char *interface_name, *property_name, *signature;
+	struct _dbus_property *property;
+	struct get_properties_state *state;
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+	struct object_node *object;
+
+	if (!l_dbus_message_get_arguments(message, "ss", &interface_name,
+						&property_name))
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Invalid arguments");
+
+	interface = l_hashmap_lookup(tree->interfaces, interface_name);
+	if (!interface)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Unknown Interface %s",
+						interface_name);
+
+	property = _dbus_interface_find_property(interface, property_name);
+	if (!property)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Unknown Property %s",
+						property_name);
+
+	object = l_hashmap_lookup(tree->objects,
+					l_dbus_message_get_path(message));
+	/* If we got here the object must exist */
+
+	instance = l_queue_find(object->instances,
+				match_interface_instance,
+				(char *) interface_name);
+	if (!instance)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Object has no interface %s",
+						interface_name);
+
+	state = l_new(struct get_properties_state, 1);
+
+	state->message = l_dbus_message_ref(message);
+	state->reply = l_dbus_message_new_method_return(message);
+	state->builder = l_dbus_message_builder_new(state->reply);
+
+	l_hashmap_insert(tree->property_requests, message, state);
+
+	signature = property->metainfo + strlen(property->metainfo) + 1;
+
+	l_dbus_message_builder_enter_variant(state->builder,
+						signature);
+
+	property->getter(dbus, state->message, state->builder,
+				properties_get_complete, instance->user_data);
+
+	return NULL;
+}
+
+static void properties_set_complete(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message *error)
+{
+	struct l_dbus_message *reply;
+	const char *interface_name, *property_name;
+	struct l_dbus_message_iter variant;
+
+	if (error) {
+		l_dbus_message_unref(message);
+
+		l_dbus_send(dbus, error);
+
+		return;
+	}
+
+	reply = l_dbus_message_new_method_return(message);
+	l_dbus_message_set_arguments(reply, "");
+	l_dbus_send(dbus, reply);
+
+	l_dbus_message_get_arguments(message, "ssv", &interface_name,
+					&property_name, &variant);
+
+	_dbus_object_tree_property_changed(dbus,
+					l_dbus_message_get_path(message),
+					interface_name, property_name,
+					&variant);
+
+	l_dbus_message_unref(message);
+}
+
+static struct l_dbus_message *properties_set(struct l_dbus *dbus,
+						struct l_dbus_message *message,
+						void *user_data)
+{
+	struct l_dbus_interface *interface;
+	struct interface_instance *instance;
+	const char *interface_name, *property_name;
+	struct _dbus_property *property;
+	struct l_dbus_message_iter variant;
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+	struct object_node *object;
+
+	if (!l_dbus_message_get_arguments(message, "ssv", &interface_name,
+						&property_name, &variant))
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Invalid arguments");
+
+	interface = l_hashmap_lookup(tree->interfaces, interface_name);
+	if (!interface)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Unknown Interface %s",
+						interface_name);
+
+	property = _dbus_interface_find_property(interface, property_name);
+	if (!property)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Unknown Property %s",
+						property_name);
+
+	if (!property->setter)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Property %s is read-only",
+						property_name);
+
+	object = l_hashmap_lookup(tree->objects,
+					l_dbus_message_get_path(message));
+	/* If we got here the object must exist */
+
+	instance = l_queue_find(object->instances,
+				match_interface_instance,
+				(char *) interface_name);
+	if (!instance)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Object has no interface %s",
+						interface_name);
+
+	property->setter(dbus, l_dbus_message_ref(message), &variant,
+				properties_set_complete, instance->user_data);
+
+	return NULL;
+}
+
+static struct l_dbus_message *properties_get_all(struct l_dbus *dbus,
+						struct l_dbus_message *message,
+						void *user_data)
+{
+	struct l_dbus_interface *interface;
+	struct interface_instance *instance;
+	const char *interface_name;
+	struct get_properties_state *state;
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+	struct object_node *object;
+
+	if (!l_dbus_message_get_arguments(message, "s", &interface_name))
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Invalid arguments");
+
+	interface = l_hashmap_lookup(tree->interfaces, interface_name);
+	if (!interface)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Unknown Interface %s",
+						interface_name);
+
+	object = l_hashmap_lookup(tree->objects,
+					l_dbus_message_get_path(message));
+	/* If we got here the object must exist */
+
+	instance = l_queue_find(object->instances,
+				match_interface_instance,
+				(char *) interface_name);
+	if (!instance)
+		return l_dbus_message_new_error(message,
+						"org.freedesktop.DBus.Error."
+						"InvalidArgs",
+						"Object has no interface %s",
+						interface_name);
+
+	state = l_new(struct get_properties_state, 1);
+
+	state->instance = instance;
+	state->done = get_properties_done;
+	state->message = l_dbus_message_ref(message);
+	state->reply = l_dbus_message_new_method_return(message);
+	state->entry = l_queue_get_entries(interface->properties);
+	state->builder = l_dbus_message_builder_new(state->reply);
+	state->user_data = instance->user_data;
+
+	get_properties_dict(dbus, state);
+
+	return NULL;
+}
+
+static void properties_setup_func(struct l_dbus_interface *interface)
+{
+	l_dbus_interface_method(interface, "Get", 0,
+				properties_get, "v", "ss",
+				"value", "interface_name", "property_name");
+	l_dbus_interface_method(interface, "Set", 0,
+				properties_set, "", "ssv",
+				"interface_name", "property_name", "value");
+	l_dbus_interface_method(interface, "GetAll", 0,
+				properties_get_all, "a{sv}", "s",
+				"props", "interface_name");
+
+	l_dbus_interface_signal(interface, "PropertiesChanged", 0, "sa{sv}as",
+				"interface_name", "changed_properties",
+				"invalidated_properties");
+}
diff --git a/ell/dbus.c b/ell/dbus.c
index 70c6f32..6a55d42 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -51,7 +51,6 @@
 
 #define DBUS_INTERFACE_DBUS		"org.freedesktop.DBus"
 #define DBUS_INTERFACE_INTROSPECTABLE	"org.freedesktop.DBus.Introspectable"
-#define DBUS_INTERFACE_PROPERTIES	"org.freedesktop.DBus.Properties"
 
 #define DBUS_MAXIMUM_MATCH_RULE_LENGTH	1024
 
diff --git a/examples/dbus-service.c b/examples/dbus-service.c
index 2158bec..6a838cc 100644
--- a/examples/dbus-service.c
+++ b/examples/dbus-service.c
@@ -236,6 +236,13 @@ int main(int argc, char *argv[])
 		goto cleanup;
 	}
 
+	if (!l_dbus_object_add_interface(dbus, "/test",
+				"org.freedesktop.DBus.Properties", NULL)) {
+		l_info("Unable to instantiate the properties interface");
+		test_data_destroy(test);
+		goto cleanup;
+	}
+
 	l_main_run();
 
 	l_dbus_unregister_object(dbus, "/test");
-- 
2.5.0


      parent reply	other threads:[~2016-02-01 14:07 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-01 14:07 [PATCH 1/8] dbus: More complete checks when removing nodes Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 2/8] unit: Update _dbus_object_tree_prune_node call parameters Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 3/8] dbus: setters and getters API for properties Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 4/8] dbus: Separate interface registration from instantiation Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 5/8] dbus: Message builder function to copy from an iter Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 6/8] dbus: Private function to retrieve the tree for a connection Andrew Zaborowski
2016-02-01 14:07 ` [PATCH 7/8] dbus: Handle legacy GetProperties and SetProperty automatically Andrew Zaborowski
2016-02-01 14:07 ` Andrew Zaborowski [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1454335644-17088-8-git-send-email-andrew.zaborowski@intel.com \
    --to=andrew.zaborowski@intel.com \
    --cc=ell@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.