summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2014-12-14 19:02:49 +0100
committerJakub Hrozek <jhrozek@redhat.com>2015-01-23 21:29:44 +0100
commitb742179ac0790068380618ab72a06af18544f09c (patch)
tree6215aaf93ac5594205481da9d5a746be0be86eaf /src
parent80d0bd38268c02fd32f62b02ae59f19229ca1a79 (diff)
downloadsssd-b742179ac0790068380618ab72a06af18544f09c.tar.gz
sssd-b742179ac0790068380618ab72a06af18544f09c.tar.xz
sssd-b742179ac0790068380618ab72a06af18544f09c.zip
sbus: support org.freedesktop.DBus.Properties
Bring back org.freedesktop.DBus.Properties with support of multiple interfaces on single object path. Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/sbus/sssd_dbus_interface.c11
-rw-r--r--src/sbus/sssd_dbus_private.h6
-rw-r--r--src/sbus/sssd_dbus_properties.c515
-rw-r--r--src/tests/sbus_codegen_tests.c2
-rw-r--r--src/tests/sbus_tests.c16
5 files changed, 328 insertions, 222 deletions
diff --git a/src/sbus/sssd_dbus_interface.c b/src/sbus/sssd_dbus_interface.c
index b67431d66..0a652ba4d 100644
--- a/src/sbus/sssd_dbus_interface.c
+++ b/src/sbus/sssd_dbus_interface.c
@@ -306,7 +306,7 @@ sbus_opath_hash_has_path(hash_table_t *table,
* in the path hierarchy and try to lookup the parent node. This continues
* until the root is reached.
*/
-static struct sbus_interface *
+struct sbus_interface *
sbus_opath_hash_lookup_iface(hash_table_t *table,
const char *object_path,
const char *iface_name)
@@ -549,8 +549,17 @@ sbus_conn_register_iface(struct sbus_connection *conn,
}
/* register standard interfaces with this object path as well */
+ ret = sbus_conn_register_iface(conn, sbus_properties_vtable(),
+ object_path, conn);
+ if (ret != EOK) {
+ return ret;
+ }
+
ret = sbus_conn_register_iface(conn, sbus_introspect_vtable(),
object_path, conn);
+ if (ret != EOK) {
+ return ret;
+ }
return ret;
}
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index 62c2d6f9e..24b6bec18 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -69,6 +69,7 @@ struct sbus_connection {
/* =Standard=interfaces=================================================== */
struct sbus_vtable *sbus_introspect_vtable(void);
+struct sbus_vtable *sbus_properties_vtable(void);
/* =Watches=============================================================== */
@@ -117,6 +118,11 @@ sbus_opath_hash_init(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn,
hash_table_t **_table);
+struct sbus_interface *
+sbus_opath_hash_lookup_iface(hash_table_t *table,
+ const char *object_path,
+ const char *iface_name);
+
errno_t
sbus_opath_hash_lookup_supported(TALLOC_CTX *mem_ctx,
hash_table_t *table,
diff --git a/src/sbus/sssd_dbus_properties.c b/src/sbus/sssd_dbus_properties.c
index c6bdffda7..bdaef4591 100644
--- a/src/sbus/sssd_dbus_properties.c
+++ b/src/sbus/sssd_dbus_properties.c
@@ -1,6 +1,7 @@
/*
Authors:
Stef Walter <stefw@redhat.com>
+ Pavel Březina <pbrezina@redhat.com>
Copyright (C) 2014 Red Hat
@@ -18,11 +19,306 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
#include "util/util.h"
#include "sbus/sssd_dbus.h"
#include "sbus/sssd_dbus_meta.h"
#include "sbus/sssd_dbus_private.h"
+#define CHECK_SIGNATURE_OR_FAIL(req, error, label, exp) do { \
+ const char *__sig; \
+ __sig = dbus_message_get_signature(req->message); \
+ if (strcmp(__sig, exp) != 0) { \
+ error = sbus_error_new(req, DBUS_ERROR_INVALID_ARGS, \
+ "Invalid arguments: expected \"%s\", got \"%s\"", exp, __sig); \
+ goto label; \
+ } \
+} while (0)
+
+struct iface_properties {
+ struct sbus_vtable vtable; /* derive from sbus_vtable */
+ sbus_msg_handler_fn Get;
+ sbus_msg_handler_fn Set;
+ sbus_msg_handler_fn GetAll;
+};
+
+static int sbus_properties_get(struct sbus_request *sbus_req, void *pvt);
+static int sbus_properties_set(struct sbus_request *sbus_req, void *pvt);
+static int sbus_properties_get_all(struct sbus_request *sbus_req, void *pvt);
+
+struct sbus_vtable *
+sbus_properties_vtable(void)
+{
+ /* Properties.Get */
+ static const struct sbus_arg_meta get_args_in[] = {
+ { "interface_name", "s" },
+ { "property_name", "s" },
+ { NULL, }
+ };
+
+ static const struct sbus_arg_meta get_args_out[] = {
+ { "value", "v" },
+ { NULL, }
+ };
+
+ /* Properties.Set */
+ static const struct sbus_arg_meta set_args_in[] = {
+ { "interface_name", "s" },
+ { "property_name", "s" },
+ { "value", "v" },
+ { NULL, }
+ };
+
+ /* Properties.GetAll */
+ static const struct sbus_arg_meta getall_args_in[] = {
+ { "interface_name", "s" },
+ { NULL, }
+ };
+
+ static const struct sbus_arg_meta getall_args_out[] = {
+ { "props", "a{sv}" },
+ { NULL, }
+ };
+
+ static const struct sbus_method_meta iface_methods[] = {
+ {
+ "Get", /* name */
+ get_args_in,
+ get_args_out,
+ offsetof(struct iface_properties, Get),
+ NULL, /* no invoker */
+ },
+ {
+ "Set", /* name */
+ set_args_in,
+ NULL, /* no out_args */
+ offsetof(struct iface_properties, Set),
+ NULL, /* no invoker */
+ },
+ {
+ "GetAll", /* name */
+ getall_args_in,
+ getall_args_out,
+ offsetof(struct iface_properties, GetAll),
+ NULL, /* no invoker */
+ },
+ { NULL, }
+ };
+
+ static const struct sbus_interface_meta iface_meta = {
+ "org.freedesktop.DBus.Properties", /* name */
+ iface_methods,
+ NULL, /* no signals */
+ NULL, /* no properties */
+ NULL, /* no GetAll invoker */
+ };
+
+ static struct iface_properties iface = {
+ { &iface_meta, 0 },
+ .Get = sbus_properties_get,
+ .Set = sbus_properties_set,
+ .GetAll = sbus_properties_get_all,
+ };
+
+ return &iface.vtable;
+}
+
+static int sbus_properties_invoke(struct sbus_request *sbus_req,
+ struct sbus_interface *iface,
+ sbus_msg_handler_fn handler_fn,
+ void *handler_data,
+ sbus_method_invoker_fn invoker_fn)
+{
+ struct sbus_request *sbus_subreq;
+
+ /* Create new sbus_request to so it contain given interface. The
+ * old sbus_request talloc context will be attached to this new one
+ * so it is freed together. */
+ sbus_subreq = sbus_new_request(sbus_req->conn, iface, sbus_req->message);
+ if (sbus_subreq == NULL) {
+ return ENOMEM;
+ }
+
+ talloc_steal(sbus_subreq, sbus_req);
+
+ sbus_request_invoke_or_finish(sbus_subreq, handler_fn, handler_data,
+ invoker_fn);
+
+ return EOK;
+}
+
+static int sbus_properties_get(struct sbus_request *sbus_req, void *pvt)
+{
+ DBusError *error;
+ struct sbus_connection *conn;
+ struct sbus_interface *iface;
+ const struct sbus_property_meta *prop;
+ sbus_msg_handler_fn handler_fn;
+ const char *interface_name;
+ const char *property_name;
+ bool bret;
+
+ conn = talloc_get_type(pvt, struct sbus_connection);
+
+ CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "ss");
+
+ bret = sbus_request_parse_or_finish(sbus_req,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_STRING, &property_name,
+ DBUS_TYPE_INVALID);
+ if (!bret) {
+ /* request was handled */
+ return EOK;
+ }
+
+ /* find interface */
+ iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
+ interface_name);
+ if (iface == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
+ "Unknown interface");
+ goto fail;
+ }
+
+ /* find property handler */
+ prop = sbus_meta_find_property(iface->vtable->meta, property_name);
+ if (prop == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
+ goto fail;
+ }
+
+ if (!(prop->flags & SBUS_PROPERTY_READABLE)) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_ACCESS_DENIED,
+ "Property is not readable");
+ goto fail;
+ }
+
+ handler_fn = VTABLE_FUNC(iface->vtable, prop->vtable_offset_get);
+ if (handler_fn == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_NOT_SUPPORTED,
+ "Getter is not implemented");
+ goto fail;
+ }
+
+ return sbus_properties_invoke(sbus_req, iface, handler_fn,
+ iface->instance_data, prop->invoker_get);
+
+fail:
+ return sbus_request_fail_and_finish(sbus_req, error);
+}
+
+/*
+ * We don't implement any handlers for setters yet. This code is for future
+ * use and it is likely it will need some changes.
+ */
+static int sbus_properties_set(struct sbus_request *sbus_req, void *pvt)
+{
+ DBusError *error;
+ DBusMessageIter iter;
+ DBusMessageIter iter_variant;
+ struct sbus_connection *conn;
+ struct sbus_interface *iface;
+ const struct sbus_property_meta *prop;
+ const char *interface_name;
+ const char *property_name;
+ const char *variant_sig;
+ sbus_msg_handler_fn handler_fn;
+
+ conn = talloc_get_type(pvt, struct sbus_connection);
+
+ CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "ssv");
+
+ /* get interface and property */
+ dbus_message_iter_init(sbus_req->message, &iter);
+ dbus_message_iter_get_basic(&iter, &interface_name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &property_name);
+ dbus_message_iter_next(&iter);
+
+ /* find interface */
+ iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
+ interface_name);
+ if (iface == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
+ "Unknown interface");
+ goto fail;
+ }
+
+ /* find property handler */
+ prop = sbus_meta_find_property(iface->vtable->meta, property_name);
+ if (prop == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
+ goto fail;
+ }
+
+ if (!(prop->flags & SBUS_PROPERTY_WRITABLE)) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_ACCESS_DENIED,
+ "Property is not writable");
+ goto fail;
+ }
+
+ handler_fn = VTABLE_FUNC(iface->vtable, prop->vtable_offset_set);
+ if (handler_fn == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_NOT_SUPPORTED,
+ "Setter is not implemented");
+ goto fail;
+ }
+
+ /* check variant type */
+ dbus_message_iter_recurse(&iter, &iter_variant);
+ variant_sig = dbus_message_iter_get_signature(&iter_variant);
+ if (strcmp(prop->type, variant_sig) != 0) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_INVALID_ARGS,
+ "Invalid data type for property");
+ goto fail;
+ }
+
+ return sbus_properties_invoke(sbus_req, iface, handler_fn,
+ iface->instance_data, prop->invoker_set);
+
+fail:
+ return sbus_request_fail_and_finish(sbus_req, error);
+}
+
+static int sbus_properties_get_all(struct sbus_request *sbus_req, void *pvt)
+{
+ DBusError *error;
+ struct sbus_connection *conn;
+ struct sbus_interface *iface;
+ const char *interface_name;
+ bool bret;
+
+ conn = talloc_get_type(pvt, struct sbus_connection);
+
+ CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "s");
+
+ bret = sbus_request_parse_or_finish(sbus_req,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_INVALID);
+ if (!bret) {
+ /* request was handled */
+ return EOK;
+ }
+
+ /* find interface */
+ iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
+ interface_name);
+ if (iface == NULL) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
+ "Unknown interface");
+ goto fail;
+ }
+
+ return sbus_properties_invoke(sbus_req, iface, NULL, NULL,
+ iface->vtable->meta->invoker_get_all);
+
+fail:
+ return sbus_request_fail_and_finish(sbus_req, error);
+}
+
static char *
type_to_string(char type, char *str)
{
@@ -166,222 +462,3 @@ int sbus_add_array_as_variant_to_dict(DBusMessageIter *iter_dict,
return EOK;
}
-
-static int
-dispatch_properties_set(struct sbus_connection *conn,
- struct sbus_interface *intf,
- DBusMessage *message)
-{
- const char *signature;
- const struct sbus_interface_meta *meta;
- const struct sbus_property_meta *property;
- const char *interface_name;
- const char *property_name;
- const char *type;
- struct sbus_request *req;
- sbus_msg_handler_fn handler_fn;
- DBusMessageIter iter;
- DBusMessageIter variant;
-
- req = sbus_new_request(conn, intf, message);
- if (!req)
- return ENOMEM;
-
- meta = intf->vtable->meta;
-
- signature = dbus_message_get_signature(message);
- if (strcmp (signature, "ssv") != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_INVALID_ARGS,
- "Invalid argument types passed " \
- "to Set method"));
- }
-
- dbus_message_iter_init (message, &iter);
- dbus_message_iter_get_basic (&iter, &interface_name);
- dbus_message_iter_next (&iter);
- dbus_message_iter_get_basic (&iter, &property_name);
- dbus_message_iter_next (&iter);
-
- if (strcmp (interface_name, meta->name) != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_UNKNOWN_INTERFACE,
- "No such interface"));
- }
-
- property = sbus_meta_find_property (intf->vtable->meta, property_name);
- if (property == NULL) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_UNKNOWN_PROPERTY,
- "No such property"));
- }
-
- if (!(property->flags & SBUS_PROPERTY_WRITABLE)) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_PROPERTY_READ_ONLY,
- "Property is not writable"));
- }
-
- dbus_message_iter_recurse(&iter, &variant);
- type = dbus_message_iter_get_signature (&variant);
- if (strcmp (property->type, type) != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_INVALID_ARGS,
- "Invalid data type for property"));
- }
-
- handler_fn = VTABLE_FUNC(intf->vtable, property->vtable_offset_set);
- if (!handler_fn) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_NOT_SUPPORTED,
- "Not implemented"));
- }
-
- sbus_request_invoke_or_finish(req, handler_fn,
- intf->instance_data,
- property->invoker_set);
- return EOK;
-}
-
-static int
-dispatch_properties_get(struct sbus_connection *conn,
- struct sbus_interface *intf,
- DBusMessage *message)
-{
- struct sbus_request *req;
- const char *signature;
- const struct sbus_interface_meta *meta;
- DBusMessageIter iter;
- sbus_msg_handler_fn handler_fn;
- const struct sbus_property_meta *property;
- const char *interface_name;
- const char *property_name;
-
- req = sbus_new_request(conn, intf, message);
- if (req == NULL) {
- return ENOMEM;
- }
-
- meta = intf->vtable->meta;
-
- signature = dbus_message_get_signature(message);
- /* Interface name, property name */
- if (strcmp(signature, "ss") != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_INVALID_ARGS,
- "Invalid argument types passed to Get method"));
- }
-
- dbus_message_iter_init(message, &iter);
- dbus_message_iter_get_basic(&iter, &interface_name);
- dbus_message_iter_next(&iter);
- dbus_message_iter_get_basic(&iter, &property_name);
-
- if (strcmp(interface_name, meta->name) != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_UNKNOWN_INTERFACE,
- "No such interface"));
- }
-
- property = sbus_meta_find_property(intf->vtable->meta, property_name);
- if (property == NULL) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_UNKNOWN_PROPERTY,
- "No such property"));
- }
-
- if (!(property->flags & SBUS_PROPERTY_READABLE)) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_ACCESS_DENIED,
- "Property is not readable"));
- }
-
- handler_fn = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
- if (!handler_fn) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_NOT_SUPPORTED,
- "Not implemented"));
- }
-
- sbus_request_invoke_or_finish(req, handler_fn,
- intf->instance_data,
- property->invoker_get);
- return EOK;
-}
-
-static int
-dispatch_properties_get_all(struct sbus_connection *conn,
- struct sbus_interface *intf,
- DBusMessage *message)
-{
- struct sbus_request *req;
- const char *signature;
- const struct sbus_interface_meta *meta;
- const char *interface_name;
- DBusMessageIter iter;
-
- req = sbus_new_request(conn, intf, message);
- if (req == NULL) {
- return ENOMEM;
- }
-
- meta = intf->vtable->meta;
-
- signature = dbus_message_get_signature(message);
- /* Interface name */
- if (strcmp(signature, "s") != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_INVALID_ARGS,
- "Invalid argument types passed " \
- "to GetAll method"));
- }
-
- dbus_message_iter_init(message, &iter);
- dbus_message_iter_get_basic(&iter, &interface_name);
-
- if (strcmp(interface_name, meta->name) != 0) {
- return sbus_request_fail_and_finish(req,
- sbus_error_new(req,
- DBUS_ERROR_UNKNOWN_INTERFACE,
- "No such interface"));
- }
-
- sbus_request_invoke_or_finish(req, NULL, NULL, meta->invoker_get_all);
- return EOK;
-}
-
-int sbus_properties_dispatch(struct sbus_request *dbus_req)
-{
- const char *member;
-
- member = dbus_message_get_member(dbus_req->message);
-
- /* Set is handled a lot like a method invocation */
- if (strcmp(member, "Set") == 0) {
- return dispatch_properties_set(dbus_req->conn,
- dbus_req->intf,
- dbus_req->message);
- } else if (strcmp (member, "Get") == 0) {
- return dispatch_properties_get(dbus_req->conn,
- dbus_req->intf,
- dbus_req->message);
- } else if (strcmp (member, "GetAll") == 0) {
- return dispatch_properties_get_all(dbus_req->conn,
- dbus_req->intf,
- dbus_req->message);
- }
-
- return ERR_SBUS_NOSUP;
-}
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index 07c62c5ef..dccb5e314 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -1353,11 +1353,9 @@ TCase *create_handler_tests(void)
TCase *tc = tcase_create("handler");
tcase_add_test(tc, test_marshal_basic_types);
-#if false
tcase_add_test(tc, test_get_basic_types);
tcase_add_test(tc, test_getall_basic_types);
tcase_add_test(tc, test_get_basic_array_types);
-#endif
return tc;
}
diff --git a/src/tests/sbus_tests.c b/src/tests/sbus_tests.c
index 04ec21847..9dda916e3 100644
--- a/src/tests/sbus_tests.c
+++ b/src/tests/sbus_tests.c
@@ -53,6 +53,22 @@
" <arg type=\"s\" name=\"data\" direction=\"out\" />\n" \
" </method>\n" \
" </interface>\n" \
+ " <interface name=\"org.freedesktop.DBus.Properties\">\n" \
+ " <method name=\"Get\">\n" \
+ " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
+ " <arg type=\"s\" name=\"property_name\" direction=\"in\" />\n" \
+ " <arg type=\"v\" name=\"value\" direction=\"out\" />\n" \
+ " </method>\n" \
+ " <method name=\"Set\">\n" \
+ " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
+ " <arg type=\"s\" name=\"property_name\" direction=\"in\" />\n" \
+ " <arg type=\"v\" name=\"value\" direction=\"in\" />\n" \
+ " </method>\n" \
+ " <method name=\"GetAll\">\n" \
+ " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
+ " <arg type=\"a{sv}\" name=\"props\" direction=\"out\" />\n" \
+ " </method>\n" \
+ " </interface>\n" \
" <interface name=\"test.Pilot\">\n" \
" <method name=\"Blink\" />\n" \
" <method name=\"Eat\" />\n" \