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