[SSSD] [PATCH] Implement type-safe getters for primitive types and their arrays

Jakub Hrozek jhrozek at redhat.com
Wed May 21 20:49:15 UTC 2014


On Fri, May 16, 2014 at 01:09:12PM +0200, Lukas Slebodnik wrote:
> On (16/05/14 00:48), Jakub Hrozek wrote:
> >On Tue, May 13, 2014 at 07:04:22PM +0200, Stef Walter wrote:
> >> On 12.05.2014 23:27, Jakub Hrozek wrote:
> >> > Hi,
> >> > 
> >> > the attached patchset implement the
> >> > org.freedesktop.DBus.Properties.Get() interface for properties of
> >> > primitive types and arrays of primitive types (except for array of bools
> >> > as DBus bool is of different size than C-sized bool).
> >> 
> >> This looks nice to me. A few comments.
> >> 
> >> +    dbus_message_iter_init_append(reply, &iter);
> >> +    dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
> >> +                                             strtype, &valiter);
> >> +    if (!dbret) {
> >> +        sbus_request_finish(dbus_req, NULL);
> >> +        ret = EINVAL;
> >> +        goto done;
> >> +    }
> >> 
> >> You probably want some diagnostics here, as this is where you'll end up
> >> if you pass in an invalid @type.
> >
> >Thanks, I was fooled by the doxygen comment that said the function only
> >returns false on OOM. But the code is pretty conclusive, so I've added a
> >nicer error messages for this case and the others as well.
> >
> >> 
> >> > +    for (i = 0; i < len; i++) {
> >> > +        addr = values + i * item_size;
> >> > +        dbret = dbus_message_iter_append_basic(&array_iter, type, addr);
> >> > +        if (!dbret) {
> >> > +            sbus_request_finish(dbus_req, NULL);
> >> > +            ret = ENOMEM;
> >> > +            goto done;
> >> > +        }
> >> > +    }
> >> 
> >> Are you planning on using this for byte arrays and such? If so it may be
> >> worth looking into special casing arrays of bytes/ints with
> >> dbus_message_iter_append_fixed_array()
> >> 
> >> http://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html#ga6e2d1e936c3c61fe00d80a3f22fd5e76
> >> 
> >> But maybe that's not needed in this initial patchset?
> >
> >I haven't changed this part in the attached patchset, but I'm fine with
> >the change you propose -- maybe I just don't see the rationale. Is there
> >a performance boost? Is it worth the additional if-else?
> >
> >> 
> >> > From d23886c484bc955bf4bc03998601aeec1650ce02 Mon Sep 17 00:00:00 2001
> >> > From: Stef Walter <stefw at redhat.com>
> >> > Date: Tue, 25 Feb 2014 18:31:03 +0100
> >> > Subject: [PATCH 4/6] WIP properties
> >> 
> >> Should I give this a better commit message? :)
> >
> >Oops, that's something I meant to change before sending the patches and
> >then didn't. The attached patchset changes the message to something
> >hopefully better..feel free to propose a different commit message,
> >though.
> >
> >> 
> >> > +    if prop.type == "s":
> >> > +        out("    out_val = prop_val == NULL ? \"\" : prop_val;")
> >> 
> >> You'll probably also want to special case object paths, returning "/" in
> >> those cases.
> >
> >Yes. I also added unit tests for both these special cases.
> >
> >Thank you very much for the review. New patches are attached.
> 
> I let review for others.
> 
> I just want to write that problem with builing patches on rhle6 is fixed
> and warnings from static analysers are gone.
> 
> LS

Thanks for running the patches through static analysers and testing the
build!

I'm attaching a new patchset that has some simplifications in the unit
test warranted by the GetAll patchset and include the Get method in the
introspection XML.

Any comments on the patches are welcome!
-------------- next part --------------
>From 9f13bc2bfe2cc64d56d2eabf7d23092933eac96c Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 12 May 2014 18:59:35 +0200
Subject: [PATCH 1/9] SBUS: Utility function sbus_request_return_as_variant

Adds a utility function that returns a single value with a given type in
a variant. This utility function will be used by the Get property call.
---
 src/sbus/sssd_dbus.h         |  4 +++
 src/sbus/sssd_dbus_request.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index 15ca521184f82c7424549907b7afa912f891c3ad..efb0296813e9946f2b2fa1fd867592315cc4ee4f 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -246,6 +246,10 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req,
                                    int first_arg_type,
                                    ...);
 
+int sbus_request_return_as_variant(struct sbus_request *dbus_req,
+                                   int type,
+                                   const void *value);
+
 /*
  * Return an error for a DBus method call request. The @error is a normal
  * DBusError.
diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
index 2d23931aa07a83c15c30b31615d5db7cfee11a0a..6c0cb4dac1e544114d7d6b2853826c44abe1d9b8 100644
--- a/src/sbus/sssd_dbus_request.c
+++ b/src/sbus/sssd_dbus_request.c
@@ -125,6 +125,70 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req,
     return ret;
 }
 
+int sbus_request_return_as_variant(struct sbus_request *dbus_req,
+                                   int type,
+                                   const void *value)
+{
+    DBusMessage *reply;
+    dbus_bool_t dbret;
+    DBusMessageIter iter;
+    DBusMessageIter valiter;
+    char strtype[2];
+    int ret;
+
+    snprintf(strtype, 2, "%c", type);
+
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (reply == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating DBus message\n");
+        sbus_request_finish(dbus_req, NULL);
+        return ENOMEM;
+    }
+
+    dbus_message_iter_init_append(reply, &iter);
+    dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                             strtype, &valiter);
+    if (!dbret) {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not open variant for [%s]\n",
+                                        strtype));
+        ret = EINVAL;
+        goto done;
+    }
+
+    dbret = dbus_message_iter_append_basic(&valiter, type, value);
+    if (!dbret) {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not append [%s] to variant\n",
+                                        strtype));
+        ret = EINVAL;
+        goto done;
+    }
+
+    dbret = dbus_message_iter_close_container(&iter, &valiter);
+    if (dbret) {
+        ret = sbus_request_finish(dbus_req, reply);
+    } else {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not close variant\n"));
+        ret = EINVAL;
+    }
+
+done:
+    dbus_message_unref(reply);
+    return ret;
+}
+
+
 int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
                                  const DBusError *error)
 {
-- 
1.9.0

-------------- next part --------------
>From d2f99b4e0ece2dd6652a266726e19ea7ce6323af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
Date: Mon, 12 May 2014 19:00:36 +0200
Subject: [PATCH 2/9] SBUS: Utility function
 sbus_request_return_array_as_variant

Adds a utility function that returns an array of types values, each of a
given size, with a given type in a variant. This utility function will be
used by the GetAll property call.
---
 src/sbus/sssd_dbus.h         |   6 +++
 src/sbus/sssd_dbus_request.c | 118 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+)

diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index efb0296813e9946f2b2fa1fd867592315cc4ee4f..a19f1d9c65656ce38e0e587b6cf71c3c947f4593 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -250,6 +250,12 @@ int sbus_request_return_as_variant(struct sbus_request *dbus_req,
                                    int type,
                                    const void *value);
 
+int sbus_request_return_array_as_variant(struct sbus_request *dbus_req,
+                                         int type,
+                                         uint8_t *values,
+                                         const int len,
+                                         const size_t item_size);
+
 /*
  * Return an error for a DBus method call request. The @error is a normal
  * DBusError.
diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
index 6c0cb4dac1e544114d7d6b2853826c44abe1d9b8..2852f87d833d448e330fb36525083c4c8eb78605 100644
--- a/src/sbus/sssd_dbus_request.c
+++ b/src/sbus/sssd_dbus_request.c
@@ -189,6 +189,124 @@ done:
 }
 
 
+int sbus_request_return_array_as_variant(struct sbus_request *dbus_req,
+                                         int type,
+                                         uint8_t *values,
+                                         const int len,
+                                         const size_t item_size)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    DBusMessage *reply = NULL;
+    dbus_bool_t dbret;
+    DBusMessageIter iter;
+    DBusMessageIter variant_iter;
+    DBusMessageIter array_iter;
+    char *variant_type = NULL;
+    char *array_type = NULL;
+    void *addr = NULL;
+    int ret;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    variant_type = talloc_asprintf(tmp_ctx, DBUS_TYPE_ARRAY_AS_STRING "%c",
+                                   type);
+    if (variant_type == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    array_type = talloc_asprintf(tmp_ctx, "%c", type);
+    if (array_type == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (reply == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating DBus message\n");
+        sbus_request_finish(dbus_req, NULL);
+        ret = ENOMEM;
+        goto done;
+    }
+
+    dbus_message_iter_init_append(reply, &iter);
+    dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                             variant_type, &variant_iter);
+    if (!dbret) {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not open variant for [%s]\n",
+                                        variant_type));
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* Open container for values */
+    dbret = dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             array_type, &array_iter);
+    if (!dbret) {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not open array for [%s]\n",
+                                        array_type));
+        ret = EINVAL;
+        goto done;
+    }
+
+    for (i = 0; i < len; i++) {
+        addr = values + i * item_size;
+        dbret = dbus_message_iter_append_basic(&array_iter, type, addr);
+        if (!dbret) {
+            sbus_request_fail_and_finish(
+                                dbus_req,
+                                sbus_error_new(dbus_req,
+                                            DBUS_ERROR_FAILED,
+                                            "Could not append [%s] to variant\n",
+                                            array_type));
+            ret = EINVAL;
+            goto done;
+        }
+    }
+
+    dbret = dbus_message_iter_close_container(&variant_iter, &array_iter);
+    if (!dbret) {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not close array\n"));
+        ret = EINVAL;
+    }
+
+    dbret = dbus_message_iter_close_container(&iter, &variant_iter);
+    if (dbret) {
+        ret = sbus_request_finish(dbus_req, reply);
+    } else {
+        sbus_request_fail_and_finish(
+                            dbus_req,
+                            sbus_error_new(dbus_req,
+                                        DBUS_ERROR_FAILED,
+                                        "Could not close variant\n"));
+        ret = EINVAL;
+    }
+
+done:
+    if (reply != NULL) {
+        dbus_message_unref(reply);
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
                                  const DBusError *error)
 {
-- 
1.9.0

-------------- next part --------------
>From 0822e21adeb0287c913e628d897deb93d2029252 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 22 Apr 2014 21:50:28 +0200
Subject: [PATCH 3/9] IFP: Allow Set, Get and GetAll from DBus.Properties

The InfoPipe will support all three of:
    DBus.Properties.Get
    DBus.Properties.GetAll
    DBus.Properties.Set

Hence it must allow these calls to be received.
---
 src/responder/ifp/org.freedesktop.sssd.infopipe.conf | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
index 56e460aa11c2534e95092fb10216b05c50c04d59..4f2a906ba812d46b6bca401d3fc14baa5c18de50 100644
--- a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
+++ b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
@@ -19,6 +19,16 @@
     <allow send_destination="org.freedesktop.sssd.infopipe"
            send_interface="org.freedesktop.DBus.Introspectable"/>
 
+    <allow send_destination="org.freedesktop.sssd.infopipe"
+           send_interface="org.freedesktop.DBus.Properties"
+           send_member="GetAll"/>
+    <allow send_destination="org.freedesktop.sssd.infopipe"
+           send_interface="org.freedesktop.DBus.Properties"
+           send_member="Get"/>
+    <allow send_destination="org.freedesktop.sssd.infopipe"
+           send_interface="org.freedesktop.DBus.Properties"
+           send_member="Set"/>
+
     <allow send_interface="org.freedesktop.sssd.infopipe"/>
   </policy>
 
-- 
1.9.0

-------------- next part --------------
>From 334390727b4cb1fc88935a90e4be79c6b3ff07c6 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 25 Feb 2014 18:31:03 +0100
Subject: [PATCH 4/9] SBUS: Start implementing property access

This patch adds the basis of SBUS getters and setters. A new module,
sssd_dbus_properties.c would contain handlers for the property methods
like Get, Set and GetAll.

Type-safe property access works in a similar fashion like type-safe
method calls - the invoker calls the getter which returns the primitive
type, which is in turn marshalled into variant by the invoker.

This patch does not contain the complete functionality, see later
patches that continue implementing the getters and setters.
---
 Makefile.am                              |   1 +
 src/sbus/sbus_codegen                    |  72 +++++++++++++++---
 src/sbus/sssd_dbus.h                     |   4 +
 src/sbus/sssd_dbus_connection.c          |  17 +++--
 src/sbus/sssd_dbus_meta.h                |   2 +
 src/sbus/sssd_dbus_private.h             |   8 ++
 src/sbus/sssd_dbus_properties.c          | 122 +++++++++++++++++++++++++++++++
 src/tests/sbus_codegen_tests_generated.c |   4 +-
 src/util/util_errors.c                   |   1 +
 src/util/util_errors.h                   |   1 +
 10 files changed, 213 insertions(+), 19 deletions(-)
 create mode 100644 src/sbus/sssd_dbus_properties.c

diff --git a/Makefile.am b/Makefile.am
index 483584e5320bfcd8e262ed03d9be7fa670a38932..138caf841ddb9b8f224fa30fa2dab1a49330c314 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -621,6 +621,7 @@ libsss_util_la_SOURCES = \
     src/sbus/sssd_dbus_connection.c \
     src/sbus/sssd_dbus_meta.c \
     src/sbus/sssd_dbus_introspect.c \
+    src/sbus/sssd_dbus_properties.c \
     src/sbus/sssd_dbus_request.c \
     src/sbus/sssd_dbus_server.c \
     src/util/util.c \
diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index 6c4b8ec9a1f64cc243afb0fe5d12617b3ef586f0..96248a62886ad03439b4a4996f4668c1b610d990 100755
--- a/src/sbus/sbus_codegen
+++ b/src/sbus/sbus_codegen
@@ -114,10 +114,9 @@ BASIC_TYPES = {
  'o': ( "DBUS_TYPE_OBJECT_PATH", "const char *", "const char *" ),
 }
 
-class Arg(Base):
-    def __init__(self, method, name, type):
+class Typed(Base):
+    def __init__(self, name, type):
         Base.__init__(self, name)
-        self.method = method
         self.type = type
         self.is_basic = False
         self.is_array = False
@@ -135,6 +134,11 @@ class Arg(Base):
             else:
                 self.is_basic = True
 
+class Arg(Typed):
+    def __init__(self, method, name, type):
+        Typed.__init__(self, name, type)
+        self.method = method
+
 class Method(Base):
     def __init__(self, iface, name):
         Base.__init__(self, name)
@@ -166,11 +170,10 @@ class Signal(Base):
     def fq_c_name(self):
         return "%s_%s" % (self.iface.c_name(), self.c_name())
 
-class Property(Base):
-    def __init__(self, iface, name, signature, access):
-        Base.__init__(self, name)
+class Property(Typed):
+    def __init__(self, iface, name, type, access):
+        Typed.__init__(self, name, type)
         self.iface = iface
-        self.signature = signature
         self.readable = False
         self.writable = False
         if access == 'readwrite':
@@ -234,7 +237,7 @@ def method_function_pointer(meth, name, with_names=False):
              with_names and "data" or "",
              method_arg_types(meth.in_args, with_names))
 
