[SSSD] [PATCH] DBus: Automatic pack/unpack of method handler arguments

Jakub Hrozek jhrozek at redhat.com
Thu Apr 17 15:17:46 UTC 2014


On Thu, Apr 17, 2014 at 02:46:06PM +0200, Pavel Březina wrote:
> On 03/20/2014 08:11 AM, Stef Walter wrote:
> >On 14.03.2014 23:00, Stef Walter wrote:
> >>Here's the next set of DBus patches. This implements automatic packing
> >>and unpacking of arguments for method handlers.
> >
> >Rebased on master. Also the last patches had incorrectly generated files
> >due to a rebase.
> >
> >Stef
> 
> Hi,
> I'm sorry for the delay. Can you rebase the patches one more time please?

I took the liberty of rebasing the patches on Stef's behalf as the only
conflict was in the Introspection piece I wrote. The first patch (a new
one) silences the warning about undefined method.

The second and third are what used to be first and second previously.
-------------- next part --------------
>From a20473ebc0f2feb64136b5a3e70dc5017e3d9a37 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Thu, 17 Apr 2014 16:55:29 +0200
Subject: [PATCH 1/3] SBUS: Create an sbus_method_meta instance for
 Introspection

---
 src/sbus/sssd_dbus_connection.c | 1 +
 src/sbus/sssd_dbus_introspect.c | 8 ++++++++
 src/sbus/sssd_dbus_private.h    | 3 +++
 3 files changed, 12 insertions(+)

diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index 64777fbe815c78d8c893ee1a3e8f5ab327c6701e..16ec72f9201dd478741c6c3223436c2c8f9d377f 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -441,6 +441,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
                 handler_fn = sbus_introspect;
                 ictx->iface = interface;
                 handler_data = ictx;
+                method = &introspect_method;
             }
         }
     }
diff --git a/src/sbus/sssd_dbus_introspect.c b/src/sbus/sssd_dbus_introspect.c
index ffc1f4d38ba70f9074d6731280136e899374c866..ef0ff2fd5d457e59100c1bd906e7dee12638be3c 100644
--- a/src/sbus/sssd_dbus_introspect.c
+++ b/src/sbus/sssd_dbus_introspect.c
@@ -28,6 +28,14 @@
 #include "sbus/sssd_dbus_private.h"
 #include "sbus/sssd_dbus_meta.h"
 
+static const struct sbus_arg_meta introspect_method_arg_out[] = {
+    { "data", "s" },
+    { NULL, }
+};
+
+const struct sbus_method_meta introspect_method =
+    { DBUS_INTROSPECT_METHOD, NULL, introspect_method_arg_out, 0 };
+
 #define SSS_INTROSPECT_DOCTYPE  \
     "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
     "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index 929caeccbcc0aca2e42fc44eacf3603826cbe329..6abe56c6642ac2370e4178add496331e7e9b38e4 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -98,6 +98,9 @@ struct sbus_request *
 sbus_new_request(struct sbus_connection *conn, struct sbus_interface *intf,
                  DBusMessage *message);
 
+/* =Interface=introspection=============================================== */
+extern const struct sbus_method_meta introspect_method;
+
 struct sbus_introspect_ctx {
     const struct sbus_interface_meta *iface;
 };
-- 
1.9.0

-------------- next part --------------
>From a081d89aeb329dbe3f9341a81cb317da431bddf6 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 25 Feb 2014 10:29:23 +0100
Subject: [PATCH 2/3] sbus: Add type-safe DBus method handlers and finish
 functions

Type safe method handlers allow methods not to have to do tedious
unwrapping and wrapping of DBus method call messages or replies.

Arguments of the following DBus types are supported in type-safe
method handlers. In addition arrays of these are supported.

 y: uint8_t
 b: bool     (but no arrays, yet)
 n: int16_t
 q: uint16_t
 i: int32_t
 u: uint32_t
 x: int64_t
 t: uint64_t
 d: double
 s: char *   (utf8 string)
 o: char *   (object path)

As an exception, arrays of booleans are not supported, but could be
added later. Other more complex types could be added later if desired.
If a method has other argument types, then it must be marked as having
a raw handler (see below).

Internally each method can have a type specific invoker function which
unpacks the incoming arguments and invokes the method handler with the
correct arguments.

Each method also has a finish which accepts the type-safe out arguments
(ie: return values) and builds the reply message. Like other request
'finish' functions, these free the request talloc context, and are to
be used in place of sbus_request_finish() or friends.

Raw method handlers parse their own method arguments, and prepare their
own reply (ideally using sbus_request_finish() helpers). They can also
do strange things like have variable arguments. To mark a DBus method
as having a raw method handler use the following annotation:

<annotation name="org.freedesktop.sssd.RawHandler" value="true"/>

Raw methods do not have invokers or finish functions.

