diff options
author | Stef Walter <stefw@redhat.com> | 2014-02-25 18:31:03 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2014-05-22 17:36:17 +0200 |
commit | 1319e71fd1680ca4864afe0b1aca2b8c8e4a1ee4 (patch) | |
tree | c507661a871ac03ca52c477a5a14bc570cfb18c1 | |
parent | e412c809508be9cdd30da679b92ed9f7292357e9 (diff) | |
download | sssd-1319e71fd1680ca4864afe0b1aca2b8c8e4a1ee4.tar.gz sssd-1319e71fd1680ca4864afe0b1aca2b8c8e4a1ee4.tar.xz sssd-1319e71fd1680ca4864afe0b1aca2b8c8e4a1ee4.zip |
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.
Reviewed-by: Stef Walter <stefw@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-rw-r--r-- | Makefile.am | 1 | ||||
-rwxr-xr-x | src/sbus/sbus_codegen | 72 | ||||
-rw-r--r-- | src/sbus/sssd_dbus.h | 4 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_connection.c | 17 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_meta.h | 2 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_private.h | 8 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_properties.c | 122 | ||||
-rw-r--r-- | src/tests/sbus_codegen_tests_generated.c | 4 | ||||
-rw-r--r-- | src/util/util_errors.c | 1 | ||||
-rw-r--r-- | src/util/util_errors.h | 1 |
10 files changed, 213 insertions, 19 deletions
diff --git a/Makefile.am b/Makefile.am index 483584e53..138caf841 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 6c4b8ec9a..96248a628 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 a19f1d9c6..9c236479e 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 4d3782e56..af1c8c56a 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 997aa9e46..0ad21df97 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 65189b5ff..fa11bc1c8 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 000000000..835b3078b --- /dev/null +++ b/src/sbus/sssd_dbus_properties.c @@ -0,0 +1,122 @@ +/* + Authors: + Stef Walter <stefw@redhat.com> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#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 4ba257748..40d40cdc4 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 2b99faf74..113567423 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 da518272b..b88c7969b 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 */ }; |