-def forward_invoker(signature, args):
+def forward_method_invoker(signature, args):
     out("")
     out("/* invokes a handler with a '%s' DBus signature */", signature)
     out("static int invoke_%s_method(struct sbus_request *dbus_req, void *function_ptr);", signature)
@@ -275,6 +278,53 @@ def source_method_invoker(signature, args):
     out(");")
     out("}")
 
+def source_getter_invoker(prop):
+    out("")
+    out("/* invokes a getter with a '%s' DBus type */", type)
+    out("static int invoke_%s_getter(struct sbus_request *request, struct sbus_interface *intf, void *function_ptr)", prop.type)
+    out("{")
+    out("    DBusError error = DBUS_ERROR_INIT;")
+    out("    int ret;")
+    for i in range(0, len(args)):
+        arg = args[i]
+        if arg.is_array:
+            out("    %s *arg_%d;", arg.dbus_type, i)
+            out("    int len_%d;", i)
+        else:
+            out("    %s arg_%d;", arg.dbus_type, i)
+    out("    int (*handler)(struct sbus_request *, void *%s) = function_ptr;", method_arg_types(args))
+    out("")
+    out("    if (!dbus_message_get_args(request->message, &error,")
+    for i in range(0, len(args)):
+        arg = args[i]
+        if arg.is_array:
+            out("                               DBUS_TYPE_ARRAY, %s, &arg_%d, &len_%d,",
+                arg.dbus_constant, i, i)
+        else:
+            out("                               %s, &arg_%d,", arg.dbus_constant, i)
+    out("                               DBUS_TYPE_INVALID)) {")
+    out("         ret = sbus_request_fail_and_finish(request, error.name, error.message);")
+    out("         dbus_error_free(&error);")
+    out("         return ret;")
+    out("    }")
+    out("")
+
+    out("    ret = (handler)(request, intf", new_line=False)
+    for i in range(0, len(args)):
+        arg = args[i]
+        out(",\n                    arg_%d", i, new_line=False)
+        if arg.is_array:
+            out(",\n                    len_%d", i, new_line=False)
+    out(");")
+    out("")
+
+    for i in range(0, len(args)):
+        arg = args[i]
+        if arg.type in ["as", "ao"]:
+            out("    dbus_free_string_array((char **)arg_%d);", i)
+    out("    return ret;")
+    out("}")
+
 def forward_method_invokers(ifaces):
     invokers = { }
     for iface in ifaces:
@@ -284,7 +334,7 @@ def forward_method_invokers(ifaces):
             signature = meth.in_signature()
             if signature in invokers:
                 continue
-            forward_invoker(signature, meth.in_args)
+            forward_method_invoker(signature, meth.in_args)
             invokers[signature] = meth
     return invokers
 
@@ -392,7 +442,7 @@ def source_properties(iface, properties):
     for prop in properties:
         out("    {")
         out("        \"%s\", /* name */", prop.name)
-        out("        \"%s\", /* signature */", prop.signature)
+        out("        \"%s\", /* type */", prop.type)
         if prop.readable and prop.writable:
             out("        SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,")
         elif prop.readable:
@@ -480,8 +530,6 @@ def header_vtable(iface, methods):
     for meth in iface.methods:
         out("    %s;", method_function_pointer(meth, meth.c_name(), with_names=True))
 