I've left all of the internal peer to peer communication using raw
method handlers. No code changes here.
---
 src/monitor/monitor_iface.xml                 |  30 ++--
 src/monitor/monitor_iface_generated.c         |  10 ++
 src/monitor/monitor_iface_generated.h         |  10 +-
 src/providers/data_provider_iface.xml         |  27 ++--
 src/providers/data_provider_iface_generated.c |   9 ++
 src/providers/data_provider_iface_generated.h |  10 +-
 src/responder/ifp/ifp_iface_generated.c       |   7 +
 src/responder/ifp/ifp_iface_generated.h       |  15 +-
 src/sbus/sbus_codegen                         | 215 +++++++++++++++++++++++++-
 src/sbus/sssd_dbus_connection.c               |  33 ++--
 src/sbus/sssd_dbus_introspect.c               |   2 +-
 src/sbus/sssd_dbus_meta.h                     |   6 +
 src/sbus/sssd_dbus_private.h                  |   8 +
 src/sbus/sssd_dbus_request.c                  |  30 ++++
 src/tests/sbus_codegen_tests.c                |  40 ++++-
 src/tests/sbus_codegen_tests.xml              |  15 ++
 src/tests/sbus_codegen_tests_generated.c      | 124 ++++++++++++++-
 src/tests/sbus_codegen_tests_generated.h      |  32 +++-
 18 files changed, 552 insertions(+), 71 deletions(-)

diff --git a/src/monitor/monitor_iface.xml b/src/monitor/monitor_iface.xml
index 506b749c8a12b2c137b433e168beaf38f0b2c97f..1f61de5b72f92cd335f6c05a9cdbdb315314c640 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 81a7c247ac94fd3e22ee7133f2cd582ad7a4bdc6..e9c3c1d52468ac6969498e79491a1d62dc75cc71 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 bd556616cdc6ccf212a7c5abb4f8f8d3a4f6f158..37e4d480b6be4433bc591b6e43195e9278fe3e04 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 90397f1b2a1dabc3b45005340cd503b0746c7bb5..143975633081ce2ae5690c4036e7169e41d776fc 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 517b7adfe74b7387427427d09a7620ca6d036833..e7eca7def576772a695457444de7aaf99795fb65 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 fc37aa8cbbb39bf23b29e2d3ba5ffe160cb6ab41..976e42b89c6aaf9523b16999b8f5103a1e6f8e66 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_generated.c b/src/responder/ifp/ifp_iface_generated.c
index db5e0e545d8d1a956ae052be52a824ed0bf5d273..fef3969fd7c5761528dab948b5f423b8df37e08b 100644
--- a/src/responder/ifp/ifp_iface_generated.c
+++ b/src/responder/ifp/ifp_iface_generated.c
@@ -5,6 +5,12 @@
 #include "sbus/sssd_dbus_meta.h"
 #include "ifp_iface_generated.h"
 
