Compare commits

...
17 Commits
Author SHA1 Message Date
Stanislav Angelovic 0b27f222c4 Fix stub generator C++ standard back to 14 2019-01-16 20:55:17 +01:00
Stanislav Angelovic 58895d2730 Bump revision up to 0.4.1 2019-01-16 20:01:05 +01:00
Stanislav Angelovic d957948274 Transform constexpr member to a getter method because of different odr-usage rules in different compilers 2019-01-16 19:58:26 +01:00
Stanislav Angelovic 47fad7dd63 Remove obsolete autotools stuff from the tutorial 2019-01-10 13:59:05 +01:00
Stanislav Angelovic 7378cea833 Bump up project version 2019-01-10 13:54:02 +01:00
Stanislav Angelovic 2526546432 Remove Eclipse project file 2019-01-10 13:52:35 +01:00
Stanislav Angelovič 9c0e98c580 Introduce support for some common D-Bus annotations (#30)
* Add ability to declare property behavior on PropertyChanged signal

* Add support for Method.NoReply annotation (WIP)

* Add support for common annotations/flags
2019-01-10 08:47:59 +01:00
Stanislav Angelovič 2c78e08d19 Remove warnings-related compiler options from CMakeLists (#31) 2019-01-06 22:16:13 +01:00
Stanislav Angelovič 97372155a6 Update ChangeLog for v0.3.3 2018-12-29 01:02:36 +01:00
Stanislav Angelovič 1def4e247a Add note on thread-safety of Variant and its const methods 2018-12-29 00:59:31 +01:00
Stanislav Angelovič d764afec93 Little fixes in tutorial code samples
Fixes #24
2018-12-24 15:43:01 +01:00
Jeremy Prater eb58d2fa52 - Rewind Message prior to access for peekValueType.
Fixes #8

(cherry picked from commit f8bed4b0faa2c0a2bc7037f3a55105060d56dbdb)
2018-12-24 15:30:55 +01:00
Stanislav Angelovič a6bb8c070e Switch from autotools to CMake build system (#23)
* Switch from autotools to CMake

* CMake: require at least cmake 3.8

* cmake: updates for tests
2018-09-26 09:28:10 +02:00
Lukas Durfina 108c33faac stub-generator: fixed issue when <arg> in <method> does not have "name" property 2018-08-24 16:39:31 +02:00
sangelovic ec06462713 Add missing constructor overload for ProxyInterfaces 2018-08-06 22:58:36 +02:00
Stanislav Angelovič 234145cade Clarify proxy and connection stuff in case of ProxyInterfaces 2018-08-06 22:52:38 +02:00
Stanislav Angelovič e971f95bad Clarify system/session connection on proxy creation 2018-08-06 22:34:08 +02:00
44 changed files with 1444 additions and 383 deletions
-35
View File
@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sdbus-cpp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.autotools.core.genmakebuilderV2</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
<nature>org.yocto.sdk.ide.YoctoSDKNature</nature>
<nature>org.eclipse.cdt.autotools.core.autotoolsNatureV2</nature>
<nature>org.yocto.sdk.ide.YoctoSDKAutotoolsNature</nature>
</natures>
</projectDescription>
Executable
+146
View File
@@ -0,0 +1,146 @@
#-------------------------------
# PROJECT INFORMATION
#-------------------------------
cmake_minimum_required(VERSION 3.8)
project(sdbus-c++ VERSION 0.4.1 LANGUAGES C CXX)
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
#-------------------------------
# PERFORMING CHECKS
#-------------------------------
find_package(PkgConfig REQUIRED)
pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
#-------------------------------
# SOURCE FILES CONFIGURATION
#-------------------------------
set(SDBUSCPP_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)
set(SDBUSCPP_INCLUDE_SUBDIR sdbus-c++)
set(SDBUSCPP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/${SDBUSCPP_INCLUDE_SUBDIR})
set(SDBUSCPP_CPP_SRCS
${SDBUSCPP_SOURCE_DIR}/Connection.cpp
${SDBUSCPP_SOURCE_DIR}/ConvenienceClasses.cpp
${SDBUSCPP_SOURCE_DIR}/Error.cpp
${SDBUSCPP_SOURCE_DIR}/Message.cpp
${SDBUSCPP_SOURCE_DIR}/MethodResult.cpp
${SDBUSCPP_SOURCE_DIR}/Object.cpp
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.cpp
${SDBUSCPP_SOURCE_DIR}/Types.cpp
${SDBUSCPP_SOURCE_DIR}/Flags.cpp
${SDBUSCPP_SOURCE_DIR}/VTableUtils.c)
set(SDBUSCPP_HDR_SRCS
${SDBUSCPP_SOURCE_DIR}/Connection.h
${SDBUSCPP_SOURCE_DIR}/IConnection.h
${SDBUSCPP_SOURCE_DIR}/MessageUtils.h
${SDBUSCPP_SOURCE_DIR}/Object.h
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.h
${SDBUSCPP_SOURCE_DIR}/ScopeGuard.h
${SDBUSCPP_SOURCE_DIR}/VTableUtils.h)
set(SDBUSCPP_PUBLIC_HDRS
${SDBUSCPP_INCLUDE_DIR}/ConvenienceClasses.h
${SDBUSCPP_INCLUDE_DIR}/ConvenienceClasses.inl
${SDBUSCPP_INCLUDE_DIR}/Error.h
${SDBUSCPP_INCLUDE_DIR}/IConnection.h
${SDBUSCPP_INCLUDE_DIR}/Interfaces.h
${SDBUSCPP_INCLUDE_DIR}/Introspection.h
${SDBUSCPP_INCLUDE_DIR}/IObject.h
${SDBUSCPP_INCLUDE_DIR}/IObjectProxy.h
${SDBUSCPP_INCLUDE_DIR}/Message.h
${SDBUSCPP_INCLUDE_DIR}/MethodResult.h
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h
${SDBUSCPP_INCLUDE_DIR}/Types.h
${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h
${SDBUSCPP_INCLUDE_DIR}/Flags.h)
set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS})
#-------------------------------
# GENERAL COMPILER CONFIGURATION
#-------------------------------
set(CMAKE_CXX_STANDARD 17)
include_directories("${CMAKE_SOURCE_DIR}/include")
include_directories("${CMAKE_SOURCE_DIR}/src")
#----------------------------------
# LIBRARY BUILD INFORMATION
#----------------------------------
set(SDBUSCPP_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
# We are building in two steps: first objects, then link them into a library,
# and that's because we need object files since unit tests link against them.
add_library(sdbuscppobjects OBJECT ${SDBUSCPP_SRCS})
target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
target_compile_definitions(sdbuscppobjects PRIVATE BUILDLIB=1)
set_target_properties(sdbuscppobjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_library(sdbus-c++ SHARED $<TARGET_OBJECTS:sdbuscppobjects>)
set_target_properties(sdbus-c++
PROPERTIES
PUBLIC_HEADER "${SDBUSCPP_PUBLIC_HDRS}"
VERSION "${SDBUSCPP_VERSION}"
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
OUTPUT_NAME "sdbus-c++")
target_link_libraries(sdbus-c++ ${SYSTEMD_LIBRARIES})
#----------------------------------
# INSTALLATION
#----------------------------------
install(TARGETS sdbus-c++
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT static_libraries
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SDBUSCPP_INCLUDE_SUBDIR} COMPONENT dev)
#----------------------------------
# TESTS
#----------------------------------
option(ENABLE_TESTS "Build and install tests (default ON)" ON)
if(ENABLE_TESTS)
enable_testing()
add_subdirectory("${CMAKE_SOURCE_DIR}/test")
endif()
#----------------------------------
# UTILS
#----------------------------------
option(BUILD_CODE_GEN "Build and install interface stub code generator (default OFF)" OFF)
if(BUILD_CODE_GEN)
add_subdirectory("${CMAKE_SOURCE_DIR}/stub-generator")
endif()
#----------------------------------
# DOCUMENTATION
#----------------------------------
# TODO Build doxygen
#----------------------------------
# CMAKE CONFIG & PACKAGE CONFIG
#----------------------------------
set(SDBUSCPP_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++)
configure_file(sdbus-c++-config.cmake.in sdbus-c++-config.cmake @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
configure_file(sdbus-c++-config-version.cmake.in sdbus-c++-config-version.cmake @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config-version.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
configure_file(sdbus-c++.pc.in sdbus-c++.pc @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)
+15
View File
@@ -26,3 +26,18 @@ v0.3.0
v0.3.1
- Fixed hogging the CPU by server with async methods (issue #15)
v0.3.2
- Switched from autotools to CMake build system
v0.3.3
- Minor fixes in tutorial examples
- Add comment on threading traits of Variant and its const methods
- Fix broken invariant of const Variant::peekValueType() method
v0.4.0
- Introduce support and implementation of common D-Bus annotations
- Remove hard-coded warning-related compiler options from the build system
v0.4.1
- Change constexpr member into a getter method to be compatible across odr-usage rules of various compiler versions
+3 -1
View File
@@ -1,5 +1,7 @@
Building:
$ ./autogen.sh ${CONFIGURE_FLAGS}
$ mkdir build
$ cd build
$ cmake .. ${CONFIGURE_FLAGS_IF_NECESSARY}
$ make
Installing:
-22
View File
@@ -1,22 +0,0 @@
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
+10 -4
View File
@@ -6,20 +6,26 @@ sdbus-c++ is a C++ API library for D-Bus IPC, based on sd-bus implementation.
Building and installing the library
-----------------------------------
The library is built using CMake:
```bash
$ ./autogen.sh ${CONFIGURE_FLAGS}
$ mkdir build
$ cd build
$ cmake .. ${CONFIGURE_FLAGS_IF_NECESSARY}
$ make
$ sudo make install
```
Use `--disable-tests` flag when configuring to disable building unit and integration tests for the library.
By default, the library builds its unit and integration tests. That incorporates downloading and building static libraries of Google Test. Use `-DENABLE_TESTS=OFF` configure flag if you want to disable building the tests.
By default, the library doesn't build the code generator for adaptor and proxy interfaces. Use `-DBUILD_CODE_GEN=ON` flag to also build the code generator.
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
* `googletest` - google unit testing framework, only necessary when building tests, will be downloaded and built automatically
Licensing
---------
@@ -41,4 +47,4 @@ Contributions that increase the library quality, functionality, or fix issues ar
Contact
-------
stanislav.angelovic[at]kistler.com
https://github.com/Kistler-Group/sdbus-cpp
-10
View File
@@ -1,10 +0,0 @@
#! /bin/sh
[ -e config.cache ] && rm -f config.cache
libtoolize --automake
aclocal ${OECORE_ACLOCAL_OPTS}
autoconf
autoheader
automake -a
./configure $@
exit
-62
View File
@@ -1,62 +0,0 @@
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, 3)
m4_define(sdbus_cpp_version_micro, 1)
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 >= 236],,
AC_MSG_ERROR([You need the libsystemd library (version 236 or newer)]
[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 ""
+18 -17
View File
@@ -29,21 +29,19 @@ method calls, signals and properties. There is room for additions and improvemen
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.
The library build system is based on CMake. The library provides a config file, so integrating it into your CMake project is rather straight-forward:
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/])
)
find_package(sdbus-c++ REQUIRED)
```
2. Update `*_CFLAGS` and `*_LDFLAGS` in Makefiles of modules that use *sdbus-c++*, for example like this:
The library also supports `pkg-config`, so it easily be integrated into e.g. an Autotools project:
```bash
AM_CXXFLAGS = -std=c++17 -pedantic -W -Wall @SDBUSCPP_CFLAGS@ ...
AM_LDFLAGS = @SDBUSCPP_LIBS@ ...
PKG_CHECK_MODULES(SDBUSCPP, [sdbus-c++ >= 0.4],,
AC_MSG_ERROR([You need the sdbus-c++ library (version 0.4 or newer)]
[http://www.kistler.com/])
)
```
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.
@@ -211,9 +209,9 @@ void onConcatenated(sdbus::Signal& signal)
int main(int argc, char *argv[])
{
// Create proxy object for the concatenator object on the server side. Since we don't pass
// the D-Bus connection object to the proxy constructor, the proxy will internally create
// its own connection to the system bus.
// Create proxy object for the concatenator object on the server side. Since here
// we are creating the proxy instance without passing connection to it, the proxy
// will create its own connection automatically, and it will be system bus connection.
const char* destinationName = "org.sdbuscpp.concatenator";
const char* objectPath = "/org/sdbuscpp/concatenator";
auto concatenatorProxy = sdbus::createObjectProxy(destinationName, objectPath);
@@ -258,9 +256,9 @@ int main(int argc, char *argv[])
}
```
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 to the *system* bus 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.
The object proxy can be created by either explicitly passing the connection object to it, or without the connection object. In the former case, we have the freedom of creating our own connection (to either system bus or to session bus) and then we can just move that connection object as the first argument of the proxy factory. The latter option is more convenient (no messing with connection for proxy), the proxy will create and manage its own connection, but the limitation is that it will be the connection to the **system** bus only.
If there are callbacks for signals, proxy will start listening to the signals upon the connection 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
---------------------------------------------------------------------------
@@ -357,7 +355,7 @@ int main(int argc, char *argv[])
// 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->uponSignal("concatenated").onInterface(interfaceName).call([](const std::string& str){ onConcatenated(str); });
concatenatorProxy->finishRegistration();
std::vector<int> numbers = {1, 2, 3};
@@ -630,10 +628,13 @@ protected:
};
```
In the above example, a proxy is created that creates and maintains its own system bus connection. However, there are `ProxyInterfaces` class template constructor overloads that also take the connection from the user as the first parameter, and pass that connection over to the underlying proxy. The connection instance is used for all D-Bus proxy interfaces listed in the `ProxyInterfaces` template parameter list.
Now let's use this proxy to make remote calls and listen to signals in a real application.
```cpp
#include "ConcatenatorProxy.h"
#include <unistd.h>
int main(int argc, char *argv[])
{
-24
View File
@@ -1,24 +0,0 @@
# 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)/MethodResult.h \
$(HEADER_DIR)/Types.h \
$(HEADER_DIR)/TypeTraits.h \
$(HEADER_DIR)/sdbus-c++.h
EXTRA_DIST = ($libsdbuscpp_HEADERS)
DISTCLEANFILES = Makefile Makefile.in
+46 -3
View File
@@ -28,6 +28,7 @@
#include <sdbus-c++/Message.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Flags.h>
#include <string>
#include <type_traits>
@@ -44,16 +45,29 @@ namespace sdbus {
{
public:
MethodRegistrator(IObject& object, const std::string& methodName);
MethodRegistrator(MethodRegistrator&& other) = default;
MethodRegistrator& operator=(MethodRegistrator&& other) = default;
~MethodRegistrator() noexcept(false);
MethodRegistrator& onInterface(const std::string& interfaceName);
template <typename _Function>
std::enable_if_t<!is_async_method_v<_Function>> implementedAs(_Function&& callback);
std::enable_if_t<!is_async_method_v<_Function>, MethodRegistrator&> implementedAs(_Function&& callback);
template <typename _Function>
std::enable_if_t<is_async_method_v<_Function>> implementedAs(_Function&& callback);
std::enable_if_t<is_async_method_v<_Function>, MethodRegistrator&> implementedAs(_Function&& callback);
MethodRegistrator& markAsDeprecated();
MethodRegistrator& markAsPrivileged();
MethodRegistrator& withNoReply();
private:
IObject& object_;
const std::string& methodName_;
std::string interfaceName_;
std::string inputSignature_;
std::string outputSignature_;
method_callback syncCallback_;
async_method_callback asyncCallback_;
Flags flags_;
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
};
class SignalRegistrator
@@ -63,14 +77,17 @@ namespace sdbus {
SignalRegistrator(SignalRegistrator&& other) = default;
SignalRegistrator& operator=(SignalRegistrator&& other) = default;
~SignalRegistrator() noexcept(false);
SignalRegistrator& onInterface(std::string interfaceName);
template <typename... _Args> void withParameters();
template <typename... _Args> SignalRegistrator& withParameters();
SignalRegistrator& markAsDeprecated();
private:
IObject& object_;
const std::string& signalName_;
std::string interfaceName_;
std::string signalSignature_;
Flags flags_;
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
};
@@ -81,9 +98,13 @@ namespace sdbus {
PropertyRegistrator(PropertyRegistrator&& other) = default;
PropertyRegistrator& operator=(PropertyRegistrator&& other) = default;
~PropertyRegistrator() noexcept(false);
PropertyRegistrator& onInterface(const std::string& interfaceName);
template <typename _Function> PropertyRegistrator& withGetter(_Function&& callback);
template <typename _Function> PropertyRegistrator& withSetter(_Function&& callback);
PropertyRegistrator& markAsDeprecated();
PropertyRegistrator& markAsPrivileged();
PropertyRegistrator& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
private:
IObject& object_;
@@ -92,9 +113,30 @@ namespace sdbus {
std::string propertySignature_;
property_get_callback getter_;
property_set_callback setter_;
Flags flags_;
int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
};
class InterfaceFlagsSetter
{
public:
InterfaceFlagsSetter(IObject& object, const std::string& interfaceName);
InterfaceFlagsSetter(InterfaceFlagsSetter&& other) = default;
InterfaceFlagsSetter& operator=(InterfaceFlagsSetter&& other) = default;
~InterfaceFlagsSetter() noexcept(false);
InterfaceFlagsSetter& markAsDeprecated();
InterfaceFlagsSetter& markAsPrivileged();
InterfaceFlagsSetter& withNoReplyMethods();
InterfaceFlagsSetter& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
private:
IObject& object_;
const std::string& interfaceName_;
Flags flags_;
int exceptions_{}; // Number of active exceptions when InterfaceFlagsSetter is constructed
};
class SignalEmitter
{
public:
@@ -123,6 +165,7 @@ namespace sdbus {
MethodInvoker& onInterface(const std::string& interfaceName);
template <typename... _Args> MethodInvoker& withArguments(_Args&&... args);
template <typename... _Args> void storeResultsTo(_Args&... args);
void dontExpectReply();
private:
IObjectProxy& objectProxy_;
+163 -19
View File
@@ -39,12 +39,41 @@
namespace sdbus {
// Moved into the library to isolate from C++17 dependency
/*
inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
: object_(object)
, methodName_(methodName)
, exceptions_(std::uncaught_exceptions()) // Needs C++17
{
}
inline MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't register the method if MethodRegistrator 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 method", EINVAL);
// registerMethod() can throw. But as the MethodRegistrator 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 registerMethod() 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.
if (syncCallback_)
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(syncCallback_));
else if(asyncCallback_)
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(asyncCallback_));
else
SDBUS_THROW_ERROR("Method handler not specified when registering a DBus method", EINVAL);
}
*/
inline MethodRegistrator& MethodRegistrator::onInterface(const std::string& interfaceName)
{
interfaceName_ = interfaceName;
@@ -53,15 +82,11 @@ namespace sdbus {
}
template <typename _Function>
inline std::enable_if_t<!is_async_method_v<_Function>> MethodRegistrator::implementedAs(_Function&& callback)
inline std::enable_if_t<!is_async_method_v<_Function>, MethodRegistrator&> 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)](MethodCall& msg, MethodReply& reply)
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
syncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodReply& reply)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the message.
@@ -78,19 +103,17 @@ namespace sdbus {
// 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;
});
};
return *this;
}
template <typename _Function>
inline std::enable_if_t<is_async_method_v<_Function>> MethodRegistrator::implementedAs(_Function&& callback)
inline std::enable_if_t<is_async_method_v<_Function>, MethodRegistrator&> 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() //signature_of<last_function_argument_t<_Function>>::str() // because last argument contains output types
, [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodResult result)
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
asyncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodResult result)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the message.
@@ -102,9 +125,33 @@ namespace sdbus {
// Invoke callback with input arguments from the tuple.
sdbus::apply(callback, std::move(result), inputArgs); // TODO: Use std::apply when switching to full C++17 support
});
};
return *this;
}
inline MethodRegistrator& MethodRegistrator::markAsDeprecated()
{
flags_.set(Flags::DEPRECATED);
return *this;
}
inline MethodRegistrator& MethodRegistrator::markAsPrivileged()
{
flags_.set(Flags::PRIVILEGED);
return *this;
}
inline MethodRegistrator& MethodRegistrator::withNoReply()
{
flags_.set(Flags::METHOD_NO_REPLY);
return *this;
}
// Moved into the library to isolate from C++17 dependency
/*
inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName)
@@ -144,9 +191,18 @@ namespace sdbus {
}
template <typename... _Args>
inline void SignalRegistrator::withParameters()
inline SignalRegistrator& SignalRegistrator::withParameters()
{
signalSignature_ = signature_of_function_input_arguments<void(_Args...)>::str();
return *this;
}
inline SignalRegistrator& SignalRegistrator::markAsDeprecated()
{
flags_.set(Flags::DEPRECATED);
return *this;
}
@@ -234,6 +290,87 @@ namespace sdbus {
return *this;
}
inline PropertyRegistrator& PropertyRegistrator::markAsDeprecated()
{
flags_.set(Flags::DEPRECATED);
return *this;
}
inline PropertyRegistrator& PropertyRegistrator::markAsPrivileged()
{
flags_.set(Flags::PRIVILEGED);
return *this;
}
inline PropertyRegistrator& PropertyRegistrator::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
{
flags_.set(behavior);
return *this;
}
// Moved into the library to isolate from C++17 dependency
/*
inline InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
: object_(object)
, interfaceName_(interfaceName)
, exceptions_(std::uncaught_exceptions())
{
}
inline InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't set any flags if InterfaceFlagsSetter 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 setting its flags", EINVAL);
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter 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 setInterfaceFlags() 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_.setInterfaceFlags( std::move(interfaceName_)
, std::move(flags_) );
}
*/
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsDeprecated()
{
flags_.set(Flags::DEPRECATED);
return *this;
}
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsPrivileged()
{
flags_.set(Flags::PRIVILEGED);
return *this;
}
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withNoReplyMethods()
{
flags_.set(Flags::METHOD_NO_REPLY);
return *this;
}
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
{
flags_.set(behavior);
return *this;
}
// Moved into the library to isolate from C++17 dependency
/*
@@ -342,6 +479,13 @@ namespace sdbus {
detail::deserialize_pack(reply, args...);
}
inline void MethodInvoker::dontExpectReply()
{
SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
method_.dontExpectReply();
}
inline SignalSubscriber::SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName)
: objectProxy_(objectProxy)
+98
View File
@@ -0,0 +1,98 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Flags.h
*
* Created on: Dec 31, 2018
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CXX_FLAGS_H_
#define SDBUS_CXX_FLAGS_H_
#include <bitset>
#include <cstdint>
namespace sdbus {
// D-Bus interface, method, signal or property flags
class Flags
{
public:
enum GeneralFlags : uint8_t
{ DEPRECATED = 0
, METHOD_NO_REPLY = 1
, PRIVILEGED = 2
};
enum PropertyUpdateBehaviorFlags : uint8_t
{ EMITS_CHANGE_SIGNAL = 3
, EMITS_INVALIDATION_SIGNAL = 4
, EMITS_NO_SIGNAL = 5
, CONST_PROPERTY_VALUE = 6
};
enum : uint8_t
{ FLAG_COUNT = 7
};
Flags()
{
// EMITS_CHANGE_SIGNAL is on by default
flags_.set(EMITS_CHANGE_SIGNAL, true);
}
void set(GeneralFlags flag, bool value = true)
{
flags_.set(flag, value);
}
void set(PropertyUpdateBehaviorFlags flag, bool value = true)
{
flags_.set(EMITS_CHANGE_SIGNAL, false);
flags_.set(EMITS_INVALIDATION_SIGNAL, false);
flags_.set(EMITS_NO_SIGNAL, false);
flags_.set(CONST_PROPERTY_VALUE, false);
flags_.set(flag, value);
}
bool test(GeneralFlags flag) const
{
return flags_.test(flag);
}
bool test(PropertyUpdateBehaviorFlags flag) const
{
return flags_.test(flag);
}
uint64_t toSdBusInterfaceFlags() const;
uint64_t toSdBusMethodFlags() const;
uint64_t toSdBusSignalFlags() const;
uint64_t toSdBusPropertyFlags() const;
uint64_t toSdBusWritablePropertyFlags() const;
private:
std::bitset<FLAG_COUNT> flags_;
};
}
#endif /* SDBUS_CXX_FLAGS_H_ */
+45 -5
View File
@@ -28,6 +28,7 @@
#include <sdbus-c++/ConvenienceClasses.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Flags.h>
#include <functional>
#include <string>
#include <memory>
@@ -61,6 +62,7 @@ namespace sdbus {
* @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
* @param[in] noReply If true, the method isn't expected to send reply
*
* @throws sdbus::Error in case of failure
*/
@@ -68,7 +70,8 @@ namespace sdbus {
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, method_callback methodCallback ) = 0;
, method_callback methodCallback
, Flags flags = {} ) = 0;
/*!
* @brief Registers method that the object will provide on D-Bus
@@ -78,6 +81,7 @@ namespace sdbus {
* @param[in] inputSignature D-Bus signature of method input parameters
* @param[in] outputSignature D-Bus signature of method output parameters
* @param[in] asyncMethodCallback Callback that implements the body of the method
* @param[in] noReply If true, the method isn't expected to send reply
*
* This overload register a method callback that will have a freedom to execute
* its body in asynchronous contexts, and send the results from those contexts.
@@ -90,7 +94,8 @@ namespace sdbus {
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, async_method_callback asyncMethodCallback ) = 0;
, async_method_callback asyncMethodCallback
, Flags flags = {} ) = 0;
/*!
* @brief Registers signal that the object will emit on D-Bus
@@ -103,7 +108,8 @@ namespace sdbus {
*/
virtual void registerSignal( const std::string& interfaceName
, const std::string& signalName
, const std::string& signature ) = 0;
, const std::string& signature
, Flags flags = {} ) = 0;
/*!
* @brief Registers read-only property that the object will provide on D-Bus
@@ -118,7 +124,8 @@ namespace sdbus {
virtual void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback ) = 0;
, property_get_callback getCallback
, Flags flags = {} ) = 0;
/*!
* @brief Registers read/write property that the object will provide on D-Bus
@@ -135,7 +142,18 @@ namespace sdbus {
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback
, property_set_callback setCallback ) = 0;
, property_set_callback setCallback
, Flags flags = {} ) = 0;
/*!
* @brief Sets flags for a given interface
*
* @param[in] interfaceName Name of an interface whose flags will be set
* @param[in] flags Flags to be set
*
* @throws sdbus::Error in case of failure
*/
virtual void setInterfaceFlags(const std::string& interfaceName, Flags flags) = 0;
/*!
* @brief Finishes the registration and exports object API on D-Bus
@@ -231,6 +249,23 @@ namespace sdbus {
*/
PropertyRegistrator registerProperty(const std::string& propertyName);
/*!
* @brief Sets flags (annotations) for a given interface
*
* @param[in] interfaceName Name of an interface whose flags will be set
* @return A helper object for convenient setting of Interface flags
*
* This is a high-level, convenience alternative to the other setInterfaceFlags overload.
*
* Example of use:
* @code
* object_.setInterfaceFlags("com.kistler.foo").markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
* @endcode
*
* @throws sdbus::Error in case of failure
*/
InterfaceFlagsSetter setInterfaceFlags(const std::string& interfaceName);
/*!
* @brief Emits signal on D-Bus
*
@@ -270,6 +305,11 @@ namespace sdbus {
return PropertyRegistrator(*this, std::move(propertyName));
}
inline InterfaceFlagsSetter IObject::setInterfaceFlags(const std::string& interfaceName)
{
return InterfaceFlagsSetter(*this, std::move(interfaceName));
}
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
{
return SignalEmitter(*this, signalName);
+8
View File
@@ -72,6 +72,14 @@ namespace sdbus {
* @brief Calls method on the proxied D-Bus object
*
* @param[in] message Message representing a method call
* @return A method reply message
*
* Normally, the call is blocking, i.e. it waits for the remote method to finish with either
* a return value or an error.
*
* If the method call argument is set to not expect reply, the call will not wait for the remote
* method to finish, i.e. the call will be non-blocking, and the function will return an empty,
* invalid MethodReply object (representing void).
*
* Note: To avoid messing with messages, use higher-level API defined below.
*
+7
View File
@@ -113,6 +113,13 @@ namespace sdbus {
{
getObject().finishRegistration();
}
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath)
: ObjectHolder<IObjectProxy>(createObjectProxy(std::move(connection), std::move(destination), std::move(objectPath)))
, _Interfaces(getObject())...
{
getObject().finishRegistration();
}
};
}
+6
View File
@@ -155,6 +155,12 @@ namespace sdbus {
MethodReply send() const;
MethodReply createReply() const;
MethodReply createErrorReply(const sdbus::Error& error) const;
void dontExpectReply();
bool doesntExpectReply() const;
private:
MethodReply sendWithReply() const;
MethodReply sendWithNoReply() const;
};
class MethodReply : public Message
+6
View File
@@ -40,6 +40,12 @@ namespace sdbus {
* @class Variant
*
* Variant can hold value of any D-Bus-supported type.
*
* Note: Even though thread-aware, Variant objects are not thread-safe.
* Some const methods are conceptually const, but not physically const,
* thus are not thread-safe. This is by design: normally, clients
* should process a single Variant object in a single thread at a time.
* Otherwise they need to take care of synchronization by themselves.
*
***********************************************/
class Variant
+11
View File
@@ -0,0 +1,11 @@
set(PACKAGE_VERSION "@SDBUSCPP_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
+14
View File
@@ -0,0 +1,14 @@
# Config file for the sdbus-c++ package.
#
# It defines the following variables:
# SDBUSCPP_VERSION - version of sdbus-c++
# SDBUSCPP_FOUND - set to true
# SDBUSCPP_INCLUDE_DIRS - include directories for sdbus-c++
# SDBUSCPP_LIBRARY_DIR - library directories for sdbus-c++
# SDBUSCPP_LIBRARIES - libraries to link against
set(SDBUSCPP_VERSION "@SDBUSCPP_VERSION@")
set(SDBUSCPP_FOUND "TRUE")
set(SDBUSCPP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
set(SDBUSCPP_LIBRARY_DIR "@CMAKE_INSTALL_FULL_LIBDIR@")
set(SDBUSCPP_LIBRARIES sdbus-c++)
Regular → Executable
+8 -8
View File
@@ -1,11 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @PACKAGE@
Description: C++ bindings library for sd-bus
Name: @PROJECT_NAME@
Description: C++ library on top of sd-bus, a systemd D-Bus library
Requires: libsystemd
Version: @VERSION@
Libs: -L${libdir} -lsdbus-c++
Version: @SDBUSCPP_VERSION@
Libs: -L${libdir} -l@PROJECT_NAME@
Cflags: -I${includedir}
+64 -2
View File
@@ -31,6 +31,38 @@
namespace sdbus {
MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
: object_(object)
, methodName_(methodName)
, exceptions_(std::uncaught_exceptions()) // Needs C++17
{
}
MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't register the method if MethodRegistrator 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 method", EINVAL);
// registerMethod() can throw. But as the MethodRegistrator 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 registerMethod() 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.
if (syncCallback_)
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(syncCallback_), flags_);
else if(asyncCallback_)
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(asyncCallback_), flags_);
else
SDBUS_THROW_ERROR("Method handler not specified when registering a DBus method", EINVAL);
}
SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName)
: object_(object)
, signalName_(signalName)
@@ -55,7 +87,7 @@ SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destruct
// 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_);
object_.registerSignal(interfaceName_, signalName_, signalSignature_, flags_);
}
@@ -87,7 +119,37 @@ PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, dest
, std::move(propertyName_)
, std::move(propertySignature_)
, std::move(getter_)
, std::move(setter_) );
, std::move(setter_)
, flags_ );
}
InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
: object_(object)
, interfaceName_(interfaceName)
, exceptions_(std::uncaught_exceptions())
{
}
InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't set any flags if InterfaceFlagsSetter 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 setting its flags", EINVAL);
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter 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 setInterfaceFlags() 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_.setInterfaceFlags( std::move(interfaceName_)
, std::move(flags_) );
}
+111
View File
@@ -0,0 +1,111 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Flags.cpp
*
* Created on: Dec 31, 2018
* 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 <http://www.gnu.org/licenses/>.
*/
#include <sdbus-c++/Flags.h>
#include <systemd/sd-bus.h>
namespace sdbus
{
uint64_t Flags::toSdBusInterfaceFlags() const
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
if (!flags_.test(Flags::PRIVILEGED))
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
sdbusFlags |= 0;
return sdbusFlags;
}
uint64_t Flags::toSdBusMethodFlags() const
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
if (!flags_.test(Flags::PRIVILEGED))
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
if (flags_.test(Flags::METHOD_NO_REPLY))
sdbusFlags |= SD_BUS_VTABLE_METHOD_NO_REPLY;
return sdbusFlags;
}
uint64_t Flags::toSdBusSignalFlags() const
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
return sdbusFlags;
}
uint64_t Flags::toSdBusPropertyFlags() const
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
//if (!flags_.test(Flags::PRIVILEGED))
// sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
sdbusFlags |= 0;
return sdbusFlags;
}
uint64_t Flags::toSdBusWritablePropertyFlags() const
{
auto sdbusFlags = toSdBusPropertyFlags();
using namespace sdbus;
if (!flags_.test(Flags::PRIVILEGED))
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
return sdbusFlags;
}
}
-27
View File
@@ -1,27 +0,0 @@
lib_LTLIBRARIES = libsdbus-c++.la
libsdbus_c___la_SOURCES = \
Connection.cpp \
ConvenienceClasses.cpp \
Message.cpp \
MethodResult.cpp \
Object.cpp \
ObjectProxy.cpp \
Types.cpp \
Error.cpp \
VTableUtils.c
libsdbus_c___la_LIBADD = @SYSTEMD_LIBS@
# Setting per-file flags
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CXXFLAGS = @libsdbus_cpp_CFLAGS@ @SYSTEMD_CFLAGS@ -std=c++17 -pipe -pedantic -W -Wall
AM_LDFLAGS = @libsdbus_cpp_LIBS@ @SYSTEMD_LIBS@
libsdbus_c___la_LDFLAGS = -version-info 0:0:0
# Cleaning
CLEANFILES = *~ *.lo *.la
MOSTLYCLEANFILES = *.o
DISTCLEANFILES = Makefile Makefile.in
+28
View File
@@ -571,7 +571,28 @@ void* Message::getMsg() const
return msg_;
}
void MethodCall::dontExpectReply()
{
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)getMsg(), 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
}
bool MethodCall::doesntExpectReply() const
{
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)getMsg());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
return r > 0 ? false : true;
}
MethodReply MethodCall::send() const
{
if (!doesntExpectReply())
return sendWithReply();
else
return sendWithNoReply();
}
MethodReply MethodCall::sendWithReply() const
{
sd_bus_message* sdbusReply{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
@@ -590,6 +611,13 @@ MethodReply MethodCall::send() const
return MethodReply(sdbusReply);
}
MethodReply MethodCall::sendWithNoReply() const
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
return MethodReply{}; // No reply
}
MethodReply MethodCall::createReply() const
{
sd_bus_message *sdbusReply{};
+32 -15
View File
@@ -28,6 +28,7 @@
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Error.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/Flags.h>
#include "IConnection.h"
#include "VTableUtils.h"
#include <systemd/sd-bus.h>
@@ -45,7 +46,8 @@ void Object::registerMethod( const std::string& interfaceName
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, method_callback methodCallback )
, method_callback methodCallback
, Flags flags )
{
SDBUS_THROW_ERROR_IF(!methodCallback, "Invalid method callback provided", EINVAL);
@@ -57,7 +59,7 @@ void Object::registerMethod( const std::string& interfaceName
};
auto& interface = interfaces_[interfaceName];
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(syncCallback)};
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(syncCallback), flags};
auto inserted = interface.methods_.emplace(methodName, std::move(methodData)).second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
@@ -67,7 +69,8 @@ void Object::registerMethod( const std::string& interfaceName
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, async_method_callback asyncMethodCallback )
, async_method_callback asyncMethodCallback
, Flags flags )
{
SDBUS_THROW_ERROR_IF(!asyncMethodCallback, "Invalid method callback provided", EINVAL);
@@ -78,7 +81,7 @@ void Object::registerMethod( const std::string& interfaceName
};
auto& interface = interfaces_[interfaceName];
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(asyncCallback)};
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(asyncCallback), flags};
auto inserted = interface.methods_.emplace(methodName, std::move(methodData)).second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
@@ -86,11 +89,12 @@ void Object::registerMethod( const std::string& interfaceName
void Object::registerSignal( const std::string& interfaceName
, const std::string& signalName
, const std::string& signature )
, const std::string& signature
, Flags flags )
{
auto& interface = interfaces_[interfaceName];
InterfaceData::SignalData signalData{signature};
InterfaceData::SignalData signalData{signature, flags};
auto inserted = interface.signals_.emplace(signalName, std::move(signalData)).second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal: signal already exists", EINVAL);
@@ -99,31 +103,40 @@ void Object::registerSignal( const std::string& interfaceName
void Object::registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback )
, property_get_callback getCallback
, Flags flags )
{
registerProperty( interfaceName
, propertyName
, signature
, getCallback
, property_set_callback{} );
, property_set_callback{}
, flags );
}
void Object::registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback
, property_set_callback setCallback )
, property_set_callback setCallback
, Flags flags )
{
SDBUS_THROW_ERROR_IF(!getCallback && !setCallback, "Invalid property callbacks provided", EINVAL);
auto& interface = interfaces_[interfaceName];
InterfaceData::PropertyData propertyData{signature, std::move(getCallback), std::move(setCallback)};
InterfaceData::PropertyData propertyData{signature, std::move(getCallback), std::move(setCallback), flags};
auto inserted = interface.properties_.emplace(propertyName, std::move(propertyData)).second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register property: property already exists", EINVAL);
}
void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags)
{
auto& interface = interfaces_[interfaceName];
interface.flags_ = flags;
}
void Object::finishRegistration()
{
for (auto& item : interfaces_)
@@ -159,7 +172,7 @@ const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& i
auto& vtable = interfaceData.vtable_;
assert(vtable.empty());
vtable.push_back(createVTableStartItem());
vtable.push_back(createVTableStartItem(interfaceData.flags_.toSdBusInterfaceFlags()));
registerMethodsToVTable(interfaceData, vtable);
registerSignalsToVTable(interfaceData, vtable);
registerPropertiesToVTable(interfaceData, vtable);
@@ -178,7 +191,8 @@ void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::ve
vtable.push_back(createVTableMethodItem( methodName.c_str()
, methodData.inputArgs_.c_str()
, methodData.outputArgs_.c_str()
, &Object::sdbus_method_callback ));
, &Object::sdbus_method_callback
, methodData.flags_.toSdBusMethodFlags() ));
}
}
@@ -190,7 +204,8 @@ void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::ve
const auto& signalData = item.second;
vtable.push_back(createVTableSignalItem( signalName.c_str()
, signalData.signature_.c_str() ));
, signalData.signature_.c_str()
, signalData.flags_.toSdBusSignalFlags() ));
}
}
@@ -204,12 +219,14 @@ void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std:
if (!propertyData.setCallback_)
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback ));
, &Object::sdbus_property_get_callback
, propertyData.flags_.toSdBusPropertyFlags() ));
else
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback
, &Object::sdbus_property_set_callback ));
, &Object::sdbus_property_set_callback
, propertyData.flags_.toSdBusWritablePropertyFlags() ));
}
}
+20 -9
View File
@@ -49,28 +49,35 @@ namespace internal {
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, method_callback methodCallback ) override;
, method_callback methodCallback
, Flags flags ) override;
void registerMethod( const std::string& interfaceName
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, async_method_callback asyncMethodCallback ) override;
, async_method_callback asyncMethodCallback
, Flags flags ) override;
void registerSignal( const std::string& interfaceName
, const std::string& signalName
, const std::string& signature ) override;
void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback ) override;
, const std::string& signature
, Flags flags ) override;
void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback
, property_set_callback setCallback ) override;
, Flags flags ) override;
void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback
, property_set_callback setCallback
, Flags flags ) override;
void setInterfaceFlags(const std::string& interfaceName, Flags flags) override;
void finishRegistration() override;
@@ -89,12 +96,14 @@ namespace internal {
std::string inputArgs_;
std::string outputArgs_;
std::function<void(MethodCall&)> callback_;
Flags flags_;
};
std::map<MethodName, MethodData> methods_;
using SignalName = std::string;
struct SignalData
{
std::string signature_;
Flags flags_;
};
std::map<SignalName, SignalData> signals_;
using PropertyName = std::string;
@@ -103,9 +112,11 @@ namespace internal {
std::string signature_;
property_get_callback getCallback_;
property_set_callback setCallback_;
Flags flags_;
};
std::map<PropertyName, PropertyData> properties_;
std::vector<sd_bus_vtable> vtable_;
Flags flags_;
std::unique_ptr<void, std::function<void(void*)>> slot_;
};
+1
View File
@@ -51,6 +51,7 @@ void Variant::deserializeFrom(Message& msg)
std::string Variant::peekValueType() const
{
msg_.rewind(false);
std::string type;
std::string contents;
msg_.peekType(type, contents);
+14 -10
View File
@@ -26,42 +26,46 @@
#include "VTableUtils.h"
#include <systemd/sd-bus.h>
sd_bus_vtable createVTableStartItem()
sd_bus_vtable createVTableStartItem(uint64_t flags)
{
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(0);
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(flags);
return vtableStart;
}
sd_bus_vtable createVTableMethodItem( const char *member
, const char *signature
, const char *result
, sd_bus_message_handler_t handler )
, sd_bus_message_handler_t handler
, uint64_t flags )
{
struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, SD_BUS_VTABLE_UNPRIVILEGED);
struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, flags);
return vtableItem;
}
sd_bus_vtable createVTableSignalItem( const char *member
, const char *signature )
, const char *signature
, uint64_t flags )
{
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, 0);
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, flags);
return vtableItem;
}
sd_bus_vtable createVTablePropertyItem( const char *member
, const char *signature
, sd_bus_property_get_t getter )
, sd_bus_property_get_t getter
, uint64_t flags )
{
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, 0);
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, flags);
return vtableItem;
}
sd_bus_vtable createVTableWritablePropertyItem( const char *member
, const char *signature
, sd_bus_property_get_t getter
, sd_bus_property_set_t setter )
, sd_bus_property_set_t setter
, uint64_t flags )
{
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, 0);
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, flags);
return vtableItem;
}
+10 -5
View File
@@ -27,25 +27,30 @@
#define SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
#include <systemd/sd-bus.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
sd_bus_vtable createVTableStartItem();
sd_bus_vtable createVTableStartItem(uint64_t flags);
sd_bus_vtable createVTableMethodItem( const char *member
, const char *signature
, const char *result
, sd_bus_message_handler_t handler );
, sd_bus_message_handler_t handler
, uint64_t flags );
sd_bus_vtable createVTableSignalItem( const char *member
, const char *signature );
, const char *signature
, uint64_t flags );
sd_bus_vtable createVTablePropertyItem( const char *member
, const char *signature
, sd_bus_property_get_t getter );
, sd_bus_property_get_t getter
, uint64_t flags );
sd_bus_vtable createVTableWritablePropertyItem( const char *member
, const char *signature
, sd_bus_property_get_t getter
, sd_bus_property_set_t setter );
, sd_bus_property_set_t setter
, uint64_t flags );
sd_bus_vtable createVTableEndItem();
#ifdef __cplusplus
+103 -12
View File
@@ -89,6 +89,30 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
Nodes signals = interface["signal"];
Nodes properties = interface["property"];
auto annotations = getAnnotations(interface);
std::string annotationRegistration;
for (const auto& annotation : annotations)
{
const auto& annotationName = annotation.first;
const auto& annotationValue = annotation.second;
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
annotationRegistration += ".markAsDeprecated()";
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
annotationRegistration += ".markAsPrivileged()";
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
annotationRegistration += ".withPropertyUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
else
std::cerr << "Node: " << ifaceName << ": "
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
}
if(!annotationRegistration.empty())
{
std::stringstream str;
str << tab << tab << "object_.setInterfaceFlags(interfaceName)" << annotationRegistration << ";" << endl;
annotationRegistration = str.str();
}
std::string methodRegistration, methodDeclaration;
std::tie(methodRegistration, methodDeclaration) = processMethods(methods);
@@ -99,10 +123,11 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
std::tie(propertyRegistration, propertyAccessorDeclaration) = processProperties(properties);
body << tab << "{" << endl
<< methodRegistration
<< signalRegistration
<< propertyRegistration
<< tab << "}" << endl << endl;
<< annotationRegistration
<< methodRegistration
<< signalRegistration
<< propertyRegistration
<< tab << "}" << endl << endl;
if (!signalMethods.empty())
{
@@ -136,17 +161,25 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
{
auto methodName = method->get("name");
auto annotations = getAnnotations(*method);
bool async{false};
Nodes annotations = (*method)["annotation"];
std::string annotationRegistration;
for (const auto& annotation : annotations)
{
if (annotation->get("name") == "org.freedesktop.DBus.Method.Async"
&& (annotation->get("value") == "server" || annotation->get("value") == "clientserver"))
{
const auto& annotationName = annotation.first;
const auto& annotationValue = annotation.second;
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
annotationRegistration += ".markAsDeprecated()";
else if (annotationName == "org.freedesktop.DBus.Method.NoReply" && annotationValue == "true")
annotationRegistration += ".withNoReply()";
else if (annotationName == "org.freedesktop.DBus.Method.Async" && (annotationValue == "server" || annotationValue == "clientserver"))
async = true;
break;
}
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
annotationRegistration += ".markAsPrivileged()";
else
std::cerr << "Node: " << methodName << ": "
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
}
Nodes args = (*method)["arg"];
@@ -167,7 +200,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
<< argTypeStr
<< "){ " << (async ? "" : "return ") << "this->" << methodName << "("
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
<< argStr << "); });" << endl;
<< argStr << "); })"
<< annotationRegistration << ";" << endl;
declarationSS << tab
<< "virtual "
@@ -190,6 +224,21 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
for (const auto& signal : signals)
{
auto name = signal->get("name");
auto annotations = getAnnotations(*signal);
std::string annotationRegistration;
for (const auto& annotation : annotations)
{
const auto& annotationName = annotation.first;
const auto& annotationValue = annotation.second;
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
annotationRegistration += ".markAsDeprecated()";
else
std::cerr << "Node: " << name << ": "
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
}
Nodes args = (*signal)["arg"];
std::string argStr, argTypeStr, typeStr;;
@@ -204,6 +253,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
signalRegistrationSS << ".withParameters<" << typeStr << ">()";
}
signalRegistrationSS << annotationRegistration;
signalRegistrationSS << ";" << endl;
signalMethodSS << tab << "void " << name << "(" << argTypeStr << ")" << endl
@@ -238,6 +288,24 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
auto propertyArg = std::string("value");
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
auto annotations = getAnnotations(*property);
std::string annotationRegistration;
for (const auto& annotation : annotations)
{
const auto& annotationName = annotation.first;
const auto& annotationValue = annotation.second;
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
annotationRegistration += ".markAsDeprecated()";
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
annotationRegistration += ".withUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
annotationRegistration += ".markAsPrivileged()";
else
std::cerr << "Node: " << propertyName << ": "
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
}
registrationSS << tab << tab << "object_.registerProperty(\""
<< propertyName << "\")"
<< ".onInterface(interfaceName)";
@@ -254,6 +322,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
"{ this->" << propertyName << "(" << propertyArg << "); })";
}
registrationSS << annotationRegistration;
registrationSS << ";" << endl;
if (propertyAccess == "read" || propertyAccess == "readwrite")
@@ -264,3 +333,25 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
return std::make_tuple(registrationSS.str(), declarationSS.str());
}
std::map<std::string, std::string> AdaptorGenerator::getAnnotations( sdbuscpp::xml::Node& node) const
{
std::map<std::string, std::string> result;
Nodes annotations = (node)["annotation"];
for (const auto& annotation : annotations)
{
result[annotation->get("name")] = annotation->get("value");
}
return result;
}
std::string AdaptorGenerator::propertyAnnotationToFlag(const std::string& annotationValue) const
{
return annotationValue == "true" ? "sdbus::Flags::EMITS_CHANGE_SIGNAL"
: annotationValue == "invalidates" ? "sdbus::Flags::EMITS_INVALIDATION_SIGNAL"
: annotationValue == "const" ? "sdbus::Flags::CONST_PROPERTY_VALUE"
: annotationValue == "false" ? "sdbus::Flags::EMITS_NO_SIGNAL"
: "EMITS_CHANGE_SIGNAL"; // Default
}
+14
View File
@@ -32,6 +32,7 @@
// STL
#include <tuple>
#include <set>
class AdaptorGenerator : public BaseGenerator
{
@@ -73,6 +74,19 @@ private:
*/
std::tuple<std::string, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
/**
* Get annotations listed for a given node
* @param node
* @return map of annotation names to their values
*/
std::map<std::string, std::string> getAnnotations(sdbuscpp::xml::Node& node) const;
/**
* Get flag for property update behavior annotation value
* @param annotationValue
* @return flag
*/
std::string propertyAnnotationToFlag(const std::string& annotationValue) const;
};
+12 -3
View File
@@ -108,12 +108,21 @@ std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndT
{
std::ostringstream argSS, argTypeSS, typeSS;
bool firstArg{true};
for (const auto& arg : args)
for (size_t i = 0; i < args.size(); ++i)
{
if (firstArg) firstArg = false; else { argSS << ", "; argTypeSS << ", "; typeSS << ", "; }
auto arg = args.at(i);
if (i > 0)
{
argSS << ", ";
argTypeSS << ", ";
typeSS << ", ";
}
auto argName = arg->get("name");
if (argName.empty())
{
argName = "arg" + std::to_string(i);
}
auto type = signature_to_type(arg->get("type"));
argSS << argName;
argTypeSS << "const " << type << "& " << argName;
+45 -6
View File
@@ -1,13 +1,52 @@
cmake_minimum_required (VERSION 3.4)
#-------------------------------
# PROJECT INFORMATION
#-------------------------------
add_definitions(-std=c++14)
cmake_minimum_required(VERSION 3.5)
project (sdbuscpp-xml2cpp)
project(sdbuscpp-xml2cpp)
add_executable(${PROJECT_NAME} xml2cpp.cpp xml.cpp generator_utils.cpp BaseGenerator.cpp AdaptorGenerator.cpp ProxyGenerator.cpp)
include(GNUInstallDirs)
find_package (EXPAT REQUIRED)
#-------------------------------
# PERFORMING CHECKS
#-------------------------------
find_package(EXPAT REQUIRED)
#-------------------------------
# SOURCE FILES CONFIGURATION
#-------------------------------
set(SDBUSCPP_XML2CPP_SRCS
xml2cpp.cpp
xml.h
xml.cpp
generator_utils.h
generator_utils.cpp
BaseGenerator.h
BaseGenerator.cpp
AdaptorGenerator.h
AdaptorGenerator.cpp
ProxyGenerator.h
ProxyGenerator.cpp)
#-------------------------------
# GENERAL COMPILER CONFIGURATION
#-------------------------------
set(CMAKE_CXX_STANDARD 14)
#----------------------------------
# EXECUTABLE BUILD INFORMATION
#----------------------------------
add_executable(${PROJECT_NAME} ${SDBUSCPP_XML2CPP_SRCS})
target_link_libraries (${PROJECT_NAME} ${EXPAT_LIBRARIES})
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION bin)
#----------------------------------
# INSTALLATION
#----------------------------------
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+22 -1
View File
@@ -127,6 +127,24 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
Nodes inArgs = args.select("direction" , "in");
Nodes outArgs = args.select("direction" , "out");
bool dontExpectReply{false};
Nodes annotations = (*method)["annotation"];
for (const auto& annotation : annotations)
{
if (annotation->get("name") == "org.freedesktop.DBus.Method.NoReply"
&& annotation->get("value") == "true")
{
dontExpectReply = true;
break;
}
}
if (dontExpectReply && outArgs.size() > 0)
{
std::cerr << "Function: " << name << ": ";
std::cerr << "Option 'org.freedesktop.DBus.Method.NoReply' not allowed for methods with 'out' variables! Option ignored..." << std::endl;
dontExpectReply = false;
}
auto retType = outArgsToType(outArgs);
std::string argStr, argTypeStr;
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs);
@@ -152,6 +170,10 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
methodSS << ".storeResultsTo(result);" << endl
<< tab << tab << "return result";
}
else if (dontExpectReply)
{
methodSS << ".dontExpectReply()";
}
methodSS << ";" << endl << tab << "}" << endl << endl;
}
@@ -159,7 +181,6 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
return methodSS.str();
}
std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes& signals) const
{
std::ostringstream registrationSS, declarationSS;
+7 -7
View File
@@ -247,15 +247,15 @@ std::string Document::to_xml() const
}
void Document::Expat::start_doctype_decl_handler(
void* data,
const XML_Char* name,
const XML_Char* sysid,
const XML_Char *pubid,
int has_internal_subset)
void* /*data*/,
const XML_Char* /*name*/,
const XML_Char* /*sysid*/,
const XML_Char */*pubid*/,
int /*has_internal_subset*/)
{
}
void Document::Expat::end_doctype_decl_handler(void* data)
void Document::Expat::end_doctype_decl_handler(void* /*data*/)
{
}
@@ -300,7 +300,7 @@ void Document::Expat::character_data_handler(void* data, const XML_Char* chars,
nod->cdata = std::string(chars, x, y + 1);
}
void Document::Expat::end_element_handler(void* data, const XML_Char* name)
void Document::Expat::end_element_handler(void* data, const XML_Char* /*name*/)
{
Document* doc = static_cast<Document*>(data);
+100
View File
@@ -0,0 +1,100 @@
#-------------------------------
# DOWNLOAD AND BUILD OF GOOGLETEST
# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
#-------------------------------
configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
#-------------------------------
# SOURCE FILES CONFIGURATION
#-------------------------------
set(UNITTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/unittests)
set(UNITTESTS_SRCS
${UNITTESTS_SOURCE_DIR}/libsdbus-c++_unittests.cpp
${UNITTESTS_SOURCE_DIR}/Message_test.cpp
${UNITTESTS_SOURCE_DIR}/Types_test.cpp
${UNITTESTS_SOURCE_DIR}/TypeTraits_test.cpp)
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
set(INTEGRATIONTESTS_SRCS
${INTEGRATIONTESTS_SOURCE_DIR}/AdaptorAndProxy_test.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/Connection_test.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/libsdbus-c++_integrationtests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/adaptor-glue.h
${INTEGRATIONTESTS_SOURCE_DIR}/defs.h
${INTEGRATIONTESTS_SOURCE_DIR}/proxy-glue.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestingAdaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestingProxy.h)
#-------------------------------
# GENERAL COMPILER CONFIGURATION
#-------------------------------
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
#----------------------------------
# BUILD INFORMATION
#----------------------------------
# Turn off -isystem gcc option that CMake uses for imported
# targets even when INTERFACE_INCLUDE_DIRECTORIES is used.
set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1")
add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
#----------------------------------
# INSTALLATION
#----------------------------------
install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
#----------------------------------
# RUNNING THE TESTS UPON BUILD
#----------------------------------
if(CMAKE_CROSSCOMPILING)
if(NOT DEFINED UNIT_TESTS_RUNNER)
set(UNIT_TESTS_RUNNER $ENV{UNIT_TESTS_RUNNER})
endif()
if(NOT DEFINED TEST_DEVICE_IP)
set(TEST_DEVICE_IP $ENV{TEST_DEVICE_IP})
endif()
if(NOT (UNIT_TESTS_RUNNER AND TEST_DEVICE_IP))
message(WARNING "UNIT_TESTS_RUNNER and TEST_DEVICE_IP variables must be defined to run tests remotely")
endif()
add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
add_test(NAME libsdbus-c++_integrationtests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_integrationtests)
else()
add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
add_test(NAME libsdbus-c++_integrationtests COMMAND libsdbus-c++_integrationtests)
endif()
-67
View File
@@ -1,67 +0,0 @@
# Defines how to build and install libsdbus-c++ tests
AUTOMAKE_OPTIONS = subdir-objects
# Target dirs for test binaries, scripts and files
testbindir = /opt/test/bin
dbusconfdir = $(sysconfdir)/dbus-1/system.d
# ENABLE_TESTS is defined by configure when user enables tests during configuration
if ENABLE_TESTS
testbin_PROGRAMS = libsdbus-c++_unittests libsdbus-c++_integrationtests
dbusconf_DATA = integrationtests/files/libsdbus-cpp-test.conf
endif
# Setting per-file flags
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src
AM_CXXFLAGS = @libsdbus_cpp_CFLAGS@ @SYSTEMD_CFLAGS@ -W -Wall -Werror -pedantic -pipe -std=c++17
AM_LDFLAGS = @libsdbus_cpp_LIBS@ @SYSTEMD_LIBS@
CLEANFILES = *~ *.lo *.la
MOSTLYCLEANFILES = *.o
TESTS =
# Configuration for libsdbus-c++_unittests
libsdbus_c___unittests_SOURCES = \
unittests/libsdbus-c++_unittests.cpp \
unittests/TypeTraits_test.cpp \
unittests/Types_test.cpp \
unittests/Message_test.cpp
libsdbus_c___unittests_LDFLAGS = -L$(top_builddir)/src -pthread
libsdbus_c___unittests_LDADD = \
-lsdbus-c++ \
@libsdbus_cpp_LIBS@ \
@SYSTEMD_LIBS@ \
-lgmock
TESTS += libsdbus-c++_unittests
# Configuration for libsdbus-c++_integrationtests
libsdbus_c___integrationtests_SOURCES = \
integrationtests/libsdbus-c++_integrationtests.cpp \
integrationtests/Connection_test.cpp \
integrationtests/AdaptorAndProxy_test.cpp
libsdbus_c___integrationtests_LDFLAGS = -L$(top_builddir)/src -pthread
libsdbus_c___integrationtests_LDADD = \
-lsdbus-c++ \
@libsdbus_cpp_LIBS@ \
@SYSTEMD_LIBS@ \
-lgmock
TESTS += libsdbus-c++_integrationtests
check_PROGRAMS = libsdbus-c++_unittests libsdbus-c++_integrationtests
DISTCLEANFILES = Makefile Makefile.in
# Post-build action: executing tests from the IDE
if ENABLE_TESTS
all-local: libsdbus-c++_unittests libsdbus-c++_integrationtests
if [ "${UNIT_TESTS_RUNNER}" ]; then "${UNIT_TESTS_RUNNER}" --deviceip="${TEST_DEVICE_IP}" --testbin=.libs/libsdbus-c++_unittests; fi; exit 0
if [ "${UNIT_TESTS_RUNNER}" ]; then "${UNIT_TESTS_RUNNER}" --deviceip="${TEST_DEVICE_IP}" --testbin=.libs/libsdbus-c++_integrationtests; fi; exit 0
endif
+17
View File
@@ -0,0 +1,17 @@
# Taken from https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
+52 -2
View File
@@ -41,6 +41,7 @@
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
using ::testing::Eq;
using ::testing::Gt;
@@ -200,6 +201,51 @@ TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
ASSERT_THAT(resComplex.count(0), Eq(1));
}
TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
{
m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE);
for (auto i = 0; i < 100; ++i)
{
if (m_adaptor->wasMultiplyCalled())
break;
std::this_thread::sleep_for(10ms);
}
ASSERT_TRUE(m_adaptor->wasMultiplyCalled());
ASSERT_THAT(m_adaptor->getMultiplyResult(), Eq(INT64_VALUE * DOUBLE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodThatThrowsError)
{
try
{
m_proxy->throwError();
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), Eq("org.freedesktop.DBus.Error.AccessDenied"));
ASSERT_THAT(e.getMessage(), Eq("A test error occurred (Operation not permitted)"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet)
{
ASSERT_NO_THROW(m_proxy->throwErrorWithNoReply());
for (auto i = 0; i < 100; ++i)
{
if (m_adaptor->wasThrowErrorCalled())
break;
std::this_thread::sleep_for(10ms);
}
ASSERT_TRUE(m_adaptor->wasThrowErrorCalled());
}
TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
{
// Yeah, this is kinda timing-dependent test, but times should be safe...
@@ -227,7 +273,6 @@ TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
{
std::mutex mtx;
std::atomic<size_t> resultCount{};
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
@@ -331,7 +376,7 @@ TEST_F(SdbusTestObject, ReadsReadPropertySuccesfully)
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
{
auto x = 42;
uint32_t x = 42;
ASSERT_NO_THROW(m_proxy->action(x));
ASSERT_THAT(m_proxy->action(), Eq(x));
}
@@ -346,3 +391,8 @@ TEST_F(SdbusTestObject, CannotReadFromWriteProperty)
{
ASSERT_THROW(m_proxy->blocking(), sdbus::Error);
}
TEST_F(SdbusTestObject, AnswersXmlApiDescriptionOnIntrospection)
{
ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription()));
}
+21
View File
@@ -29,6 +29,7 @@
#include "adaptor-glue.h"
#include <thread>
#include <chrono>
#include <atomic>
class TestingAdaptor : public sdbus::Interfaces<testing_adaptor>
{
@@ -38,6 +39,10 @@ public:
virtual ~TestingAdaptor() { }
bool wasMultiplyCalled() const { return m_multiplyCalled; }
double getMultiplyResult() const { return m_multiplyResult; }
bool wasThrowErrorCalled() const { return m_throwErrorCalled; }
protected:
void noArgNoReturn() const { }
@@ -48,6 +53,12 @@ protected:
double multiply(const int64_t& a, const double& b) const { return a * b; }
void multiplyWithNoReply(const int64_t& a, const double& b) const
{
m_multiplyResult = a * b;
m_multiplyCalled = true;
}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const
{
std::vector<int16_t> res{x.get<1>()};
@@ -154,6 +165,12 @@ protected:
};
}
void throwError() const
{
m_throwErrorCalled = true;
throw sdbus::createError(1, "A test error occurred");
}
std::string state() { return STRING_VALUE; }
uint32_t action() { return m_action; }
void action(const uint32_t& value) { m_action = value; }
@@ -164,6 +181,10 @@ private:
uint32_t m_action;
bool m_blocking;
// For dont-expect-reply method call verifications
mutable std::atomic<bool> m_multiplyCalled{};
mutable double m_multiplyResult{};
mutable std::atomic<bool> m_throwErrorCalled{};
};
+2 -2
View File
@@ -28,10 +28,10 @@
#include "proxy-glue.h"
class TestingProxy : public sdbus::ProxyInterfaces<::testing_proxy>
class TestingProxy : public sdbus::ProxyInterfaces<::testing_proxy, sdbus::introspectable_proxy>
{
public:
using sdbus::ProxyInterfaces<::testing_proxy>::ProxyInterfaces;
using sdbus::ProxyInterfaces<::testing_proxy, sdbus::introspectable_proxy>::ProxyInterfaces;
int getSimpleCallCount() const { return m_simpleCallCounter; }
std::map<int32_t, std::string> getMap() const { return m_map; }
+150 -4
View File
@@ -57,11 +57,14 @@ protected:
testing_adaptor(sdbus::IObject& object) :
object_(object)
{
object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
object_.registerMethod("getInt").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getInt(); });
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getTuple(); });
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).implementedAs([this](
const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x){ return this->getInts16FromStruct(x); });
@@ -95,15 +98,20 @@ protected:
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getSignature(); });
object_.registerMethod("getObjectPath").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getObjectPath(); });
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); });
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); }).markAsDeprecated();
object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); });
object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ this->throwError(); }).withNoReply();
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([](){}).markAsPrivileged();
// registration of signals is optional, it is useful because of introspection
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME);
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>();
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>();
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); });
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); });
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
object_.registerProperty("blocking").onInterface(INTERFACE_NAME)./*withGetter([this](){ return this->blocking(); }).*/withSetter([this](const bool& value){ this->blocking(value); });
}
@@ -143,6 +151,7 @@ protected:
virtual int32_t getInt() const = 0;
virtual std::tuple<uint32_t, std::string> getTuple() const = 0;
virtual double multiply(const int64_t& a, const double& b) const = 0;
virtual void multiplyWithNoReply(const int64_t& a, const double& b) const = 0;
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const = 0;
virtual sdbus::Variant processVariant(sdbus::Variant& v) = 0;
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) const = 0;
@@ -154,6 +163,7 @@ protected:
virtual sdbus::Signature getSignature() const = 0;
virtual sdbus::ObjectPath getObjectPath() const = 0;
virtual ComplexType getComplex() const = 0;
virtual void throwError() const = 0;
virtual std::string state() = 0;
virtual uint32_t action() = 0;
@@ -161,6 +171,142 @@ protected:
virtual bool blocking() = 0;
virtual void blocking(const bool& value) = 0;
public: // For testing purposes
std::string getExpectedXmlApiDescription()
{
return
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" type="s" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="GetAll">
<arg name="interface" direction="in" type="s"/>
<arg name="properties" direction="out" type="a{sv}"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="com.kistler.testsdbuscpp">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<method name="doOperationAsync">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doOperationSync">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doPrivilegedStuff">
<annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
</method>
<method name="getComplex">
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</method>
<method name="getInt">
<arg type="i" direction="out"/>
</method>
<method name="getInts16FromStruct">
<arg type="(yndsan)" direction="in"/>
<arg type="an" direction="out"/>
</method>
<method name="getMapOfVariants">
<arg type="ai" direction="in"/>
<arg type="(vv)" direction="in"/>
<arg type="a{iv}" direction="out"/>
</method>
<method name="getObjectPath">
<arg type="o" direction="out"/>
</method>
<method name="getSignature">
<arg type="g" direction="out"/>
</method>
<method name="getStructInStruct">
<arg type="(s(a{ii}))" direction="out"/>
</method>
<method name="getTuple">
<arg type="u" direction="out"/>
<arg type="s" direction="out"/>
</method>
<method name="multiply">
<arg type="x" direction="in"/>
<arg type="d" direction="in"/>
<arg type="d" direction="out"/>
</method>
<method name="multiplyWithNoReply">
<arg type="x" direction="in"/>
<arg type="d" direction="in"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="noArgNoReturn">
</method>
<method name="processVariant">
<arg type="v" direction="in"/>
<arg type="v" direction="out"/>
</method>
<method name="sumStructItems">
<arg type="(yq)" direction="in"/>
<arg type="(ix)" direction="in"/>
<arg type="i" direction="out"/>
</method>
<method name="sumVectorItems">
<arg type="aq" direction="in"/>
<arg type="at" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="throwError">
</method>
<method name="throwErrorWithNoReply">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<signal name="signalWithMap">
<arg type="a{is}"/>
</signal>
<signal name="signalWithVariant">
<arg type="v"/>
</signal>
<signal name="simpleSignal">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</signal>
<property name="action" type="u" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<property name="blocking" type="b" access="readwrite">
</property>
<property name="state" type="s" access="read">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
)delimiter";
}
};
+15 -1
View File
@@ -45,7 +45,6 @@ protected:
{ this->onSignalWithoutRegistration(s); });
}
virtual void onSimpleSignal() = 0;
virtual void onSignalWithMap(const std::map<int32_t, std::string>& map) = 0;
virtual void onSignalWithVariant(const sdbus::Variant& v) = 0;
@@ -78,6 +77,11 @@ public:
return result;
}
void multiplyWithNoReply(const int64_t& a, const double& b)
{
object_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
{
std::vector<int16_t> result;
@@ -155,6 +159,16 @@ public:
return result;
}
void throwError()
{
object_.callMethod("throwError").onInterface(INTERFACE_NAME);
}
void throwErrorWithNoReply()
{
object_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
}
int32_t callNonexistentMethod()
{
int32_t result;