-    # TODO: Property getters and setters will go here
-
     out("};")
 
 def header_constants(iface):
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index a19f1d9c65656ce38e0e587b6cf71c3c947f4593..9c236479e5474b884d8e051ea221c77a40ed6ac7 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -80,6 +80,9 @@ struct sbus_vtable {
 #define DBUS_INTROSPECT_INTERFACE "org.freedesktop.DBus.Introspectable"
 #define DBUS_INTROSPECT_METHOD "Introspect"
 
+/* Special interface and method for D-BUS properties */
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+
 struct sbus_interface {
     const char *path;
     struct sbus_vtable *vtable;
@@ -257,6 +260,7 @@ int sbus_request_return_array_as_variant(struct sbus_request *dbus_req,
                                          const size_t item_size);
 
 /*
+
  * Return an error for a DBus method call request. The @error is a normal
  * DBusError.
  *
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index 4d3782e56770d6ea1c16837a91089417dddba755..af1c8c56afee7a033e90bc6b2e92c7d8258139a0 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -437,6 +437,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
 
     /* Validate the method interface */
     if (strcmp(msg_interface, intf_p->intf->vtable->meta->name) == 0 ||
+             strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0 ||
             (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
                 strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0)) {
 
@@ -510,11 +511,7 @@ static void sbus_handler_got_caller_id(struct tevent_req *req)
             dbus_error = DBUS_ERROR_NOT_SUPPORTED;
             goto fail;
         }
-    } else {
-        /* Special case: check for Introspection request
-         * This is usually only useful for system bus connections
-         */
-        if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
+    } else if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
                 strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0) {
             DEBUG(SSSDBG_TRACE_LIBS, "Got introspection request\n");
             ictx = talloc(dbus_req->conn, struct sbus_introspect_ctx);
@@ -527,7 +524,17 @@ static void sbus_handler_got_caller_id(struct tevent_req *req)
             ictx->iface = interface;
             handler_data = ictx;
             method = &introspect_method;
+    } else if (strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0) {
+        ret = sbus_properties_dispatch(dbus_req);
+        if (ret == ERR_SBUS_NOSUP) {
+            /* No known method matched */
+            dbus_error = DBUS_ERROR_NOT_SUPPORTED;
+            goto fail;
         }
+        /* sbus_properties_dispatch handles all other errors
+         * or success internally
+         */
+        return;
     }
 
     if (handler_fn == NULL) {
diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h
index 997aa9e464df91d2378ae42fcf7fdaaa05a9a2f3..0ad21df97f8cb321628896f0e06088db4533101a 100644
--- a/src/sbus/sssd_dbus_meta.h
+++ b/src/sbus/sssd_dbus_meta.h
@@ -60,6 +60,8 @@ struct sbus_property_meta {
     const char *name;
     const char *type;
     int flags;
+    size_t vtable_offset_set;
+    sbus_method_invoker_fn invoker_set;
 };
 
 struct sbus_signal_meta {
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index 65189b5ff980e34e653a0bc10760290a223e60b6..fa11bc1c8ef625ba6c6e9382d7ccd146eabdbb26 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -68,6 +68,10 @@ struct sbus_connection {
     struct sbus_watch_ctx *watch_list;
 };
 
+/* Looks up a vtable func, in a struct derived from struct sbus_vtable */
+#define VTABLE_FUNC(vtable, offset) \
+    (*((void **)((char *)(vtable) + (offset))))
+
 /* =Watches=============================================================== */
 
 struct sbus_watch_ctx {
@@ -137,4 +141,8 @@ struct tevent_req *sbus_get_sender_id_send(TALLOC_CTX *mem_ctx,
                                            const char *sender);
 int sbus_get_sender_id_recv(struct tevent_req *req, int64_t *_uid);
 
+/* =Properties============================================================ */
+
+int sbus_properties_dispatch(struct sbus_request *dbus_req);
+
 #endif /* _SSSD_DBUS_PRIVATE_H_ */
diff --git a/src/sbus/sssd_dbus_properties.c b/src/sbus/sssd_dbus_properties.c
new file mode 100644
index 0000000000000000000000000000000000000000..835b3078b5abd124ab98265401aa48533a306ee3
--- /dev/null
+++ b/src/sbus/sssd_dbus_properties.c
@@ -0,0 +1,122 @@
+/*
+    Authors:
+        Stef Walter <stefw at redhat.com>
+
+    Copyright (C) 2014 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_meta.h"
+#include "sbus/sssd_dbus_private.h"
+
+static int
+dispatch_properties_set(struct sbus_connection *conn,
+                        struct sbus_interface *intf,
+                        DBusMessage *message)
+{
+    const char *signature;
+    const struct sbus_interface_meta *meta;
+    const struct sbus_property_meta *property;
+    const char *interface_name;
+    const char *property_name;
+    const char *type;
+    struct sbus_request *req;
+    sbus_msg_handler_fn handler_fn;
+    DBusMessageIter iter;
+    DBusMessageIter variant;
+
+    req = sbus_new_request(conn, intf, message);
+    if (!req)
+        return ENOMEM;
+
+    meta = intf->vtable->meta;
+
+    signature = dbus_message_get_signature(message);
+    if (strcmp (signature, "ssv") != 0) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_INVALID_ARGS,
+                                   "Invalid argument types passed " \
+                                   "to Set method"));
+    }
+
+    dbus_message_iter_init (message, &iter);
+    dbus_message_iter_get_basic (&iter, &interface_name);
+    dbus_message_iter_next (&iter);
+    dbus_message_iter_get_basic (&iter, &property_name);
+    dbus_message_iter_next (&iter);
+
+    if (strcmp (interface_name, meta->name) != 0) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_UNKNOWN_INTERFACE,
+                                   "No such interface"));
+    }
+
+    property = sbus_meta_find_property (intf->vtable->meta, property_name);
+    if (property == NULL) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_UNKNOWN_PROPERTY,
+                                   "No such property"));
+    }
+
+    if (!(property->flags & SBUS_PROPERTY_WRITABLE)) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_PROPERTY_READ_ONLY,
+                                   "Property is not writable"));
+    }
+
+    dbus_message_iter_recurse(&iter, &variant);
+    type = dbus_message_iter_get_signature (&variant);
+    if (strcmp (property->type, type) != 0) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_INVALID_ARGS,
+                                   "Invalid data type for property"));
+    }
+
+    handler_fn = VTABLE_FUNC(intf->vtable, property->vtable_offset_set);
+    if (!handler_fn) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_NOT_SUPPORTED,
+                                   "Not implemented"));
+    }
+
+    sbus_request_invoke_or_finish(req, handler_fn,
+                                  intf->instance_data,
+                                  property->invoker_set);
+    return EOK;
+}
+
+int sbus_properties_dispatch(struct sbus_request *dbus_req)
+{
+    const char *member;
+
+    member = dbus_message_get_member(dbus_req->message);
+
+    /* Set is handled a lot like a method invocation */
+    if (strcmp(member, "Set") == 0) {
+        return dispatch_properties_set(dbus_req->conn,
+                                       dbus_req->intf,
+                                       dbus_req->message);
+    }
+
+    return ERR_SBUS_NOSUP;
+}
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index 4ba2577489ddb2e1c7c72a37b97561946f4f23b8..40d40cdc471b90f6b0d3fb52033f7ec9817c1772 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -94,7 +94,7 @@ const struct sbus_signal_meta com_planetexpress_Ship__signals[] = {
 const struct sbus_property_meta com_planetexpress_Ship__properties[] = {
     {
         "Color", /* name */
-        "s", /* signature */
+        "s", /* type */
         SBUS_PROPERTY_READABLE,
     },
     { NULL, }
@@ -231,7 +231,7 @@ const struct sbus_method_meta test_pilot__methods[] = {
 const struct sbus_property_meta test_pilot__properties[] = {
     {
         "FullName", /* name */
-        "s", /* signature */
+        "s", /* type */
         SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,
     },
     { NULL, }
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index 2b99faf747515f00677273b8630ff49a742e738d..113567423007cb39d3314ddfad9ba168fddb4f63 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -59,6 +59,7 @@ struct err_string error_to_str[] = {
     { "Cannot get bus message sender" }, /* ERR_SBUS_GET_SENDER_ERROR */
     { "Bus message has no sender" }, /* ERR_SBUS_NO_SENDER */
     { "User/Group SIDs not found" }, /* ERR_NO_SIDS */
+    { "Bus method not supported" }, /* ERR_SBUS_NOSUP */
 };
 
 
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index da518272b8a6a8b89a91cddabfa8e0d21fc05e7b..b88c7969bea90208ccb61cc1240b181cc0330774 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -81,6 +81,7 @@ enum sssd_errors {
     ERR_SBUS_GET_SENDER_ERROR,
     ERR_SBUS_NO_SENDER,
     ERR_NO_SIDS,
+    ERR_SBUS_NOSUP,
     ERR_LAST            /* ALWAYS LAST */
 };
 
-- 
1.9.0

-------------- next part --------------
>From a8a648e51bb35f5a067a3aeaed8a0c43f8869e2e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 23 Apr 2014 03:01:21 +0200
Subject: [PATCH 5/9] SBUS: Implement org.freedesktop.DBus.Properties.Get for
 primitive types

This patch implements type-safe getters for primitive types and their
arrays.  The patch includes unit tests of all supported types and arrays
of these types.

All getter are synchronous. The getters never fail, instead, they return
a default or 'not defined' value.  Making the getters synchronous and
always returning a value will make it significantly easier to implement
the GetAll method.
---
 src/sbus/sbus_codegen                    | 114 ++++---
 src/sbus/sssd_dbus_meta.h                |   2 +
 src/sbus/sssd_dbus_properties.c          |  75 +++++
 src/tests/sbus_codegen_tests.c           | 490 ++++++++++++++++++++++++++++-
 src/tests/sbus_codegen_tests.xml         |  26 ++
 src/tests/sbus_codegen_tests_generated.c | 522 +++++++++++++++++++++++++++++++
 src/tests/sbus_codegen_tests_generated.h |  44 +++
 7 files changed, 1229 insertions(+), 44 deletions(-)

diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index 96248a62886ad03439b4a4996f4668c1b610d990..a8f91b784ffaa5a17620792df7285df4b508749f 100755
--- a/src/sbus/sbus_codegen
+++ b/src/sbus/sbus_codegen
@@ -187,6 +187,16 @@ class Property(Typed):
             raise DBusXmlException('Invalid access type %s'%self.access)
     def fq_c_name(self):
         return "%s_%s" % (self.iface.c_name(), self.c_name())
+    def getter_name(self):
+        return "%s_get_%s" % (self.iface.c_name(), self.c_name())
+    def getter_invoker_name(self):
+        return "invoke_get_%s" % self.type
+    def getter_signature(self, name):
+        sig = "void (*%s)(struct sbus_request *, void *data, %s *" % (name, self.sssd_type)
+        if self.is_array:
+            sig += " *, int *"
+        sig += ")"
+        return sig
 
 class Interface(Base):
     def __init__(self, name):
@@ -237,6 +247,9 @@ def method_function_pointer(meth, name, with_names=False):
              with_names and "data" or "",
              method_arg_types(meth.in_args, with_names))
 
+def property_handlers(prop):
+    return prop.getter_signature(prop.getter_name())
+
 def forward_method_invoker(signature, args):
     out("")
     out("/* invokes a handler with a '%s' DBus signature */", signature)
@@ -280,49 +293,36 @@ def source_method_invoker(signature, args):
 
 def source_getter_invoker(prop):
     out("")
-    out("/* invokes a getter with a '%s' DBus type */", type)
-    out("static int invoke_%s_getter(struct sbus_request *request, struct sbus_interface *intf, void *function_ptr)", prop.type)
+    if prop.is_array:
+        out("/* invokes a getter with an array of '%s' DBus type */", prop.dbus_type)
+    else:
+        out("/* invokes a getter with a '%s' DBus type */", prop.dbus_type)
+    out("static int %s(struct sbus_request *dbus_req, void *function_ptr)",
+        prop.getter_invoker_name())
     out("{")
-    out("    DBusError error = DBUS_ERROR_INIT;")
-    out("    int ret;")
-    for i in range(0, len(args)):
-        arg = args[i]
-        if arg.is_array:
-            out("    %s *arg_%d;", arg.dbus_type, i)
-            out("    int len_%d;", i)
-        else:
-            out("    %s arg_%d;", arg.dbus_type, i)
-    out("    int (*handler)(struct sbus_request *, void *%s) = function_ptr;", method_arg_types(args))
+    if prop.is_array:
+        out("    %s *prop_val;", prop.sssd_type)
+        out("    int prop_len;")
+        out("    %s *out_val;", prop.dbus_type)
+    else:
+        out("    %s prop_val;", prop.sssd_type)
+        out("    %s out_val;", prop.dbus_type)
     out("")
-    out("    if (!dbus_message_get_args(request->message, &error,")
-    for i in range(0, len(args)):
-        arg = args[i]
-        if arg.is_array:
-            out("                               DBUS_TYPE_ARRAY, %s, &arg_%d, &len_%d,",
-                arg.dbus_constant, i, i)
-        else:
-            out("                               %s, &arg_%d,", arg.dbus_constant, i)
-    out("                               DBUS_TYPE_INVALID)) {")
-    out("         ret = sbus_request_fail_and_finish(request, error.name, error.message);")
-    out("         dbus_error_free(&error);")
-    out("         return ret;")
-    out("    }")
+    out("    %s", prop.getter_signature("handler"), new_line=False)
+    out(" = function_ptr;")
     out("")
 
-    out("    ret = (handler)(request, intf", new_line=False)
-    for i in range(0, len(args)):
-        arg = args[i]
-        out(",\n                    arg_%d", i, new_line=False)
-        if arg.is_array:
-            out(",\n                    len_%d", i, new_line=False)
+    out("    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val", new_line=False)
+    if prop.is_array:
+        out(", &prop_len", new_line=False)
     out(");")
-    out("")
 
-    for i in range(0, len(args)):
-        arg = args[i]
-        if arg.type in ["as", "ao"]:
-            out("    dbus_free_string_array((char **)arg_%d);", i)
-    out("    return ret;")
+    out("")
+    out("    out_val = prop_val;")
+    if prop.is_array:
+        out("    return sbus_request_return_array_as_variant(dbus_req, %s, (uint8_t*)out_val, prop_len, sizeof(%s));", prop.dbus_constant, prop.sssd_type)
+    else:
+        out("    return sbus_request_return_as_variant(dbus_req, %s, &out_val);", prop.dbus_constant)
     out("}")
 
 def forward_method_invokers(ifaces):
@@ -342,6 +342,27 @@ def source_method_invokers(invokers):
     for (signature, meth) in invokers.items():
         source_method_invoker(signature, meth.in_args)
 
+def forward_prop_invoker(prop):
+    out("static int %s(struct sbus_request *dbus_req, void *function_ptr);",
+        prop.getter_invoker_name())
+
+def forward_prop_invokers(ifaces):
+    invokers = { }
+    for iface in ifaces:
+        for prop in iface.properties:
+            if not prop.is_basic:
+                continue
+            if prop.type in invokers:
+                continue
+            forward_prop_invoker(prop)
+            invokers[prop.type] = prop
+    return invokers
+
+def source_prop_invokers(invokers):
+    for (type, prop) in invokers.items():
+        if prop.readable:
+            source_getter_invoker(prop)
+
 def source_finisher(meth):
     out("")
     out("int %s_finish(struct sbus_request *req%s)",
@@ -438,6 +459,7 @@ def source_signals(iface, signals):
 def source_properties(iface, properties):
     out("")
     out("/* property info for %s */", iface.name)
+
     out("const struct sbus_property_meta %s__properties[] = {", iface.c_name())
     for prop in properties:
         out("    {")
@@ -451,6 +473,14 @@ def source_properties(iface, properties):
             out("        SBUS_PROPERTY_WRITABLE,")
         else:
             assert False, "should not be reached"
+        if prop.readable:
+            out("        offsetof(struct %s, %s),", iface.c_name(), prop.getter_name())
+            out("        %s,", prop.getter_invoker_name())
+        else:
+            out("        0, /* not readable */")
+            out("        NULL, /* no invoker */")
+        out("        0, /* not writable */")
+        out("        NULL, /* no invoker */")
         out("    },")
     out("    { NULL, }")
     out("};")
@@ -491,7 +521,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)
+    meth_invokers = forward_method_invokers(ifaces)
+    prop_invokers = forward_prop_invokers(ifaces)
 
     for iface in ifaces:
 
@@ -510,7 +541,8 @@ def generate_source(ifaces, filename, include_header=None):
         # The sbus_interface structure
         source_interface(iface)
 
-    source_method_invokers(invokers)
+    source_method_invokers(meth_invokers)
+    source_prop_invokers(prop_invokers)
 
 def header_finisher(iface, meth):
     if meth.use_raw_handler():
@@ -529,6 +561,8 @@ def header_vtable(iface, methods):
     # All methods
     for meth in iface.methods:
         out("    %s;", method_function_pointer(meth, meth.c_name(), with_names=True))
+    for prop in iface.properties:
+        out("    %s;", property_handlers(prop))
 
     out("};")
 
@@ -584,7 +618,7 @@ def generate_header(ifaces, filename):
     out(" */")
 
     for iface in ifaces:
-        if iface.methods:
+        if iface.methods or iface.properties:
             header_vtable(iface, iface.methods)
             for meth in iface.methods:
                 header_finisher(iface, meth)
diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h
index 0ad21df97f8cb321628896f0e06088db4533101a..4e170b7d6ce5fb8f68109e496ab96cfdf889d864 100644
--- a/src/sbus/sssd_dbus_meta.h
+++ b/src/sbus/sssd_dbus_meta.h
@@ -60,6 +60,8 @@ struct sbus_property_meta {
     const char *name;
     const char *type;
     int flags;
+    size_t vtable_offset_get;
+    sbus_method_invoker_fn invoker_get;
     size_t vtable_offset_set;
     sbus_method_invoker_fn invoker_set;
 };
diff --git a/src/sbus/sssd_dbus_properties.c b/src/sbus/sssd_dbus_properties.c
index 835b3078b5abd124ab98265401aa48533a306ee3..bdd5b432fe57ca66a4d06f98720578b3a175a65c 100644
--- a/src/sbus/sssd_dbus_properties.c
+++ b/src/sbus/sssd_dbus_properties.c
@@ -105,6 +105,77 @@ dispatch_properties_set(struct sbus_connection *conn,
     return EOK;
 }
 
+static int
+dispatch_properties_get(struct sbus_connection *conn,
+                        struct sbus_interface *intf,
+                        DBusMessage *message)
+{
+    struct sbus_request *req;
+    const char *signature;
+    const struct sbus_interface_meta *meta;
+    DBusMessageIter iter;
+    sbus_msg_handler_fn handler_fn;
+    const struct sbus_property_meta *property;
+    const char *interface_name;
+    const char *property_name;
+
+    req = sbus_new_request(conn, intf, message);
+    if (req == NULL) {
+        return ENOMEM;
+    }
+
+    meta = intf->vtable->meta;
+
+    signature = dbus_message_get_signature(message);
+    /* Interface name, property name */
+    if (strcmp(signature, "ss") != 0) {
+        return sbus_request_fail_and_finish(req,
+                 sbus_error_new(req,
+                                DBUS_ERROR_INVALID_ARGS,
+                                "Invalid argument types passed to Get method"));
+    }
+
+    dbus_message_iter_init(message, &iter);
+    dbus_message_iter_get_basic(&iter, &interface_name);
+    dbus_message_iter_next(&iter);
+    dbus_message_iter_get_basic(&iter, &property_name);
+
+    if (strcmp(interface_name, meta->name) != 0) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_UNKNOWN_INTERFACE,
+                                   "No such interface"));
+    }
+
+    property = sbus_meta_find_property(intf->vtable->meta, property_name);
+    if (property == NULL) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_UNKNOWN_PROPERTY,
+                                   "No such property"));
+    }
+
+    if (!(property->flags & SBUS_PROPERTY_READABLE)) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_ACCESS_DENIED,
+                                   "Property is not readable"));
+    }
+
+    handler_fn = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+    if (!handler_fn) {
+        return sbus_request_fail_and_finish(req,
+                    sbus_error_new(req,
+                                   DBUS_ERROR_NOT_SUPPORTED,
+                                   "Not implemented"));
+    }
+
+    sbus_request_invoke_or_finish(req, handler_fn,
+                                  intf->instance_data,
+                                  property->invoker_get);
+    return EOK;
+}
+
 int sbus_properties_dispatch(struct sbus_request *dbus_req)
 {
     const char *member;
@@ -116,6 +187,10 @@ int sbus_properties_dispatch(struct sbus_request *dbus_req)
         return dispatch_properties_set(dbus_req->conn,
                                        dbus_req->intf,
                                        dbus_req->message);
+    } else if (strcmp (member, "Get") == 0) {
+        return dispatch_properties_get(dbus_req->conn,
+                                       dbus_req->intf,
+                                       dbus_req->message);
     }
 
     return ERR_SBUS_NOSUP;
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index a88bbac38e7d4f89ec92043061cf25bb4ed7b972..fa31ad64dae578470cc004c0be066771d07ef2bf 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -33,6 +33,9 @@
 #include "tests/sbus_codegen_tests_generated.h"
 #include "util/util_errors.h"
 
