diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d0828e4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,42 @@
+# c++
+*.o
+*.lo
+*.la
+m4/
+build/
+.deps/
+.dirstamp
+.libs/
+test/libsdbus-c++_unittests
+test/libsdbus-c++_integrationtests
+test/run-test-on-device.sh
+
+#eclipse
+.cproject
+.settings
+*.log
+
+#autotools
+sdbus-cpp.pc
+*Makefile
+*Makefile.in
+aclocal.m4
+arm-poky-linux-gnueabi-libtool
+autom4te.cache
+configure
+config.h
+config.status
+config.guess
+config.h.in
+config.sub
+compile
+depcomp
+install-sh
+ltmain.sh
+missing
+stamp-h1
+test-driver
+.autotools
+.gdbinit
+sdbus-cpp_gdb_arm-poky-linux-gnueabi.launch
+sdbus-c++.pc
diff --git a/.project b/.project
new file mode 100644
index 0000000..0abe63f
--- /dev/null
+++ b/.project
@@ -0,0 +1,35 @@
+
+
+ sdbus-cpp
+
+
+
+
+
+ org.eclipse.cdt.autotools.core.genmakebuilderV2
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+ org.yocto.sdk.ide.YoctoSDKNature
+ org.eclipse.cdt.autotools.core.autotoolsNatureV2
+ org.yocto.sdk.ide.YoctoSDKAutotoolsNature
+
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..90d2a75
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+The library:
+ Stanislav Angelovic (stanislav.angelovic[at]kistler.com)
+
+Stub generator:
+ Lukas Durfina (lukas.durfina[at]kistler.com)
diff --git a/LICENSE b/COPYING
similarity index 100%
rename from LICENSE
rename to COPYING
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5635a77
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,6 @@
+Building:
+ $ ./autogen.sh ${CONFIGURE_FLAGS}
+ $ make
+
+Installing:
+ $ sudo make install
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6b7e4c3
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,22 @@
+EXTRA_DIST = autogen.sh
+SUBDIRS = include src test
+
+DISTCHECK_CONFIGURE_FLAGS=
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sdbus-c++.pc
+
+CLEANFILES = *~ *.lo *.la
+
+MOSTLYCLEANFILES = *.o
+
+DISTCLEANFILES = \
+ *libtool* \
+ aclocal.m4 \
+ compile config.* configure \
+ depcomp install-sh \
+ ltmain.sh \
+ Makefile Makefile.in \
+ missing \
+ stamp-h1 \
+ sdbus-c++.pc
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..eb2d119
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,4 @@
+sdbus-c++: D-Bus IPC C++ binding library based on sd-bus
+
+v0.2.3:
+ * sdbus-c++ v0.2.3 released to the public!
diff --git a/README b/README
new file mode 100644
index 0000000..96dc92f
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+See README.md
diff --git a/README.md b/README.md
index d0660dd..aa82b49 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,44 @@
-# sdbus-cpp
-D-Bus IPC C++ binding library build on top of sd-bus
+sdbus-c++
+=========
+
+sdbus-c++ is a C++ API library for D-Bus IPC, based on sd-bus implementation.
+
+Building and installing the library
+-----------------------------------
+
+```bash
+$ ./autogen.sh ${CONFIGURE_FLAGS}
+$ make
+$ sudo make install
+```
+
+Use `--disable-tests` flag when configuring to disable building unit and integration tests for the library.
+
+Dependencies
+------------
+
+* `C++17` - the library uses C++17 `std::uncaught_exceptions()` feature. When building sdbus-c++ manually, make sure you use a compiler that supports that feature.
+* `libsystemd` - systemd library containing sd-bus implementation. Systemd v236 at least is needed for sdbus-c++ to compile.
+* `googletest` - google unit testing framework, only necessary when building tests
+
+Licensing
+---------
+
+The library is distributed under LGPLv2.1+ license.
+
+References/documentation
+------------------------
+
+* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
+* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
+* [Tutorial: Using sdbus-c++](doc/using-sdbus-c++.md)
+
+Contributing
+------------
+
+Contributions that increase the library quality, functionality, or fix issues are very welcome. To introduce a change, please submit a merge request with a description.
+
+Contact
+-------
+
+stanislav.angelovic[at]kistler.com
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..7fd81e2
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,10 @@
+#! /bin/sh
+[ -e config.cache ] && rm -f config.cache
+
+libtoolize --automake
+aclocal ${OECORE_ACLOCAL_OPTS}
+autoconf
+autoheader
+automake -a
+./configure $@
+exit
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4459a99
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,62 @@
+AC_PREREQ(2.61)
+
+# package version number (not shared library version)
+# odd micro numbers indicate in-progress development
+# even micro numbers indicate released versions
+m4_define(sdbus_cpp_version_major, 0)
+m4_define(sdbus_cpp_version_minor, 2)
+m4_define(sdbus_cpp_version_micro, 3)
+
+m4_define([sdbus_cpp_version],
+ [sdbus_cpp_version_major.sdbus_cpp_version_minor.sdbus_cpp_version_micro])
+m4_define([sdbus_cpp_api_version],
+ [sdbus_cpp_version_major.sdbus_cpp_version_minor])
+
+AC_INIT(libsdbus-c++, sdbus_cpp_version)
+AM_INIT_AUTOMAKE
+AC_CONFIG_HEADERS(config.h)
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_INSTALL
+
+# enable pkg-config
+PKG_PROG_PKG_CONFIG
+
+PKG_CHECK_MODULES(SYSTEMD, [libsystemd >= 0.10.1],,
+ AC_MSG_ERROR([You need the libsystemd library (version 0.10.1 or better)]
+ [https://www.freedesktop.org/wiki/Software/systemd/])
+)
+
+# Checks for library functions.
+#AC_CHECK_FUNCS([memset])
+
+AC_SUBST(libsdbus_cpp_CFLAGS)
+AC_SUBST(libsdbus_cpp_LIBS)
+
+AC_ARG_ENABLE([tests],
+ [AS_HELP_STRING([--enable-tests],
+ [build and install tests @<:@default=yes@:>@])],
+ [],
+ [enable_tests=yes])
+AM_CONDITIONAL([ENABLE_TESTS], [test x$enable_tests = xyes])
+
+#icondir=${datadir}/icons/hicolor/32x32/apps
+#AC_SUBST(icondir)
+
+AC_OUTPUT([
+Makefile
+include/Makefile
+src/Makefile
+test/Makefile
+sdbus-c++.pc
+])
+
+echo ""
+echo " sdbus-cpp $VERSION"
+echo " ====================="
+echo ""
+echo " To build the project, run \"make\""
+echo ""
diff --git a/doc/using-sdbus-c++.md b/doc/using-sdbus-c++.md
new file mode 100644
index 0000000..7db7d26
--- /dev/null
+++ b/doc/using-sdbus-c++.md
@@ -0,0 +1,727 @@
+Using sdbus-c++ library
+=======================
+
+**Table of contents**
+
+1. [Introduction](#introduction)
+2. [Integrating sdbus-c++ into your project](#integrating-sdbus-c-into-your-project)
+3. [Header files and namespaces](#header-files-and-namespaces)
+4. [Error signalling and propagation](#error-signalling-and-propagation)
+5. [Multiple layers of sdbus-c++ API](#multiple-layers-of-sdbus-c-api)
+6. [An example: Number concatenator](#an-example-number-concatenator)
+7. [Implementing the Concatenator example using basic sdbus-c++ API layer](#implementing-the-concatenator-example-using-basic-sdbus-c-api-layer)
+8. [Implementing the Concatenator example using convenience sdbus-c++ API layer](#implementing-the-concatenator-example-using-convenience-sdbus-c-api-layer)
+9. [Implementing the Concatenator example using sdbus-c++-generated stubs](#implementing-the-concatenator-example-using-sdbus-c-generated-stubs)
+10. [Using D-Bus properties](#using-d-bus-properties)
+11. [Conclusion](#conclusion)
+
+Introduction
+------------
+
+sdbus-c++ is a C++ wrapper library built on top of [sd-bus](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html), a lightweight D-Bus client
+library implemented within systemd project. It provides D-Bus functionality on a higher level of abstraction, trying to employ C++ type system
+to shift as much work as possible from the developer to the compiler.
+
+sdbus-c++ does not cover the entire sd-bus API, but provides tools for implementing the most common functionality - RPC
+method calls, signals and properties. There is room for additions and improvements, as needed and when needed.
+
+Integrating sdbus-c++ into your project
+---------------------------------------
+
+The library build system is based on Autotools. The library supports `pkg-config`, so integrating it into your autotools project
+is a two step process.
+
+1. Add `PKG_CHECK_MODULES` macro into your `configure.ac`:
+```bash
+PKG_CHECK_MODULES(SDBUSCPP, [sdbus-c++ >= 0.1],,
+ AC_MSG_ERROR([You need the sdbus-c++ library (version 0.1 or better)]
+ [http://www.kistler.com/])
+)
+```
+
+2. Update `*_CFLAGS` and `*_LDFLAGS` in Makefiles of modules that use *sdbus-c++*, for example like this:
+```bash
+AM_CXXFLAGS = -std=c++17 -pedantic -W -Wall @SDBUSCPP_CFLAGS@ ...
+AM_LDFLAGS = @SDBUSCPP_LIBS@ ...
+```
+
+Note: sdbus-c++ library depends on C++17, since it uses C++17 `std::uncaught_exceptions()` feature. When building sdbus-c++ manually, make sure you use a compiler that supports that feature. To use the library, make sure you have a C++ standard library that supports the feature. The feature is supported by e.g. gcc >= 6, and clang >= 3.7.
+
+Header files and namespaces
+---------------------------
+
+All sdbus-c++ header files reside in the `sdbus-c++` subdirectory within the standard include directory. Users can either include
+individual header files, like so:
+
+```cpp
+#include
+#include
+```
+
+or just include the global header file that pulls in everything:
+
+```cpp
+#include
+```
+
+All public types and functions of sdbus-c++ reside in the `sdbus` namespace.
+
+Error signalling and propagation
+--------------------------------
+
+`sdbus::Error` exception is used to signal errors in sdbus-c++. There are two types of errors:
+ * D-Bus related errors, like call timeouts, failed socket allocation, etc.
+ * user errors, i.e. errors signalled and propagated from remote methods back to the caller.
+
+The exception object carries the error name and error message with it.
+
+Multiple layers of sdbus-c++ API
+-------------------------------
+
+sdbus-c++ API comes in two layers:
+ * the basic layer, which is almost pure wrapper layer on top of sd-bus, using mechanisms that are native to C++,
+ * the convenience layer, building on top of the basic layer, which aims at providing shorter, safer, and more expressive way of writing the
+ client code.
+
+sdbus-c++ also ships with a stub generator tool that converts D-Bus IDL in XML format into stub code for the adaptor as well as proxy part.
+Hierarchically, these stubs provide yet another layer of convenience (the "stubs layer"), making it possible for D-Bus RPC calls to look like
+native C++ calls on a local object.
+
+An example: Number concatenator
+-------------------------------
+
+Let's have an object `/org/sdbuscpp/concatenator` that implements the `org.sdbuscpp.concatenator` interface. The interface exposes the following:
+* a `concatenate` method that takes a collection of integers and a separator string and returns a string that is the concatenation of all
+ integers from the collection using given separator,
+* a `concatenated` signal that is emitted at the end of each successful concatenation.
+
+In the following sections, we will elaborate on the ways of implementing such an object on both the server and the client side.
+
+Implementing the Concatenator example using basic sdbus-c++ API layer
+---------------------------------------------------------------------
+
+In the basic API layer, we already have abstractions for D-Bus connections, objects and object proxies, with which we can interact via
+interfaces. However, we still work with the concept of messages. To issue a method call for example, we have to go through several steps:
+we have to create a method call message first, serialize method arguments into the message, and send the message at last. We get the reply
+message (if applicable) in return, so we have to deserialize the return values from it manually.
+
+Overloaded versions of C++ insertion/extraction operators are used for serialization/deserialization. That makes the client code much simpler.
+
+### Server side
+
+```c++
+#include
+#include
+#include
+
+// Yeah, global variable is ugly, but this is just an example and we want to access
+// the concatenator instance from within the concatenate method handler to be able
+// to emit signals.
+sdbus::IObject* g_concatenator{};
+
+void concatenate(sdbus::Message& msg, sdbus::Message& reply)
+{
+ // Deserialize the collection of numbers from the message
+ std::vector numbers;
+ msg >> numbers;
+
+ // Deserialize separator from the message
+ std::string separator;
+ msg >> separator;
+
+ // Return error if there are no numbers in the collection
+ if (numbers.empty())
+ throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
+
+ std::string result;
+ for (auto number : numbers)
+ {
+ result += (result.empty() ? std::string() : separator) + std::to_string(number);
+ }
+
+ // Serialize resulting string to the reply
+ reply << result;
+
+ // Emit 'concatenated' signal
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ auto signalMsg = g_concatenator->createSignal(interfaceName, "concatenated");
+ signalMsg << result;
+ g_concatenator->emitSignal(signalMsg);
+}
+
+int main(int argc, char *argv[])
+{
+ // Create D-Bus connection and requests name on it.
+ const char* serviceName = "org.sdbuscpp.concatenator";
+ auto connection = sdbus::createConnection(serviceName);
+
+ // Create concatenator D-Bus object.
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ auto concatenator = sdbus::createObject(*connection, objectPath);
+
+ g_concatenator = concatenator.get();
+
+ // Register D-Bus methods and signals on the concatenator object, and exports the object.
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ concatenator->registerMethod(interfaceName, "concatenate", "ais", "s", &concatenate);
+ concatenator->registerSignal(interfaceName, "concatenated", "s");
+ concatenator->finishRegistration();
+
+ // Run the loop on the connection.
+ connection->enterProcessingLoop();
+}
+```
+
+### Client side
+
+```c++
+#include
+#include
+#include
+#include
+#include
+
+void onConcatenated(sdbus::Message& signalMsg)
+{
+ std::string concatenatedString;
+ msg >> concatenatedString;
+
+ std::cout << "Received signal with concatenated string " << concatenatedString << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+ // Create proxy object for the concatenator object on the server side
+ const char* destinationName = "org.sdbuscpp.concatenator";
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ auto concatenatorProxy = sdbus::createObjectProxy(destinationName, objectPath);
+
+ // Let's subscribe for the 'concatenated' signals
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ concatenatorProxy->registerSignalHandler(interfaceName, "concatenated", &onConcatenated);
+ concatenatorProxy->finishRegistration();
+
+ std::vector numbers = {1, 2, 3};
+ std::string separator = ":";
+
+ // Invoke concatenate on given interface of the object
+ {
+ auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
+ method << numbers << separator;
+ auto reply = concatenatorProxy->callMethod(method);
+ std::string result;
+ reply >> result;
+ assert(result == "1:2:3");
+ }
+
+ // Invoke concatenate again, this time with no numbers and we shall get an error
+ {
+ auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
+ method << std::vector() << separator;
+ try
+ {
+ auto reply = concatenatorProxy->callMethod(method);
+ assert(false);
+ }
+ catch(const sdbus::Error& e)
+ {
+ std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
+ }
+ }
+
+ // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation
+ sleep(1);
+
+ return 0;
+}
+```
+
+The object proxy is created without explicitly providing a D-Bus connection as an argument in its factory function. In that case, the proxy
+will create its own connection and listen to signals on it in a separate thread. That means the `onConcatenated` method is invoked always
+in the context of a thread different from the main thread.
+
+Implementing the Concatenator example using convenience sdbus-c++ API layer
+---------------------------------------------------------------------------
+
+One of the major sdbus-c++ design goals is to make the sdbus-c++ API easy to use correctly, and hard to use incorrectly.
+
+The convenience API layer abstracts the concept of underlying D-Bus messages away completely. It abstracts away D-Bus signatures. And it tries
+to provide an interface that uses small, focused functions, with one or zero parameters, to form a chained function statement that reads like
+a sentence to a human reading the code. To achieve that, sdbus-c++ utilizes the power of the C++ type system, so many issues are resolved at
+compile time, and the run-time performance cost compared to the basic layer is close to zero.
+
+Thus, in the end of the day, the code written using the convenience API is:
+- more expressive,
+- closer to the abstraction level of the problem being solved,
+- shorter,
+- almost as fast (if not equally fast) as one written using the basic API layer.
+
+Rather than *how*, the code written using this layer expresses *what* it does. Let's look at code samples to see if you agree :)
+
+### Server side
+
+```c++
+#include
+#include
+#include
+
+// Yeah, global variable is ugly, but this is just an example and we want to access
+// the concatenator instance from within the concatenate method handler to be able
+// to emit signals.
+sdbus::IObject* g_concatenator{};
+
+std::string concatenate(const std::vector numbers, const std::string& separator)
+{
+ // Return error if there are no numbers in the collection
+ if (numbers.empty())
+ throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
+
+ std::string result;
+ for (auto number : numbers)
+ {
+ result += (result.empty() ? std::string() : separator) + std::to_string(number);
+ }
+
+ // Emit 'concatenated' signal
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ g_concatenator->emitSignal("concatenated").onInterface(interfaceName).withArguments(result);
+
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ // Create D-Bus connection and requests name on it.
+ const char* serviceName = "org.sdbuscpp.concatenator";
+ auto connection = sdbus::createConnection(serviceName);
+
+ // Create concatenator D-Bus object.
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ auto concatenator = sdbus::createObject(*connection, objectPath);
+
+ g_concatenator = concatenator.get();
+
+ // Register D-Bus methods and signals on the concatenator object, and exports the object.
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ concatenator->registerMethod("concatenate").onInterface(interfaceName).implementedAs(&concatenate);
+ concatenator->registerSignal("concatenated").onInterface(interfaceName).withParameters();
+ concatenator->finishRegistration();
+
+ // Run the loop on the connection.
+ connection->enterProcessingLoop();
+}
+```
+
+### Client side
+
+```c++
+#include
+#include
+#include
+#include
+#include
+
+void onConcatenated(const std::string& concatenatedString)
+{
+ std::cout << "Received signal with concatenated string " << concatenatedString << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+ // Create proxy object for the concatenator object on the server side
+ const char* destinationName = "org.sdbuscpp.concatenator";
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ auto concatenatorProxy = sdbus::createObjectProxy(destinationName, objectPath);
+
+ // Let's subscribe for the 'concatenated' signals
+ const char* interfaceName = "org.sdbuscpp.Concatenator";
+ concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([this](const std::string& str){ onConcatenated(str); });
+ concatenatorProxy->finishRegistration();
+
+ std::vector numbers = {1, 2, 3};
+ std::string separator = ":";
+
+ // Invoke concatenate on given interface of the object
+ {
+ std::string concatenatedString;
+ concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(numbers, separator).storeResultsTo(concatenatedString);
+ assert(concatenatedString == "1:2:3");
+ }
+
+ // Invoke concatenate again, this time with no numbers and we shall get an error
+ {
+ try
+ {
+ concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(std::vector(), separator);
+ assert(false);
+ }
+ catch(const sdbus::Error& e)
+ {
+ std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
+ }
+ }
+
+ // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation
+ sleep(1);
+
+ return 0;
+}
+```
+
+Several lines of code have shrunk into one-liners when registering/calling methods or signals. D-Bus signatures and the serialization/deserialization
+of arguments from the messages is generated at compile time, by introspecting signatures of provided callbacks or deducing types of provided arguments.
+
+Implementing the Concatenator example using sdbus-c++-generated stubs
+---------------------------------------------------------------------
+
+sdbus-c++ ships with the native stub generator tool called sdbuscpp-xml2cpp. The tool is very similar to dbusxx-xml2cpp tool that comes from
+dbus-c++ project.
+
+The generator tool takes D-Bus XML IDL description of D-Bus interfaces on its input, and can be instructed to generate one or both of these:
+an adaptor header file for use at server side, and a proxy header file for use at client side. Like this:
+
+```bash
+sdbuscpp-xml2cpp database-bindings.xml --adaptor=database-server-glue.h --proxy=database-client-glue.h
+```
+
+The adaptor header file contains classes that can be used to implement described interfaces. The proxy header file contains classes that can be used
+to make calls to remote objects.
+
+### XML description of the Concatenator interface
+
+As an example, let's look at an XML description of our Concatenator's interfaces.
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+After running this through the stubs generator, we get the stub code that is described in the following two subsections.
+
+### concatenator-server-glue.h
+
+There is specific class for each interface in the XML IDL file. The class is de facto an interface which shall be implemented by inheriting from it.
+The class' constructor takes care of registering all methods, signals and properties. For each D-Bus method there is a pure virtual member function.
+These pure virtual functions must be implemented in the child class. For each signal, there is a public function member that emits this signal.
+
+```cpp
+/*
+ * This file was automatically generated by sdbuscpp-xml2cpp; DO NOT EDIT!
+ */
+
+#ifndef __sdbuscpp__concatenator_server_glue_h__adaptor__H__
+#define __sdbuscpp__concatenator_server_glue_h__adaptor__H__
+
+#include
+#include
+#include
+
+namespace org {
+namespace sdbuscpp {
+
+class Concatenator_adaptor
+{
+public:
+ static constexpr const char* interfaceName = "org.sdbuscpp.Concatenator";
+
+protected:
+ Concatenator_adaptor(sdbus::IObject& object)
+ : object_(object)
+ {
+ object_.registerMethod("concatenate").onInterface(interfaceName).implementedAs([this](const std::vector& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
+ object_.registerSignal("concatenated").onInterface(interfaceName).withParameters();
+ }
+
+public:
+ void concatenated(const std::string& concatenatedString)
+ {
+ object_.emitSignal("concatenated").onInterface(interfaceName).withArguments(concatenatedString);
+ }
+
+private:
+ virtual std::string concatenate(const std::vector& numbers, const std::string& separator) = 0;
+
+private:
+ sdbus::IObject& object_;
+};
+
+}} // namespaces
+
+#endif
+```
+
+### concatenator-client-glue.h
+
+Analogously to the adaptor classes described above, there is specific class for each interface in the XML IDL file. The class is de facto a proxy
+to the concrete interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child
+class. For each method, there is a public function member that calls the method remotely.
+
+```cpp
+/*
+ * This file was automatically generated by sdbuscpp-xml2cpp; DO NOT EDIT!
+ */
+
+#ifndef __sdbuscpp__concatenator_client_glue_h__proxy__H__
+#define __sdbuscpp__concatenator_client_glue_h__proxy__H__
+
+#include
+#include
+#include
+
+namespace org {
+namespace sdbuscpp {
+
+class Concatenator_proxy
+{
+public:
+ static constexpr const char* interfaceName = "org.sdbuscpp.Concatenator";
+
+protected:
+ Concatenator_proxy(sdbus::IObjectProxy& object)
+ : object_(object)
+ {
+ object_.uponSignal("concatenated").onInterface(interfaceName).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
+ }
+
+ virtual void onConcatenated(const std::string& concatenatedString) = 0;
+
+public:
+ std::string concatenate(const std::vector& numbers, const std::string& separator)
+ {
+ std::string result;
+ object_.callMethod("concatenate").onInterface(interfaceName).withArguments(numbers, separator).storeResultsTo(result);
+ return result;
+ }
+
+private:
+ sdbus::IObjectProxy& object_;
+};
+
+}} // namespaces
+
+#endif
+```
+
+### Providing server implementation based on generated adaptors
+
+To implement a D-Bus object that implements all its D-Bus interfaces, we shall create a class representing the object that inherits from all
+corresponding `*_adaptor` classes and implements all pure virtual member functions. Specifically, the object class shall inherit from the
+`Interfaces` template class, the template arguments of which are individual adaptor classes. The `Interfaces` is just a convenience class that
+hides a few boiler-plate details. For example, in its constructor, it creates an `Object` instance, it takes care of proper initialization of
+all adaptor superclasses, and exports the object finally.
+
+```cpp
+#include
+#include "concatenator-server-glue.h"
+
+class Concatenator : public sdbus::Interfaces
+{
+public:
+ Concatenator(sdbus::IConnection& connection, std::string objectPath)
+ : sdbus::Interfaces(connection, std::move(objectPath))
+ {
+ }
+
+protected:
+ std::string concatenate(const std::vector& numbers, const std::string& separator) override
+ {
+ // Return error if there are no numbers in the collection
+ if (numbers.empty())
+ throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
+
+ // Concatenate the numbers
+ std::string result;
+ for (auto number : numbers)
+ {
+ result += (result.empty() ? std::string() : separator) + std::to_string(number);
+ }
+
+ // Emit the 'concatenated' signal with the resulting string
+ concatenated(result);
+
+ // Return the resulting string
+ return result;
+ }
+};
+```
+
+That's it. We now have an implementation of a D-Bus object implementing `org.sdbuscpp.Concatenator` interface. Let's now create a service
+publishing the object.
+
+```cpp
+#include "Concatenator.h"
+
+int main(int argc, char *argv[])
+{
+ // Create D-Bus connection and requests name on it.
+ const char* serviceName = "org.sdbuscpp.concatenator";
+ auto connection = sdbus::createConnection(serviceName);
+
+ // Create concatenator D-Bus object.
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ Concatenator concatenator(*connection, objectPath);
+
+ // Run the loop on the connection.
+ connection->enterProcessingLoop();
+}
+```
+
+It's that simple!
+
+### Providing client implementation based on generated proxies
+
+To implement a proxy for a remote D-Bus object, we shall create a class representing the object proxy that inherits from all corresponding
+`*_proxy` classes and -- if applicable -- implements all pure virtual member functions. Specifically, the object proxy class shall inherit
+from the `ProxyInterfaces` template class. As its template arguments we shall provide all proxy classes. The `ProxyInterfaces` is just a
+convenience class that hides a few boiler-plate details. For example, in its constructor, it creates an `ObjectProxy` instance, and it takes
+care of proper initialization of all proxy superclasses.
+
+```cpp
+#include
+#include "concatenator-client-glue.h"
+
+class ConcatenatorProxy : public sdbus::ProxyInterfaces
+{
+public:
+ ConcatenatorProxy(std::string destination, std::string objectPath)
+ : sdbus::ProxyInterfaces(std::move(destination), std::move(objectPath))
+ {
+ }
+
+protected:
+ void onConcatenated(const std::string& concatenatedString) override
+ {
+ std::cout << "Received signal with concatenated string " << concatenatedString << std::endl;
+ }
+};
+```
+
+Now let's use this proxy to make remote calls and listen to signals in a real application.
+
+```cpp
+#include "ConcatenatorProxy.h"
+
+int main(int argc, char *argv[])
+{
+ // Create proxy object for the concatenator object on the server side
+ const char* destinationName = "org.sdbuscpp.concatenator";
+ const char* objectPath = "/org/sdbuscpp/concatenator";
+ ConcatenatorProxy concatenatorProxy(destinationName, objectPath);
+
+ std::vector numbers = {1, 2, 3};
+ std::string separator = ":";
+
+ // Invoke concatenate with some numbers
+ auto concatenatedString = concatenatorProxy.concatenate(numbers, separator);
+ assert(concatenatedString == "1:2:3");
+
+ // Invoke concatenate again, this time with no numbers and we shall get an error
+ try
+ {
+ auto concatenatedString = concatenatorProxy.concatenate(std::vector(), separator);
+ assert(false);
+ }
+ catch(const sdbus::Error& e)
+ {
+ std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
+ }
+
+ // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation
+ sleep(1);
+
+ return 0;
+}
+```
+
+Using D-Bus properties
+----------------------
+
+Defining and working with D-Bus properties using XML description is quite easy.
+
+### Defining a property in the XML
+
+A property element has no arg child element. It just has the attributes name, type and access, which are all mandatory. The access attribute allows the values ‘readwrite’, ‘read’, and ‘write’.
+
+An example of a read-write property `status`:
+
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+### Generated stubs
+
+This is how generated adaptor and proxy classes would look like with the read-write `status` property. The adaptor:
+
+```cpp
+class PropertyProvider_adaptor
+{
+ /*...*/
+
+public:
+ PropertyProvider_adaptor(sdbus::IObject& object)
+ : object_(object)
+ {
+ object_.registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
+ }
+
+private:
+ // property getter
+ virtual uint32_t status() = 0;
+ // property setter
+ virtual void status(const uint32_t& value) = 0;
+
+ /*...*/
+};
+#endif
+```
+
+The proxy:
+
+```cpp
+class PropertyProvider_proxy
+{
+ /*...*/
+
+public:
+ // getting the property value
+ uint32_t status()
+ {
+ return object_.getProperty("status").onInterface(INTERFACE_NAME);
+ }
+
+ // setting the property value
+ void status(const uint32_t& value)
+ {
+ object_.setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
+ }
+
+ /*...*/
+};
+```
+
+When implementing the adaptor, we simply need to provide the body for `status` getter and setter method by overriding them. Then in the proxy, we just call them.
+
+Conclusion
+----------
+
+There is no conclusion. Happy journeys by D-Bus with sdbus-c++!
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..cc92c51
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,23 @@
+
+# Distribution
+# Headers will be installed to $(includedir)/sdbus-c++ directory
+
+HEADER_DIR = sdbus-c++
+libsdbuscppdir = $(includedir)/$(HEADER_DIR)
+libsdbuscpp_HEADERS = \
+ $(HEADER_DIR)/ConvenienceClasses.h \
+ $(HEADER_DIR)/ConvenienceClasses.inl \
+ $(HEADER_DIR)/Error.h \
+ $(HEADER_DIR)/IConnection.h \
+ $(HEADER_DIR)/Interfaces.h \
+ $(HEADER_DIR)/Introspection.h \
+ $(HEADER_DIR)/IObject.h \
+ $(HEADER_DIR)/IObjectProxy.h \
+ $(HEADER_DIR)/Message.h \
+ $(HEADER_DIR)/Types.h \
+ $(HEADER_DIR)/TypeTraits.h \
+ $(HEADER_DIR)/sdbus-c++.h
+
+EXTRA_DIST = ($libsdbuscpp_HEADERS)
+
+DISTCLEANFILES = Makefile Makefile.in
diff --git a/include/sdbus-c++/ConvenienceClasses.h b/include/sdbus-c++/ConvenienceClasses.h
new file mode 100644
index 0000000..25fd742
--- /dev/null
+++ b/include/sdbus-c++/ConvenienceClasses.h
@@ -0,0 +1,169 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file ConvenienceClasses.h
+ *
+ * Created on: Jan 19, 2017
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_CONVENIENCECLASSES_H_
+#define SDBUS_CXX_CONVENIENCECLASSES_H_
+
+#include
+#include
+
+// Forward declarations
+namespace sdbus {
+ class IObject;
+ class IObjectProxy;
+ class Variant;
+}
+
+namespace sdbus {
+
+ class MethodRegistrator
+ {
+ public:
+ MethodRegistrator(IObject& object, const std::string& methodName);
+ MethodRegistrator& onInterface(const std::string& interfaceName);
+ template void implementedAs(_Function&& callback);
+
+ private:
+ IObject& object_;
+ const std::string& methodName_;
+ std::string interfaceName_;
+ };
+
+ class SignalRegistrator
+ {
+ public:
+ SignalRegistrator(IObject& object, const std::string& signalName);
+ SignalRegistrator(SignalRegistrator&& other) = default;
+ SignalRegistrator& operator=(SignalRegistrator&& other) = default;
+ ~SignalRegistrator() noexcept(false);
+ SignalRegistrator& onInterface(std::string interfaceName);
+ template void withParameters();
+
+ private:
+ IObject& object_;
+ const std::string& signalName_;
+ std::string interfaceName_;
+ std::string signalSignature_;
+ int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
+ };
+
+ class PropertyRegistrator
+ {
+ public:
+ PropertyRegistrator(IObject& object, const std::string& propertyName);
+ PropertyRegistrator(PropertyRegistrator&& other) = default;
+ PropertyRegistrator& operator=(PropertyRegistrator&& other) = default;
+ ~PropertyRegistrator() noexcept(false);
+ PropertyRegistrator& onInterface(const std::string& interfaceName);
+ template PropertyRegistrator& withGetter(_Function&& callback);
+ template PropertyRegistrator& withSetter(_Function&& callback);
+
+ private:
+ IObject& object_;
+ const std::string& propertyName_;
+ std::string interfaceName_;
+ std::string propertySignature_;
+ property_get_callback getter_;
+ property_set_callback setter_;
+ int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
+ };
+
+ class SignalEmitter
+ {
+ public:
+ SignalEmitter(IObject& object, const std::string& signalName);
+ SignalEmitter(SignalEmitter&& other) = default;
+ SignalEmitter& operator=(SignalEmitter&& other) = default;
+ ~SignalEmitter() noexcept(false);
+ SignalEmitter& onInterface(const std::string& interfaceName);
+ template void withArguments(_Args&&... args);
+
+ private:
+ IObject& object_;
+ const std::string& signalName_;
+ Message signal_;
+ int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed
+ };
+
+ class MethodInvoker
+ {
+ public:
+ MethodInvoker(IObjectProxy& objectProxy, const std::string& methodName);
+ MethodInvoker(MethodInvoker&& other) = default;
+ MethodInvoker& operator=(MethodInvoker&& other) = default;
+ ~MethodInvoker() noexcept(false);
+
+ MethodInvoker& onInterface(const std::string& interfaceName);
+ template MethodInvoker& withArguments(_Args&&... args);
+ template void storeResultsTo(_Args&... args);
+
+ private:
+ IObjectProxy& objectProxy_;
+ const std::string& methodName_;
+ Message method_;
+ int exceptions_{}; // Number of active exceptions when MethodInvoker is constructed
+ bool methodCalled_{};
+ };
+
+ class SignalSubscriber
+ {
+ public:
+ SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName);
+ SignalSubscriber& onInterface(const std::string& interfaceName);
+ template void call(_Function&& callback);
+
+ private:
+ IObjectProxy& objectProxy_;
+ std::string signalName_;
+ std::string interfaceName_;
+ };
+
+ class PropertyGetter
+ {
+ public:
+ PropertyGetter(IObjectProxy& objectProxy, const std::string& propertyName);
+ sdbus::Variant onInterface(const std::string& interfaceName);
+
+ private:
+ IObjectProxy& objectProxy_;
+ std::string propertyName_;
+ };
+
+ class PropertySetter
+ {
+ public:
+ PropertySetter(IObjectProxy& objectProxy, const std::string& propertyName);
+ PropertySetter& onInterface(const std::string& interfaceName);
+ template void toValue(const _Value& value);
+
+ private:
+ IObjectProxy& objectProxy_;
+ const std::string& propertyName_;
+ std::string interfaceName_;
+ };
+
+}
+
+#endif /* SDBUS_CXX_CONVENIENCECLASSES_H_ */
diff --git a/include/sdbus-c++/ConvenienceClasses.inl b/include/sdbus-c++/ConvenienceClasses.inl
new file mode 100644
index 0000000..84b6876
--- /dev/null
+++ b/include/sdbus-c++/ConvenienceClasses.inl
@@ -0,0 +1,401 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file ConvenienceClasses.inl
+ *
+ * Created on: Dec 19, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CPP_CONVENIENCECLASSES_INL_
+#define SDBUS_CPP_CONVENIENCECLASSES_INL_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+/*#include */
+
+namespace sdbus {
+
+ inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
+ : object_(object)
+ , methodName_(methodName)
+ {
+ }
+
+ inline MethodRegistrator& MethodRegistrator::onInterface(const std::string& interfaceName)
+ {
+ interfaceName_ = interfaceName;
+
+ return *this;
+ }
+
+ template
+ inline void MethodRegistrator::implementedAs(_Function&& callback)
+ {
+ SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
+
+ object_.registerMethod( interfaceName_
+ , methodName_
+ , signature_of_function_input_arguments<_Function>::str()
+ , signature_of_function_output_arguments<_Function>::str()
+ , [callback = std::forward<_Function>(callback)](Message& msg, Message& reply)
+ {
+ // Create a tuple of callback input arguments' types, which will be used
+ // as a storage for the argument values deserialized from the message.
+ tuple_of_function_input_arg_types_t<_Function> inputArgs;
+
+ // Deserialize input arguments from the message into the tuple
+ msg >> inputArgs;
+
+ // Invoke callback with input arguments from the tuple.
+ // For callbacks returning a non-void value, `apply' also returns that value.
+ // For callbacks returning void, `apply' returns an empty tuple.
+ auto ret = apply(callback, inputArgs); // We don't yet have C++17's std::apply :-(
+
+ // The return value is stored to the reply message.
+ // In case of void functions, ret is an empty tuple and thus nothing is stored.
+ reply << ret;
+ });
+ }
+
+
+ // Moved into the library to isolate from C++17 dependency
+ /*
+ inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName)
+ : object_(object)
+ , signalName_(std::move(signalName))
+ , exceptions_(std::uncaught_exceptions())
+ {
+ }
+
+ inline SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destructors must
+ { // explicitly be allowed to throw
+ // Don't register the signal if SignalRegistrator threw an exception in one of its methods
+ if (std::uncaught_exceptions() != exceptions_)
+ return;
+
+ if (interfaceName_.empty())
+ throw sdbus::Exception("DBus interface not specified when registering a DBus signal");
+
+ // registerSignal() can throw. But as the SignalRegistrator shall always be used as an unnamed,
+ // temporary object, i.e. not as a stack-allocated object, the double-exception situation
+ // shall never happen. I.e. it should not happen that this destructor is directly called
+ // in the stack-unwinding process of another flying exception (which would lead to immediate
+ // termination). It can be called indirectly in the destructor of another object, but that's
+ // fine and safe provided that the caller catches exceptions thrown from here.
+ // Therefore, we can allow registerSignal() to throw even if we are in the destructor.
+ // Bottomline is, to be on the safe side, the caller must take care of catching and reacting
+ // to the exception thrown from here if the caller is a destructor itself.
+ object_.registerSignal(interfaceName_, signalName_, signalSignature_);
+ }
+ */
+
+ inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName)
+ {
+ interfaceName_ = std::move(interfaceName);
+
+ return *this;
+ }
+
+ template
+ inline void SignalRegistrator::withParameters()
+ {
+ signalSignature_ = signature_of_function_input_arguments::str();
+ }
+
+
+ // Moved into the library to isolate from C++17 dependency
+ /*
+ inline PropertyRegistrator::PropertyRegistrator(IObject& object, std::string propertyName)
+ : object_(object)
+ , propertyName_(std::move(propertyName))
+ , exceptions_(std::uncaught_exceptions())
+ {
+ }
+
+ inline PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, destructors must
+ { // explicitly be allowed to throw
+ // Don't register the property if PropertyRegistrator threw an exception in one of its methods
+ if (std::uncaught_exceptions() != exceptions_)
+ return;
+
+ SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus property", EINVAL);
+
+ // registerProperty() can throw. But as the PropertyRegistrator shall always be used as an unnamed,
+ // temporary object, i.e. not as a stack-allocated object, the double-exception situation
+ // shall never happen. I.e. it should not happen that this destructor is directly called
+ // in the stack-unwinding process of another flying exception (which would lead to immediate
+ // termination). It can be called indirectly in the destructor of another object, but that's
+ // fine and safe provided that the caller catches exceptions thrown from here.
+ // Therefore, we can allow registerProperty() to throw even if we are in the destructor.
+ // Bottomline is, to be on the safe side, the caller must take care of catching and reacting
+ // to the exception thrown from here if the caller is a destructor itself.
+ object_.registerProperty( std::move(interfaceName_)
+ , std::move(propertyName_)
+ , std::move(propertySignature_)
+ , std::move(getter_)
+ , std::move(setter_) );
+ }
+ */
+
+ inline PropertyRegistrator& PropertyRegistrator::onInterface(const std::string& interfaceName)
+ {
+ interfaceName_ = interfaceName;
+
+ return *this;
+ }
+
+ template
+ inline PropertyRegistrator& PropertyRegistrator::withGetter(_Function&& callback)
+ {
+ static_assert(function_traits<_Function>::arity == 0, "Property getter function must not take any arguments");
+ static_assert(!std::is_void>::value, "Property getter function must return property value");
+
+ if (propertySignature_.empty())
+ propertySignature_ = signature_of_function_output_arguments<_Function>::str();
+
+ getter_ = [callback = std::forward<_Function>(callback)](Message& msg)
+ {
+ // Get the propety value and serialize it into the message
+ msg << callback();
+ };
+
+ return *this;
+ }
+
+ template
+ inline PropertyRegistrator& PropertyRegistrator::withSetter(_Function&& callback)
+ {
+ static_assert(function_traits<_Function>::arity == 1, "Property setter function must take one parameter - the property value");
+ static_assert(std::is_void>::value, "Property setter function must not return any value");
+
+ if (propertySignature_.empty())
+ propertySignature_ = signature_of_function_input_arguments<_Function>::str();
+
+ setter_ = [callback = std::forward<_Function>(callback)](Message& msg)
+ {
+ // Default-construct property value
+ using property_type = function_argument_t<_Function, 0>;
+ std::decay_t property;
+
+ // Deserialize property value from the message
+ msg >> property;
+
+ // Invoke setter with the value
+ callback(property);
+ };
+
+ return *this;
+ }
+
+
+ // Moved into the library to isolate from C++17 dependency
+ /*
+ inline SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName)
+ : object_(object)
+ , signalName_(signalName)
+ , exceptions_(std::uncaught_exceptions())
+ {
+ }
+
+ inline SignalEmitter::~SignalEmitter() noexcept(false) // since C++11, destructors must
+ { // explicitly be allowed to throw
+ // Don't emit the signal if SignalEmitter threw an exception in one of its methods
+ if (std::uncaught_exceptions() != exceptions_)
+ return;
+
+ if (!signal_.isValid())
+ throw sdbus::Exception("DBus interface not specified when emitting a DBus signal");
+
+ // emitSignal() can throw. But as the SignalEmitter shall always be used as an unnamed,
+ // temporary object, i.e. not as a stack-allocated object, the double-exception situation
+ // shall never happen. I.e. it should not happen that this destructor is directly called
+ // in the stack-unwinding process of another flying exception (which would lead to immediate
+ // termination). It can be called indirectly in the destructor of another object, but that's
+ // fine and safe provided that the caller catches exceptions thrown from here.
+ // Therefore, we can allow emitSignal() to throw even if we are in the destructor.
+ // Bottomline is, to be on the safe side, the caller must take care of catching and reacting
+ // to the exception thrown from here if the caller is a destructor itself.
+ object_.emitSignal(signal_);
+ }
+ */
+
+ inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName)
+ {
+ signal_ = object_.createSignal(interfaceName, signalName_);
+
+ return *this;
+ }
+
+ template
+ inline void SignalEmitter::withArguments(_Args&&... args)
+ {
+ SDBUS_THROW_ERROR_IF(!signal_.isValid(), "DBus interface not specified when emitting a DBus signal", EINVAL);
+
+ detail::serialize_pack(signal_, std::forward<_Args>(args)...);
+ }
+
+
+ // Moved into the library to isolate from C++17 dependency
+ /*
+ inline MethodInvoker::MethodInvoker(IObjectProxy& objectProxy, const std::string& methodName)
+ : objectProxy_(objectProxy)
+ , methodName_(methodName)
+ , exceptions_(std::uncaught_exceptions())
+ {
+ }
+
+ inline MethodInvoker::~MethodInvoker() noexcept(false) // since C++11, destructors must
+ { // explicitly be allowed to throw
+ // Don't call the method if it has been called already or if MethodInvoker
+ // threw an exception in one of its methods
+ if (methodCalled_ || std::uncaught_exceptions() != exceptions_)
+ return;
+
+ if (!method_.isValid())
+ throw sdbus::Exception("DBus interface not specified when calling a DBus method");
+
+ // callMethod() can throw. But as the MethodInvoker shall always be used as an unnamed,
+ // temporary object, i.e. not as a stack-allocated object, the double-exception situation
+ // shall never happen. I.e. it should not happen that this destructor is directly called
+ // in the stack-unwinding process of another flying exception (which would lead to immediate
+ // termination). It can be called indirectly in the destructor of another object, but that's
+ // fine and safe provided that the caller catches exceptions thrown from here.
+ // Therefore, we can allow callMethod() to throw even if we are in the destructor.
+ // Bottomline is, to be on the safe side, the caller must take care of catching and reacting
+ // to the exception thrown from here if the caller is a destructor itself.
+ objectProxy_.callMethod(method_);
+ }
+ */
+
+ inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName)
+ {
+ method_ = objectProxy_.createMethodCall(interfaceName, methodName_);
+
+ return *this;
+ }
+
+ template
+ inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args)
+ {
+ SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
+
+ detail::serialize_pack(method_, std::forward<_Args>(args)...);
+
+ return *this;
+ }
+
+ template
+ inline void MethodInvoker::storeResultsTo(_Args&... args)
+ {
+ SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
+
+ auto reply = objectProxy_.callMethod(method_);
+ methodCalled_ = true;
+
+ detail::deserialize_pack(reply, args...);
+ }
+
+
+ inline SignalSubscriber::SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName)
+ : objectProxy_(objectProxy)
+ , signalName_(signalName)
+ {
+ }
+
+ inline SignalSubscriber& SignalSubscriber::onInterface(const std::string& interfaceName)
+ {
+ interfaceName_ = interfaceName;
+
+ return *this;
+ }
+
+ template
+ inline void SignalSubscriber::call(_Function&& callback)
+ {
+ SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when subscribing to a signal", EINVAL);
+
+ objectProxy_.registerSignalHandler( interfaceName_
+ , signalName_
+ , [callback = std::forward<_Function>(callback)](Message& signal)
+ {
+ // Create a tuple of callback input arguments' types, which will be used
+ // as a storage for the argument values deserialized from the signal message.
+ tuple_of_function_input_arg_types_t<_Function> signalArgs;
+
+ // Deserialize input arguments from the signal message into the tuple
+ signal >> signalArgs;
+
+ // Invoke callback with input arguments from the tuple.
+ apply(callback, signalArgs); // We don't yet have C++17's std::apply :-(
+ });
+ }
+
+
+ inline PropertyGetter::PropertyGetter(IObjectProxy& objectProxy, const std::string& propertyName)
+ : objectProxy_(objectProxy)
+ , propertyName_(propertyName)
+ {
+ }
+
+ inline sdbus::Variant PropertyGetter::onInterface(const std::string& interfaceName)
+ {
+ sdbus::Variant var;
+ objectProxy_
+ .callMethod("Get")
+ .onInterface("org.freedesktop.DBus.Properties")
+ .withArguments(interfaceName, propertyName_)
+ .storeResultsTo(var);
+ return var;
+ }
+
+
+ inline PropertySetter::PropertySetter(IObjectProxy& objectProxy, const std::string& propertyName)
+ : objectProxy_(objectProxy)
+ , propertyName_(propertyName)
+ {
+ }
+
+ inline PropertySetter& PropertySetter::onInterface(const std::string& interfaceName)
+ {
+ interfaceName_ = interfaceName;
+
+ return *this;
+ }
+
+ template
+ inline void PropertySetter::toValue(const _Value& value)
+ {
+ SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting a property", EINVAL);
+
+ objectProxy_
+ .callMethod("Set")
+ .onInterface("org.freedesktop.DBus.Properties")
+ .withArguments(interfaceName_, propertyName_, sdbus::Variant{value});
+ }
+
+}
+
+#endif /* SDBUS_CPP_CONVENIENCECLASSES_INL_ */
diff --git a/include/sdbus-c++/Error.h b/include/sdbus-c++/Error.h
new file mode 100755
index 0000000..efdcd41
--- /dev/null
+++ b/include/sdbus-c++/Error.h
@@ -0,0 +1,76 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file ConvenienceClasses.h
+ *
+ * Created on: Nov 8, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_ERROR_H_
+#define SDBUS_CXX_ERROR_H_
+
+#include
+
+namespace sdbus {
+
+ /********************************************//**
+ * @class Error
+ *
+ * Represents a common sdbus-c++ exception.
+ *
+ ***********************************************/
+ class Error
+ : public std::runtime_error
+ {
+ public:
+ Error(const std::string& name, const std::string& message)
+ : std::runtime_error("[" + name + "] " + message)
+ , name_(name)
+ , message_(message)
+ {
+ }
+
+ const std::string& getName() const
+ {
+ return name_;
+ }
+
+ const std::string& getMessage() const
+ {
+ return message_;
+ }
+
+ private:
+ std::string name_;
+ std::string message_;
+ };
+
+ sdbus::Error createError(int errNo, const std::string& customMsg);
+}
+
+#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
+ throw sdbus::createError((_ERRNO), (_MSG)) \
+ /**/
+
+#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
+ if (_COND) SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
+ /**/
+
+#endif /* SDBUS_CXX_ERROR_H_ */
diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h
new file mode 100644
index 0000000..de5d3a6
--- /dev/null
+++ b/include/sdbus-c++/IConnection.h
@@ -0,0 +1,157 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file IConnection.h
+ *
+ * Created on: Nov 8, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_ICONNECTION_H_
+#define SDBUS_CXX_ICONNECTION_H_
+
+//#include
+#include
+#include
+
+namespace sdbus {
+
+ /********************************************//**
+ * @class IConnection
+ *
+ * An interface to D-Bus bus connection. Incorporates implementation
+ * of both synchronous and asynchronous processing loop.
+ *
+ * All methods throw @sdbus::Error in case of failure. The class is
+ * thread-aware, but not thread-safe.
+ *
+ ***********************************************/
+ class IConnection
+ {
+ public:
+ /*!
+ * @brief Requests D-Bus name on the connection
+ *
+ * @param[in] name Name to request
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void requestName(const std::string& name) = 0;
+
+ /*!
+ * @brief Releases D-Bus name on the connection
+ *
+ * @param[in] name Name to release
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void releaseName(const std::string& name) = 0;
+
+ /*!
+ * @brief Enters the D-Bus processing loop
+ *
+ * The incoming D-Bus messages are processed in the loop. The method
+ * blocks indefinitely, until unblocked via @leaveProcessingLoop.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void enterProcessingLoop() = 0;
+
+ /*!
+ * @brief Enters the D-Bus processing loop in a separate thread
+ *
+ * The same as @enterProcessingLoop, except that it doesn't block
+ * because it runs the loop in a separate thread managed internally.
+ */
+ virtual void enterProcessingLoopAsync() = 0;
+
+ /*!
+ * @brief Leaves the D-Bus processing loop
+ *
+ * Ends the previously started processing loop.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void leaveProcessingLoop() = 0;
+
+ inline virtual ~IConnection() = 0;
+ };
+
+ IConnection::~IConnection() {}
+
+ /*!
+ * @brief Creates/opens D-Bus system connection
+ *
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createConnection();
+
+ /*!
+ * @brief Creates/opens D-Bus system connection with a name
+ *
+ * @param[in] name Name to request on the connection after its opening
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createConnection(const std::string& name);
+
+ /*!
+ * @brief Creates/opens D-Bus system connection
+ *
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createSystemBusConnection();
+
+ /*!
+ * @brief Creates/opens D-Bus system connection with a name
+ *
+ * @param[in] name Name to request on the connection after its opening
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createSystemBusConnection(const std::string& name);
+
+ /*!
+ * @brief Creates/opens D-Bus session connection
+ *
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createSessionBusConnection();
+
+ /*!
+ * @brief Creates/opens D-Bus session connection with a name
+ *
+ * @param[in] name Name to request on the connection after its opening
+ * @return Connection instance
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ std::unique_ptr createSessionBusConnection(const std::string& name);
+
+}
+
+#endif /* SDBUS_CXX_ICONNECTION_H_ */
diff --git a/include/sdbus-c++/IObject.h b/include/sdbus-c++/IObject.h
new file mode 100755
index 0000000..75ccd7c
--- /dev/null
+++ b/include/sdbus-c++/IObject.h
@@ -0,0 +1,279 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file IObject.h
+ *
+ * Created on: Nov 8, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_IOBJECT_H_
+#define SDBUS_CXX_IOBJECT_H_
+
+#include
+#include
+#include
+#include
+#include
+
+// Forward declarations
+namespace sdbus {
+ class Message;
+ class IConnection;
+}
+
+namespace sdbus {
+
+ /********************************************//**
+ * @class IObject
+ *
+ * An interface to D-Bus object. Provides API for registration
+ * of methods, signals, properties, and for emitting signals.
+ *
+ * All methods throw @c sdbus::Error in case of failure. The class is
+ * thread-aware, but not thread-safe.
+ *
+ ***********************************************/
+ class IObject
+ {
+ public:
+ /*!
+ * @brief Registers method that the object will provide on D-Bus
+ *
+ * @param[in] interfaceName Name of an interface that the method will belong to
+ * @param[in] methodName Name of the method
+ * @param[in] inputSignature D-Bus signature of method input parameters
+ * @param[in] outputSignature D-Bus signature of method output parameters
+ * @param[in] methodCallback Callback that implements the body of the method
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void registerMethod( const std::string& interfaceName
+ , const std::string& methodName
+ , const std::string& inputSignature
+ , const std::string& outputSignature
+ , method_callback methodCallback ) = 0;
+
+ /*!
+ * @brief Registers signal that the object will emit on D-Bus
+ *
+ * @param[in] interfaceName Name of an interface that the signal will fall under
+ * @param[in] signalName Name of the signal
+ * @param[in] signature D-Bus signature of signal parameters
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void registerSignal( const std::string& interfaceName
+ , const std::string& signalName
+ , const std::string& signature ) = 0;
+
+ /*!
+ * @brief Registers read-only property that the object will provide on D-Bus
+ *
+ * @param[in] interfaceName Name of an interface that the property will fall under
+ * @param[in] propertyName Name of the property
+ * @param[in] signature D-Bus signature of property parameters
+ * @param[in] getCallback Callback that implements the body of the property getter
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void registerProperty( const std::string& interfaceName
+ , const std::string& propertyName
+ , const std::string& signature
+ , property_get_callback getCallback ) = 0;
+
+ /*!
+ * @brief Registers read/write property that the object will provide on D-Bus
+ *
+ * @param[in] interfaceName Name of an interface that the property will fall under
+ * @param[in] propertyName Name of the property
+ * @param[in] signature D-Bus signature of property parameters
+ * @param[in] getCallback Callback that implements the body of the property getter
+ * @param[in] setCallback Callback that implements the body of the property setter
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void registerProperty( const std::string& interfaceName
+ , const std::string& propertyName
+ , const std::string& signature
+ , property_get_callback getCallback
+ , property_set_callback setCallback ) = 0;
+
+ /*!
+ * @brief Finishes the registration and exports object API on D-Bus
+ *
+ * The method exports all up to now registered methods, signals and properties on D-Bus.
+ * Must be called only once, after all methods, signals and properties have been registered.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void finishRegistration() = 0;
+
+ /*!
+ * @brief Creates a signal message
+ *
+ * @param[in] interfaceName Name of an interface that the signal belongs under
+ * @param[in] signalName Name of the signal
+ * @return A signal message
+ *
+ * Serialize signal arguments into the returned message and emit the signal by passing
+ * the message with serialized arguments to the @c emitSignal function.
+ * Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual Message createSignal(const std::string& interfaceName, const std::string& signalName) = 0;
+
+ /*!
+ * @brief Emits signal on D-Bus
+ *
+ * @param[in] message Signal message to be sent out
+ *
+ * Note: To avoid messing with messages, use higher-level API defined below.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void emitSignal(const sdbus::Message& message) = 0;
+
+ /*!
+ * @brief Registers method that the object will provide on D-Bus
+ *
+ * @param[in] methodName Name of the method
+ * @return A helper object for convenient registration of the method
+ *
+ * This is a high-level, convenience way of registering D-Bus methods that abstracts
+ * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
+ * in a message and D-Bus signatures automatically deduced from the parameters and return type
+ * of the provided native method implementation callback.
+ *
+ * Example of use:
+ * @code
+ * object.registerMethod("doFoo").onInterface("com.kistler.foo").implementedAs([this](int value){ return this->doFoo(value); });
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ MethodRegistrator registerMethod(const std::string& methodName);
+
+ /*!
+ * @brief Registers signal that the object will provide on D-Bus
+ *
+ * @param[in] signalName Name of the signal
+ * @return A helper object for convenient registration of the signal
+ *
+ * This is a high-level, convenience way of registering D-Bus signals that abstracts
+ * from the D-Bus message concept. Signal arguments are automatically (de)serialized
+ * in a message and D-Bus signatures automatically deduced from the provided native parameters.
+ *
+ * Example of use:
+ * @code
+ * object.registerSignal("paramChange").onInterface("com.kistler.foo").withParameters>();
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ SignalRegistrator registerSignal(const std::string& signalName);
+
+ /*!
+ * @brief Registers property that the object will provide on D-Bus
+ *
+ * @param[in] propertyName Name of the property
+ * @return A helper object for convenient registration of the property
+ *
+ * This is a high-level, convenience way of registering D-Bus properties that abstracts
+ * from the D-Bus message concept. Property arguments are automatically (de)serialized
+ * in a message and D-Bus signatures automatically deduced from the provided native callbacks.
+ *
+ * Example of use:
+ * @code
+ * object_.registerProperty("state").onInterface("com.kistler.foo").withGetter([this](){ return this->state(); });
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ PropertyRegistrator registerProperty(const std::string& propertyName);
+
+ /*!
+ * @brief Emits signal on D-Bus
+ *
+ * @param[in] signalName Name of the signal
+ * @return A helper object for convenient emission of signals
+ *
+ * This is a high-level, convenience way of emitting D-Bus signals that abstracts
+ * from the D-Bus message concept. Signal arguments are automatically serialized
+ * in a message and D-Bus signatures automatically deduced from the provided native arguments.
+ *
+ * Example of use:
+ * @code
+ * int arg1 = ...;
+ * double arg2 = ...;
+ * object_.emitSignal("fooSignal").onInterface("com.kistler.foo").withArguments(arg1, arg2);
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ SignalEmitter emitSignal(const std::string& signalName);
+
+ virtual ~IObject() = 0;
+ };
+
+ inline MethodRegistrator IObject::registerMethod(const std::string& methodName)
+ {
+ return MethodRegistrator(*this, methodName);
+ }
+
+ inline SignalRegistrator IObject::registerSignal(const std::string& signalName)
+ {
+ return SignalRegistrator(*this, std::move(signalName));
+ }
+
+ inline PropertyRegistrator IObject::registerProperty(const std::string& propertyName)
+ {
+ return PropertyRegistrator(*this, std::move(propertyName));
+ }
+
+ inline SignalEmitter IObject::emitSignal(const std::string& signalName)
+ {
+ return SignalEmitter(*this, signalName);
+ }
+
+ inline IObject::~IObject() {}
+
+ /*!
+ * @brief Creates instance representing a D-Bus object
+ *
+ * @param[in] connection D-Bus connection to be used by the object
+ * @param[in] objectPath Path of the D-Bus object
+ * @return Pointer to the object representation instance
+ *
+ * The provided connection will be used by the object to export methods,
+ * issue signals and provide properties.
+ *
+ * Code example:
+ * @code
+ * auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
+ * @endcode
+ */
+ std::unique_ptr createObject(sdbus::IConnection& connection, std::string objectPath);
+
+}
+
+#include
+
+#endif /* SDBUS_CXX_IOBJECT_H_ */
diff --git a/include/sdbus-c++/IObjectProxy.h b/include/sdbus-c++/IObjectProxy.h
new file mode 100755
index 0000000..27104ef
--- /dev/null
+++ b/include/sdbus-c++/IObjectProxy.h
@@ -0,0 +1,249 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file IObjectProxy.h
+ *
+ * Created on: Nov 8, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_IOBJECTPROXY_H_
+#define SDBUS_CXX_IOBJECTPROXY_H_
+
+#include
+#include
+#include
+#include
+
+// Forward declarations
+namespace sdbus {
+ class Message;
+ class IConnection;
+}
+
+namespace sdbus {
+
+ /********************************************//**
+ * @class IObjectProxy
+ *
+ * An interface to D-Bus object proxy. Provides API for calling
+ * methods, getting/setting properties, and for registering to signals.
+ *
+ * All methods throw @c sdbus::Error in case of failure. The class is
+ * thread-aware, but not thread-safe.
+ *
+ ***********************************************/
+ class IObjectProxy
+ {
+ public:
+ /*!
+ * @brief Creates a method call message
+ *
+ * @param[in] interfaceName Name of an interface that the method is defined under
+ * @param[in] methodName Name of the method
+ * @return A method call message message
+ *
+ * Serialize method arguments into the returned message and invoke the method by passing
+ * the message with serialized arguments to the @c callMethod function.
+ * Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual Message createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
+
+ /*!
+ * @brief Calls method on the proxied D-Bus object
+ *
+ * @param[in] message Message representing a method call
+ *
+ * Note: To avoid messing with messages, use higher-level API defined below.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual Message callMethod(const sdbus::Message& message) = 0;
+
+ /*!
+ * @brief Registers a handler for the desired signal emitted by the proxied D-Bus object
+ *
+ * @param[in] interfaceName Name of an interface that the signal belongs to
+ * @param[in] signalName Name of the signal
+ * @param[in] signalHandler Callback that implements the body of the signal handler
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void registerSignalHandler( const std::string& interfaceName
+ , const std::string& signalName
+ , signal_handler signalHandler ) = 0;
+
+ /*!
+ * @brief Finishes the registration of signal handlers
+ *
+ * The method physically subscribes to the desired signals.
+ * Must be called only once, after all signals have been registered already.
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ virtual void finishRegistration() = 0;
+
+ /*!
+ * @brief Calls method on the proxied D-Bus object
+ *
+ * @param[in] methodName Name of the method
+ * @return A helper object for convenient invocation of the method
+ *
+ * This is a high-level, convenience way of calling D-Bus methods that abstracts
+ * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
+ * in a message and D-Bus signatures automatically deduced from the provided native arguments
+ * and return values.
+ *
+ * Example of use:
+ * @code
+ * int result, a = ..., b = ...;
+ * object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ MethodInvoker callMethod(const std::string& methodName);
+
+ /*!
+ * @brief Registers signal handler for a given signal of the proxied D-Bus object
+ *
+ * @param[in] signalName Name of the signal
+ * @return A helper object for convenient registration of the signal handler
+ *
+ * This is a high-level, convenience way of registering to D-Bus signals that abstracts
+ * from the D-Bus message concept. Signal arguments are automatically serialized
+ * in a message and D-Bus signatures automatically deduced from the parameters
+ * of the provided native signal callback.
+ *
+ * Example of use:
+ * @code
+ * object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ SignalSubscriber uponSignal(const std::string& signalName);
+
+ /*!
+ * @brief Gets value of a property of the proxied D-Bus object
+ *
+ * @param[in] propertyName Name of the property
+ * @return A helper object for convenient getting of property value
+ *
+ * This is a high-level, convenience way of reading D-Bus property values that abstracts
+ * from the D-Bus message concept. sdbus::Variant is returned which shall then be converted
+ * to the real property type (implicit conversion is supported).
+ *
+ * Example of use:
+ * @code
+ * int state = object.getProperty("state").onInterface("com.kistler.foo");
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ PropertyGetter getProperty(const std::string& propertyName);
+
+ /*!
+ * @brief Sets value of a property of the proxied D-Bus object
+ *
+ * @param[in] propertyName Name of the property
+ * @return A helper object for convenient setting of property value
+ *
+ * This is a high-level, convenience way of writing D-Bus property values that abstracts
+ * from the D-Bus message concept.
+ *
+ * Example of use:
+ * @code
+ * int state = ...;
+ * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state);
+ * @endcode
+ *
+ * @throws sdbus::Error in case of failure
+ */
+ PropertySetter setProperty(const std::string& propertyName);
+
+ virtual ~IObjectProxy() = 0;
+ };
+
+ inline MethodInvoker IObjectProxy::callMethod(const std::string& methodName)
+ {
+ return MethodInvoker(*this, methodName);
+ }
+
+ inline SignalSubscriber IObjectProxy::uponSignal(const std::string& signalName)
+ {
+ return SignalSubscriber(*this, signalName);
+ }
+
+ inline PropertyGetter IObjectProxy::getProperty(const std::string& propertyName)
+ {
+ return PropertyGetter(*this, propertyName);
+ }
+
+ inline PropertySetter IObjectProxy::setProperty(const std::string& propertyName)
+ {
+ return PropertySetter(*this, propertyName);
+ }
+
+ inline IObjectProxy::~IObjectProxy() {}
+
+ /*!
+ * @brief Creates object proxy instance
+ *
+ * @param[in] connection D-Bus connection to be used by the proxy object
+ * @param[in] destination Bus name that provides a D-Bus object
+ * @param[in] objectPath Path of the D-Bus object
+ * @return Pointer to the object proxy instance
+ *
+ * The provided connection will be used by the proxy to issue calls against the object,
+ * and signals, if any, will be subscribed to on this connection.
+ *
+ * Code example:
+ * @code
+ * auto proxy = sdbus::createObjectProxy(connection, "com.kistler.foo", "/com/kistler/foo");
+ * @endcode
+ */
+ std::unique_ptr createObjectProxy( sdbus::IConnection& connection
+ , std::string destination
+ , std::string objectPath );
+
+ /*!
+ * @brief Creates object proxy instance that uses its own D-Bus connection
+ *
+ * @param[in] destination Bus name that provides a D-Bus object
+ * @param[in] objectPath Path of the D-Bus object
+ * @return Pointer to the object proxy instance
+ *
+ * This factory overload creates a proxy that manages its own D-Bus connection(s).
+ *
+ * Code example:
+ * @code
+ * auto proxy = sdbus::createObjectProxy(connection, "com.kistler.foo", "/com/kistler/foo");
+ * @endcode
+ */
+ std::unique_ptr createObjectProxy( std::string destination
+ , std::string objectPath );
+
+}
+
+#include
+
+#endif /* SDBUS_CXX_IOBJECTPROXY_H_ */
diff --git a/include/sdbus-c++/Interfaces.h b/include/sdbus-c++/Interfaces.h
new file mode 100644
index 0000000..8aa0da5
--- /dev/null
+++ b/include/sdbus-c++/Interfaces.h
@@ -0,0 +1,120 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file Interfaces.h
+ *
+ * Created on: Nov 8, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_INTERFACES_H_
+#define SDBUS_CXX_INTERFACES_H_
+
+#include
+#include
+#include
+#include
+#include
+
+// Forward declarations
+namespace sdbus {
+ class IConnection;
+}
+
+namespace sdbus {
+
+ template
+ class ObjectHolder
+ {
+ protected:
+ ObjectHolder(std::unique_ptr<_Object>&& object)
+ : object_(std::move(object))
+ {
+ }
+
+ const _Object& getObject() const
+ {
+ assert(object_ != nullptr);
+ return *object_;
+ }
+
+ _Object& getObject()
+ {
+ assert(object_ != nullptr);
+ return *object_;
+ }
+
+ private:
+ std::unique_ptr<_Object> object_;
+ };
+
+ /********************************************//**
+ * @class Interfaces
+ *
+ * A helper template class that a user class representing a D-Bus object
+ * should inherit from, providing as template arguments the adaptor
+ * classes representing D-Bus interfaces that the object implements.
+ *
+ ***********************************************/
+ template
+ class Interfaces
+ : private ObjectHolder
+ , public _Interfaces...
+ {
+ public:
+ Interfaces(IConnection& connection, std::string objectPath)
+ : ObjectHolder(createObject(connection, std::move(objectPath)))
+ , _Interfaces(getObject())...
+ {
+ getObject().finishRegistration();
+ }
+ };
+
+ /********************************************//**
+ * @class Interfaces
+ *
+ * A helper template class that a user class representing a proxy of a
+ * D-Bus object should inherit from, providing as template arguments the proxy
+ * classes representing object D-Bus interfaces that the object implements.
+ *
+ ***********************************************/
+ template
+ class ProxyInterfaces
+ : private ObjectHolder
+ , public _Interfaces...
+ {
+ public:
+ ProxyInterfaces(std::string destination, std::string objectPath)
+ : ObjectHolder(createObjectProxy(std::move(destination), std::move(objectPath)))
+ , _Interfaces(getObject())...
+ {
+ getObject().finishRegistration();
+ }
+
+ ProxyInterfaces(IConnection& connection, std::string destination, std::string objectPath)
+ : ObjectHolder(createObjectProxy(connection, std::move(destination), std::move(objectPath)))
+ , _Interfaces(getObject())...
+ {
+ getObject().finishRegistration();
+ }
+ };
+
+}
+
+#endif /* SDBUS_CXX_INTERFACES_H_ */
diff --git a/include/sdbus-c++/Introspection.h b/include/sdbus-c++/Introspection.h
new file mode 100644
index 0000000..3fa297d
--- /dev/null
+++ b/include/sdbus-c++/Introspection.h
@@ -0,0 +1,84 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file Introspection.h
+ *
+ * Created on: Dec 13, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_INTROSPECTION_H_
+#define SDBUS_CXX_INTROSPECTION_H_
+
+#include
+#include
+#include
+
+namespace sdbus {
+
+ // Proxy for introspection
+ class introspectable_proxy
+ {
+ static constexpr const char* interfaceName = "org.freedesktop.DBus.Introspectable";
+
+ protected:
+ introspectable_proxy(sdbus::IObjectProxy& object)
+ : object_(object)
+ {
+ }
+
+ public:
+ std::string Introspect()
+ {
+ std::string xml;
+ object_.callMethod("Introspect").onInterface(interfaceName).storeResultsTo(xml);
+ return xml;
+ }
+
+ private:
+ sdbus::IObjectProxy& object_;
+ };
+
+ // Adaptor is not necessary if we want to rely on sdbus-provided introspection
+// class introspectable_adaptor
+// {
+// static constexpr const char* interfaceName = "org.freedesktop.DBus.Introspectable";
+//
+// protected:
+// introspectable_adaptor(sdbus::IObject& object)
+// : object_(object)
+// {
+// object_.registerMethod("Introspect").onInterface(interfaceName).implementedAs([this](){ return object_.introspect(); });
+// }
+//
+// public:
+// std::string introspect()
+// {
+// std::string xml;
+// object_.callMethod("Introspect").onInterface(interfaceName).storeResultsTo(xml);
+// return xml;
+// }
+//
+// private:
+// sdbus::IObject& object_;
+// };
+
+}
+
+#endif /* SDBUS_CXX_INTROSPECTION_H_ */
diff --git a/include/sdbus-c++/Message.h b/include/sdbus-c++/Message.h
new file mode 100644
index 0000000..a4d630d
--- /dev/null
+++ b/include/sdbus-c++/Message.h
@@ -0,0 +1,330 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file Message.h
+ *
+ * Created on: Nov 9, 2016
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_MESSAGE_H_
+#define SDBUS_CXX_MESSAGE_H_
+
+#include
+#include
+#include
+#include
+#include