>From 334390727b4cb1fc88935a90e4be79c6b3ff07c6 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 25 Feb 2014 18:31:03 +0100 Subject: [PATCH 4/9] SBUS: Start implementing property access This patch adds the basis of SBUS getters and setters. A new module, sssd_dbus_properties.c would contain handlers for the property methods like Get, Set and GetAll. Type-safe property access works in a similar fashion like type-safe method calls - the invoker calls the getter which returns the primitive type, which is in turn marshalled into variant by the invoker. This patch does not contain the complete functionality, see later patches that continue implementing the getters and setters. --- Makefile.am | 1 + src/sbus/sbus_codegen | 72 +++++++++++++++--- src/sbus/sssd_dbus.h | 4 + src/sbus/sssd_dbus_connection.c | 17 +++-- src/sbus/sssd_dbus_meta.h | 2 + src/sbus/sssd_dbus_private.h | 8 ++ src/sbus/sssd_dbus_properties.c | 122 +++++++++++++++++++++++++++++++ src/tests/sbus_codegen_tests_generated.c | 4 +- src/util/util_errors.c | 1 + src/util/util_errors.h | 1 + 10 files changed, 213 insertions(+), 19 deletions(-) create mode 100644 src/sbus/sssd_dbus_properties.c diff --git a/Makefile.am b/Makefile.am index 483584e5320bfcd8e262ed03d9be7fa670a38932..138caf841ddb9b8f224fa30fa2dab1a49330c314 100644 --- a/Makefile.am +++ b/Makefile.am @@ -621,6 +621,7 @@ libsss_util_la_SOURCES = \ src/sbus/sssd_dbus_connection.c \ src/sbus/sssd_dbus_meta.c \ src/sbus/sssd_dbus_introspect.c \ + src/sbus/sssd_dbus_properties.c \ src/sbus/sssd_dbus_request.c \ src/sbus/sssd_dbus_server.c \ src/util/util.c \ diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen index 6c4b8ec9a1f64cc243afb0fe5d12617b3ef586f0..96248a62886ad03439b4a4996f4668c1b610d990 100755 --- a/src/sbus/sbus_codegen +++ b/src/sbus/sbus_codegen @@ -114,10 +114,9 @@ BASIC_TYPES = { 'o': ( "DBUS_TYPE_OBJECT_PATH", "const char *", "const char *" ), } -class Arg(Base): - def __init__(self, method, name, type): +class Typed(Base): + def __init__(self, name, type): Base.__init__(self, name) - self.method = method self.type = type self.is_basic = False self.is_array = False @@ -135,6 +134,11 @@ class Arg(Base): else: self.is_basic = True +class Arg(Typed): + def __init__(self, method, name, type): + Typed.__init__(self, name, type) + self.method = method + class Method(Base): def __init__(self, iface, name): Base.__init__(self, name) @@ -166,11 +170,10 @@ class Signal(Base): def fq_c_name(self): return "%s_%s" % (self.iface.c_name(), self.c_name()) -class Property(Base): - def __init__(self, iface, name, signature, access): - Base.__init__(self, name) +class Property(Typed): + def __init__(self, iface, name, type, access): + Typed.__init__(self, name, type) self.iface = iface - self.signature = signature self.readable = False self.writable = False if access == 'readwrite': @@ -234,7 +237,7 @@ def method_function_pointer(meth, name, with_names=False): with_names and "data" or "", method_arg_types(meth.in_args, with_names)) -def forward_invoker(signature, args): +def forward_method_invoker(signature, args): out("") out("/* invokes a handler with a '%s' DBus signature */", signature) out("static int invoke_%s_method(struct sbus_request *dbus_req, void *function_ptr);", signature) @@ -275,6 +278,53 @@ def source_method_invoker(signature, args): out(");") out("}") +def source_getter_invoker(prop): + out("") + out("/* invokes a getter with a '%s' DBus type */", type) + out("static int invoke_%s_getter(struct sbus_request *request, struct sbus_interface *intf, void *function_ptr)", prop.type) + out("{") + out(" DBusError error = DBUS_ERROR_INIT;") + out(" int ret;") + for i in range(0, len(args)): + arg = args[i] + if arg.is_array: + out(" %s *arg_%d;", arg.dbus_type, i) + out(" int len_%d;", i) + else: + out(" %s arg_%d;", arg.dbus_type, i) + out(" int (*handler)(struct sbus_request *, void *%s) = function_ptr;", method_arg_types(args)) + out("") + out(" if (!dbus_message_get_args(request->message, &error,") + for i in range(0, len(args)): + arg = args[i] + if arg.is_array: + out(" DBUS_TYPE_ARRAY, %s, &arg_%d, &len_%d,", + arg.dbus_constant, i, i) + else: + out(" %s, &arg_%d,", arg.dbus_constant, i) + out(" DBUS_TYPE_INVALID)) {") + out(" ret = sbus_request_fail_and_finish(request, error.name, error.message);") + out(" dbus_error_free(&error);") + out(" return ret;") + out(" }") + out("") + + out(" ret = (handler)(request, intf", new_line=False) + for i in range(0, len(args)): + arg = args[i] + out(",\n arg_%d", i, new_line=False) + if arg.is_array: + out(",\n len_%d", i, new_line=False) + out(");") + out("") + + for i in range(0, len(args)): + arg = args[i] + if arg.type in ["as", "ao"]: + out(" dbus_free_string_array((char **)arg_%d);", i) + out(" return ret;") + out("}") + def forward_method_invokers(ifaces): invokers = { } for iface in ifaces: @@ -284,7 +334,7 @@ def forward_method_invokers(ifaces): signature = meth.in_signature() if signature in invokers: continue - forward_invoker(signature, meth.in_args) + forward_method_invoker(signature, meth.in_args) invokers[signature] = meth return invokers @@ -392,7 +442,7 @@ def source_properties(iface, properties): for prop in properties: out(" {") out(" \"%s\", /* name */", prop.name) - out(" \"%s\", /* signature */", prop.signature) + out(" \"%s\", /* type */", prop.type) if prop.readable and prop.writable: out(" SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,") elif prop.readable: @@ -480,8 +530,6 @@ def header_vtable(iface, methods): for meth in iface.methods: out(" %s;", method_function_pointer(meth, meth.c_name(), with_names=True)) - # TODO: Property getters and setters will go here - out("};") def header_constants(iface): diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h index a19f1d9c65656ce38e0e587b6cf71c3c947f4593..9c236479e5474b884d8e051ea221c77a40ed6ac7 100644 --- a/src/sbus/sssd_dbus.h +++ b/src/sbus/sssd_dbus.h @@ -80,6 +80,9 @@ struct sbus_vtable { #define DBUS_INTROSPECT_INTERFACE "org.freedesktop.DBus.Introspectable" #define DBUS_INTROSPECT_METHOD "Introspect" +/* Special interface and method for D-BUS properties */ +#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" + struct sbus_interface { const char *path; struct sbus_vtable *vtable; @@ -257,6 +260,7 @@ int sbus_request_return_array_as_variant(struct sbus_request *dbus_req, const size_t item_size); /* + * Return an error for a DBus method call request. The @error is a normal * DBusError. * diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c index 4d3782e56770d6ea1c16837a91089417dddba755..af1c8c56afee7a033e90bc6b2e92c7d8258139a0 100644 --- a/src/sbus/sssd_dbus_connection.c +++ b/src/sbus/sssd_dbus_connection.c @@ -437,6 +437,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, /* Validate the method interface */ if (strcmp(msg_interface, intf_p->intf->vtable->meta->name) == 0 || + strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0 || (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 && strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0)) { @@ -510,11 +511,7 @@ static void sbus_handler_got_caller_id(struct tevent_req *req) dbus_error = DBUS_ERROR_NOT_SUPPORTED; goto fail; } - } else { - /* Special case: check for Introspection request - * This is usually only useful for system bus connections - */ - if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 && + } else if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 && strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0) { DEBUG(SSSDBG_TRACE_LIBS, "Got introspection request\n"); ictx = talloc(dbus_req->conn, struct sbus_introspect_ctx); @@ -527,7 +524,17 @@ static void sbus_handler_got_caller_id(struct tevent_req *req) ictx->iface = interface; handler_data = ictx; method = &introspect_method; + } else if (strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0) { + ret = sbus_properties_dispatch(dbus_req); + if (ret == ERR_SBUS_NOSUP) { + /* No known method matched */ + dbus_error = DBUS_ERROR_NOT_SUPPORTED; + goto fail; } + /* sbus_properties_dispatch handles all other errors + * or success internally + */ + return; } if (handler_fn == NULL) { diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h index 997aa9e464df91d2378ae42fcf7fdaaa05a9a2f3..0ad21df97f8cb321628896f0e06088db4533101a 100644 --- a/src/sbus/sssd_dbus_meta.h +++ b/src/sbus/sssd_dbus_meta.h @@ -60,6 +60,8 @@ struct sbus_property_meta { const char *name; const char *type; int flags; + size_t vtable_offset_set; + sbus_method_invoker_fn invoker_set; }; struct sbus_signal_meta { diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h index 65189b5ff980e34e653a0bc10760290a223e60b6..fa11bc1c8ef625ba6c6e9382d7ccd146eabdbb26 100644 --- a/src/sbus/sssd_dbus_private.h +++ b/src/sbus/sssd_dbus_private.h @@ -68,6 +68,10 @@ struct sbus_connection { struct sbus_watch_ctx *watch_list; }; +/* Looks up a vtable func, in a struct derived from struct sbus_vtable */ +#define VTABLE_FUNC(vtable, offset) \ + (*((void **)((char *)(vtable) + (offset)))) + /* =Watches=============================================================== */ struct sbus_watch_ctx { @@ -137,4 +141,8 @@ struct tevent_req *sbus_get_sender_id_send(TALLOC_CTX *mem_ctx, const char *sender); int sbus_get_sender_id_recv(struct tevent_req *req, int64_t *_uid); +/* =Properties============================================================ */ + +int sbus_properties_dispatch(struct sbus_request *dbus_req); + #endif /* _SSSD_DBUS_PRIVATE_H_ */ diff --git a/src/sbus/sssd_dbus_properties.c b/src/sbus/sssd_dbus_properties.c new file mode 100644 index 0000000000000000000000000000000000000000..835b3078b5abd124ab98265401aa48533a306ee3 --- /dev/null +++ b/src/sbus/sssd_dbus_properties.c @@ -0,0 +1,122 @@ +/* + Authors: + Stef Walter + + Copyright (C) 2014 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "util/util.h" +#include "sbus/sssd_dbus.h" +#include "sbus/sssd_dbus_meta.h" +#include "sbus/sssd_dbus_private.h" + +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; +} + +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); + } + + return ERR_SBUS_NOSUP; +} diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c index 4ba2577489ddb2e1c7c72a37b97561946f4f23b8..40d40cdc471b90f6b0d3fb52033f7ec9817c1772 100644 --- a/src/tests/sbus_codegen_tests_generated.c +++ b/src/tests/sbus_codegen_tests_generated.c @@ -94,7 +94,7 @@ const struct sbus_signal_meta com_planetexpress_Ship__signals[] = { const struct sbus_property_meta com_planetexpress_Ship__properties[] = { { "Color", /* name */ - "s", /* signature */ + "s", /* type */ SBUS_PROPERTY_READABLE, }, { NULL, } @@ -231,7 +231,7 @@ const struct sbus_method_meta test_pilot__methods[] = { const struct sbus_property_meta test_pilot__properties[] = { { "FullName", /* name */ - "s", /* signature */ + "s", /* type */ SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE, }, { NULL, } diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 2b99faf747515f00677273b8630ff49a742e738d..113567423007cb39d3314ddfad9ba168fddb4f63 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -59,6 +59,7 @@ struct err_string error_to_str[] = { { "Cannot get bus message sender" }, /* ERR_SBUS_GET_SENDER_ERROR */ { "Bus message has no sender" }, /* ERR_SBUS_NO_SENDER */ { "User/Group SIDs not found" }, /* ERR_NO_SIDS */ + { "Bus method not supported" }, /* ERR_SBUS_NOSUP */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index da518272b8a6a8b89a91cddabfa8e0d21fc05e7b..b88c7969bea90208ccb61cc1240b181cc0330774 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -81,6 +81,7 @@ enum sssd_errors { ERR_SBUS_GET_SENDER_ERROR, ERR_SBUS_NO_SENDER, ERR_NO_SIDS, + ERR_SBUS_NOSUP, ERR_LAST /* ALWAYS LAST */ }; -- 1.9.0