+#define N_ELEMENTS(arr) \
+    (sizeof(arr) / sizeof(arr[0]))
+
 /* The following 2 macros were taken from check's project source files (0.9.10)
  * http://check.sourceforge.net/
  */
@@ -329,12 +332,225 @@ static int eject_handler(struct sbus_request *req, void *instance_data,
                                    arg_object_path_array, len_object_path_array);
 }
 
-#define N_ELEMENTS(arr) \
-    (sizeof(arr) / sizeof(arr[0]))
+#define getter_body(in, out) do {           \
+    ck_assert(dbus_req != NULL);            \
+    ck_assert(out != NULL);                 \
+    *out = in;                              \
+} while(0);
 
-struct test_pilot pilot_methods = {
+static const bool pilot_bool = true;
+void pilot_get_boolean_handler(struct sbus_request *dbus_req,
+                               void *instance_data,
+                               bool *val)
+{
+    getter_body(pilot_bool, val);
+}
+
+static const char *pilot_full_name = "Turanga Leela";
+void pilot_get_full_name_handler(struct sbus_request *dbus_req,
+                                 void *instance_data,
+                                 const char **name)
+{
+    getter_body(pilot_full_name, name);
+}
+
+static const uint8_t pilot_byte = 42;
+void pilot_get_byte_handler(struct sbus_request *dbus_req,
+                            void *instance_data,
+                            uint8_t *byte)
+{
+    getter_body(pilot_byte, byte);
+}
+
+static const int16_t pilot_int16 = -123;
+void pilot_get_int16_handler(struct sbus_request *dbus_req,
+                             void *instance_data,
+                             int16_t *int16)
+{
+    getter_body(pilot_int16, int16);
+}
+
+static const uint16_t pilot_uint16 = 123;
+void pilot_get_uint16_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              uint16_t *uint16)
+{
+    getter_body(pilot_uint16, uint16);
+}
+
+static const int32_t pilot_int32 = -456;
+void pilot_get_int32_handler(struct sbus_request *dbus_req,
+                             void *instance_data,
+                             int32_t *int32)
+{
+    getter_body(pilot_int32, int32);
+}
+
+static const uint32_t pilot_uint32 = 456;
+void pilot_get_uint32_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              uint32_t *uint32)
+{
+    getter_body(pilot_uint32, uint32);
+}
+
+static const int64_t pilot_int64 = -456;
+void pilot_get_int64_handler(struct sbus_request *dbus_req,
+                             void *instance_data,
+                             int64_t *int64)
+{
+    getter_body(pilot_int64, int64);
+}
+
+static const uint64_t pilot_uint64 = 456;
+void pilot_get_uint64_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              uint64_t *uint64)
+{
+    getter_body(pilot_uint64, uint64);
+}
+
+static const double pilot_double = 3.14;
+void pilot_get_double_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              double *double_val)
+{
+    getter_body(pilot_double, double_val);
+}
+
+static const char *pilot_string = "leela";
+void pilot_get_string_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              const char **string_val)
+{
+    *string_val = pilot_string;
+}
+
+static const char *pilot_path = "/path/leela";
+void pilot_get_objpath_handler(struct sbus_request *dbus_req,
+                              void *instance_data,
+                              const char **path_val)
+{
+    *path_val = pilot_path;
+}
+
+#define array_getter_body(in, out, outlen) do {     \
+    ck_assert(dbus_req != NULL);                    \
+    ck_assert(out != NULL);                         \
+    ck_assert(outlen != NULL);                      \
+    *out = in;                                      \
+    *outlen = N_ELEMENTS(in);                       \
+} while(0);
+
+static uint8_t pilot_byte_array[] = { 42, 0 };
+void pilot_get_byte_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  uint8_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_byte_array, arr_out, arr_len);
+}
+
+static int16_t pilot_int16_array[] = { -123, 0 };
+void pilot_get_int16_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  int16_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_int16_array, arr_out, arr_len);
+}
+
+static uint16_t pilot_uint16_array[] = { 123, 0 };
+void pilot_get_uint16_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  uint16_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_uint16_array, arr_out, arr_len);
+}
+
+static int32_t pilot_int32_array[] = { -456, 0 };
+void pilot_get_int32_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  int32_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_int32_array, arr_out, arr_len);
+}
+
+static uint32_t pilot_uint32_array[] = { 456, 0 };
+void pilot_get_uint32_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  uint32_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_uint32_array, arr_out, arr_len);
+}
+
+static int64_t pilot_int64_array[] = { -789, 0 };
+void pilot_get_int64_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  int64_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_int64_array, arr_out, arr_len);
+}
+
+static uint64_t pilot_uint64_array[] = { 789, 0 };
+void pilot_get_uint64_array_handler(struct sbus_request *dbus_req,
+                                  void *instance_data,
+                                  uint64_t **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_uint64_array, arr_out, arr_len);
+}
+
+static double pilot_double_array[] = { 3.14, 0 };
+void pilot_get_double_array_handler(struct sbus_request *dbus_req,
+                                    void *instance_data,
+                                    double **arr_out, int *arr_len)
+{
+    array_getter_body(pilot_double_array, arr_out, arr_len);
+}
+
+static const char *pilot_string_array[] = { "Turanga", "Leela" };
+void pilot_get_string_array_handler(struct sbus_request *dbus_req,
+                                    void *data,
+                                    const char ***arr_out,
+                                    int *arr_len)
+{
+    array_getter_body(pilot_string_array, arr_out, arr_len);
+}
+
+static const char *pilot_path_array[] = { "/some/path", "/another/path" };
+void pilot_get_path_array_handler(struct sbus_request *dbus_req,
+                                    void *data,
+                                    const char ***arr_out,
+                                    int *arr_len)
+{
+    array_getter_body(pilot_path_array, arr_out, arr_len);
+}
+
+struct test_pilot pilot_iface = {
     { &test_pilot_meta, 0 },
     .Eject = eject_handler,
+
+    .test_pilot_get_FullName = pilot_get_full_name_handler,
+    .test_pilot_get_byte = pilot_get_byte_handler,
+    .test_pilot_get_boolean = pilot_get_boolean_handler,
+    .test_pilot_get_int16 = pilot_get_int16_handler,
+    .test_pilot_get_uint16 = pilot_get_uint16_handler,
+    .test_pilot_get_int32 = pilot_get_int32_handler,
+    .test_pilot_get_uint32 = pilot_get_uint32_handler,
+    .test_pilot_get_int64 = pilot_get_int64_handler,
+    .test_pilot_get_uint64 = pilot_get_uint64_handler,
+    .test_pilot_get_double = pilot_get_double_handler,
+    .test_pilot_get_string = pilot_get_string_handler,
+    .test_pilot_get_object_path = pilot_get_objpath_handler,
+
+    .test_pilot_get_byte_array = pilot_get_byte_array_handler,
+    .test_pilot_get_int16_array = pilot_get_int16_array_handler,
+    .test_pilot_get_uint16_array = pilot_get_uint16_array_handler,
+    .test_pilot_get_int32_array = pilot_get_int32_array_handler,
+    .test_pilot_get_uint32_array = pilot_get_uint32_array_handler,
+    .test_pilot_get_int64_array = pilot_get_int64_array_handler,
+    .test_pilot_get_uint64_array = pilot_get_uint64_array_handler,
+    .test_pilot_get_double_array = pilot_get_double_array_handler,
+    .test_pilot_get_string_array = pilot_get_string_array_handler,
+    .test_pilot_get_object_path_array = pilot_get_path_array_handler,
 };
 
 static int pilot_test_server_init(struct sbus_connection *server, void *unused)