+int infopipe_iface_Ping_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* methods for org.freedesktop.sssd.infopipe */
 const struct sbus_method_meta infopipe_iface__methods[] = {
     {
@@ -12,6 +18,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 8db83fc115d62390560e9be94ac1480ade48296f..9f32f09209c08f30a49e4e1823f26a812446d88b 100644
--- a/src/responder/ifp/ifp_iface_generated.h
+++ b/src/responder/ifp/ifp_iface_generated.h
@@ -16,23 +16,32 @@
 #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 */
 struct infopipe_iface {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
-    sbus_msg_handler_fn Ping;
+    int (*Ping)(struct sbus_request *req, void *data);
 };
 
+/* finish function for Ping */
+int infopipe_iface_Ping_finish(struct sbus_request *req);
+
 /* ------------------------------------------------------------------------
  * DBus Interface Metadata
  *
diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index d2fe5073d9314385a09b9074d61d2b9ab8efbb24..6c4b8ec9a1f64cc243afb0fe5d12617b3ef586f0 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 16ec72f9201dd478741c6c3223436c2c8f9d377f..3cbc72437b051f5c19579ca33499e16c160851c5 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 ef0ff2fd5d457e59100c1bd906e7dee12638be3c..c8e8c97a18e746ba9056b13bb14efb369dcf8cda 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 abc992137811be6c6930ff86831a03f7b43fb485..997aa9e464df91d2378ae42fcf7fdaaa05a9a2f3 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 6abe56c6642ac2370e4178add496331e7e9b38e4..4916700b533650c12184a931f1e548b64e0a98fa 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 c45f3a9fdb7204a2f296f1a0870c1275aa42e0d8..1546f0ddf349ea595af3d505fd9d6b8931ca9d92 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 8055cf206f2f632a47b57f36d3f77220e970e4c2..798d394df226dc70dc29e2caf30f559aae39373f 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 e571dbc17b9e5c0e065d2ab87fb37458072f10b0..331538ef9ed79aa08b0552c1dc3f66f6ec9f50b1 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 ccf6129965e8b7753d6f63286078d1f296bcf07e..b5ff08d9dad7c554e055dcefd9fee99b5ac76d44 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 f41eca74bbb83dc3fc59ef6a5e8bfcdd9f800acd..23091a7bfb48f47bf49ea1692e1095d7648a4e09 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
  *
-- 
1.9.0

-------------- next part --------------
>From 5579ffc5bb19fedeae9e6e770f62cd273e7881e6 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 25 Feb 2014 10:30:06 +0100
Subject: [PATCH 3/3] sbus_codegen_tests: Add test case type-safe handler args

This adds a big test case for invoking a handler with all supported
basic arguments, and constructing a reply with the same. Lots of
tedious code, but worth it to make sure things work well.
---
 Makefile.am                              |   1 +
 src/tests/sbus_codegen_tests.c           | 334 ++++++++++++++++++++++++++++++-
 src/tests/sbus_codegen_tests.xml         |  47 +++++
 src/tests/sbus_codegen_tests_generated.c | 186 +++++++++++++++++
 src/tests/sbus_codegen_tests_generated.h |   5 +
 5 files changed, 568 insertions(+), 5 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 3ebb54aed87859740ed3808f8e42e60bbebd4840..dc8a99771893ebd9fecb6e1d3ecc9cc2f8bcd8b4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1386,6 +1386,7 @@ sbus_tests_LDADD = \
     $(CHECK_LIBS)
 
 sbus_codegen_tests_SOURCES = \
+   src/tests/common_dbus.c \
    src/tests/sbus_codegen_tests.c \
    src/tests/sbus_codegen_tests_generated.c \
    src/tests/sbus_codegen_tests_generated.h
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index 798d394df226dc70dc29e2caf30f559aae39373f..d9da5c0ce9394880eebad45fb2cef32aad2e1026 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -29,7 +29,9 @@
 #include <popt.h>
 
 #include "sbus/sssd_dbus_meta.h"
+#include "tests/common.h"
 #include "tests/sbus_codegen_tests_generated.h"
+#include "util/util_errors.h"
 
 static const struct sbus_arg_meta *
 find_arg(const struct sbus_arg_meta *args,
@@ -186,10 +188,8 @@ START_TEST(test_constants)
 }
 END_TEST
 
-Suite *create_suite(void)
+TCase *create_defs_tests(void)
 {
-    Suite *s = suite_create("sbus_codegen");
-
     TCase *tc = tcase_create("defs");
 
     /* Do some testing */
@@ -200,8 +200,332 @@ Suite *create_suite(void)
     tcase_add_test(tc, test_vtable);
     tcase_add_test(tc, test_constants);
 
-    /* Add all test cases to the test suite */
-    suite_add_tcase(s, tc);
+    return tc;
+}
+
+/* This is a handler which has all the basic arguments types */
+static int eject_handler(struct sbus_request *req, void *instance_data,
+                         uint8_t arg_byte, bool arg_boolean,
+                         int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32,
+                         uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64,
+                         double arg_double, const char *arg_string, const char *arg_object_path,
+                         uint8_t arg_byte_array[], int len_byte_array,
+                         int16_t arg_int16_array[], int len_int16_array,
+                         uint16_t arg_uint16_array[], int len_uint16_array,
+                         int32_t arg_int32_array[], int len_int32_array,
+                         uint32_t arg_uint32_array[], int len_uint32_array,
+                         int64_t arg_int64_array[], int len_int64_array,
+                         uint64_t arg_uint64_array[], int len_uint64_array,
+                         double arg_double_array[], int len_double_array,
+                         const char *arg_string_array[], int len_string_array,
+                         const char *arg_object_path_array[], int len_object_path_array)
+{
+    int i;
+
+    /* Only called for leela, so double check here */
+    ck_assert_str_eq(instance_data, "Crash into the billboard");
+
+    /* Murge the various values for test case */
+    ck_assert_uint_eq(arg_byte, 11);
+    arg_byte++;
+    ck_assert(arg_boolean == TRUE);
+    arg_boolean = !arg_boolean;
+    ck_assert_int_eq(arg_int16, -2222);
+    arg_int16++;
+    ck_assert_uint_eq(arg_uint16, 3333);
+    arg_uint16++;
+    ck_assert_int_eq(arg_int32, -44444444);
+    arg_int32++;
+    ck_assert_uint_eq(arg_uint32, 55555555);
+    arg_uint32++;
+    ck_assert(arg_int64 == -6666666666666666);
+    arg_int64++;
+    ck_assert(arg_uint64 == 7777777777777777);
+    arg_uint64++;
+    ck_assert(arg_double == 1.1);
+    arg_double++;
+
+    ck_assert_str_eq(arg_string, "hello");
+    arg_string = "bears, beets, battlestar galactica";
+    ck_assert_str_eq(arg_object_path, "/original/object/path");
+    arg_object_path = "/another/object/path";
+
+    arg_byte_array = talloc_memdup(req, arg_byte_array, sizeof(uint8_t) * len_byte_array);
+    for (i = 0; i < len_byte_array; i++)
+        arg_byte_array[i]++;
+
+    arg_int16_array = talloc_memdup(req, arg_int16_array, sizeof(int16_t) * len_int16_array);
+    for (i = 0; i < len_int16_array; i++)
+        arg_int16_array[i]++;
+    len_int16_array--;
+
+    arg_uint16_array = talloc_memdup(req, arg_uint16_array, sizeof(uint16_t) * len_uint16_array);
+    for (i = 0; i < len_uint16_array; i++)
+        arg_uint16_array[i]++;
+
+    arg_int32_array = talloc_memdup(req, arg_int32_array, sizeof(int32_t) * len_int32_array);
+    for (i = 0; i < len_int32_array; i++)
+        arg_int32_array[i]++;
+    len_int32_array--;
+
+    arg_uint32_array = talloc_memdup(req, arg_uint32_array, sizeof(uint32_t) * len_uint32_array);
+    for (i = 0; i < len_uint32_array; i++)
+        arg_uint32_array[i]++;
+
+    arg_int64_array = talloc_memdup(req, arg_int64_array, sizeof(int64_t) * len_int64_array);
+    for (i = 0; i < len_int64_array; i++)
+        arg_int64_array[i]++;
+
+    arg_uint64_array = talloc_memdup(req, arg_uint64_array, sizeof(uint64_t) * len_uint64_array);
+    for (i = 0; i < len_uint64_array; i++)
+        arg_uint64_array[i]++;
+
+    arg_double_array = talloc_memdup(req, arg_double_array, sizeof(double) * len_double_array);
+    for (i = 0; i < len_double_array; i++)
+        arg_double_array[i]++;
+
+    arg_string_array = talloc_memdup(req, arg_string_array, sizeof(char *) * len_string_array);
+    for (i = 0; i < len_double_array; i++) {
+        ck_assert_str_eq(arg_string_array[i], "bears");
+        arg_string_array[i] = "beets";
+    }
+    len_string_array--;
+
+    arg_object_path_array = talloc_memdup(req, arg_object_path_array, sizeof(char *) * len_object_path_array);
+    for (i = 0; i < len_object_path_array; i++) {
+        ck_assert_str_eq(arg_object_path_array[i], "/original");
+        arg_object_path_array[i] = "/changed";
+    }
+
+    /* And reply with those values */
+    return test_pilot_Eject_finish(req, arg_byte, arg_boolean, arg_int16,
+                                   arg_uint16, arg_int32, arg_uint32,
+                                   arg_int64, arg_uint64, arg_double,
+                                   arg_string, arg_object_path,
+                                   arg_byte_array, len_byte_array,
+                                   arg_int16_array, len_int16_array,
+                                   arg_uint16_array, len_uint16_array,
+                                   arg_int32_array, len_int32_array,
+                                   arg_uint32_array, len_uint32_array,
+                                   arg_int64_array, len_int64_array,
+                                   arg_uint64_array, len_uint64_array,
+                                   arg_double_array, len_double_array,
+                                   arg_string_array, len_string_array,
+                                   arg_object_path_array, len_object_path_array);
+}
+
+#define N_ELEMENTS(arr) \
+    (sizeof(arr) / sizeof(arr[0]))
+
+struct test_pilot pilot_methods = {
+    { &test_pilot_meta, 0 },
+    .Eject = eject_handler,
+};
+
+static int pilot_test_server_init(struct sbus_connection *server, void *unused)
+{
+    int ret;
+
+    ret = sbus_conn_add_interface(server,
+                                  sbus_new_interface(server, "/test/leela",
+                                                     &pilot_methods.vtable,
+                                                     "Crash into the billboard"));
+    ck_assert_int_eq(ret, EOK);
+
+    return EOK;
+}
+
+START_TEST(test_marshal_basic_types)
+{
+    unsigned char arg_byte = 11;
+    dbus_bool_t arg_boolean = TRUE;
+    dbus_int16_t arg_int16 = -2222;
+    dbus_uint16_t arg_uint16 = 3333;
+    dbus_int32_t arg_int32 = -44444444;
+    dbus_uint32_t arg_uint32 = 55555555;
+    dbus_int64_t arg_int64 = -6666666666666666;
+    dbus_uint64_t arg_uint64 = 7777777777777777;
+    double arg_double = 1.1;
+    const char *arg_string = "hello";
+    const char *arg_object_path = "/original/object/path";
+
+    unsigned char v_byte[] = { 11, 12 };
+    dbus_int16_t v_int16[] = { 1, -22, 333, -4444 };
+    dbus_uint16_t v_uint16[] = { 1, 2, 3, 4, 5 };
+    dbus_int32_t v_int32[] = { -1, -23, 34, -56, -90000000, 78 };
+    dbus_uint32_t v_uint32[] = { 11111111, 22222222, 33333333 };
+    dbus_int64_t v_int64[] = { -6666666666666666, 7777777777777777 };
+    dbus_uint64_t v_uint64[] = { 7777777777777777, 888888888888888888 };
+    double v_double[] = { 1.1, 2.2, 3.3 };
+    char *v_string[] = { "bears", "bears", "bears" };
+    char *v_object_path[] = { "/original", "/original" };
+
+    unsigned char *arr_byte = v_byte;
+    dbus_int16_t *arr_int16 = v_int16;
+    dbus_uint16_t *arr_uint16 = v_uint16;
+    dbus_int32_t *arr_int32 = v_int32;
+    dbus_uint32_t *arr_uint32 = v_uint32;
+    dbus_int64_t *arr_int64 = v_int64;
+    dbus_uint64_t *arr_uint64 = v_uint64;
+    double *arr_double = v_double;
+    char **arr_string = v_string;
+    char **arr_object_path = v_object_path;
+
+    int len_byte = N_ELEMENTS(v_byte);
+    int len_int16 = N_ELEMENTS(v_int16);
+    int len_uint16 = N_ELEMENTS(v_uint16);
+    int len_int32 = N_ELEMENTS(v_int32);
+    int len_uint32 = N_ELEMENTS(v_uint32);
+    int len_int64 = N_ELEMENTS(v_int64);
+    int len_uint64 = N_ELEMENTS(v_uint64);
+    int len_double = N_ELEMENTS(v_double);
+    int len_string = N_ELEMENTS(v_string);
+    int len_object_path = N_ELEMENTS(v_object_path);
+
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    DBusError error = DBUS_ERROR_INIT;
+    DBusMessage *reply;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    reply = test_dbus_call_sync(client,
+                                "/test/leela",
+                                TEST_PILOT,
+                                TEST_PILOT_EJECT,
+                                &error,
+                                DBUS_TYPE_BYTE, &arg_byte,
+                                DBUS_TYPE_BOOLEAN, &arg_boolean,
+                                DBUS_TYPE_INT16, &arg_int16,
+                                DBUS_TYPE_UINT16, &arg_uint16,
+                                DBUS_TYPE_INT32, &arg_int32,
+                                DBUS_TYPE_UINT32, &arg_uint32,
+                                DBUS_TYPE_INT64, &arg_int64,
+                                DBUS_TYPE_UINT64, &arg_uint64,
+                                DBUS_TYPE_DOUBLE, &arg_double,
+                                DBUS_TYPE_STRING, &arg_string,
+                                DBUS_TYPE_OBJECT_PATH, &arg_object_path,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &arr_byte, len_byte,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_INT16, &arr_int16, len_int16,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16, &arr_uint16, len_uint16,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &arr_int32, len_int32,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arr_uint32, len_uint32,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &arr_int64, len_int64,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &arr_uint64, len_uint64,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &arr_double, len_double,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arr_string, len_string,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arr_object_path, len_object_path,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    ck_assert(!dbus_error_is_set(&error));
+    ck_assert(dbus_message_get_args(reply, NULL,
+                                    DBUS_TYPE_BYTE, &arg_byte,
+                                    DBUS_TYPE_BOOLEAN, &arg_boolean,
+                                    DBUS_TYPE_INT16, &arg_int16,
+                                    DBUS_TYPE_UINT16, &arg_uint16,
+                                    DBUS_TYPE_INT32, &arg_int32,
+                                    DBUS_TYPE_UINT32, &arg_uint32,
+                                    DBUS_TYPE_INT64, &arg_int64,
+                                    DBUS_TYPE_UINT64, &arg_uint64,
+                                    DBUS_TYPE_DOUBLE, &arg_double,
+                                    DBUS_TYPE_STRING, &arg_string,
+                                    DBUS_TYPE_OBJECT_PATH, &arg_object_path,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &arr_byte, &len_byte,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT16, &arr_int16, &len_int16,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16, &arr_uint16, &len_uint16,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &arr_int32, &len_int32,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arr_uint32, &len_uint32,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &arr_int64, &len_int64,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &arr_uint64, &len_uint64,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &arr_double, &len_double,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arr_string, &len_string,
+                                    DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arr_object_path, &len_object_path,
+                                    DBUS_TYPE_INVALID));
+
+    ck_assert_uint_eq(arg_byte, 12);
+    ck_assert(arg_boolean == FALSE);
+    ck_assert_int_eq(arg_int16, -2221);
+    ck_assert_uint_eq(arg_uint16, 3334);
+    ck_assert_int_eq(arg_int32, -44444443);
+    ck_assert_uint_eq(arg_uint32, 55555556);
+    ck_assert(arg_int64 ==-6666666666666665);
+    ck_assert(arg_uint64 == 7777777777777778);
+    ck_assert(arg_double == 2.1);
+    ck_assert_str_eq(arg_string, "bears, beets, battlestar galactica");
+    ck_assert_str_eq(arg_object_path, "/another/object/path");
+
+    ck_assert_int_eq(len_byte, 2);
+    ck_assert_int_eq(arr_byte[0], 12);
+    ck_assert_int_eq(arr_byte[1], 13);
+
+    ck_assert_int_eq(len_int16, 3);
+    ck_assert_int_eq(arr_int16[0], 2);
+    ck_assert_int_eq(arr_int16[1], -21);
+    ck_assert_int_eq(arr_int16[2], 334);
+
+    ck_assert_int_eq(len_uint16, 5);
+    ck_assert_uint_eq(arr_uint16[0], 2);
+    ck_assert_uint_eq(arr_uint16[1], 3);
+    ck_assert_uint_eq(arr_uint16[2], 4);
+    ck_assert_uint_eq(arr_uint16[3], 5);
+    ck_assert_uint_eq(arr_uint16[4], 6);
+
+    ck_assert_int_eq(len_int32, 5);
+    ck_assert_int_eq(arr_int32[0], 0);
+    ck_assert_int_eq(arr_int32[1], -22);
+    ck_assert_int_eq(arr_int32[2], 35);
+    ck_assert_int_eq(arr_int32[3], -55);
+    ck_assert_int_eq(arr_int32[4], -89999999);
+
+    ck_assert_int_eq(len_uint32, 3);
+    ck_assert_uint_eq(arr_uint32[0], 11111112);
+    ck_assert_uint_eq(arr_uint32[1], 22222223);
+    ck_assert_uint_eq(arr_uint32[2], 33333334);
+
+    ck_assert_int_eq(len_int64, 2);
+    ck_assert(arr_int64[0] == -6666666666666665);
+    ck_assert(arr_int64[1] == 7777777777777778);
+
+    ck_assert_int_eq(len_uint64, 2);
+    ck_assert(arr_uint64[0] == 7777777777777778);
+    ck_assert(arr_uint64[1] == 888888888888888889);
+
+    ck_assert_int_eq(len_double, 3);
+    ck_assert(arr_double[0] == 2.1);
+    ck_assert(arr_double[1] == 3.2);
+    ck_assert(arr_double[2] == 4.3);
+
+    ck_assert_int_eq(len_string, 2);
+    ck_assert_str_eq(arr_string[0], "beets");
+    ck_assert_str_eq(arr_string[1], "beets");
+    dbus_free_string_array(arr_string);
+
+    ck_assert_int_eq(len_object_path, 2);
+    ck_assert_str_eq(arr_object_path[0], "/changed");
+    ck_assert_str_eq(arr_object_path[1], "/changed");
+    dbus_free_string_array(arr_object_path);
+
+    dbus_message_unref (reply);
+    talloc_free(ctx);
+}
+END_TEST
+
+TCase *create_handler_tests(void)
+{
+    TCase *tc = tcase_create("handler");
+
+    tcase_add_test(tc, test_marshal_basic_types);
+
+    return tc;
+}
+
+Suite *create_suite(void)
+{
+    Suite *s = suite_create("sbus_codegen");
+
+    suite_add_tcase(s, create_defs_tests ());
+    suite_add_tcase(s, create_handler_tests ());
 
     return s;
 }
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
index 331538ef9ed79aa08b0552c1dc3f66f6ec9f50b1..83807b9c287f633ad59398519a7520e667003f00 100755
--- a/src/tests/sbus_codegen_tests.xml
+++ b/src/tests/sbus_codegen_tests.xml
@@ -52,6 +52,7 @@
         <!-- A property -->
         <property name="FullName" type="s" access="readwrite"/>
 
+
         <!-- A simple method -->
         <method name="Blink">
             <!-- This is an uint32 arg -->
@@ -60,6 +61,52 @@
             <arg name="crashed" type="b" direction="out"/>
         </method>
 
+        <!-- A method with every type of basic argument, in both directions -->
+        <method name="Eject">
+            <arg name="byte" type="y" direction="in"/>
+            <arg name="boolean" type="b" direction="in"/>
+            <arg name="int16" type="n" direction="in"/>
+            <arg name="uint16" type="q" direction="in"/>
+            <arg name="int32" type="i" direction="in"/>
+            <arg name="uint32" type="u" direction="in"/>
+            <arg name="int64" type="x" direction="in"/>
+            <arg name="uint64" type="t" direction="in"/>
+            <arg name="double" type="d" direction="in"/>
+            <arg name="string" type="s" direction="in"/>
+            <arg name="object_path" type="o" direction="in"/>
+            <arg name="byte_array" type="ay" direction="in"/>
+            <arg name="int16_array" type="an" direction="in"/>
+            <arg name="uint16_array" type="aq" direction="in"/>
+            <arg name="int32_array" type="ai" direction="in"/>
+            <arg name="uint32_array" type="au" direction="in"/>
+            <arg name="int64_array" type="ax" direction="in"/>
+            <arg name="uint64_array" type="at" direction="in"/>
+            <arg name="double_array" type="ad" direction="in"/>
+            <arg name="string_array" type="as" direction="in"/>
+            <arg name="object_path_array" type="ao" direction="in"/>
+            <arg name="byte" type="y" direction="out"/>
+            <arg name="boolean" type="b" direction="out"/>
+            <arg name="int16" type="n" direction="out"/>
+            <arg name="uint16" type="q" direction="out"/>
+            <arg name="int32" type="i" direction="out"/>
+            <arg name="uint32" type="u" direction="out"/>
+            <arg name="int64" type="x" direction="out"/>
+            <arg name="uint64" type="t" direction="out"/>
+            <arg name="double" type="d" direction="out"/>
+            <arg name="string" type="s" direction="out"/>
+            <arg name="object_path" type="o" direction="out"/>
+            <arg name="byte_array" type="ay" direction="out"/>
+            <arg name="int16_array" type="an" direction="out"/>
+            <arg name="uint16_array" type="aq" direction="out"/>
+            <arg name="int32_array" type="ai" direction="out"/>
+            <arg name="uint32_array" type="au" direction="out"/>
+            <arg name="int64_array" type="ax" direction="out"/>
+            <arg name="uint64_array" type="at" direction="out"/>
+            <arg name="double_array" type="ad" direction="out"/>
+            <arg name="string_array" type="as" direction="out"/>
+            <arg name="object_path_array" type="ao" direction="out"/>
+        </method>
+
     </interface>
 
 </node>
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index b5ff08d9dad7c554e055dcefd9fee99b5ac76d44..4ba2577489ddb2e1c7c72a37b97561946f4f23b8 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -14,6 +14,9 @@ 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);
 
+/* invokes a handler with a 'ybnqiuxtdsoayanaqaiauaxatadasao' DBus signature */
+static int invoke_ybnqiuxtdsoayanaqaiauaxatadasao_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" },
@@ -125,6 +128,86 @@ int test_pilot_Blink_finish(struct sbus_request *req, bool arg_crashed)
                                          DBUS_TYPE_INVALID);
 }
 
