diff options
-rw-r--r-- | src/monitor/monitor_iface.xml | 30 | ||||
-rw-r--r-- | src/monitor/monitor_iface_generated.c | 10 | ||||
-rw-r--r-- | src/monitor/monitor_iface_generated.h | 10 | ||||
-rw-r--r-- | src/providers/data_provider_iface.xml | 27 | ||||
-rw-r--r-- | src/providers/data_provider_iface_generated.c | 9 | ||||
-rw-r--r-- | src/providers/data_provider_iface_generated.h | 10 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface.xml | 3 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.c | 1 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.h | 10 | ||||
-rwxr-xr-x | src/sbus/sbus_codegen | 215 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_connection.c | 33 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_introspect.c | 2 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_meta.h | 6 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_private.h | 8 | ||||
-rw-r--r-- | src/sbus/sssd_dbus_request.c | 30 | ||||
-rw-r--r-- | src/tests/sbus_codegen_tests.c | 40 | ||||
-rwxr-xr-x | src/tests/sbus_codegen_tests.xml | 15 | ||||
-rw-r--r-- | src/tests/sbus_codegen_tests_generated.c | 124 | ||||
-rw-r--r-- | src/tests/sbus_codegen_tests_generated.h | 32 |
19 files changed, 544 insertions, 71 deletions
diff --git a/src/monitor/monitor_iface.xml b/src/monitor/monitor_iface.xml index 506b749c8..1f61de5b7 100644 --- a/src/monitor/monitor_iface.xml +++ b/src/monitor/monitor_iface.xml @@ -4,38 +4,48 @@ <interface name="org.freedesktop.sssd.monitor"> <annotation value="mon_srv_iface" name="org.freedesktop.DBus.GLib.CSymbol"/> <method name="getVersion"> - <!-- manual argument parsing --> + <!-- manual argument parsing, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="RegisterService"> - <!-- manual argument parsing --> + <!-- manual argument parsing, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> <interface name="org.freedesktop.sssd.service"> <annotation value="mon_cli_iface" name="org.freedesktop.DBus.GLib.CSymbol"/> <method name="ping"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="resInit"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="shutDown"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="goOffline"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="resetOffline"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="rotateLogs"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="clearMemcache"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="clearEnumCache"> - <!-- no arguments --> + <!-- no arguments, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> </node> diff --git a/src/monitor/monitor_iface_generated.c b/src/monitor/monitor_iface_generated.c index 81a7c247a..e9c3c1d52 100644 --- a/src/monitor/monitor_iface_generated.c +++ b/src/monitor/monitor_iface_generated.c @@ -12,12 +12,14 @@ const struct sbus_method_meta mon_srv_iface__methods[] = { NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_srv_iface, getVersion), + NULL, /* no invoker */ }, { "RegisterService", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_srv_iface, RegisterService), + NULL, /* no invoker */ }, { NULL, } }; @@ -37,48 +39,56 @@ const struct sbus_method_meta mon_cli_iface__methods[] = { NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, ping), + NULL, /* no invoker */ }, { "resInit", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, resInit), + NULL, /* no invoker */ }, { "shutDown", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, shutDown), + NULL, /* no invoker */ }, { "goOffline", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, goOffline), + NULL, /* no invoker */ }, { "resetOffline", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, resetOffline), + NULL, /* no invoker */ }, { "rotateLogs", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, rotateLogs), + NULL, /* no invoker */ }, { "clearMemcache", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, clearMemcache), + NULL, /* no invoker */ }, { "clearEnumCache", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct mon_cli_iface, clearEnumCache), + NULL, /* no invoker */ }, { NULL, } }; diff --git a/src/monitor/monitor_iface_generated.h b/src/monitor/monitor_iface_generated.h index bd556616c..37e4d480b 100644 --- a/src/monitor/monitor_iface_generated.h +++ b/src/monitor/monitor_iface_generated.h @@ -28,15 +28,21 @@ #define MON_CLI_IFACE_CLEARENUMCACHE "clearEnumCache" /* ------------------------------------------------------------------------ - * DBus Vtable handler structures + * DBus handlers * * These structures are filled in by implementors of the different * dbus interfaces to handle method calls. * * Handler functions of type sbus_msg_handler_fn accept raw messages, - * other handlers will be typed appropriately. If a handler that is + * other handlers are typed appropriately. If a handler that is * set to NULL is invoked it will result in a * org.freedesktop.DBus.Error.NotSupported error for the caller. + * + * Handlers have a matching xxx_finish() function (unless the method has + * accepts raw messages). These finish functions the + * sbus_request_return_and_finish() with the appropriate arguments to + * construct a valid reply. Once a finish function has been called, the + * @dbus_req it was called with is freed and no longer valid. */ /* vtable for org.freedesktop.sssd.monitor */ diff --git a/src/providers/data_provider_iface.xml b/src/providers/data_provider_iface.xml index 90397f1b2..143975633 100644 --- a/src/providers/data_provider_iface.xml +++ b/src/providers/data_provider_iface.xml @@ -4,25 +4,32 @@ <interface name="org.freedesktop.sssd.dataprovider"> <annotation value="data_provider_iface" name="org.freedesktop.DBus.GLib.CSymbol"/> <method name="RegisterService"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="pamHandler"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="sudoHandler"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="autofsHandler"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="hostHandler"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="getDomains"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="getAccountInfo"> - <!-- arguments parsed manually --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> @@ -35,10 +42,12 @@ <interface name="org.freedesktop.sssd.dataprovider_rev"> <annotation value="data_provider_rev_iface" name="org.freedesktop.DBus.GLib.CSymbol"/> <method name="updateCache"> - <!-- manual argument parsing --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> <method name="initgrCheck"> - <!-- manual argument parsing --> + <!-- arguments parsed manually, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> </node> diff --git a/src/providers/data_provider_iface_generated.c b/src/providers/data_provider_iface_generated.c index 517b7adfe..e7eca7def 100644 --- a/src/providers/data_provider_iface_generated.c +++ b/src/providers/data_provider_iface_generated.c @@ -12,42 +12,49 @@ const struct sbus_method_meta data_provider_iface__methods[] = { NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, RegisterService), + NULL, /* no invoker */ }, { "pamHandler", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, pamHandler), + NULL, /* no invoker */ }, { "sudoHandler", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, sudoHandler), + NULL, /* no invoker */ }, { "autofsHandler", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, autofsHandler), + NULL, /* no invoker */ }, { "hostHandler", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, hostHandler), + NULL, /* no invoker */ }, { "getDomains", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, getDomains), + NULL, /* no invoker */ }, { "getAccountInfo", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_iface, getAccountInfo), + NULL, /* no invoker */ }, { NULL, } }; @@ -67,12 +74,14 @@ const struct sbus_method_meta data_provider_rev_iface__methods[] = { NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_rev_iface, updateCache), + NULL, /* no invoker */ }, { "initgrCheck", /* name */ NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct data_provider_rev_iface, initgrCheck), + NULL, /* no invoker */ }, { NULL, } }; diff --git a/src/providers/data_provider_iface_generated.h b/src/providers/data_provider_iface_generated.h index fc37aa8cb..976e42b89 100644 --- a/src/providers/data_provider_iface_generated.h +++ b/src/providers/data_provider_iface_generated.h @@ -27,15 +27,21 @@ #define DATA_PROVIDER_REV_IFACE_INITGRCHECK "initgrCheck" /* ------------------------------------------------------------------------ - * DBus Vtable handler structures + * DBus handlers * * These structures are filled in by implementors of the different * dbus interfaces to handle method calls. * * Handler functions of type sbus_msg_handler_fn accept raw messages, - * other handlers will be typed appropriately. If a handler that is + * other handlers are typed appropriately. If a handler that is * set to NULL is invoked it will result in a * org.freedesktop.DBus.Error.NotSupported error for the caller. + * + * Handlers have a matching xxx_finish() function (unless the method has + * accepts raw messages). These finish functions the + * sbus_request_return_and_finish() with the appropriate arguments to + * construct a valid reply. Once a finish function has been called, the + * @dbus_req it was called with is freed and no longer valid. */ /* vtable for org.freedesktop.sssd.dataprovider */ diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml index e3221b577..078d29e2d 100644 --- a/src/responder/ifp/ifp_iface.xml +++ b/src/responder/ifp/ifp_iface.xml @@ -4,7 +4,8 @@ <interface name="org.freedesktop.sssd.infopipe"> <annotation value="infopipe_iface" name="org.freedesktop.DBus.GLib.CSymbol"/> <method name="Ping"> - <!-- arguments parsed manually --> + <!-- manual argument parsing, raw handler --> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> </node> diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index db5e0e545..57c67f8bc 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -12,6 +12,7 @@ const struct sbus_method_meta infopipe_iface__methods[] = { NULL, /* no in_args */ NULL, /* no out_args */ offsetof(struct infopipe_iface, Ping), + NULL, /* no invoker */ }, { NULL, } }; diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h index 8db83fc11..f69fb162d 100644 --- a/src/responder/ifp/ifp_iface_generated.h +++ b/src/responder/ifp/ifp_iface_generated.h @@ -16,15 +16,21 @@ #define INFOPIPE_IFACE_PING "Ping" /* ------------------------------------------------------------------------ - * DBus Vtable handler structures + * DBus handlers * * These structures are filled in by implementors of the different * dbus interfaces to handle method calls. * * Handler functions of type sbus_msg_handler_fn accept raw messages, - * other handlers will be typed appropriately. If a handler that is + * other handlers are typed appropriately. If a handler that is * set to NULL is invoked it will result in a * org.freedesktop.DBus.Error.NotSupported error for the caller. + * + * Handlers have a matching xxx_finish() function (unless the method has + * accepts raw messages). These finish functions the + * sbus_request_return_and_finish() with the appropriate arguments to + * construct a valid reply. Once a finish function has been called, the + * @dbus_req it was called with is freed and no longer valid. */ /* vtable for org.freedesktop.sssd.infopipe */ diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen index d2fe5073d..6c4b8ec9a 100755 --- a/src/sbus/sbus_codegen +++ b/src/sbus/sbus_codegen @@ -91,14 +91,49 @@ class Base: raise DBusXmlException('No name on element') self.name = name self.annotations = { } + def validate(self): + pass def c_name(self): return self.annotations.get("org.freedesktop.DBus.GLib.CSymbol", self.name) +# The basic types that we support marshalling right now. These +# are the ones we can pass as basic arguments to libdbus directly. +# If the dbus and sssd types are identical we pass things directly. +# otherwise some copying is necessary. +BASIC_TYPES = { + 'y': ( "DBUS_TYPE_BYTE", "uint8_t", "uint8_t" ), + 'b': ( "DBUS_TYPE_BOOLEAN", "dbus_bool_t", "bool" ), + 'n': ( "DBUS_TYPE_INT16", "int16_t", "int16_t" ), + 'q': ( "DBUS_TYPE_UINT16", "uint16_t", "uint16_t" ), + 'i': ( "DBUS_TYPE_INT32", "int32_t", "int32_t" ), + 'u': ( "DBUS_TYPE_UINT32", "uint32_t", "uint32_t" ), + 'x': ( "DBUS_TYPE_INT64", "int64_t", "int64_t" ), + 't': ( "DBUS_TYPE_UINT64", "uint64_t", "uint64_t" ), + 'd': ( "DBUS_TYPE_DOUBLE", "double", "double" ), + 's': ( "DBUS_TYPE_STRING", "const char *", "const char *" ), + 'o': ( "DBUS_TYPE_OBJECT_PATH", "const char *", "const char *" ), +} + class Arg(Base): - def __init__(self, method, name, signature): + def __init__(self, method, name, type): Base.__init__(self, name) self.method = method - self.signature = signature + self.type = type + self.is_basic = False + self.is_array = False + self.dbus_constant = None + self.dbus_type = None + self.sssd_type = None + if type[0] == 'a': + type = type[1:] + self.is_array = True + if type in BASIC_TYPES: + (self.dbus_constant, self.dbus_type, self.sssd_type) = BASIC_TYPES[type] + # If types are not identical, we can't do array (yet) + if self.is_array: + self.is_basic = (self.dbus_type == self.sssd_type) + else: + self.is_basic = True class Method(Base): def __init__(self, iface, name): @@ -106,8 +141,22 @@ class Method(Base): self.iface = iface self.in_args = [] self.out_args = [] + def validate(self): + if not self.only_basic_args() and not self.use_raw_handler(): + raise DBusXmlException("Method has complex arguments and requires " + + "the 'org.freedesktop.sssd.RawHandler' annotation") def fq_c_name(self): return "%s_%s" % (self.iface.c_name(), self.c_name()) + def use_raw_handler(self): + anno = 'org.freedesktop.sssd.RawHandler' + return self.annotations.get(anno, self.iface.annotations.get(anno)) == 'true' + def in_signature(self): + return "".join([arg.type for arg in self.in_args]) + def only_basic_args(self): + for arg in self.in_args + self.out_args: + if not arg.is_basic: + return False + return True class Signal(Base): def __init__(self, iface, name): @@ -149,17 +198,138 @@ class Interface(Base): # ----------------------------------------------------------------------------- # Code Generation -def out(format, *args): +def out(format, *args, **kwargs): str = format % args sys.stdout.write(str) - sys.stdout.write("\n") + # NOTE: Would like to use the following syntax for this function + # but need to wait until python3 until it is supported: + # def out(format, *args, new_line=True) + if kwargs.pop("new_line", True): + sys.stdout.write("\n") + assert not kwargs, "unknown keyword argument(s): %s" % str(kwargs) + +def method_arg_types(args, with_names=False): + str = "" + for arg in args: + str += ", " + str += arg.sssd_type + if with_names: + if str[-1] != '*': + str += " " + str += "arg_" + str += arg.c_name() + if arg.is_array: + str += "[], int" + if with_names: + str += " len_" + str += arg.c_name() + return str + +def method_function_pointer(meth, name, with_names=False): + if meth.use_raw_handler(): + return "sbus_msg_handler_fn " + name + else: + return "int (*%s)(struct sbus_request *%s, void *%s%s)" % \ + (name, with_names and "req" or "", + with_names and "data" or "", + method_arg_types(meth.in_args, with_names)) + +def forward_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) + +def source_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) + out("{") + 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 (!sbus_request_parse_or_finish(dbus_req,") + 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(" return EOK; /* request handled */") + out(" }") + out("") + + out(" return (handler)(dbus_req, dbus_req->intf->instance_data", 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("}") + +def forward_method_invokers(ifaces): + invokers = { } + for iface in ifaces: + for meth in iface.methods: + if meth.use_raw_handler() or not meth.in_args: + continue + signature = meth.in_signature() + if signature in invokers: + continue + forward_invoker(signature, meth.in_args) + invokers[signature] = meth + return invokers + +def source_method_invokers(invokers): + for (signature, meth) in invokers.items(): + source_method_invoker(signature, meth.in_args) + +def source_finisher(meth): + out("") + out("int %s_finish(struct sbus_request *req%s)", + meth.fq_c_name(), method_arg_types(meth.out_args, with_names=True)) + out("{") + + for arg in meth.out_args: + if arg.dbus_type != arg.sssd_type: + out(" %s cast_%s = arg_%s;", arg.dbus_type, arg.c_name(), arg.c_name()) + + out(" return sbus_request_return_and_finish(req,") + for arg in meth.out_args: + out(" ", new_line=False) + if arg.is_array: + out("DBUS_TYPE_ARRAY, %s, &arg_%s, len_%s,", + arg.dbus_constant, arg.c_name(), arg.c_name()) + elif arg.dbus_type != arg.sssd_type: + out("%s, &cast_%s,", arg.dbus_constant, arg.c_name()) + else: + out("%s, &arg_%s,", arg.dbus_constant, arg.c_name()) + out(" DBUS_TYPE_INVALID);") + out("}") + +def header_reply(meth): + for arg in meth.out_args: + if arg.is_array: + out(" %s *%s", arg.dbus_type, arg.c_name()) + out(" int %s__len", arg.c_name()) + else: + out(" %s %s;", arg.dbus_type, arg.c_name()) + types = [arg.sssd_type for arg in meth.in_args] def source_args(parent, args, suffix): out("") out("/* arguments for %s.%s */", parent.iface.name, parent.name) out("const struct sbus_arg_meta %s%s[] = {", parent.fq_c_name(), suffix) for arg in args: - out(" { \"%s\", \"%s\" },", arg.name, arg.signature) + out(" { \"%s\", \"%s\" },", arg.name, arg.type) out(" { NULL, }") out("};") @@ -170,6 +340,9 @@ def source_methods(iface, methods): if meth.out_args: source_args(meth, meth.out_args, "__out") + if not meth.use_raw_handler(): + source_finisher(meth) + out("") out("/* methods for %s */", iface.name) out("const struct sbus_method_meta %s__methods[] = {", iface.c_name()) @@ -185,6 +358,10 @@ def source_methods(iface, methods): else: out(" NULL, /* no out_args */") out(" offsetof(struct %s, %s),", iface.c_name(), meth.c_name()) + if meth.use_raw_handler() or not meth.in_args: + out(" NULL, /* no invoker */") + else: + out(" invoke_%s_method,", meth.in_signature()) out(" },") out(" { NULL, }") out("};") @@ -264,6 +441,8 @@ def generate_source(ifaces, filename, include_header=None): if include_header: out("#include \"%s\"", os.path.basename(include_header)) + invokers = forward_method_invokers(ifaces) + for iface in ifaces: # The methods @@ -281,6 +460,16 @@ def generate_source(ifaces, filename, include_header=None): # The sbus_interface structure source_interface(iface) + source_method_invokers(invokers) + +def header_finisher(iface, meth): + if meth.use_raw_handler(): + return + out("") + out("/* finish function for %s */", meth.name) + out("int %s_finish(struct sbus_request *req%s);", + meth.fq_c_name(), method_arg_types(meth.out_args, with_names=True)) + def header_vtable(iface, methods): out("") out("/* vtable for %s */", iface.name) @@ -289,7 +478,7 @@ def header_vtable(iface, methods): # All methods for meth in iface.methods: - out(" sbus_msg_handler_fn %s;", meth.c_name()) + out(" %s;", method_function_pointer(meth, meth.c_name(), with_names=True)) # TODO: Property getters and setters will go here @@ -329,20 +518,28 @@ def generate_header(ifaces, filename): out("") out("/* ------------------------------------------------------------------------") - out(" * DBus Vtable handler structures") + out(" * DBus handlers") out(" *") out(" * These structures are filled in by implementors of the different") out(" * dbus interfaces to handle method calls.") out(" *") out(" * Handler functions of type sbus_msg_handler_fn accept raw messages,") - out(" * other handlers will be typed appropriately. If a handler that is") + out(" * other handlers are typed appropriately. If a handler that is") out(" * set to NULL is invoked it will result in a") out(" * org.freedesktop.DBus.Error.NotSupported error for the caller.") + out(" *") + out(" * Handlers have a matching xxx_finish() function (unless the method has") + out(" * accepts raw messages). These finish functions the") + out(" * sbus_request_return_and_finish() with the appropriate arguments to") + out(" * construct a valid reply. Once a finish function has been called, the") + out(" * @dbus_req it was called with is freed and no longer valid.") out(" */") for iface in ifaces: if iface.methods: header_vtable(iface, iface.methods) + for meth in iface.methods: + header_finisher(iface, meth) out("") out("/* ------------------------------------------------------------------------") @@ -505,6 +702,8 @@ class DBusXMLParser: self.cur_object_stack.append(old_cur_object) def handle_end_element(self, name): + if self.cur_object: + self.cur_object.validate() self.state = self.state_stack.pop() self.cur_object = self.cur_object_stack.pop() diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c index 16ec72f92..3cbc72437 100644 --- a/src/sbus/sssd_dbus_connection.c +++ b/src/sbus/sssd_dbus_connection.c @@ -346,18 +346,6 @@ void sbus_disconnect (struct sbus_connection *conn) DEBUG(SSSDBG_TRACE_FUNC ,"Disconnected %p\n", conn->dbus.conn); } -static int sbus_reply_internal_error(DBusMessage *message, - struct sbus_connection *conn) { - DBusMessage *reply = dbus_message_new_error(message, DBUS_ERROR_IO_ERROR, - "Internal Error"); - if (reply) { - sbus_conn_send_reply(conn, reply); - dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; - } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - /* Looks up a vtable func, in a struct derived from struct sbus_vtable */ #define VTABLE_FUNC(vtable, offset) \ (*((void **)((char *)(vtable) + (offset)))) @@ -381,7 +369,6 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, void *handler_data = NULL; /* Must be a talloc pointer! */ struct sbus_introspect_ctx *ictx = NULL; DBusHandlerResult result; - int ret; if (!user_data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -436,7 +423,11 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, DEBUG(SSSDBG_TRACE_LIBS, "Got introspection request\n"); ictx = talloc(intf_p->conn, struct sbus_introspect_ctx); if (ictx == NULL) { - result = sbus_reply_internal_error(message, intf_p->conn); + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, NULL); + sbus_conn_send_reply(intf_p->conn, reply); + dbus_message_unref(reply); + result = DBUS_HANDLER_RESULT_HANDLED; } else { handler_fn = sbus_introspect; ictx->iface = interface; @@ -448,10 +439,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, if (handler_fn) { dbus_req = sbus_new_request(intf_p->conn, intf_p->intf, message); - if (!dbus_req) { - talloc_zfree(handler_data); - ret = ENOMEM; - } else { + if (dbus_req) { dbus_req->method = method; if (handler_data) { /* If the handler uses private instance data, make @@ -464,12 +452,9 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, */ handler_data = intf_p->intf->instance_data; } - ret = handler_fn(dbus_req, handler_data); - } - if (ret != EOK) { - talloc_free(dbus_req); - result = sbus_reply_internal_error(message, intf_p->conn); - } else { + + sbus_request_invoke_or_finish(dbus_req, handler_fn, handler_data, + method->invoker); result = DBUS_HANDLER_RESULT_HANDLED; } } diff --git a/src/sbus/sssd_dbus_introspect.c b/src/sbus/sssd_dbus_introspect.c index ef0ff2fd5..c8e8c97a1 100644 --- a/src/sbus/sssd_dbus_introspect.c +++ b/src/sbus/sssd_dbus_introspect.c @@ -34,7 +34,7 @@ static const struct sbus_arg_meta introspect_method_arg_out[] = { }; const struct sbus_method_meta introspect_method = - { DBUS_INTROSPECT_METHOD, NULL, introspect_method_arg_out, 0 }; + { DBUS_INTROSPECT_METHOD, NULL, introspect_method_arg_out, 0, NULL }; #define SSS_INTROSPECT_DOCTYPE \ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \ diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h index abc992137..997aa9e46 100644 --- a/src/sbus/sssd_dbus_meta.h +++ b/src/sbus/sssd_dbus_meta.h @@ -38,11 +38,17 @@ struct sbus_arg_meta { const char *type; }; +struct sbus_request; +struct sbus_interface; + +typedef int (* sbus_method_invoker_fn)(struct sbus_request *dbus_req, void *handler_fn); + struct sbus_method_meta { const char *name; const struct sbus_arg_meta *in_args; const struct sbus_arg_meta *out_args; size_t vtable_offset; + sbus_method_invoker_fn invoker; }; enum { diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h index 6abe56c66..4916700b5 100644 --- a/src/sbus/sssd_dbus_private.h +++ b/src/sbus/sssd_dbus_private.h @@ -22,6 +22,8 @@ #ifndef _SSSD_DBUS_PRIVATE_H_ #define _SSSD_DBUS_PRIVATE_H_ +#include "sssd_dbus_meta.h" + union dbus_conn_pointer { DBusServer *server; DBusConnection *conn; @@ -107,4 +109,10 @@ struct sbus_introspect_ctx { int sbus_introspect(struct sbus_request *dbus_req, void *pvt); +void +sbus_request_invoke_or_finish(struct sbus_request *dbus_req, + sbus_msg_handler_fn handler_fn, + void *handler_data, + sbus_method_invoker_fn invoker_fn); + #endif /* _SSSD_DBUS_PRIVATE_H_ */ diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c index c45f3a9fd..1546f0ddf 100644 --- a/src/sbus/sssd_dbus_request.c +++ b/src/sbus/sssd_dbus_request.c @@ -20,10 +20,13 @@ #include "util/util.h" #include "sbus/sssd_dbus.h" +#include "sbus/sssd_dbus_private.h" #include <sys/time.h> #include <dbus/dbus.h> +static const DBusError error_internal = { DBUS_ERROR_FAILED, "Internal Error" }; + static int sbus_request_destructor(struct sbus_request *dbus_req) { dbus_message_unref(dbus_req->message); @@ -51,6 +54,33 @@ sbus_new_request(struct sbus_connection *conn, return dbus_req; } +void +sbus_request_invoke_or_finish(struct sbus_request *dbus_req, + sbus_msg_handler_fn handler_fn, + void *handler_data, + sbus_method_invoker_fn invoker_fn) +{ + int ret; + + if (invoker_fn) { + ret = invoker_fn(dbus_req, handler_fn); + } else { + ret = handler_fn(dbus_req, handler_data); + } + + switch(ret) { + case EOK: + return; + case ENOMEM: + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory handling DBus message\n"); + sbus_request_finish(dbus_req, NULL); + break; + default: + sbus_request_fail_and_finish(dbus_req, &error_internal); + break; + } +} + int sbus_request_finish(struct sbus_request *dbus_req, DBusMessage *reply) { diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c index 8055cf206..798d394df 100644 --- a/src/tests/sbus_codegen_tests.c +++ b/src/tests/sbus_codegen_tests.c @@ -53,7 +53,7 @@ START_TEST(test_interfaces) /* Explicit C Symbol */ ck_assert_str_eq(test_pilot_meta.name, "com.planetexpress.Pilot"); - ck_assert(test_pilot_meta.methods == NULL); /* no methods */ + ck_assert(test_pilot_meta.methods != NULL); ck_assert(test_pilot_meta.signals == NULL); /* no signals */ ck_assert(test_pilot_meta.properties != NULL); @@ -113,16 +113,42 @@ START_TEST(test_signals) END_TEST static int -mock_move_universe(struct sbus_request *dbus_req, void *data) +mock_move_universe(struct sbus_request *dbus_req, void *data, + bool arg_smoothly, uint32_t arg_speed_factor) { - /* not called */ - return 0; + /* + * The above arguments should match the handler signature, + * and the below finish function should have the right signature. + * + * Not called, just testing compilation + */ + ck_assert(FALSE); + return com_planetexpress_Ship_MoveUniverse_finish(dbus_req, "here"); } static int -mock_crash_now(struct sbus_request *dbus_req, void *data) +mock_crash_now(struct sbus_request *dbus_req, void *data, + const char *where) { - /* not called */ + /* + * One argument, no return value, yet a finish function should + * have been generated. + * + * Not called, just testing compilation + */ + ck_assert(FALSE); + return com_planetexpress_Ship_crash_now_finish(dbus_req); +} + +static int +mock_land(struct sbus_request *req, void *data) +{ + /* + * Raw handler, no finish function, no special arguments. + * + * Not called, just testing compilation + */ + ck_assert(FALSE); return 0; } @@ -132,6 +158,7 @@ START_TEST(test_vtable) { &com_planetexpress_Ship_meta, 0 }, mock_move_universe, mock_crash_now, + mock_land, }; /* @@ -141,6 +168,7 @@ START_TEST(test_vtable) */ ck_assert(vtable.crash_now == mock_crash_now); ck_assert(vtable.MoveUniverse == mock_move_universe); + ck_assert(vtable.Land == mock_land); } END_TEST diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml index e571dbc17..331538ef9 100755 --- a/src/tests/sbus_codegen_tests.xml +++ b/src/tests/sbus_codegen_tests.xml @@ -33,6 +33,12 @@ <!-- A method with a specific c name --> <method name="Crash"> <annotation value="crash_now" name="org.freedesktop.DBus.GLib.CSymbol"/> + <arg name="where" type="s" direction="in"/> + </method> + + <!-- A method without a type-safe handler --> + <method name="Land"> + <annotation name="org.freedesktop.sssd.RawHandler" value="true"/> </method> </interface> @@ -45,6 +51,15 @@ <!-- A property --> <property name="FullName" type="s" access="readwrite"/> + + <!-- A simple method --> + <method name="Blink"> + <!-- This is an uint32 arg --> + <arg name="duration" type="u" direction="in"/> + <!-- This is a boolean return value --> + <arg name="crashed" type="b" direction="out"/> + </method> + </interface> </node> diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c index ccf612996..b5ff08d9d 100644 --- a/src/tests/sbus_codegen_tests_generated.c +++ b/src/tests/sbus_codegen_tests_generated.c @@ -5,6 +5,15 @@ #include "sbus/sssd_dbus_meta.h" #include "sbus_codegen_tests_generated.h" +/* invokes a handler with a 'bu' DBus signature */ +static int invoke_bu_method(struct sbus_request *dbus_req, void *function_ptr); + +/* invokes a handler with a 's' DBus signature */ +static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr); + +/* invokes a handler with a 'u' DBus signature */ +static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr); + /* arguments for com.planetexpress.Ship.MoveUniverse */ const struct sbus_arg_meta com_planetexpress_Ship_MoveUniverse__in[] = { { "smoothly", "b" }, @@ -18,6 +27,25 @@ const struct sbus_arg_meta com_planetexpress_Ship_MoveUniverse__out[] = { { NULL, } }; +int com_planetexpress_Ship_MoveUniverse_finish(struct sbus_request *req, const char *arg_where_we_crashed) +{ + return sbus_request_return_and_finish(req, + DBUS_TYPE_STRING, &arg_where_we_crashed, + DBUS_TYPE_INVALID); +} + +/* arguments for com.planetexpress.Ship.Crash */ +const struct sbus_arg_meta com_planetexpress_Ship_crash_now__in[] = { + { "where", "s" }, + { NULL, } +}; + +int com_planetexpress_Ship_crash_now_finish(struct sbus_request *req) +{ + return sbus_request_return_and_finish(req, + DBUS_TYPE_INVALID); +} + /* methods for com.planetexpress.Ship */ const struct sbus_method_meta com_planetexpress_Ship__methods[] = { { @@ -25,12 +53,21 @@ const struct sbus_method_meta com_planetexpress_Ship__methods[] = { com_planetexpress_Ship_MoveUniverse__in, com_planetexpress_Ship_MoveUniverse__out, offsetof(struct com_planetexpress_Ship, MoveUniverse), + invoke_bu_method, }, { "Crash", /* name */ - NULL, /* no in_args */ + com_planetexpress_Ship_crash_now__in, NULL, /* no out_args */ offsetof(struct com_planetexpress_Ship, crash_now), + invoke_s_method, + }, + { + "Land", /* name */ + NULL, /* no in_args */ + NULL, /* no out_args */ + offsetof(struct com_planetexpress_Ship, Land), + NULL, /* no invoker */ }, { NULL, } }; @@ -68,6 +105,38 @@ const struct sbus_interface_meta com_planetexpress_Ship_meta = { com_planetexpress_Ship__properties }; +/* arguments for com.planetexpress.Pilot.Blink */ +const struct sbus_arg_meta test_pilot_Blink__in[] = { + { "duration", "u" }, + { NULL, } +}; + +/* arguments for com.planetexpress.Pilot.Blink */ +const struct sbus_arg_meta test_pilot_Blink__out[] = { + { "crashed", "b" }, + { NULL, } +}; + +int test_pilot_Blink_finish(struct sbus_request *req, bool arg_crashed) +{ + dbus_bool_t cast_crashed = arg_crashed; + return sbus_request_return_and_finish(req, + DBUS_TYPE_BOOLEAN, &cast_crashed, + DBUS_TYPE_INVALID); +} + +/* methods for com.planetexpress.Pilot */ +const struct sbus_method_meta test_pilot__methods[] = { + { + "Blink", /* name */ + test_pilot_Blink__in, + test_pilot_Blink__out, + offsetof(struct test_pilot, Blink), + invoke_u_method, + }, + { NULL, } +}; + /* property info for com.planetexpress.Pilot */ const struct sbus_property_meta test_pilot__properties[] = { { @@ -81,7 +150,58 @@ const struct sbus_property_meta test_pilot__properties[] = { /* interface info for com.planetexpress.Pilot */ const struct sbus_interface_meta test_pilot_meta = { "com.planetexpress.Pilot", /* name */ - NULL, /* no methods */ + test_pilot__methods, NULL, /* no signals */ test_pilot__properties }; + +/* invokes a handler with a 'bu' DBus signature */ +static int invoke_bu_method(struct sbus_request *dbus_req, void *function_ptr) +{ + dbus_bool_t arg_0; + uint32_t arg_1; + int (*handler)(struct sbus_request *, void *, bool, uint32_t) = function_ptr; + + if (!sbus_request_parse_or_finish(dbus_req, + DBUS_TYPE_BOOLEAN, &arg_0, + DBUS_TYPE_UINT32, &arg_1, + DBUS_TYPE_INVALID)) { + return EOK; /* request handled */ + } + + return (handler)(dbus_req, dbus_req->intf->instance_data, + arg_0, + arg_1); +} + +/* invokes a handler with a 's' DBus signature */ +static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr) +{ + const char * arg_0; + int (*handler)(struct sbus_request *, void *, const char *) = function_ptr; + + if (!sbus_request_parse_or_finish(dbus_req, + DBUS_TYPE_STRING, &arg_0, + DBUS_TYPE_INVALID)) { + return EOK; /* request handled */ + } + + return (handler)(dbus_req, dbus_req->intf->instance_data, + arg_0); +} + +/* invokes a handler with a 'u' DBus signature */ +static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr) +{ + uint32_t arg_0; + int (*handler)(struct sbus_request *, void *, uint32_t) = function_ptr; + + if (!sbus_request_parse_or_finish(dbus_req, + DBUS_TYPE_UINT32, &arg_0, + DBUS_TYPE_INVALID)) { + return EOK; /* request handled */ + } + + return (handler)(dbus_req, dbus_req->intf->instance_data, + arg_0); +} diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h index f41eca74b..23091a7bf 100644 --- a/src/tests/sbus_codegen_tests_generated.h +++ b/src/tests/sbus_codegen_tests_generated.h @@ -15,32 +15,56 @@ #define COM_PLANETEXPRESS_SHIP "com.planetexpress.Ship" #define COM_PLANETEXPRESS_SHIP_MOVEUNIVERSE "MoveUniverse" #define COM_PLANETEXPRESS_SHIP_CRASH_NOW "Crash" +#define COM_PLANETEXPRESS_SHIP_LAND "Land" #define COM_PLANETEXPRESS_SHIP_BECAMESENTIENT "BecameSentient" #define COM_PLANETEXPRESS_SHIP_COLOR "Color" /* constants for com.planetexpress.Pilot */ #define TEST_PILOT "com.planetexpress.Pilot" +#define TEST_PILOT_BLINK "Blink" #define TEST_PILOT_FULLNAME "FullName" /* ------------------------------------------------------------------------ - * DBus Vtable handler structures + * DBus handlers * * These structures are filled in by implementors of the different * dbus interfaces to handle method calls. * * Handler functions of type sbus_msg_handler_fn accept raw messages, - * other handlers will be typed appropriately. If a handler that is + * other handlers are typed appropriately. If a handler that is * set to NULL is invoked it will result in a * org.freedesktop.DBus.Error.NotSupported error for the caller. + * + * Handlers have a matching xxx_finish() function (unless the method has + * accepts raw messages). These finish functions the + * sbus_request_return_and_finish() with the appropriate arguments to + * construct a valid reply. Once a finish function has been called, the + * @dbus_req it was called with is freed and no longer valid. */ /* vtable for com.planetexpress.Ship */ struct com_planetexpress_Ship { struct sbus_vtable vtable; /* derive from sbus_vtable */ - sbus_msg_handler_fn MoveUniverse; - sbus_msg_handler_fn crash_now; + int (*MoveUniverse)(struct sbus_request *req, void *data, bool arg_smoothly, uint32_t arg_speed_factor); + int (*crash_now)(struct sbus_request *req, void *data, const char *arg_where); + sbus_msg_handler_fn Land; }; +/* finish function for MoveUniverse */ +int com_planetexpress_Ship_MoveUniverse_finish(struct sbus_request *req, const char *arg_where_we_crashed); + +/* finish function for Crash */ +int com_planetexpress_Ship_crash_now_finish(struct sbus_request *req); + +/* vtable for com.planetexpress.Pilot */ +struct test_pilot { + struct sbus_vtable vtable; /* derive from sbus_vtable */ + int (*Blink)(struct sbus_request *req, void *data, uint32_t arg_duration); +}; + +/* finish function for Blink */ +int test_pilot_Blink_finish(struct sbus_request *req, bool arg_crashed); + /* ------------------------------------------------------------------------ * DBus Interface Metadata * |