@@ -343,7 +559,7 @@ static int pilot_test_server_init(struct sbus_connection *server, void *unused)
 
     ret = sbus_conn_add_interface(server,
                                   sbus_new_interface(server, "/test/leela",
-                                                     &pilot_methods.vtable,
+                                                     &pilot_iface.vtable,
                                                      "Crash into the billboard"));
     ck_assert_int_eq(ret, EOK);
 
@@ -526,11 +742,277 @@ START_TEST(test_marshal_basic_types)
 }
 END_TEST
 
+static void parse_get_reply(DBusMessage *reply, const int type, void *val)
+{
+    DBusMessageIter iter;
+    DBusMessageIter variter;
+    dbus_bool_t dbret;
+
+    dbret = dbus_message_iter_init(reply, &iter);
+    ck_assert(dbret == TRUE);
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&iter), DBUS_TYPE_VARIANT);
+    dbus_message_iter_recurse(&iter, &variter);
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&variter), type);
+    dbus_message_iter_get_basic(&variter, val);
+}
+
+static void call_get(DBusConnection *client,
+                     const char *object_path,
+                     const char *iface,
+                     const char *prop,
+                     int type,
+                     void *val)
+{
+    DBusMessage *reply;
+    DBusError error = DBUS_ERROR_INIT;
+
+    reply = test_dbus_call_sync(client,
+                                object_path,
+                                DBUS_PROPERTIES_INTERFACE,
+                                "Get",
+                                &error,
+                                DBUS_TYPE_STRING, &iface,
+                                DBUS_TYPE_STRING, &prop,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    parse_get_reply(reply, type, val);
+}
+
+START_TEST(test_get_basic_types)
+{
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    dbus_bool_t bool_val;
+    const char *string_val;
+    const char *path_val;
+    uint8_t byte_val;
+    int16_t int16_val;
+    uint16_t uint16_val;
+    int32_t int32_val;
+    uint32_t uint32_val;
+    int64_t int64_val;
+    uint64_t uint64_val;
+    double double_val;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "boolean",
+             DBUS_TYPE_BOOLEAN, &bool_val);
+    ck_assert(bool_val == pilot_bool);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "FullName",
+             DBUS_TYPE_STRING, &string_val);
+    ck_assert_str_eq(string_val, pilot_full_name);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "byte",
+             DBUS_TYPE_BYTE, &byte_val);
+    ck_assert_int_eq(byte_val, pilot_byte);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "int16",
+             DBUS_TYPE_INT16, &int16_val);
+    ck_assert_int_eq(int16_val, pilot_int16);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "uint16",
+             DBUS_TYPE_UINT16, &uint16_val);
+    ck_assert_int_eq(uint16_val, pilot_uint16);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "int32",
+             DBUS_TYPE_INT32, &int32_val);
+    ck_assert_int_eq(int32_val, pilot_int32);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "uint32",
+             DBUS_TYPE_UINT32, &uint32_val);
+    ck_assert_int_eq(uint32_val, pilot_uint32);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "int64",
+             DBUS_TYPE_INT64, &int64_val);
+    ck_assert_int_eq(int64_val, pilot_int64);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "uint64",
+             DBUS_TYPE_UINT64, &uint64_val);
+    ck_assert_int_eq(uint64_val, pilot_uint64);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "double",
+             DBUS_TYPE_DOUBLE, &double_val);
+    ck_assert_int_eq(double_val, pilot_double);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "string",
+             DBUS_TYPE_STRING, &string_val);
+    ck_assert_str_eq(string_val, pilot_string);
+
+    call_get(client, "/test/leela", test_pilot_meta.name, "object_path",
+             DBUS_TYPE_OBJECT_PATH, &path_val);
+    ck_assert_str_eq(path_val, pilot_path);
+}
+END_TEST
+
+static void parse_get_array_reply(DBusMessage *reply, const int type,
+                                  void **values, int *nels)
+{
+    DBusMessageIter iter;
+    DBusMessageIter variter;
+    DBusMessageIter arriter;
+    dbus_bool_t dbret;
+
+    dbret = dbus_message_iter_init(reply, &iter);
+    ck_assert(dbret == TRUE);
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&iter), DBUS_TYPE_VARIANT);
+    dbus_message_iter_recurse(&iter, &variter);
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&variter), DBUS_TYPE_ARRAY);
+    ck_assert_int_eq(dbus_message_iter_get_element_type(&variter), type);
+    dbus_message_iter_recurse(&variter, &arriter);
+    if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+        int n = 0, i = 0;;
+        const char **strings;
+        const char *s;
+
+        do {
+            n++;
+        } while (dbus_message_iter_next(&arriter));
+
+        /* Allocating on NULL is bad, but this is unit test */
+        strings = talloc_array(NULL, const char *, n);
+        ck_assert(strings != NULL);
+
+        dbus_message_iter_recurse(&variter, &arriter);
+        do {
+            dbus_message_iter_get_basic(&arriter, &s);
+            strings[i] = talloc_strdup(strings, s);
+            ck_assert(strings[i] != NULL);
+            i++;
+        } while (dbus_message_iter_next(&arriter));
+
+        *nels = n;
+        *values = strings;
+    } else {
+        /* Fixed types are easy */
+        dbus_message_iter_get_fixed_array(&arriter, values, nels);
+    }
+}
+
+static void call_get_array(DBusConnection *client,
+                           const char *object_path,
+                           const char *iface,
+                           const char *prop,
+                           int type,
+                           void **values,
+                           int *nels)
+{
+    DBusMessage *reply;
+    DBusError error = DBUS_ERROR_INIT;
+
+    reply = test_dbus_call_sync(client,
+                                object_path,
+                                DBUS_PROPERTIES_INTERFACE,
+                                "Get",
+                                &error,
+                                DBUS_TYPE_STRING, &iface,
+                                DBUS_TYPE_STRING, &prop,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    parse_get_array_reply(reply, type, values, nels);
+}
+
+#define _check_array(reply, len, known, fn) do {    \
+    fn(len, 2);                                     \
+    fn(reply[0], known[0]);                         \
+    fn(reply[1], known[1]);                         \
+} while(0);                                         \
+
+#define check_int_array(reply, len, known) \
+    _check_array(reply, len, known, ck_assert_int_eq)
+#define check_uint_array(reply, len, known) \
+    _check_array(reply, len, known, ck_assert_uint_eq)
+
+START_TEST(test_get_basic_array_types)
+{
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    const char **string_arr_val;
+    int string_arr_len;
+    const char **path_arr_val;
+    int path_arr_len;
+    uint8_t *byte_arr_val;
+    int byte_arr_len;
+    int16_t *int16_arr_val;
+    int int16_arr_len;
+    uint16_t *uint16_arr_val;
+    int uint16_arr_len;
+    int32_t *int32_arr_val;
+    int int32_arr_len;
+    uint32_t *uint32_arr_val;
+    int uint32_arr_len;
+    int64_t *int64_arr_val;
+    int int64_arr_len;
+    uint64_t *uint64_arr_val;
+    int uint64_arr_len;
+    double *double_arr_val;
+    int double_arr_len;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "byte_array",
+                   DBUS_TYPE_BYTE, (void **) &byte_arr_val, &byte_arr_len);
+    check_uint_array(byte_arr_val, byte_arr_len, pilot_byte_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "int16_array",
+                   DBUS_TYPE_INT16, (void **) &int16_arr_val, &int16_arr_len);
+    check_int_array(int16_arr_val, int16_arr_len, pilot_int16_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "uint16_array",
+                   DBUS_TYPE_UINT16, (void **) &uint16_arr_val, &uint16_arr_len);
+    check_uint_array(uint16_arr_val, uint16_arr_len, pilot_uint16_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "int32_array",
+                   DBUS_TYPE_INT32, (void **) &int32_arr_val, &int32_arr_len);
+    check_int_array(int32_arr_val, int32_arr_len, pilot_int32_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "uint32_array",
+                   DBUS_TYPE_UINT32, (void **) &uint32_arr_val, &uint32_arr_len);
+    check_uint_array(uint32_arr_val, uint32_arr_len, pilot_uint32_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "int64_array",
+                   DBUS_TYPE_INT64, (void **) &int64_arr_val, &int64_arr_len);
+    check_int_array(int64_arr_val, int64_arr_len, pilot_int64_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "uint64_array",
+                   DBUS_TYPE_UINT64, (void **) &uint64_arr_val, &uint64_arr_len);
+    check_uint_array(uint64_arr_val, uint64_arr_len, pilot_uint64_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "double_array",
+                   DBUS_TYPE_DOUBLE, (void **) &double_arr_val, &double_arr_len);
+    check_int_array(double_arr_val, double_arr_len, pilot_double_array);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "string_array",
+                   DBUS_TYPE_STRING, (void **) &string_arr_val, &string_arr_len);
+    ck_assert_int_eq(string_arr_len, 2);
+    ck_assert_str_eq(string_arr_val[0], pilot_string_array[0]);
+    ck_assert_str_eq(string_arr_val[1], pilot_string_array[1]);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "string_array",
+                   DBUS_TYPE_STRING, (void **) &string_arr_val, &string_arr_len);
+    ck_assert_int_eq(string_arr_len, 2);
+    ck_assert_str_eq(string_arr_val[0], pilot_string_array[0]);
+    ck_assert_str_eq(string_arr_val[1], pilot_string_array[1]);
+
+    call_get_array(client, "/test/leela", test_pilot_meta.name, "object_path_array",
+                   DBUS_TYPE_OBJECT_PATH, (void **) &path_arr_val, &path_arr_len);
+    ck_assert_int_eq(path_arr_len, 2);
+    ck_assert_str_eq(path_arr_val[0], pilot_path_array[0]);
+    ck_assert_str_eq(path_arr_val[1], pilot_path_array[1]);
+
+}
+END_TEST
+
 TCase *create_handler_tests(void)
 {
     TCase *tc = tcase_create("handler");
 
     tcase_add_test(tc, test_marshal_basic_types);
+    tcase_add_test(tc, test_get_basic_types);
+    tcase_add_test(tc, test_get_basic_array_types);
 
     return tc;
 }
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
index 83807b9c287f633ad59398519a7520e667003f00..74037cc4002198f8c8d4b6a8c12edbd34fe338ef 100755
--- a/src/tests/sbus_codegen_tests.xml
+++ b/src/tests/sbus_codegen_tests.xml
@@ -107,6 +107,32 @@
             <arg name="object_path_array" type="ao" direction="out"/>
         </method>
 