+/* arguments for com.planetexpress.Pilot.Eject */
+const struct sbus_arg_meta test_pilot_Eject__in[] = {
+    { "byte", "y" },
+    { "boolean", "b" },
+    { "int16", "n" },
+    { "uint16", "q" },
+    { "int32", "i" },
+    { "uint32", "u" },
+    { "int64", "x" },
+    { "uint64", "t" },
+    { "double", "d" },
+    { "string", "s" },
+    { "object_path", "o" },
+    { "byte_array", "ay" },
+    { "int16_array", "an" },
+    { "uint16_array", "aq" },
+    { "int32_array", "ai" },
+    { "uint32_array", "au" },
+    { "int64_array", "ax" },
+    { "uint64_array", "at" },
+    { "double_array", "ad" },
+    { "string_array", "as" },
+    { "object_path_array", "ao" },
+    { NULL, }
+};
+
+/* arguments for com.planetexpress.Pilot.Eject */
+const struct sbus_arg_meta test_pilot_Eject__out[] = {
+    { "byte", "y" },
+    { "boolean", "b" },
+    { "int16", "n" },
+    { "uint16", "q" },
+    { "int32", "i" },
+    { "uint32", "u" },
+    { "int64", "x" },
+    { "uint64", "t" },
+    { "double", "d" },
+    { "string", "s" },
+    { "object_path", "o" },
+    { "byte_array", "ay" },
+    { "int16_array", "an" },
+    { "uint16_array", "aq" },
+    { "int32_array", "ai" },
+    { "uint32_array", "au" },
+    { "int64_array", "ax" },
+    { "uint64_array", "at" },
+    { "double_array", "ad" },
+    { "string_array", "as" },
+    { "object_path_array", "ao" },
+    { NULL, }
+};
+
+int test_pilot_Eject_finish(struct sbus_request *req, uint8_t arg_byte, bool arg_boolean, int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32, uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64, double arg_double, const char *arg_string, const char *arg_object_path, uint8_t arg_byte_array[], int len_byte_array, int16_t arg_int16_array[], int len_int16_array, uint16_t arg_uint16_array[], int len_uint16_array, int32_t arg_int32_array[], int len_int32_array, uint32_t arg_uint32_array[], int len_uint32_array, int64_t arg_int64_array[], int len_int64_array, uint64_t arg_uint64_array[], int len_uint64_array, double arg_double_array[], int len_double_array, const char *arg_string_array[], int len_string_array, const char *arg_object_path_array[], int len_object_path_array)
+{
+    dbus_bool_t cast_boolean = arg_boolean;
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_BYTE, &arg_byte,
+                                         DBUS_TYPE_BOOLEAN, &cast_boolean,
+                                         DBUS_TYPE_INT16, &arg_int16,
+                                         DBUS_TYPE_UINT16, &arg_uint16,
+                                         DBUS_TYPE_INT32, &arg_int32,
+                                         DBUS_TYPE_UINT32, &arg_uint32,
+                                         DBUS_TYPE_INT64, &arg_int64,
+                                         DBUS_TYPE_UINT64, &arg_uint64,
+                                         DBUS_TYPE_DOUBLE, &arg_double,
+                                         DBUS_TYPE_STRING, &arg_string,
+                                         DBUS_TYPE_OBJECT_PATH, &arg_object_path,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &arg_byte_array, len_byte_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_INT16, &arg_int16_array, len_int16_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16, &arg_uint16_array, len_uint16_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &arg_int32_array, len_int32_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arg_uint32_array, len_uint32_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &arg_int64_array, len_int64_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &arg_uint64_array, len_uint64_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &arg_double_array, len_double_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_string_array, len_string_array,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_object_path_array, len_object_path_array,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* methods for com.planetexpress.Pilot */
 const struct sbus_method_meta test_pilot__methods[] = {
     {
@@ -134,6 +217,13 @@ const struct sbus_method_meta test_pilot__methods[] = {
         offsetof(struct test_pilot, Blink),
         invoke_u_method,
     },
+    {
+        "Eject", /* name */
+        test_pilot_Eject__in,
+        test_pilot_Eject__out,
+        offsetof(struct test_pilot, Eject),
+        invoke_ybnqiuxtdsoayanaqaiauaxatadasao_method,
+    },
     { NULL, }
 };
 
@@ -205,3 +295,99 @@ static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr)
     return (handler)(dbus_req, dbus_req->intf->instance_data,
                      arg_0);
 }
