diff options
author | Pavel Březina <pbrezina@redhat.com> | 2014-12-14 19:02:49 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2015-01-23 21:29:44 +0100 |
commit | b742179ac0790068380618ab72a06af18544f09c (patch) | |
tree | 6215aaf93ac5594205481da9d5a746be0be86eaf /src | |
parent | 80d0bd38268c02fd32f62b02ae59f19229ca1a79 (diff) | |
download | sssd-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.c | 11 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_private.h | 6 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_properties.c | 515 | ||||
-rw-r--r-- | src/tests/sbus_codegen_tests.c | 2 | ||||
-rw-r--r-- | src/tests/sbus_tests.c | 16 |
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" \ |