+        <!-- Properties with every type of basic argument, so far read only -->
+        <property name="byte" type="y" access="read"/>
+        <property name="boolean" type="b" access="read"/>
+        <property name="int16" type="n" access="read"/>
+        <property name="uint16" type="q" access="read"/>
+        <property name="int32" type="i" access="read"/>
+        <property name="uint32" type="u" access="read"/>
+        <property name="int64" type="x" access="read"/>
+        <property name="uint64" type="t" access="read"/>
+        <property name="double" type="d" access="read"/>
+        <property name="string" type="s" access="read"/>
+        <property name="object_path" type="o" access="read"/>
+
+        <!-- Property arrays with every type of basic argument except boolean
+             which we can't do (yet) -->
+        <property name="byte_array" type="ay" access="read"/>
+        <property name="int16_array" type="an" access="read"/>
+        <property name="uint16_array" type="aq" access="read"/>
+        <property name="int32_array" type="ai" access="read"/>
+        <property name="uint32_array" type="au" access="read"/>
+        <property name="int64_array" type="ax" access="read"/>
+        <property name="uint64_array" type="at" access="read"/>
+        <property name="double_array" type="ad" access="read"/>
+        <property name="string_array" type="as" access="read"/>
+        <property name="object_path_array" type="ao" access="read"/>
+
     </interface>
 
 </node>
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index 40d40cdc471b90f6b0d3fb52033f7ec9817c1772..4ace0365044ac1edec3c8774da2231c82e054017 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -16,6 +16,27 @@ 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);
+static int invoke_get_s(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_y(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_b(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_n(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_q(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_i(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_u(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_x(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_t(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_d(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_o(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_ay(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_an(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_aq(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_ai(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_au(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_ax(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_at(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_ad(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_as(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_ao(struct sbus_request *dbus_req, void *function_ptr);
 
 /* arguments for com.planetexpress.Ship.MoveUniverse */
 const struct sbus_arg_meta com_planetexpress_Ship_MoveUniverse__in[] = {
@@ -96,6 +117,10 @@ const struct sbus_property_meta com_planetexpress_Ship__properties[] = {
         "Color", /* name */
         "s", /* type */
         SBUS_PROPERTY_READABLE,
+        offsetof(struct com_planetexpress_Ship, com_planetexpress_Ship_get_Color),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
     },
     { NULL, }
 };
@@ -233,6 +258,199 @@ const struct sbus_property_meta test_pilot__properties[] = {
         "FullName", /* name */
         "s", /* type */
         SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,
+        offsetof(struct test_pilot, test_pilot_get_FullName),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "byte", /* name */
+        "y", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_byte),
+        invoke_get_y,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "boolean", /* name */
+        "b", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_boolean),
+        invoke_get_b,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int16", /* name */
+        "n", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int16),
+        invoke_get_n,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint16", /* name */
+        "q", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint16),
+        invoke_get_q,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int32", /* name */
+        "i", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int32),
+        invoke_get_i,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint32", /* name */
+        "u", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint32),
+        invoke_get_u,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int64", /* name */
+        "x", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int64),
+        invoke_get_x,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint64", /* name */
+        "t", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint64),
+        invoke_get_t,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "double", /* name */
+        "d", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_double),
+        invoke_get_d,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "string", /* name */
+        "s", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_string),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "object_path", /* name */
+        "o", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_object_path),
+        invoke_get_o,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "byte_array", /* name */
+        "ay", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_byte_array),
+        invoke_get_ay,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int16_array", /* name */
+        "an", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int16_array),
+        invoke_get_an,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint16_array", /* name */
+        "aq", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint16_array),
+        invoke_get_aq,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int32_array", /* name */
+        "ai", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int32_array),
+        invoke_get_ai,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint32_array", /* name */
+        "au", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint32_array),
+        invoke_get_au,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "int64_array", /* name */
+        "ax", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_int64_array),
+        invoke_get_ax,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "uint64_array", /* name */
+        "at", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_uint64_array),
+        invoke_get_at,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "double_array", /* name */
+        "ad", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_double_array),
+        invoke_get_ad,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "string_array", /* name */
+        "as", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_string_array),
+        invoke_get_as,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "object_path_array", /* name */
+        "ao", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_object_path_array),
+        invoke_get_ao,
+        0, /* not writable */
+        NULL, /* no invoker */
     },
     { NULL, }
 };
@@ -391,3 +609,307 @@ static int invoke_ybnqiuxtdsoayanaqaiauaxatadasao_method(struct sbus_request *db
                      arg_20,
                      len_20);
 }
+
+/* invokes a getter with an array of 'uint16_t' DBus type */
+static int invoke_get_aq(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint16_t *prop_val;
+    int prop_len;
+    uint16_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint16_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_UINT16, (uint8_t*)out_val, prop_len, sizeof(uint16_t));
+}
+
+/* invokes a getter with a 'dbus_bool_t' DBus type */
+static int invoke_get_b(struct sbus_request *dbus_req, void *function_ptr)
+{
+    bool prop_val;
+    dbus_bool_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, bool *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_BOOLEAN, &out_val);
+}
+
+/* invokes a getter with a 'double' DBus type */
+static int invoke_get_d(struct sbus_request *dbus_req, void *function_ptr)
+{
+    double prop_val;
+    double out_val;
+
+    void (*handler)(struct sbus_request *, void *data, double *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_DOUBLE, &out_val);
+}
+
+/* invokes a getter with an array of 'const char *' DBus type */
+static int invoke_get_ao(struct sbus_request *dbus_req, void *function_ptr)
+{
+    const char * *prop_val;
+    int prop_len;
+    const char * *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, const char * * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_OBJECT_PATH, (uint8_t*)out_val, prop_len, sizeof(const char *));
+}
+
+/* invokes a getter with a 'int32_t' DBus type */
+static int invoke_get_i(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int32_t prop_val;
+    int32_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int32_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_INT32, &out_val);
+}
+
+/* invokes a getter with an array of 'const char *' DBus type */
+static int invoke_get_as(struct sbus_request *dbus_req, void *function_ptr)
+{
+    const char * *prop_val;
+    int prop_len;
+    const char * *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, const char * * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_STRING, (uint8_t*)out_val, prop_len, sizeof(const char *));
+}
+
+/* invokes a getter with a 'const char *' DBus type */
+static int invoke_get_o(struct sbus_request *dbus_req, void *function_ptr)
+{
+    const char * prop_val;
+    const char * out_val;
+
+    void (*handler)(struct sbus_request *, void *data, const char * *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_OBJECT_PATH, &out_val);
+}
+
+/* invokes a getter with a 'int16_t' DBus type */
+static int invoke_get_n(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int16_t prop_val;
+    int16_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int16_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_INT16, &out_val);
+}
+
+/* invokes a getter with a 'uint16_t' DBus type */
+static int invoke_get_q(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint16_t prop_val;
+    uint16_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint16_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_UINT16, &out_val);
+}
+
+/* invokes a getter with an array of 'uint8_t' DBus type */
+static int invoke_get_ay(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint8_t *prop_val;
+    int prop_len;
+    uint8_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint8_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_BYTE, (uint8_t*)out_val, prop_len, sizeof(uint8_t));
+}
+
+/* invokes a getter with a 'const char *' DBus type */
+static int invoke_get_s(struct sbus_request *dbus_req, void *function_ptr)
+{
+    const char * prop_val;
+    const char * out_val;
+
+    void (*handler)(struct sbus_request *, void *data, const char * *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_STRING, &out_val);
+}
+
+/* invokes a getter with a 'uint32_t' DBus type */
+static int invoke_get_u(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint32_t prop_val;
+    uint32_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint32_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_UINT32, &out_val);
+}
+
+/* invokes a getter with a 'uint64_t' DBus type */
+static int invoke_get_t(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint64_t prop_val;
+    uint64_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint64_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_UINT64, &out_val);
+}
+
+/* invokes a getter with an array of 'int64_t' DBus type */
+static int invoke_get_ax(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int64_t *prop_val;
+    int prop_len;
+    int64_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int64_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_INT64, (uint8_t*)out_val, prop_len, sizeof(int64_t));
+}
+
+/* invokes a getter with a 'uint8_t' DBus type */
+static int invoke_get_y(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint8_t prop_val;
+    uint8_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint8_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_BYTE, &out_val);
+}
+
+/* invokes a getter with a 'int64_t' DBus type */
+static int invoke_get_x(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int64_t prop_val;
+    int64_t out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int64_t *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
+
+    out_val = prop_val;
+    return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_INT64, &out_val);
+}
+
+/* invokes a getter with an array of 'uint32_t' DBus type */
+static int invoke_get_au(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint32_t *prop_val;
+    int prop_len;
+    uint32_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint32_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_UINT32, (uint8_t*)out_val, prop_len, sizeof(uint32_t));
+}
+
+/* invokes a getter with an array of 'int16_t' DBus type */
+static int invoke_get_an(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int16_t *prop_val;
+    int prop_len;
+    int16_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int16_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_INT16, (uint8_t*)out_val, prop_len, sizeof(int16_t));
+}
+
+/* invokes a getter with an array of 'double' DBus type */
+static int invoke_get_ad(struct sbus_request *dbus_req, void *function_ptr)
+{
+    double *prop_val;
+    int prop_len;
+    double *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, double * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_DOUBLE, (uint8_t*)out_val, prop_len, sizeof(double));
+}
+
+/* invokes a getter with an array of 'int32_t' DBus type */
+static int invoke_get_ai(struct sbus_request *dbus_req, void *function_ptr)
+{
+    int32_t *prop_val;
+    int prop_len;
+    int32_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, int32_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_INT32, (uint8_t*)out_val, prop_len, sizeof(int32_t));
+}
+
+/* invokes a getter with an array of 'uint64_t' DBus type */
+static int invoke_get_at(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint64_t *prop_val;
+    int prop_len;
+    uint64_t *out_val;
+
+    void (*handler)(struct sbus_request *, void *data, uint64_t * *, int *) = function_ptr;
+
+    (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val, &prop_len);
+
+    out_val = prop_val;
+    return sbus_request_return_array_as_variant(dbus_req, DBUS_TYPE_UINT64, (uint8_t*)out_val, prop_len, sizeof(uint64_t));
+}
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
index 137dab8a08502b482b445f254c42095202047526..9599091dd0627c7af84fb211858d918d9128ecf0 100644
--- a/src/tests/sbus_codegen_tests_generated.h
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -24,6 +24,27 @@
 #define TEST_PILOT_BLINK "Blink"
 #define TEST_PILOT_EJECT "Eject"
 #define TEST_PILOT_FULLNAME "FullName"