+
+/* invokes a handler with a 'ybnqiuxtdsoayanaqaiauaxatadasao' DBus signature */
+static int invoke_ybnqiuxtdsoayanaqaiauaxatadasao_method(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint8_t arg_0;
+    dbus_bool_t arg_1;
+    int16_t arg_2;
+    uint16_t arg_3;
+    int32_t arg_4;
+    uint32_t arg_5;
+    int64_t arg_6;
+    uint64_t arg_7;
+    double arg_8;
+    const char * arg_9;
+    const char * arg_10;
+    uint8_t *arg_11;
+    int len_11;
+    int16_t *arg_12;
+    int len_12;
+    uint16_t *arg_13;
+    int len_13;
+    int32_t *arg_14;
+    int len_14;
+    uint32_t *arg_15;
+    int len_15;
+    int64_t *arg_16;
+    int len_16;
+    uint64_t *arg_17;
+    int len_17;
+    double *arg_18;
+    int len_18;
+    const char * *arg_19;
+    int len_19;
+    const char * *arg_20;
+    int len_20;
+    int (*handler)(struct sbus_request *, void *, uint8_t, bool, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, double, const char *, const char *, uint8_t[], int, int16_t[], int, uint16_t[], int, int32_t[], int, uint32_t[], int, int64_t[], int, uint64_t[], int, double[], int, const char *[], int, const char *[], int) = function_ptr;
+
+    if (!sbus_request_parse_or_finish(dbus_req,
+                               DBUS_TYPE_BYTE, &arg_0,
+                               DBUS_TYPE_BOOLEAN, &arg_1,
+                               DBUS_TYPE_INT16, &arg_2,
+                               DBUS_TYPE_UINT16, &arg_3,
+                               DBUS_TYPE_INT32, &arg_4,
+                               DBUS_TYPE_UINT32, &arg_5,
+                               DBUS_TYPE_INT64, &arg_6,
+                               DBUS_TYPE_UINT64, &arg_7,
+                               DBUS_TYPE_DOUBLE, &arg_8,
+                               DBUS_TYPE_STRING, &arg_9,
+                               DBUS_TYPE_OBJECT_PATH, &arg_10,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &arg_11, &len_11,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_INT16, &arg_12, &len_12,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16, &arg_13, &len_13,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &arg_14, &len_14,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arg_15, &len_15,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &arg_16, &len_16,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &arg_17, &len_17,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &arg_18, &len_18,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_19, &len_19,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_20, &len_20,
+                               DBUS_TYPE_INVALID)) {
+         return EOK; /* request handled */
+    }
+
+    return (handler)(dbus_req, dbus_req->intf->instance_data,
+                     arg_0,
+                     arg_1,
+                     arg_2,
+                     arg_3,
+                     arg_4,
+                     arg_5,
+                     arg_6,
+                     arg_7,
+                     arg_8,
+                     arg_9,
+                     arg_10,
+                     arg_11,
+                     len_11,
+                     arg_12,
+                     len_12,
+                     arg_13,
+                     len_13,
+                     arg_14,
+                     len_14,
+                     arg_15,
+                     len_15,
+                     arg_16,
+                     len_16,
+                     arg_17,
+                     len_17,
+                     arg_18,
+                     len_18,
+                     arg_19,
+                     len_19,
+                     arg_20,
+                     len_20);
+}
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
index 23091a7bfb48f47bf49ea1692e1095d7648a4e09..137dab8a08502b482b445f254c42095202047526 100644
--- a/src/tests/sbus_codegen_tests_generated.h
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -22,6 +22,7 @@
 /* constants for com.planetexpress.Pilot */
 #define TEST_PILOT "com.planetexpress.Pilot"
 #define TEST_PILOT_BLINK "Blink"
