diff options
Diffstat (limited to 'src')
-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 |
9 files changed, 212 insertions, 19 deletions
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 */ }; |