+#define TEST_PILOT_BYTE "byte"
+#define TEST_PILOT_BOOLEAN "boolean"
+#define TEST_PILOT_INT16 "int16"
+#define TEST_PILOT_UINT16 "uint16"
+#define TEST_PILOT_INT32 "int32"
+#define TEST_PILOT_UINT32 "uint32"
+#define TEST_PILOT_INT64 "int64"
+#define TEST_PILOT_UINT64 "uint64"
+#define TEST_PILOT_DOUBLE "double"
+#define TEST_PILOT_STRING "string"
+#define TEST_PILOT_OBJECT_PATH "object_path"
+#define TEST_PILOT_BYTE_ARRAY "byte_array"
+#define TEST_PILOT_INT16_ARRAY "int16_array"
+#define TEST_PILOT_UINT16_ARRAY "uint16_array"
+#define TEST_PILOT_INT32_ARRAY "int32_array"
+#define TEST_PILOT_UINT32_ARRAY "uint32_array"
+#define TEST_PILOT_INT64_ARRAY "int64_array"
+#define TEST_PILOT_UINT64_ARRAY "uint64_array"
+#define TEST_PILOT_DOUBLE_ARRAY "double_array"
+#define TEST_PILOT_STRING_ARRAY "string_array"
+#define TEST_PILOT_OBJECT_PATH_ARRAY "object_path_array"
 
 /* ------------------------------------------------------------------------
  * DBus handlers
@@ -49,6 +70,7 @@ struct com_planetexpress_Ship {
     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;
+    void (*com_planetexpress_Ship_get_Color)(struct sbus_request *, void *data, const char * *);
 };
 
 /* finish function for MoveUniverse */
@@ -62,6 +84,28 @@ 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);
+    void (*test_pilot_get_FullName)(struct sbus_request *, void *data, const char * *);
+    void (*test_pilot_get_byte)(struct sbus_request *, void *data, uint8_t *);
+    void (*test_pilot_get_boolean)(struct sbus_request *, void *data, bool *);
+    void (*test_pilot_get_int16)(struct sbus_request *, void *data, int16_t *);
+    void (*test_pilot_get_uint16)(struct sbus_request *, void *data, uint16_t *);
+    void (*test_pilot_get_int32)(struct sbus_request *, void *data, int32_t *);
+    void (*test_pilot_get_uint32)(struct sbus_request *, void *data, uint32_t *);
+    void (*test_pilot_get_int64)(struct sbus_request *, void *data, int64_t *);
+    void (*test_pilot_get_uint64)(struct sbus_request *, void *data, uint64_t *);
+    void (*test_pilot_get_double)(struct sbus_request *, void *data, double *);
+    void (*test_pilot_get_string)(struct sbus_request *, void *data, const char * *);
+    void (*test_pilot_get_object_path)(struct sbus_request *, void *data, const char * *);
+    void (*test_pilot_get_byte_array)(struct sbus_request *, void *data, uint8_t * *, int *);
+    void (*test_pilot_get_int16_array)(struct sbus_request *, void *data, int16_t * *, int *);
+    void (*test_pilot_get_uint16_array)(struct sbus_request *, void *data, uint16_t * *, int *);
+    void (*test_pilot_get_int32_array)(struct sbus_request *, void *data, int32_t * *, int *);
+    void (*test_pilot_get_uint32_array)(struct sbus_request *, void *data, uint32_t * *, int *);
+    void (*test_pilot_get_int64_array)(struct sbus_request *, void *data, int64_t * *, int *);
+    void (*test_pilot_get_uint64_array)(struct sbus_request *, void *data, uint64_t * *, int *);
+    void (*test_pilot_get_double_array)(struct sbus_request *, void *data, double * *, int *);
+    void (*test_pilot_get_string_array)(struct sbus_request *, void *data, const char * * *, int *);
+    void (*test_pilot_get_object_path_array)(struct sbus_request *, void *data, const char * * *, int *);
 };
 
 /* finish function for Blink */
-- 
1.9.0

-------------- next part --------------
>From 9e02bddffc8fd0eed5c4fabfd6340436c1731314 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
Date: Mon, 12 May 2014 22:54:01 +0200
Subject: [PATCH 6/9] SBUS: Return empty string if a string getter returns NULL

In line with getters never returning errors, a getter should return an
empty string instead of NULL in case a string-like property in SSSD is
not set.
---
 src/sbus/sbus_codegen                    |  5 ++++-
 src/tests/sbus_codegen_tests.c           | 13 +++++++++++++
 src/tests/sbus_codegen_tests.xml         |  3 +++
 src/tests/sbus_codegen_tests_generated.c | 11 ++++++++++-
 src/tests/sbus_codegen_tests_generated.h |  2 ++
 5 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index a8f91b784ffaa5a17620792df7285df4b508749f..b671e939fcc7c29a2ba424e785e967111d32323c 100755
--- a/src/sbus/sbus_codegen
+++ b/src/sbus/sbus_codegen
@@ -318,7 +318,10 @@ def source_getter_invoker(prop):
     out(");")
 
     out("")
-    out("    out_val = prop_val;")
+    if prop.type == "s":
+        out("    out_val = prop_val == NULL ? \"\" : prop_val;")
+    else:
+        out("    out_val = prop_val;")
     if prop.is_array:
         out("    return sbus_request_return_array_as_variant(dbus_req, %s, (uint8_t*)out_val, prop_len, sizeof(%s));", prop.dbus_constant, prop.sssd_type)
     else:
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index fa31ad64dae578470cc004c0be066771d07ef2bf..e92c5f78411e7c09d41e24ceb920a0bcb9955337 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -434,6 +434,13 @@ void pilot_get_objpath_handler(struct sbus_request *dbus_req,
     *path_val = pilot_path;
 }
 
+void pilot_get_null_string_handler(struct sbus_request *dbus_req,
+                                   void *instance_data,
+                                   const char **string_val)
+{
+    *string_val = NULL;
+}
+
 #define array_getter_body(in, out, outlen) do {     \
     ck_assert(dbus_req != NULL);                    \
     ck_assert(out != NULL);                         \
@@ -540,6 +547,7 @@ struct test_pilot pilot_iface = {
     .test_pilot_get_double = pilot_get_double_handler,
     .test_pilot_get_string = pilot_get_string_handler,
     .test_pilot_get_object_path = pilot_get_objpath_handler,
+    .test_pilot_get_null_string = pilot_get_null_string_handler,
 
     .test_pilot_get_byte_array = pilot_get_byte_array_handler,
     .test_pilot_get_int16_array = pilot_get_int16_array_handler,
@@ -844,6 +852,11 @@ START_TEST(test_get_basic_types)
     call_get(client, "/test/leela", test_pilot_meta.name, "object_path",
              DBUS_TYPE_OBJECT_PATH, &path_val);
     ck_assert_str_eq(path_val, pilot_path);
+
+    /* If a string getter returns NULL, the caller should receive "" */
+    call_get(client, "/test/leela", test_pilot_meta.name, "null_string",
+             DBUS_TYPE_STRING, &string_val);
+    ck_assert_str_eq(string_val, "");
 }
 END_TEST
 
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
index 74037cc4002198f8c8d4b6a8c12edbd34fe338ef..c44f38305a9a2e6eb1fb402a45ce6002e103639d 100755
--- a/src/tests/sbus_codegen_tests.xml
+++ b/src/tests/sbus_codegen_tests.xml
@@ -120,6 +120,9 @@
         <property name="string" type="s" access="read"/>
         <property name="object_path" type="o" access="read"/>
 
+        <!-- Special properties to test error codes -->
+        <property name="null_string" type="s" access="read"/>
+
         <!-- Property arrays with every type of basic argument except boolean
              which we can't do (yet) -->
         <property name="byte_array" type="ay" access="read"/>
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index 4ace0365044ac1edec3c8774da2231c82e054017..211ad8967f4c3cf3d00c6b53004c42dd15fbe715 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -363,6 +363,15 @@ const struct sbus_property_meta test_pilot__properties[] = {
         NULL, /* no invoker */
     },
     {
+        "null_string", /* name */
+        "s", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_null_string),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
         "byte_array", /* name */
         "ay", /* type */
         SBUS_PROPERTY_READABLE,