+#define TEST_PILOT_EJECT "Eject"
 #define TEST_PILOT_FULLNAME "FullName"
 
 /* ------------------------------------------------------------------------
@@ -60,11 +61,15 @@ int com_planetexpress_Ship_crash_now_finish(struct sbus_request *req);
 struct test_pilot {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
     int (*Blink)(struct sbus_request *req, void *data, uint32_t arg_duration);
+    int (*Eject)(struct sbus_request *req, void *data, uint8_t arg_byte, bool arg_boolean, int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32, uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64, double arg_double, const char *arg_string, const char *arg_object_path, uint8_t arg_byte_array[], int len_byte_array, int16_t arg_int16_array[], int len_int16_array, uint16_t arg_uint16_array[], int len_uint16_array, int32_t arg_int32_array[], int len_int32_array, uint32_t arg_uint32_array[], int len_uint32_array, int64_t arg_int64_array[], int len_int64_array, uint64_t arg_uint64_array[], int len_uint64_array, double arg_double_array[], int len_double_array, const char *arg_string_array[], int len_string_array, const char *arg_object_path_array[], int len_object_path_array);
 };
 
 /* finish function for Blink */
 int test_pilot_Blink_finish(struct sbus_request *req, bool arg_crashed);
 
+/* finish function for Eject */
+int test_pilot_Eject_finish(struct sbus_request *req, uint8_t arg_byte, bool arg_boolean, int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32, uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64, double arg_double, const char *arg_string, const char *arg_object_path, uint8_t arg_byte_array[], int len_byte_array, int16_t arg_int16_array[], int len_int16_array, uint16_t arg_uint16_array[], int len_uint16_array, int32_t arg_int32_array[], int len_int32_array, uint32_t arg_uint32_array[], int len_uint32_array, int64_t arg_int64_array[], int len_int64_array, uint64_t arg_uint64_array[], int len_uint64_array, double arg_double_array[], int len_double_array, const char *arg_string_array[], int len_string_array, const char *arg_object_path_array[], int len_object_path_array);
+
 /* ------------------------------------------------------------------------
  * DBus Interface Metadata
  *
-- 
1.9.0



More information about the sssd-devel mailing list