@@ -764,7 +773,7 @@ static int invoke_get_s(struct sbus_request *dbus_req, void *function_ptr)
 
     (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
 
-    out_val = prop_val;
+    out_val = prop_val == NULL ? "" : prop_val;
     return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_STRING, &out_val);
 }
 
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
index 9599091dd0627c7af84fb211858d918d9128ecf0..7dc817edf9bac331ec8d5647721cb4fd9e737d55 100644
--- a/src/tests/sbus_codegen_tests_generated.h
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -35,6 +35,7 @@
 #define TEST_PILOT_DOUBLE "double"
 #define TEST_PILOT_STRING "string"
 #define TEST_PILOT_OBJECT_PATH "object_path"
+#define TEST_PILOT_NULL_STRING "null_string"
 #define TEST_PILOT_BYTE_ARRAY "byte_array"
 #define TEST_PILOT_INT16_ARRAY "int16_array"
 #define TEST_PILOT_UINT16_ARRAY "uint16_array"
@@ -96,6 +97,7 @@ struct test_pilot {
     void (*test_pilot_get_double)(struct sbus_request *, void *data, double *);
     void (*test_pilot_get_string)(struct sbus_request *, void *data, const char * *);
     void (*test_pilot_get_object_path)(struct sbus_request *, void *data, const char * *);
+    void (*test_pilot_get_null_string)(struct sbus_request *, void *data, const char * *);
     void (*test_pilot_get_byte_array)(struct sbus_request *, void *data, uint8_t * *, int *);
     void (*test_pilot_get_int16_array)(struct sbus_request *, void *data, int16_t * *, int *);
     void (*test_pilot_get_uint16_array)(struct sbus_request *, void *data, uint16_t * *, int *);
-- 
1.9.0

-------------- next part --------------
>From b897b24223c8a4b6dee709dd98cb316cf7f39e74 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Thu, 15 May 2014 23:11:54 +0200
Subject: [PATCH 7/9] SBUS: Return / if an object path getter returns NULL

---
 src/sbus/sbus_codegen                    |  2 ++
 src/tests/sbus_codegen_tests.c           | 14 ++++++++++++++
 src/tests/sbus_codegen_tests.xml         |  1 +
 src/tests/sbus_codegen_tests_generated.c | 11 ++++++++++-
 src/tests/sbus_codegen_tests_generated.h |  2 ++
 5 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index b671e939fcc7c29a2ba424e785e967111d32323c..6507753f2797b354da8aaa2503b7d9bd701668c8 100755
--- a/src/sbus/sbus_codegen
+++ b/src/sbus/sbus_codegen
@@ -320,6 +320,8 @@ def source_getter_invoker(prop):
     out("")
     if prop.type == "s":
         out("    out_val = prop_val == NULL ? \"\" : prop_val;")
+    elif prop.type == "o":
+        out("    out_val = prop_val == NULL ? \"/\" : prop_val;")
     else:
         out("    out_val = prop_val;")
     if prop.is_array:
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index e92c5f78411e7c09d41e24ceb920a0bcb9955337..c7da414fe30f46d9d317f3a4205ab38c4e905081 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -441,6 +441,13 @@ void pilot_get_null_string_handler(struct sbus_request *dbus_req,
     *string_val = NULL;
 }
 
+void pilot_get_null_path_handler(struct sbus_request *dbus_req,
+                                 void *instance_data,
+                                 const char **path_val)
+{
+    *path_val = NULL;
+}
+
 #define array_getter_body(in, out, outlen) do {     \
     ck_assert(dbus_req != NULL);                    \
     ck_assert(out != NULL);                         \
@@ -548,6 +555,7 @@ struct test_pilot pilot_iface = {
     .test_pilot_get_string = pilot_get_string_handler,
     .test_pilot_get_object_path = pilot_get_objpath_handler,
     .test_pilot_get_null_string = pilot_get_null_string_handler,
+    .test_pilot_get_null_path = pilot_get_null_path_handler,
 
     .test_pilot_get_byte_array = pilot_get_byte_array_handler,
     .test_pilot_get_int16_array = pilot_get_int16_array_handler,
@@ -857,6 +865,12 @@ START_TEST(test_get_basic_types)
     call_get(client, "/test/leela", test_pilot_meta.name, "null_string",
              DBUS_TYPE_STRING, &string_val);
     ck_assert_str_eq(string_val, "");
+
+    /* If a string getter returns NULL, the caller should receive "/" */
+    call_get(client, "/test/leela", test_pilot_meta.name, "null_path",
+             DBUS_TYPE_OBJECT_PATH, &path_val);
+    ck_assert_str_eq(path_val, "/");
+
 }
 END_TEST
 
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
index c44f38305a9a2e6eb1fb402a45ce6002e103639d..90e27425414167f025c34da3ae5c06dc5a36f165 100755
--- a/src/tests/sbus_codegen_tests.xml
+++ b/src/tests/sbus_codegen_tests.xml
@@ -122,6 +122,7 @@
 
         <!-- Special properties to test error codes -->
         <property name="null_string" type="s" access="read"/>
+        <property name="null_path" type="o" access="read"/>
 
         <!-- Property arrays with every type of basic argument except boolean
              which we can't do (yet) -->
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index 211ad8967f4c3cf3d00c6b53004c42dd15fbe715..70302daff7c7a7f5b042428be7d994fa0cdd660a 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -372,6 +372,15 @@ const struct sbus_property_meta test_pilot__properties[] = {
         NULL, /* no invoker */
     },
     {
+        "null_path", /* name */
+        "o", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_pilot, test_pilot_get_null_path),
+        invoke_get_o,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
         "byte_array", /* name */
         "ay", /* type */
         SBUS_PROPERTY_READABLE,
@@ -716,7 +725,7 @@ static int invoke_get_o(struct sbus_request *dbus_req, void *function_ptr)
 
     (handler)(dbus_req, dbus_req->intf->instance_data, &prop_val);
 
-    out_val = prop_val;
+    out_val = prop_val == NULL ? "/" : prop_val;
     return sbus_request_return_as_variant(dbus_req, DBUS_TYPE_OBJECT_PATH, &out_val);
 }
 
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
index 7dc817edf9bac331ec8d5647721cb4fd9e737d55..e6fb10c5ef5724c865735ed5938f7a7b96b995aa 100644
--- a/src/tests/sbus_codegen_tests_generated.h
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -36,6 +36,7 @@
 #define TEST_PILOT_STRING "string"
 #define TEST_PILOT_OBJECT_PATH "object_path"
 #define TEST_PILOT_NULL_STRING "null_string"
+#define TEST_PILOT_NULL_PATH "null_path"
 #define TEST_PILOT_BYTE_ARRAY "byte_array"
 #define TEST_PILOT_INT16_ARRAY "int16_array"
 #define TEST_PILOT_UINT16_ARRAY "uint16_array"
@@ -98,6 +99,7 @@ struct test_pilot {
     void (*test_pilot_get_string)(struct sbus_request *, void *data, const char * *);
     void (*test_pilot_get_object_path)(struct sbus_request *, void *data, const char * *);
     void (*test_pilot_get_null_string)(struct sbus_request *, void *data, const char * *);
+    void (*test_pilot_get_null_path)(struct sbus_request *, void *data, const char * *);
     void (*test_pilot_get_byte_array)(struct sbus_request *, void *data, uint8_t * *, int *);
     void (*test_pilot_get_int16_array)(struct sbus_request *, void *data, int16_t * *, int *);
     void (*test_pilot_get_uint16_array)(struct sbus_request *, void *data, uint16_t * *, int *);
-- 
1.9.0

-------------- next part --------------
>From baaf118034a3c75df0d43e4fd2d0658e74449157 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 16 May 2014 00:18:55 +0200
Subject: [PATCH 8/9] SBUS: Add several error constant definitions

Several error constants we use were added in later DBus versions. This
patch conditionally #defines them.
---
 src/sbus/sssd_dbus.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index 9c236479e5474b884d8e051ea221c77a40ed6ac7..4ae64f054cdcf0e4005d99d907b878abb85c7137 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -30,6 +30,26 @@ struct sbus_request;
 #include <sys/types.h>
 #include "util/util.h"
 
+/* Older platforms (such as RHEL-6) might not have these error constants
+ * defined */
+#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
+/** Interface you invoked a method on isn't known by the object. */
+#define DBUS_ERROR_UNKNOWN_INTERFACE \
+    "org.freedesktop.DBus.Error.UnknownInterface"
+#endif /* DBUS_ERROR_UNKNOWN_INTERFACE */
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+/** Property you tried to access isn't known by the object. */
+#define DBUS_ERROR_UNKNOWN_PROPERTY \
+    "org.freedesktop.DBus.Error.UnknownProperty"
+#endif /* DBUS_ERROR_UNKNOWN_PROPERTY */
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+/** Property you tried to set is read-only. */
+#define DBUS_ERROR_PROPERTY_READ_ONLY \
+    "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif /* DBUS_ERROR_PROPERTY_READ_ONLY */
+
 typedef int (*sbus_msg_handler_fn)(struct sbus_request *dbus_req,
                                    void *instance_data);
 
-- 
1.9.0

-------------- next part --------------
>From ca936f583c66985b5297f4627d0924f1b6c3cbe0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 May 2014 20:06:06 +0200
Subject: [PATCH 9/9] SBUS: Add org.freedesktop.DBus.Properties.Get to
 Introspection

---
 src/sbus/sssd_dbus_introspect.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/sbus/sssd_dbus_introspect.c b/src/sbus/sssd_dbus_introspect.c
index f310aeb7495e826483d27061d0cd13f5cfba2be7..4bd9563e6dad31009e92a0f4f7de97428a0185ca 100644
--- a/src/sbus/sssd_dbus_introspect.c
+++ b/src/sbus/sssd_dbus_introspect.c
@@ -47,6 +47,14 @@ const struct sbus_method_meta introspect_method =
      "   </method>\n"                                                \
      " </interface>\n"
 
+#define SSS_INTROSPECT_INTERFACE_PROPERTIES                                 \
+     " <interface name=\"org.freedesktop.DBus.Properties\">\n"              \
+     "   <method name=\"Get\">\n"                                           \
+     "     <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"         \
+     "     <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"          \
+     "     <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"            \
+     "   </method>\n"                                                       \
+     " </interface>\n"
 
 struct introspect_ctx {
     FILE *f;
@@ -253,6 +261,9 @@ static errno_t introspect_finish(struct introspect_ctx *ictx)
     ret = fputs(SSS_INTROSPECT_INTERFACE_INTROSPECTABLE, ictx->f);
     if (ret < 0) return EIO;
 
+    ret = fputs(SSS_INTROSPECT_INTERFACE_PROPERTIES, ictx->f);
+    if (ret < 0) return EIO;
+
     ret = fputs("</node>\n", ictx->f);
     if (ret < 0) return EIO;
 
-- 
1.9.0



More information about the sssd-devel mailing list