Compare commits

..
102 changed files with 1835 additions and 6069 deletions
-23
View File
@@ -1,23 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Real (buggy) behavior**
A clear and concise description of what really happened in contrast to your expectation.
**Additional context**
Add any other context about the problem here, like version of sdbus-c++ library, version of systemd used, OS used.
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+13 -50
View File
@@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-22.04]
os: [ubuntu-18.04, ubuntu-20.04]
compiler: [g++, clang]
build: [shared-libsystemd]
include:
@@ -20,7 +20,7 @@ jobs:
compiler: g++
build: embedded-static-libsystemd
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: install-libsystemd-toolchain
if: matrix.build == 'embedded-static-libsystemd'
run: |
@@ -39,67 +39,30 @@ jobs:
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 10
sudo update-alternatives --remove-all c++
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 10
- name: install-googletest
if: matrix.os == 'ubuntu-22.04' # On older ubuntus the libgmock-dev package is either unavailable or has faulty pkg-config file
run: |
sudo apt-get install -y libgmock-dev
- name: configure-debug
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-18.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
- name: configure-release
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
- name: configure-release
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-22.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
- name: configure-with-embedded-libsystemd
if: matrix.build == 'embedded-static-libsystemd'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DBUILD_LIBSYSTEMD=ON -DLIBSYSTEMD_VERSION=244 ..
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DBUILD_LIBSYSTEMD=ON -DLIBSYSTEMD_VERSION=244 ..
- name: make
run: |
cd build
cmake --build . -j4
make -j2
- name: verify
run: |
cd build
sudo cmake --build . --target install
ctest --output-on-failure
- name: pack
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
run: |
cd build
cpack -G DEB
- name: 'Upload Artifact'
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04' && matrix.compiler == 'g++'
uses: actions/upload-artifact@v3
with:
name: "debian-packages-${{ matrix.os }}-${{ matrix.compiler }}"
path: |
build/sdbus-c++*.deb
build/sdbus-c++*.ddeb
retention-days: 10
freebsd-build:
name: build (freebsd, clang/libc++, basu)
runs-on: ubuntu-22.04 # until https://github.com/actions/runner/issues/385
steps:
- uses: actions/checkout@v2
- name: Test in FreeBSD VM
uses: vmactions/freebsd-vm@v1
with:
copyback: false
usesh: true
prepare: |
pkg install -y cmake ninja pkgconf basu expat googletest
run: |
cmake -B _build -G Ninja -DBUILD_CODE_GEN=ON -DBUILD_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON
cmake --build _build
cmake --install _build
pkg install -y dbus
service dbus onestart
ctest --output-on-failure --test-dir _build
sudo make install
ctest
+14 -87
View File
@@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.13)
project(sdbus-c++ VERSION 1.5.0 LANGUAGES C CXX)
project(sdbus-c++ VERSION 0.8.3 LANGUAGES C CXX)
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
@@ -12,49 +12,23 @@ include(GNUInstallDirs) # Installation directories for `install` command and pkg
# PERFORMING CHECKS & PREPARING THE DEPENDENCIES
#-------------------------------
set(LIBSYSTEMD_IMPL "systemd")
set(LIBSYSTEMD_LIB "libsystemd")
option(BUILD_LIBSYSTEMD "Build libsystemd static library and incorporate it into libsdbus-c++" OFF)
if(NOT BUILD_LIBSYSTEMD)
find_package(PkgConfig REQUIRED)
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libsystemd>=236)
if(NOT TARGET PkgConfig::Systemd)
message(WARNING "libsystemd not found, checking for libelogind instead")
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libelogind>=236)
if(TARGET PkgConfig::Systemd)
set(LIBSYSTEMD_IMPL "elogind")
set(LIBSYSTEMD_LIB "libelogind")
string(REPLACE "." ";" VERSION_LIST ${Systemd_VERSION})
list(GET VERSION_LIST 0 Systemd_VERSION)
else()
message(WARNING "libelogind not found, checking for basu instead")
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL basu)
set(LIBSYSTEMD_IMPL "basu")
set(LIBSYSTEMD_LIB "basu")
# https://git.sr.ht/~emersion/basu/commit/d4d185d29a26
set(Systemd_VERSION "240")
endif()
endif()
if(NOT TARGET PkgConfig::Systemd)
message(FATAL_ERROR "libsystemd of version at least 236 is required, but was not found "
"(if you have systemd in your OS, you may want to install package containing pkgconfig "
" files for libsystemd library. On Ubuntu, that is libsystemd-dev. "
" Alternatively, you may turn BUILD_LIBSYSTEMD on for sdbus-c++ to download, build "
"and incorporate libsystemd as embedded library within sdbus-c++)")
"(you may turn BUILD_LIBSYSTEMD on for sdbus-c++ to try downloading "
"and building libsystemd in as part of sdbus-c++ during configuration)")
endif()
add_library(Systemd::Libsystemd ALIAS PkgConfig::Systemd)
string(REGEX MATCHALL "([0-9]+)" SYSTEMD_VERSION_LIST "${Systemd_VERSION}")
list(GET SYSTEMD_VERSION_LIST 0 LIBSYSTEMD_VERSION)
message(STATUS "Building with libsystemd v${LIBSYSTEMD_VERSION}")
set(LIBSYSTEMD_VERSION ${Systemd_VERSION})
else()
# Build static libsystemd library as an external project
include(cmake/LibsystemdExternalProject.cmake)
endif()
find_package(Threads REQUIRED)
#-------------------------------
# SOURCE FILES CONFIGURATION
#-------------------------------
@@ -78,7 +52,6 @@ set(SDBUSCPP_HDR_SRCS
${SDBUSCPP_SOURCE_DIR}/Connection.h
${SDBUSCPP_SOURCE_DIR}/IConnection.h
${SDBUSCPP_SOURCE_DIR}/MessageUtils.h
${SDBUSCPP_SOURCE_DIR}/Utils.h
${SDBUSCPP_SOURCE_DIR}/Object.h
${SDBUSCPP_SOURCE_DIR}/Proxy.h
${SDBUSCPP_SOURCE_DIR}/ScopeGuard.h
@@ -118,30 +91,23 @@ set(CMAKE_CXX_STANDARD 17)
set(SDBUSCPP_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
# We promote the BUILD_SHARED_LIBS flag to a (global) option only if we are the main project
# We promote BUILD_SHARED_LIBS flags to (global) option only if we are the main project
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
option(BUILD_SHARED_LIBS "Build shared libraries (.so) instead of static ones (.a)" ON)
endif()
# Having an object target allows unit tests to reuse already built sources without re-building
add_library(sdbus-c++-objlib OBJECT ${SDBUSCPP_SRCS})
target_compile_definitions(sdbus-c++-objlib PRIVATE
BUILD_LIB=1
LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION}
SDBUS_${LIBSYSTEMD_IMPL}
SDBUS_HEADER=<${LIBSYSTEMD_IMPL}/sd-bus.h>)
target_compile_definitions(sdbus-c++-objlib PRIVATE BUILD_LIB=1 LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
target_include_directories(sdbus-c++-objlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
if(BUILD_SHARED_LIBS)
set_target_properties(sdbus-c++-objlib PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(DEFINED BUILD_SHARED_LIBS)
set_target_properties(sdbus-c++-objlib PROPERTIES POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS})
endif()
if(BUILD_LIBSYSTEMD)
add_dependencies(sdbus-c++-objlib LibsystemdBuildProject)
endif()
target_link_libraries(sdbus-c++-objlib
PUBLIC
Systemd::Libsystemd
Threads::Threads)
target_link_libraries(sdbus-c++-objlib PUBLIC Systemd::Libsystemd)
add_library(sdbus-c++)
target_include_directories(sdbus-c++ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
@@ -163,16 +129,16 @@ endif()
install(TARGETS ${EXPORT_SET}
EXPORT sdbus-c++-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT dev
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev
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(BUILD_TESTS "Build tests (default OFF)" OFF)
option(BUILD_TESTS "Build and install tests (default OFF)" OFF)
if(BUILD_TESTS)
message(STATUS "Building with tests")
@@ -191,17 +157,6 @@ if(BUILD_CODE_GEN)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tools")
endif()
#----------------------------------
# EXAMPLES
#----------------------------------
option(BUILD_EXAMPLES "Build example programs (default OFF)" OFF)
if(BUILD_EXAMPLES)
message(STATUS "Building with examples")
add_subdirectory(examples)
endif()
#----------------------------------
# DOCUMENTATION
#----------------------------------
@@ -212,7 +167,7 @@ if(BUILD_DOC)
message(STATUS "Building with documentation")
option(BUILD_DOXYGEN_DOC "Build doxygen documentation for sdbus-c++ API" OFF)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/docs")
install(FILES README README.md NEWS COPYING ChangeLog AUTHORS DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT doc)
install(FILES README README.md NEWS COPYING ChangeLog AUTHORS DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
#----------------------------------
@@ -234,34 +189,6 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++
COMPONENT dev)
if(BUILD_SHARED_LIBS AND (BUILD_LIBSYSTEMD OR Systemd_LINK_LIBRARIES MATCHES "/libsystemd\.a(;|$)"))
set(PKGCONFIG_REQS ".private")
else()
set(PKGCONFIG_REQS "")
endif()
set(PKGCONFIG_DEPS ${LIBSYSTEMD_LIB})
configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/sdbus-c++.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)
#----------------------------------
# CPack
#----------------------------------
set(CPACK_PACKAGE_VENDOR "Kistler")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "high-level C++ D-Bus library")
set(CPACK_PACKAGE_CONTACT "info@kistler.com")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_COMPONENTS_ALL runtime dev doc)
set(CPACK_COMPONENT_DEV_DEPENDS "runtime")
# specific for DEB generator
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_RUNTIME_DEBUGINFO_PACKAGE ON)
set(CPACK_DEBIAN_RUNTIME_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS ON)
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libsystemd-dev (>=236)")
include(CPack)
+1 -1
View File
@@ -4,7 +4,7 @@ As an additional permission to the GNU Lesser General Public License version
2.1, the object code form of a "work that uses the Library" may incorporate
material from a header file that is part of the Library. You may distribute
such object code under terms of your choice, provided that:
(i) the header files of the Library have not been modified; and
(i) the header files of the Library have not been modified; and
(ii) the incorporated material is limited to numerical parameters, data
structure layouts, accessors, macros, inline functions and
templates; and
-79
View File
@@ -169,82 +169,3 @@ v0.8.3
- Update CMake configuration flag names
- Fix unused variable warning for release builds
- Introduce CI workflow based on GitHub Actions
v0.9.0
- Provide CMake config and PkgConfig files for tools
- Provide access to D-Bus message in high-level API
- Add API to set signal destination
- Add IProxy::getConnection() method
- Add README and sdbus-c++ tutorial as additional pages in doxydocs
- Enable default construction of PendingAsyncCall
- Add API to get message path and message destination
- Avoid propagating msg unpack exceptions to the event loop
- Fix issue #145: signals are not filtered by sender
- Fix race condition in Proxy and Object destructor
- Fix seg fault in Message::peekType()
- Add information to documentation about conan recipe
- Add cpack to build debian packages, split the packages by components
- Catch sdbus-c++ exceptions flying from Proxy callbacks to libsystemd
- Add createDefaultBusConnection() method
- Make resetting loop thread ID exception-safe
- Support Error parameter in signal handlers
- Add specific sections for tips and notes in the tutorial
- A few additional documentation and test updates and improvements
v1.0.0
- [[Breaking API change]] Fixed the API to send org.freedesktop.DBus.ObjectManager.InterfacesAdded and org.freedesktop.DBus.ObjectManager.InterfacesRemoved signals via the generated stubs layer.
- StandardInterfaces.h: Split ObjectManager_adaptor and ManagedObject_adaptor.
- New examples directory. First example covers the object manager. Further examples might follow.
v1.1.0
- Fix timeout handling for asynchronous method calls
- Add support for unregistering signal handler
- Add support for chrono literals in sdbus-c++-xml2cpp generator
- Additional little fixes and improvements in code, build system, and documentation
v1.2.0
- Add support for match rules
- Add support for session bus connection at custom address
- Add CMake variable for extra libsystemd config options
- Use pseudo D-Bus connection for plain messages
- Rename dont_request_slot tag to floating_slot
- Add validity checks for names and paths
- Remove executable flag from source files
- Detect missing type after array declaration
- Fix invalid assert on event fd
- Enable move for ObjectPath and Signature
- Add printer for std::chrono in googletest v1.11.0
- Fix potential undefined behavior in creation of sdbus::Error
- Additional little fixes and improvements in code, build system, and documentation
v1.3.0
- Add support for light-weight proxies (proxies without own event loop threads)
- Extend documentation with explicit mapping between D-Bus and corresponding C++ types
- Support move semantics in generated adaptor and proxy classes
- Adaptations for libsystemd v251
- Fix for proper complete sending of long D-Bus messages by explicitly flushing them
- Add support for std::future-based async calls
- Fix race condition in async Proxy::callMethod
- Fix pseudo-connection static lifetime issue with Phoenix pattern
- Speed up performance of of serialization of arrays of trivial D-Bus types
- Make sdbus::Struct a tuple-like class, so it's usable wherever std::tuple is
- Add support for std::array, std::span and std::unordered_map as additional C++ types for D-Bus array types
- Add support for libelogind as an addition to libsystemd
- Add support for std::future-based async methods in codegen tool
- Additional little fixes and improvements in code, build system, CI, and documentation
v1.4.0
- Implement API for convenient asynchronous property get/set on the client-side
- Add support for FreeBSD systems (including support for basu implementation of sd-bus on non-systemd machines)
- Add support for direct, peer-to-peer connections
- Add option to create IConnection directly from an underlying sd_bus instance
- Some additional fixes
v1.5.0
- Improve handling of exceptions from callback handlers
- Add support for async registration of matches
- Correctly add libsystemd dependency to pkgconfi
- Fix request name signal handling issue
- Add INSTALL_TESTS CMake option
- Minor UnixFd cleanups
- Additional little fixes and updates in code, build system, CI, and documentation
+8 -25
View File
@@ -20,8 +20,8 @@ The library is built using CMake:
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Release ${OTHER_CONFIG_FLAGS}
$ cmake --build .
$ sudo cmake --build . --target install
$ make
$ sudo make install
```
### CMake configuration flags for sdbus-c++
@@ -36,11 +36,11 @@ $ sudo cmake --build . --target install
* `BUILD_DOXYGEN_DOC` [boolean]
Option for building Doxygen documentation of sdbus-c++ API. If enabled, the documentation must still be built explicitly through `cmake --build . --target doc`. Default value: `OFF`. Use `-DBUILD_DOXYGEN_DOC=OFF` to disable searching for Doxygen and building Doxygen documentation of sdbus-c++ API.
Option for building Doxygen documentation of sdbus-c++ API. If enabled, the documentation must still be built explicitly through `make doc`. Default value: `OFF`. Use `-DBUILD_DOXYGEN_DOC=OFF` to disable searching for Doxygen and building Doxygen documentation of sdbus-c++ API.
* `BUILD_TESTS` [boolean]
Option for building sdbus-c++ unit and integration tests, invokable by `cmake --build . --target test` (Note: before invoking `cmake --build . --target test`, make sure you copy `tests/integrationtests/files/org.sdbuscpp.integrationtests.conf` file to `/etc/dbus-1/system.d` directory). That incorporates downloading and building static libraries of Google Test. Default value: `OFF`. Use `-DBUILD_TESTS=ON` to enable building the tests. With this option turned on, you may also enable/disable the following options:
Option for building sdbus-c++ unit and integration tests, invokable by `make test`. That incorporates downloading and building static libraries of Google Test. Default value: `OFF`. Use `-DBUILD_TESTS=ON` to enable building the tests. With this option turned on, you may also enable/disable the following options:
* `ENABLE_PERF_TESTS` [boolean]
@@ -50,13 +50,9 @@ $ sudo cmake --build . --target install
Option for building sdbus-c++ stress tests. Default value: `OFF`.
* `INSTALL_TESTS` [boolean]
Option for installing tests that were built. Default value: `OFF`.
* `TESTS_INSTALL_PATH` [string]
Path where the test binaries shall get installed. Default value: `${CMAKE_INSTALL_PREFIX}/tests/sdbus-c++` (previously: `/opt/test/bin`).
Path where the test binaries shall get installed. Default value: `/opt/test/bin`.
* `BUILD_LIBSYSTEMD` [boolean]
@@ -66,42 +62,29 @@ $ sudo cmake --build . --target install
Defines version of systemd to be downloaded, built and integrated into sdbus-c++. Default value: `242`.
* `LIBSYSTEMD_EXTRA_CONFIG_OPTS` [string]
Additional options to be passed as-is to the libsystemd build system (meson for systemd v242) in its configure step. Can be used for passing e.g. toolchain file path in case of cross builds. Default value: empty.
* `CMAKE_BUILD_TYPE` [string]
This is a CMake-builtin option. Set to `Release` to build sdbus-c++ for production use. Set to `Debug` if you want to help further develop (and debug) the library :)
* `BUILD_SHARED_LIBS` [boolean]
This is a global CMake flag, promoted in sdbus-c++ project to a CMake option. Use this to control whether sdbus-c++ is built as either a shared or static library. Default value: `ON`.
* `BUILD_EXAMPLES` [boolean]
Build example programs which are located in the _example_ directory. Examples are not installed. Default value: `OFF`
Dependencies
------------
* `C++17` - the library uses C++17 features.
* `libsystemd`/`libelogind`/`basu` - libraries containing sd-bus implementation that sdbus-c++ is written around. In case of `libsystemd` and `libelogind`, version >= 236 is needed. (In case you have a non-systemd environment, don't worry, see [Solving libsystemd dependency](docs/using-sdbus-c++.md#solving-libsystemd-dependency) for more information.)
* `libsystemd` - systemd library containing sd-bus implementation. This library is part of systemd. Systemd at least v236 is needed. (In case you have a non-systemd environment, don't worry, see [Solving libsystemd dependency](docs/using-sdbus-c++.md#solving-libsystemd-dependency) for more information.)
* `googletest` - google unit testing framework, only necessary when building tests, will be downloaded and built automatically.
* `pkgconfig` - required for sdbus-c++ to be able to find some dependency packages.
* `expat` - necessary when building xml2cpp code generator (`BUILD_CODE_GEN` option is ON).
Licensing
---------
The library is distributed under LGPLv2.1 license, with a specific exception for macro/template/inline code in library header files.
The library is distributed under LGPLv2.1 license.
References/documentation
------------------------
* [Using sdbus-c++](docs/using-sdbus-c++.md) - *the* main, comprehensive tutorial on sdbus-c++
* [Systemd and dbus configuration](docs/systemd-dbus-config.md)
* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
* [D-Bus Specification](https://dbus.freedesktop.org/docs/dbus-specification.html)
* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
Contributing
+2 -9
View File
@@ -1,15 +1,10 @@
find_program(MESON meson)
find_program(NINJA ninja)
find_program(GPERF gperf)
if((NOT MESON) OR (NOT NINJA))
message(FATAL_ERROR "Meson and Ninja are required to build libsystemd")
endif()
if(NOT GPERF)
message(WARNING "gperf was not found, libsystemd configuration may fail")
endif()
find_library(GLIBC_RT_LIBRARY rt)
find_package(PkgConfig REQUIRED)
pkg_check_modules(MOUNT mount)
@@ -19,7 +14,6 @@ if (NOT CAP_FOUND)
endif()
set(LIBSYSTEMD_VERSION "242" CACHE STRING "libsystemd version (>=239) to build and incorporate into libsdbus-c++")
set(LIBSYSTEMD_EXTRA_CONFIG_OPTS "" CACHE STRING "Additional configuration options to be passed as-is to libsystemd build system")
if(NOT CMAKE_BUILD_TYPE)
set(LIBSYSTEMD_BUILD_TYPE "plain")
@@ -46,13 +40,12 @@ ExternalProject_Add(LibsystemdBuildProject
GIT_SHALLOW 1
UPDATE_COMMAND ""
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove <BINARY_DIR>/*
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Drootprefix=<INSTALL_DIR> -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR> ${LIBSYSTEMD_EXTRA_CONFIG_OPTS}
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR>
BUILD_COMMAND ${BUILD_VERSION_H}
COMMAND ${NINJA} -C <BINARY_DIR> libsystemd.a
BUILD_ALWAYS 0
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/src/systemd <INSTALL_DIR>/include/systemd
LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1
BUILD_BYPRODUCTS <BINARY_DIR>/libsystemd.a)
LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1)
ExternalProject_Get_property(LibsystemdBuildProject SOURCE_DIR)
ExternalProject_Get_property(LibsystemdBuildProject BINARY_DIR)
+2 -6
View File
@@ -12,11 +12,7 @@ if(BUILD_DOXYGEN_DOC)
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
# workaround bug https://github.com/doxygen/doxygen/pull/6787
add_custom_command(TARGET doc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/sdbus-c++-class-diagram.png ${CMAKE_CURRENT_BINARY_DIR}/html/.)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL COMPONENT doc)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
else()
message(WARNING "Documentation enabled, but Doxygen cannot be found")
endif()
@@ -26,4 +22,4 @@ install(FILES sdbus-c++-class-diagram.png
sdbus-c++-class-diagram.uml
systemd-dbus-config.md
using-sdbus-c++.md
DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT doc)
DESTINATION ${CMAKE_INSTALL_DOCDIR})
+3 -5
View File
@@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ @PROJECT_BINARY_DIR@
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -790,9 +790,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/../include" \
@CMAKE_CURRENT_SOURCE_DIR@/../README.md \
@CMAKE_CURRENT_SOURCE_DIR@/using-sdbus-c++.md
INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/../include"
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -984,7 +982,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = README.md
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
+11 -7
View File
@@ -1,4 +1,4 @@
Systemd and D-Bus configuration
Systemd and dbus configuration
=======================
**Table of contents**
@@ -10,13 +10,15 @@ Systemd and D-Bus configuration
Introduction
------------
To run executable as a systemd service you may need some additional setup. For example, you may need explicitly allow the usage of your service. Following chapters contain template configurations.
To run executable as a systemd service you may need some additional setup. For example, you may need explicitly allow
the usage of your service. Following chapters contain template configurations.
Systemd configuration
---------------------------------------
Filename should use `.service` extension. It also must be placed in configuration directory (/etc/systemd/system in Ubuntu 18.04.1 LTS)
Filename should use `.service` extension. It also must be placed in configuration directory (/etc/systemd/system in
Ubuntu 18.04.1 LTS)
```
[Unit]
@@ -29,10 +31,12 @@ ExecStart=/path/to/executable
WantedBy=multi-user.target
```
D-Bus configuration
Dbus configuration
------------------
Typical default D-Bus configuration does not allow to register services except explicitly allowed. To allow a service to register its D-Bus API, we must place an appropriate conf file in `/etc/dbus-1/system.d/` directory. The conf file name must be `<service-name>.conf`. I.e., full file path for Concatenator example from sdbus-c++ tutorial would be `/etc/dbus-1/system.d/org.sdbuscpp.concatenator.conf`. And here is template configuration to use its D-Bus interface under root:
Typical default D-Bus configuration does not allow to register services except explicitly allowed. Filename should
contain name of your service, e.g `/etc/dbus-1/system.d/org.sdbuscpp.concatenator.conf`. So, here is template
configuration to use dbus interface under root:
```
<!DOCTYPE busconfig PUBLIC
@@ -41,10 +45,10 @@ Typical default D-Bus configuration does not allow to register services except e
<busconfig>
<policy user="root">
<allow own="org.sdbuscpp.concatenator"/>
<allow send_destination="org.sdbuscpp.concatenator"/>
<allow send_destination="org.sdbuscpp"/>
<allow send_interface="org.sdbuscpp.concatenator"/>
</policy>
</busconfig>
```
If you need access from other user then `root` should be substituted by desired username. Or you can simply use policy `<policy context="default">` like [conf file](/tests/integrationtests/files/org.sdbuscpp.integrationtests.conf) for sdbus-c++ integration tests is doing it. For more information refer to `man dbus-daemon`.
If you need access from other user `root` should be substituted by desired username. For more refer to `man dbus-daemon`.
+131 -668
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1,6 +0,0 @@
add_executable(obj-manager-server org.freedesktop.DBus.ObjectManager/obj-manager-server.cpp)
target_link_libraries(obj-manager-server sdbus-c++)
add_executable(obj-manager-client org.freedesktop.DBus.ObjectManager/obj-manager-client.cpp)
target_link_libraries(obj-manager-client sdbus-c++)
@@ -1,50 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__examplemanager_planet1_client_glue_h__proxy__H__
#define __sdbuscpp__examplemanager_planet1_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace sdbuscpp {
namespace ExampleManager {
class Planet1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.ExampleManager.Planet1";
protected:
Planet1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~Planet1_proxy() = default;
public:
uint64_t GetPopulation()
{
uint64_t result;
proxy_.callMethod("GetPopulation").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
public:
std::string Name()
{
return proxy_.getProperty("Name").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -1,44 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__examplemanager_planet1_server_glue_h__adaptor__H__
#define __sdbuscpp__examplemanager_planet1_server_glue_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace sdbuscpp {
namespace ExampleManager {
class Planet1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.ExampleManager.Planet1";
protected:
Planet1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("GetPopulation").onInterface(INTERFACE_NAME).withOutputParamNames("population").implementedAs([this](){ return this->GetPopulation(); });
object_.registerProperty("Name").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Name(); });
}
~Planet1_adaptor() = default;
private:
virtual uint64_t GetPopulation() = 0;
private:
virtual std::string Name() = 0;
private:
sdbus::IObject& object_;
};
}}} // namespaces
#endif
@@ -1,110 +0,0 @@
/**
* Example of a D-Bus client which implements org.freedesktop.DBus.ObjectManager
*
* The example uses the generated stub API layer to listen to interfaces added to new objects under
* "org.sdbuscpp.examplemanager". If added, we access "org.sdbuscpp.ExampleManager.Planet1" to print
* info like this:
* /org/sdbuscpp/examplemanager/Planet1/Earth added: org.sdbuscpp.ExampleManager.Planet1
* Earth has a population of 7874965825.
*
*/
#include "examplemanager-planet1-client-glue.h"
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <thread>
class PlanetProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::ExampleManager::Planet1_proxy >
{
public:
PlanetProxy(sdbus::IConnection& connection, std::string destination, std::string path)
: ProxyInterfaces(connection, std::move(destination), std::move(path))
{
registerProxy();
}
~PlanetProxy()
{
unregisterProxy();
}
};
class ManagerProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
{
public:
ManagerProxy(sdbus::IConnection& connection, const std::string& destination, std::string path)
: ProxyInterfaces(connection, destination, std::move(path))
, m_connection(connection)
, m_destination(destination)
{
registerProxy();
}
~ManagerProxy()
{
unregisterProxy();
}
void handleExistingObjects()
{
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
objectsInterfacesAndProperties = GetManagedObjects();
for (const auto& [object, interfacesAndProperties] : objectsInterfacesAndProperties) {
onInterfacesAdded(object, interfacesAndProperties);
}
}
private:
void onInterfacesAdded( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
{
std::cout << objectPath << " added:\t";
for (const auto& [interface, _] : interfacesAndProperties) {
std::cout << interface << " ";
}
std::cout << std::endl;
// Parse and print some more info
auto planetInterface = interfacesAndProperties.find(org::sdbuscpp::ExampleManager::Planet1_proxy::INTERFACE_NAME);
if (planetInterface == interfacesAndProperties.end()) {
return;
}
const auto& properties = planetInterface->second;
// get a property which was passed as part of the signal.
const auto& name = properties.at("Name").get<std::string>();
// or create a proxy instance to the newly added object.
PlanetProxy planet(m_connection, m_destination, objectPath);
std::cout << name << " has a population of " << planet.GetPopulation() << ".\n" << std::endl;
}
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces) override
{
std::cout << objectPath << " removed:\t";
for (const auto& interface : interfaces) {
std::cout << interface << " ";
}
std::cout << std::endl;
}
sdbus::IConnection& m_connection;
std::string m_destination;
};
int main()
{
auto connection = sdbus::createSessionBusConnection();
auto managerProxy = std::make_unique<ManagerProxy>(*connection, "org.sdbuscpp.examplemanager", "/org/sdbuscpp/examplemanager");
try {
managerProxy->handleExistingObjects();
}
catch (const sdbus::Error& e) {
if (e.getName() == "org.freedesktop.DBus.Error.ServiceUnknown") {
std::cout << "Waiting for server to start ..." << std::endl;
}
}
connection->enterEventLoop();
return 0;
}
@@ -1,108 +0,0 @@
/**
* Example of a D-Bus server which implements org.freedesktop.DBus.ObjectManager
*
* The example uses the generated stub API layer to register an object manager under "org.sdbuscpp.examplemanager"
* and add objects underneath which implement "org.sdbuscpp.ExampleManager.Planet1".
*
* We add and remove objects after a few seconds and print info like this:
* Creating PlanetAdaptor in 5 4 3 2 1
* Creating PlanetAdaptor in 5 4 3 2 1
* Creating PlanetAdaptor in 5 4 3 2 1
* Removing PlanetAdaptor in 5 4 3 2 1
* Removing PlanetAdaptor in 5 4 3 2 1
*/
#include "examplemanager-planet1-server-glue.h"
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
class ManagerAdaptor : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
{
public:
ManagerAdaptor(sdbus::IConnection& connection, std::string path)
: AdaptorInterfaces(connection, std::move(path))
{
registerAdaptor();
}
~ManagerAdaptor()
{
unregisterAdaptor();
}
};
class PlanetAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::ExampleManager::Planet1_adaptor,
sdbus::ManagedObject_adaptor,
sdbus::Properties_adaptor >
{
public:
PlanetAdaptor(sdbus::IConnection& connection, std::string path, std::string name, uint64_t poulation)
: AdaptorInterfaces(connection, std::move(path))
, m_name(std::move(name))
, m_population(poulation)
{
registerAdaptor();
emitInterfacesAddedSignal({org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME});
}
~PlanetAdaptor()
{
emitInterfacesRemovedSignal({org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME});
unregisterAdaptor();
}
uint64_t GetPopulation() override
{
return m_population;
}
std::string Name() override
{
return m_name;
}
private:
std::string m_name;
uint64_t m_population;
};
void printCountDown(const std::string& message, int seconds)
{
std::cout << message << std::flush;
for (int i = seconds; i > 0; i--) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << i << " " << std::flush;
}
std::cout << std::endl;
}
int main()
{
auto connection = sdbus::createSessionBusConnection();
connection->requestName("org.sdbuscpp.examplemanager");
connection->enterEventLoopAsync();
auto manager = std::make_unique<ManagerAdaptor>(*connection, "/org/sdbuscpp/examplemanager");
while (true)
{
printCountDown("Creating PlanetAdaptor in ", 5);
auto earth = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Earth", "Earth", 7'874'965'825);
printCountDown("Creating PlanetAdaptor in ", 5);
auto trantor = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Trantor", "Trantor", 40'000'000'000);
printCountDown("Creating PlanetAdaptor in ", 5);
auto laconia = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Laconia", "Laconia", 231'721);
printCountDown("Removing PlanetAdaptor in ", 5);
earth.reset();
printCountDown("Removing PlanetAdaptor in ", 5);
trantor.reset();
printCountDown("Removing PlanetAdaptor in ", 5);
laconia.reset();
}
connection->releaseName("org.sdbuscpp.examplemanager");
connection->leaveEventLoop();
return 0;
}
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!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.sdbuscpp.ExampleManager.Planet1">
<!--
@brief get the population of this planet
@param [out] population of the planet
-->
<method name="GetPopulation">
<arg name="population" type="t" direction="out" />
</method>
<!--
@brief This planet's name
-->
<property name="Name" type="s" access="read"/>
</interface>
</node>
+2 -7
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorInterfaces.h
*
@@ -141,11 +141,6 @@ namespace sdbus {
protected:
using base_type = AdaptorInterfaces;
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
AdaptorInterfaces(AdaptorInterfaces&&) = default;
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = default;
~AdaptorInterfaces() = default;
};
+11 -83
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ConvenienceApiClasses.h
*
@@ -29,19 +29,18 @@
#include <sdbus-c++/Message.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Types.h>
#include <sdbus-c++/Flags.h>
#include <string>
#include <vector>
#include <type_traits>
#include <chrono>
#include <future>
#include <cstdint>
// Forward declarations
namespace sdbus {
class IObject;
class IProxy;
class Variant;
class Error;
class PendingAsyncCall;
}
@@ -51,7 +50,7 @@ namespace sdbus {
class MethodRegistrator
{
public:
MethodRegistrator(IObject& object, std::string methodName);
MethodRegistrator(IObject& object, const std::string& methodName);
MethodRegistrator(MethodRegistrator&& other) = default;
~MethodRegistrator() noexcept(false);
@@ -67,7 +66,7 @@ namespace sdbus {
private:
IObject& object_;
std::string methodName_;
const std::string& methodName_;
std::string interfaceName_;
std::string inputSignature_;
std::vector<std::string> inputParamNames_;
@@ -81,7 +80,7 @@ namespace sdbus {
class SignalRegistrator
{
public:
SignalRegistrator(IObject& object, std::string signalName);
SignalRegistrator(IObject& object, const std::string& signalName);
SignalRegistrator(SignalRegistrator&& other) = default;
~SignalRegistrator() noexcept(false);
@@ -93,7 +92,7 @@ namespace sdbus {
private:
IObject& object_;
std::string signalName_;
const std::string& signalName_;
std::string interfaceName_;
std::string signalSignature_;
std::vector<std::string> paramNames_;
@@ -196,10 +195,6 @@ namespace sdbus {
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
// Returned future will be std::future<void> for no (void) D-Bus method return value
// or std::future<T> for single D-Bus method return value
// or std::future<std::tuple<...>> for multiple method return values
template <typename... _Args> std::future<future_return_t<_Args...>> getResultAsFuture();
private:
IProxy& proxy_;
@@ -221,96 +216,29 @@ namespace sdbus {
std::string interfaceName_;
};
class SignalUnsubscriber
{
public:
SignalUnsubscriber(IProxy& proxy, const std::string& signalName);
void onInterface(const std::string& interfaceName);
private:
IProxy& proxy_;
const std::string& signalName_;
};
class PropertyGetter
{
public:
PropertyGetter(IProxy& proxy, const std::string& propertyName);
Variant onInterface(const std::string& interfaceName);
sdbus::Variant onInterface(const std::string& interfaceName);
private:
IProxy& proxy_;
const std::string& propertyName_;
};
class AsyncPropertyGetter
{
public:
AsyncPropertyGetter(IProxy& proxy, const std::string& propertyName);
AsyncPropertyGetter& onInterface(const std::string& interfaceName);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
std::future<Variant> getResultAsFuture();
private:
IProxy& proxy_;
const std::string& propertyName_;
const std::string* interfaceName_{};
};
class PropertySetter
{
public:
PropertySetter(IProxy& proxy, const std::string& propertyName);
PropertySetter& onInterface(const std::string& interfaceName);
PropertySetter& onInterface(std::string interfaceName);
template <typename _Value> void toValue(const _Value& value);
template <typename _Value> void toValue(const _Value& value, dont_expect_reply_t);
void toValue(const Variant& value);
void toValue(const Variant& value, dont_expect_reply_t);
void toValue(const sdbus::Variant& value);
private:
IProxy& proxy_;
const std::string& propertyName_;
const std::string* interfaceName_{};
};
class AsyncPropertySetter
{
public:
AsyncPropertySetter(IProxy& proxy, const std::string& propertyName);
AsyncPropertySetter& onInterface(const std::string& interfaceName);
template <typename _Value> AsyncPropertySetter& toValue(_Value&& value);
AsyncPropertySetter& toValue(Variant value);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
std::future<void> getResultAsFuture();
private:
IProxy& proxy_;
const std::string& propertyName_;
const std::string* interfaceName_{};
Variant value_;
};
class AllPropertiesGetter
{
public:
AllPropertiesGetter(IProxy& proxy);
std::map<std::string, Variant> onInterface(const std::string& interfaceName);
private:
IProxy& proxy_;
};
class AsyncAllPropertiesGetter
{
public:
AsyncAllPropertiesGetter(IProxy& proxy);
AsyncAllPropertiesGetter& onInterface(const std::string& interfaceName);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
std::future<std::map<std::string, Variant>> getResultAsFuture();
private:
IProxy& proxy_;
const std::string* interfaceName_{};
std::string interfaceName_;
};
}
+32 -273
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ConvenienceApiClasses.inl
*
@@ -45,9 +45,9 @@ namespace sdbus {
/*** MethodRegistrator ***/
/*** ----------------- ***/
inline MethodRegistrator::MethodRegistrator(IObject& object, std::string methodName)
inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
: object_(object)
, methodName_(std::move(methodName))
, methodName_(methodName)
, exceptions_(std::uncaught_exceptions())
{
}
@@ -73,9 +73,9 @@ namespace sdbus {
object_.registerMethod( interfaceName_
, std::move(methodName_)
, std::move(inputSignature_)
, inputParamNames_
, std::move(inputParamNames_)
, std::move(outputSignature_)
, outputParamNames_
, std::move(outputParamNames_)
, std::move(methodCallback_)
, std::move(flags_));
}
@@ -177,9 +177,9 @@ namespace sdbus {
/*** SignalRegistrator ***/
/*** ----------------- ***/
inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName)
inline SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName)
: object_(object)
, signalName_(std::move(signalName))
, signalName_(signalName)
, exceptions_(std::uncaught_exceptions())
{
}
@@ -204,7 +204,7 @@ namespace sdbus {
object_.registerSignal( interfaceName_
, std::move(signalName_)
, std::move(signalSignature_)
, paramNames_
, std::move(paramNames_)
, std::move(flags_) );
}
@@ -293,7 +293,7 @@ namespace sdbus {
template <typename _Function>
inline PropertyRegistrator& PropertyRegistrator::withGetter(_Function&& callback)
{
static_assert(function_argument_count_v<_Function> == 0, "Property getter function must not take any arguments");
static_assert(function_traits<_Function>::arity == 0, "Property getter function must not take any arguments");
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
if (propertySignature_.empty())
@@ -311,7 +311,7 @@ namespace sdbus {
template <typename _Function>
inline PropertyRegistrator& PropertyRegistrator::withSetter(_Function&& callback)
{
static_assert(function_argument_count_v<_Function> == 1, "Property setter function must take one parameter - the property value");
static_assert(function_traits<_Function>::arity == 1, "Property setter function must take one parameter - the property value");
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
if (propertySignature_.empty())
@@ -588,19 +588,7 @@ namespace sdbus {
// Deserialize input arguments from the message into the tuple (if no error occurred).
if (error == nullptr)
{
try
{
reply >> args;
}
catch (const Error& e)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, &e, args);
return;
}
}
reply >> args;
// Invoke callback with input arguments from the tuple.
sdbus::apply(callback, error, args);
@@ -609,29 +597,6 @@ namespace sdbus {
return proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
}
template <typename... _Args>
std::future<future_return_t<_Args...>> AsyncMethodInvoker::getResultAsFuture()
{
auto promise = std::make_shared<std::promise<future_return_t<_Args...>>>();
auto future = promise->get_future();
uponReplyInvoke([promise = std::move(promise)](const Error* error, _Args... args)
{
if (error == nullptr)
if constexpr (!std::is_void_v<future_return_t<_Args...>>)
promise->set_value({std::move(args)...});
else
promise->set_value();
else
promise->set_exception(std::make_exception_ptr(*error));
});
// Will be std::future<void> for no D-Bus method return value
// or std::future<T> for single D-Bus method return value
// or std::future<std::tuple<...>> for multiple method return values
return future;
}
/*** ---------------- ***/
/*** SignalSubscriber ***/
/*** ---------------- ***/
@@ -662,54 +627,14 @@ namespace sdbus {
// as a storage for the argument values deserialized from the signal message.
tuple_of_function_input_arg_types_t<_Function> signalArgs;
// The signal handler can take pure signal parameters only, or an additional `const Error*` as its first
// parameter. In the former case, if the deserialization fails (e.g. due to signature mismatch),
// the failure is ignored (and signal simply dropped). In the latter case, the deserialization failure
// will be communicated as a non-zero Error pointer to the client's signal handler.
if constexpr (has_error_param_v<_Function>)
{
// Deserialize input arguments from the signal message into the tuple
try
{
signal >> signalArgs;
}
catch (const sdbus::Error& e)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, &e, signalArgs);
return;
}
// Deserialize input arguments from the signal message into the tuple
signal >> signalArgs;
// Invoke callback with no error and input arguments from the tuple.
sdbus::apply(callback, nullptr, signalArgs);
}
else
{
// Deserialize input arguments from the signal message into the tuple
signal >> signalArgs;
// Invoke callback with input arguments from the tuple.
sdbus::apply(callback, signalArgs);
}
// Invoke callback with input arguments from the tuple.
sdbus::apply(callback, signalArgs);
});
}
/*** ------------------ ***/
/*** SignalUnsubscriber ***/
/*** ------------------ ***/
inline SignalUnsubscriber::SignalUnsubscriber(IProxy& proxy, const std::string& signalName)
: proxy_(proxy)
, signalName_(signalName)
{
}
inline void SignalUnsubscriber::onInterface(const std::string& interfaceName)
{
proxy_.unregisterSignalHandler(interfaceName, signalName_);
}
/*** -------------- ***/
/*** PropertyGetter ***/
/*** -------------- ***/
@@ -720,56 +645,17 @@ namespace sdbus {
{
}
inline Variant PropertyGetter::onInterface(const std::string& interfaceName)
inline sdbus::Variant PropertyGetter::onInterface(const std::string& interfaceName)
{
Variant var;
proxy_.callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName, propertyName_)
.storeResultsTo(var);
sdbus::Variant var;
proxy_
.callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName, propertyName_)
.storeResultsTo(var);
return var;
}
/*** ------------------- ***/
/*** AsyncPropertyGetter ***/
/*** ------------------- ***/
inline AsyncPropertyGetter::AsyncPropertyGetter(IProxy& proxy, const std::string& propertyName)
: proxy_(proxy)
, propertyName_(propertyName)
{
}
inline AsyncPropertyGetter& AsyncPropertyGetter::onInterface(const std::string& interfaceName)
{
interfaceName_ = &interfaceName;
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncPropertyGetter::uponReplyInvoke(_Function&& callback)
{
static_assert(std::is_invocable_r_v<void, _Function, const Error*, Variant>, "Property get callback function must accept Error* and property value as Variant");
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_)
.uponReplyInvoke(std::forward<_Function>(callback));
}
inline std::future<Variant> AsyncPropertyGetter::getResultAsFuture()
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_)
.getResultAsFuture<Variant>();
}
/*** -------------- ***/
/*** PropertySetter ***/
/*** -------------- ***/
@@ -780,9 +666,9 @@ namespace sdbus {
{
}
inline PropertySetter& PropertySetter::onInterface(const std::string& interfaceName)
inline PropertySetter& PropertySetter::onInterface(std::string interfaceName)
{
interfaceName_ = &interfaceName;
interfaceName_ = std::move(interfaceName);
return *this;
}
@@ -790,144 +676,17 @@ namespace sdbus {
template <typename _Value>
inline void PropertySetter::toValue(const _Value& value)
{
PropertySetter::toValue(Variant{value});
PropertySetter::toValue(sdbus::Variant{value});
}
template <typename _Value>
inline void PropertySetter::toValue(const _Value& value, dont_expect_reply_t)
inline void PropertySetter::toValue(const sdbus::Variant& value)
{
PropertySetter::toValue(Variant{value}, dont_expect_reply);
}
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
inline void PropertySetter::toValue(const Variant& value)
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
proxy_.callMethod("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_, value);
}
inline void PropertySetter::toValue(const Variant& value, dont_expect_reply_t)
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
proxy_.callMethod("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_, value)
.dontExpectReply();
}
/*** ------------------- ***/
/*** AsyncPropertySetter ***/
/*** ------------------- ***/
inline AsyncPropertySetter::AsyncPropertySetter(IProxy& proxy, const std::string& propertyName)
: proxy_(proxy)
, propertyName_(propertyName)
{
}
inline AsyncPropertySetter& AsyncPropertySetter::onInterface(const std::string& interfaceName)
{
interfaceName_ = &interfaceName;
return *this;
}
template <typename _Value>
inline AsyncPropertySetter& AsyncPropertySetter::toValue(_Value&& value)
{
return AsyncPropertySetter::toValue(Variant{std::forward<_Value>(value)});
}
inline AsyncPropertySetter& AsyncPropertySetter::toValue(Variant value)
{
value_ = std::move(value);
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncPropertySetter::uponReplyInvoke(_Function&& callback)
{
static_assert(std::is_invocable_r_v<void, _Function, const Error*>, "Property set callback function must accept Error* only");
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_, std::move(value_))
.uponReplyInvoke(std::forward<_Function>(callback));
}
inline std::future<void> AsyncPropertySetter::getResultAsFuture()
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_, propertyName_, std::move(value_))
.getResultAsFuture<>();
}
/*** ------------------- ***/
/*** AllPropertiesGetter ***/
/*** ------------------- ***/
inline AllPropertiesGetter::AllPropertiesGetter(IProxy& proxy)
: proxy_(proxy)
{
}
inline std::map<std::string, Variant> AllPropertiesGetter::onInterface(const std::string& interfaceName)
{
std::map<std::string, Variant> props;
proxy_.callMethod("GetAll")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName)
.storeResultsTo(props);
return props;
}
/*** ------------------------ ***/
/*** AsyncAllPropertiesGetter ***/
/*** ------------------------ ***/
inline AsyncAllPropertiesGetter::AsyncAllPropertiesGetter(IProxy& proxy)
: proxy_(proxy)
{
}
inline AsyncAllPropertiesGetter& AsyncAllPropertiesGetter::onInterface(const std::string& interfaceName)
{
interfaceName_ = &interfaceName;
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncAllPropertiesGetter::uponReplyInvoke(_Function&& callback)
{
static_assert( std::is_invocable_r_v<void, _Function, const Error*, std::map<std::string, Variant>>
, "All properties get callback function must accept Error* and a map of property names to their values" );
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("GetAll")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_)
.uponReplyInvoke(std::forward<_Function>(callback));
}
inline std::future<std::map<std::string, Variant>> AsyncAllPropertiesGetter::getResultAsFuture()
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("GetAll")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(*interfaceName_)
.getResultAsFuture<std::map<std::string, Variant>>();
proxy_
.callMethod("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName_, propertyName_, value);
}
}
+2 -9
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Error.h
*
@@ -43,11 +43,6 @@ namespace sdbus {
: public std::runtime_error
{
public:
explicit Error(const std::string& name, const char* message = nullptr)
: Error(name, std::string(message ? message : ""))
{
}
Error(const std::string& name, const std::string& message)
: std::runtime_error("[" + name + "] " + message)
, name_(name)
@@ -76,8 +71,6 @@ namespace sdbus {
};
sdbus::Error createError(int errNo, const std::string& customMsg);
inline const char* SDBUSCPP_ERROR_NAME = "org.sdbuscpp.Error";
}
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Flags.h
*
@@ -93,7 +93,7 @@ namespace sdbus {
private:
std::bitset<FLAG_COUNT> flags_;
};
}
#endif /* SDBUS_CXX_FLAGS_H_ */
+12 -267
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file IConnection.h
*
@@ -27,14 +27,10 @@
#ifndef SDBUS_CXX_ICONNECTION_H_
#define SDBUS_CXX_ICONNECTION_H_
#include <sdbus-c++/TypeTraits.h>
#include <string>
#include <memory>
#include <chrono>
#include <cstdint>
#include <optional>
struct sd_bus;
namespace sdbus {
@@ -51,61 +47,11 @@ namespace sdbus {
class IConnection
{
public:
/*!
* Poll Data for external event loop implementations.
*
* To integrate sdbus with your app's own custom event handling system
* you can use this method to query which file descriptors, poll events
* and timeouts you should add to your app's poll(2), or select(2)
* call in your main event loop.
*
* If you are unsure what this all means then use
* enterEventLoop() or enterEventLoopAsync() instead.
*
* See: getEventLoopPollData()
*/
struct PollData
{
/*!
* The read fd to be monitored by the event loop.
*/
int fd;
/*!
* The events to use for poll(2) alongside fd.
*/
short int events;
/*!
* Absolute timeout value in micro seconds and based of CLOCK_MONOTONIC.
*/
uint64_t timeout_usec;
/*!
* Get the event poll timeout.
*
* The timeout is an absolute value based of CLOCK_MONOTONIC.
*
* @return a duration since the CLOCK_MONOTONIC epoch started.
*/
[[nodiscard]] std::chrono::microseconds getAbsoluteTimeout() const
{
return std::chrono::microseconds(timeout_usec);
}
/*!
* Get the timeout as relative value from now
*
* @return std::nullopt if the timeout is indefinite. A duration otherwise.
*/
[[nodiscard]] std::optional<std::chrono::microseconds> getRelativeTimeout() const;
/*!
* Get a converted, relative timeout which can be passed as argument 'timeout' to poll(2)
*
* @return -1 if the timeout is indefinite. 0 if the poll(2) shouldn't block. An integer in milli
* seconds otherwise.
*/
[[nodiscard]] int getPollTimeout() const;
};
virtual ~IConnection() = default;
@@ -169,15 +115,9 @@ namespace sdbus {
* the connection. This is a convenient way to interrogate a connection
* to see what objects it has.
*
* This call creates a floating registration. The ObjectManager will
* be there for the object path until the connection is destroyed.
*
* Another, recommended way to add object managers is directly through
* IObject API.
*
* @throws sdbus::Error in case of failure
*/
[[deprecated("Use one of other addObjectManager overloads")]] virtual void addObjectManager(const std::string& objectPath) = 0;
virtual void addObjectManager(const std::string& objectPath) = 0;
/*!
* @brief Returns fd, I/O events and timeout data you can pass to poll
@@ -250,102 +190,6 @@ namespace sdbus {
*/
virtual uint64_t getMethodCallTimeout() const = 0;
/*!
* @brief Adds an ObjectManager at the specified D-Bus object path
*
* Creates an ObjectManager interface at the specified object path on
* the connection. This is a convenient way to interrogate a connection
* to see what objects it has.
*
* This call creates a floating registration. The ObjectManager will
* be there for the object path until the connection is destroyed.
*
* Another, recommended way to add object managers is directly through
* IObject API.
*
* @throws sdbus::Error in case of failure
*/
virtual void addObjectManager(const std::string& objectPath, floating_slot_t) = 0;
/*!
* @brief Installs a match rule for messages received on this bus connection
*
* @param[in] match Match expression to filter incoming D-Bus message
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
* @return RAII-style slot handle representing the ownership of the subscription
*
* The method installs a match rule for messages received on the specified bus connection.
* The syntax of the match rule expression passed in match is described in the D-Bus specification.
* The specified handler function callback is called for each incoming message matching the specified
* expression. The match is installed synchronously when connected to a bus broker, i.e. the call
* sends a control message requested the match to be added to the broker and waits until the broker
* confirms the match has been installed successfully.
*
* Simply let go of the slot instance to uninstall the match rule from the bus connection. The slot
* must not outlive the connection for the slot is associated with it.
*
* For more information, consult `man sd_bus_add_match`.
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler callback) = 0;
/*!
* @brief Installs a floating match rule for messages received on this bus connection
*
* @param[in] match Match expression to filter incoming D-Bus message
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
*
* The method installs a floating match rule for messages received on the specified bus connection.
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
* is bound to the lifetime of the bus connection.
*
* Refer to the @c addMatch(const std::string& match, message_handler callback) documentation for more
* information.
*
* @throws sdbus::Error in case of failure
*/
virtual void addMatch(const std::string& match, message_handler callback, floating_slot_t) = 0;
/*!
* @brief Asynchronously installs a match rule for messages received on this bus connection
*
* @param[in] match Match expression to filter incoming D-Bus message
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
* @return RAII-style slot handle representing the ownership of the subscription
*
* This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously,
* in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response.
* The `installCallback' callable is called when the response is later received, with the response message
* from the broker as parameter. If it's an empty function object, a default implementation is used that
* terminates the bus connection should installing the match fail.
*
* Refer to the @c addMatch(const std::string& match, message_handler callback) documentation, and consult
* `man sd_bus_add_match`, for more information.
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] virtual Slot addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0;
/*!
* @brief Asynchronously installs a floating match rule for messages received on this bus connection
*
* @param[in] match Match expression to filter incoming D-Bus message
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
*
* The method installs a floating match rule for messages received on the specified bus connection.
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
* is bound to the lifetime of the bus connection.
*
* Refer to the @c addMatch(const std::string& match, message_handler callback, message_handler installCallback)
* documentation for more information.
*
* @throws sdbus::Error in case of failure
*/
virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) = 0;
/*!
* @copydoc IConnection::enterEventLoop()
*
@@ -354,21 +198,21 @@ namespace sdbus {
[[deprecated("This function has been replaced by enterEventLoop()")]] void enterProcessingLoop();
/*!
* @copydoc IConnection::enterEventLoopAsync()
* @copydoc IConnection::enterProcessingLoopAsync()
*
* @deprecated This function has been replaced by enterEventLoopAsync()
*/
[[deprecated("This function has been replaced by enterEventLoopAsync()")]] void enterProcessingLoopAsync();
/*!
* @copydoc IConnection::leaveEventLoop()
* @copydoc IConnection::leaveProcessingLoop()
*
* @deprecated This function has been replaced by leaveEventLoop()
*/
[[deprecated("This function has been replaced by leaveEventLoop()")]] void leaveProcessingLoop();
/*!
* @copydoc IConnection::getEventLoopPollData()
* @copydoc IConnection::getProcessLoopPollData()
*
* @deprecated This function has been replaced by getEventLoopPollData()
*/
@@ -403,7 +247,7 @@ namespace sdbus {
}
/*!
* @brief Creates/opens D-Bus system bus connection
* @brief Creates/opens D-Bus system connection
*
* @return Connection instance
*
@@ -412,7 +256,7 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createConnection();
/*!
* @brief Creates/opens D-Bus system bus connection with a name
* @brief Creates/opens D-Bus system connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
@@ -422,26 +266,7 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus session bus connection when in a user context, and a system bus connection, otherwise.
*
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDefaultBusConnection();
/*!
* @brief Creates/opens D-Bus session bus connection with a name when in a user context, and a system bus connection with a name, otherwise.
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDefaultBusConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus system bus connection
* @brief Creates/opens D-Bus system connection
*
* @return Connection instance
*
@@ -450,7 +275,7 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection();
/*!
* @brief Creates/opens D-Bus system bus connection with a name
* @brief Creates/opens D-Bus system connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
@@ -460,7 +285,7 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus session bus connection
* @brief Creates/opens D-Bus session connection
*
* @return Connection instance
*
@@ -469,7 +294,7 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection();
/*!
* @brief Creates/opens D-Bus session bus connection with a name
* @brief Creates/opens D-Bus session connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
@@ -478,18 +303,6 @@ namespace sdbus {
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus session bus connection at a custom address
*
* @param[in] address ";"-separated list of addresses of bus brokers to try to connect
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*
* Consult manual pages for `sd_bus_set_address` of the underlying sd-bus library for more information.
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string& address);
/*!
* @brief Creates/opens D-Bus system connection on a remote host using ssh
*
@@ -499,74 +312,6 @@ namespace sdbus {
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host);
/*!
* @brief Opens direct D-Bus connection at a custom address
*
* @param[in] address ";"-separated list of addresses of bus brokers to try to connect to
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address);
/*!
* @brief Opens direct D-Bus connection at the given file descriptor
*
* @param[in] fd File descriptor used to communicate directly from/to a D-Bus server
* @return Connection instance
*
* The underlying sdbus-c++ connection instance takes over ownership of fd, so the caller can let it go.
* If, however, the call throws an exception, the ownership of fd remains with the caller.
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd);
/*!
* @brief Opens direct D-Bus connection at fd as a server
*
* @param[in] fd File descriptor to use for server DBus connection
* @return Server connection instance
*
* This creates a new, custom bus object in server mode. One can then call createDirectBusConnection()
* on client side to connect to this bus.
*
* The underlying sdbus-c++ connection instance takes over ownership of fd, so the caller can let it go.
* If, however, the call throws an exception, the ownership of fd remains with the caller.
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createServerBus(int fd);
/*!
* @brief Creates sdbus-c++ bus connection representation out of underlying sd_bus instance
*
* @param[in] bus File descriptor to use for server DBus connection
* @return Connection instance
*
* This functions is helpful in cases where clients need a custom, tweaked configuration of their
* bus object. Since sdbus-c++ does not provide C++ API for all bus connection configuration
* functions of the underlying sd-bus library, clients can use these sd-bus functions themselves
* to create and configure their sd_bus object, and create sdbus-c++ IConnection on top of it.
*
* The IConnection instance assumes unique ownership of the provided bus object. The bus object
* must have been started by the client before this call.
* The bus object will get flushed, closed, and unreffed when the IConnection instance is destroyed.
*
* @throws sdbus::Error in case of failure
*
* Code example:
* @code
* sd_bus* bus{};
* ::sd_bus_new(&bus);
* ::sd_bus_set_address(bus, address);
* ::sd_bus_set_anonymous(bus, true);
* ::sd_bus_start(bus);
* auto con = sdbus::createBusConnection(bus); // IConnection consumes sd_bus object
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus);
}
#endif /* SDBUS_CXX_ICONNECTION_H_ */
+2 -18
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file IObject.h
*
@@ -440,22 +440,6 @@ namespace sdbus {
* @brief Returns object path of the underlying DBus object
*/
virtual const std::string& getObjectPath() const = 0;
/*!
* @brief Provides currently processed D-Bus message
*
* This method provides immutable access to the currently processed incoming D-Bus message.
* "Currently processed" means that the registered callback handler(s) for that message
* are being invoked. This method is meant to be called from within a callback handler
* (e.g. D-Bus method implementation handler). In such a case it is guaranteed to return
* a valid pointer to the D-Bus message for which the handler is called. If called from other
* contexts/threads, it may return a nonzero pointer or a nullptr, depending on whether a message
* was processed at the time of call or not, but the value is nondereferencable, since the pointed-to
* message may have gone in the meantime.
*
* @return A pointer to the currently processed D-Bus message
*/
virtual const Message* getCurrentlyProcessedMessage() const = 0;
};
// Out-of-line member definitions
+11 -261
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file IProxy.h
*
@@ -28,12 +28,10 @@
#define SDBUS_CXX_IPROXY_H_
#include <sdbus-c++/ConvenienceApiClasses.h>
#include <sdbus-c++/TypeTraits.h>
#include <string>
#include <memory>
#include <functional>
#include <chrono>
#include <future>
// Forward declarations
namespace sdbus {
@@ -83,7 +81,7 @@ namespace sdbus {
virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
/*!
* @brief Calls method on the D-Bus object
* @brief Calls method on the proxied D-Bus object
*
* @param[in] message Message representing a method call
* @param[in] timeout Timeout for dbus call in microseconds
@@ -109,7 +107,7 @@ namespace sdbus {
MethodReply callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout);
/*!
* @brief Calls method on the D-Bus object asynchronously
* @brief Calls method on the proxied D-Bus object asynchronously
*
* @param[in] message Message representing an async method call
* @param[in] asyncReplyCallback Handler for the async reply
@@ -133,7 +131,7 @@ namespace sdbus {
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout);
/*!
* @brief Registers a handler for the desired signal emitted by the D-Bus object
* @brief Registers a handler for the desired signal emitted by the proxied D-Bus object
*
* @param[in] interfaceName Name of an interface that the signal belongs to
* @param[in] signalName Name of the signal
@@ -145,17 +143,6 @@ namespace sdbus {
, const std::string& signalName
, signal_handler signalHandler ) = 0;
/*!
* @brief Unregisters the handler of the desired signal
*
* @param[in] interfaceName Name of an interface that the signal belongs to
* @param[in] signalName Name of the signal
*
* @throws sdbus::Error in case of failure
*/
virtual void unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName ) = 0;
/*!
* @brief Finishes the registration of signal handlers
*
@@ -178,7 +165,7 @@ namespace sdbus {
virtual void unregister() = 0;
/*!
* @brief Calls method on the D-Bus object
* @brief Calls method on the proxied D-Bus object
*
* @param[in] methodName Name of the method
* @return A helper object for convenient invocation of the method
@@ -199,7 +186,7 @@ namespace sdbus {
[[nodiscard]] MethodInvoker callMethod(const std::string& methodName);
/*!
* @brief Calls method on the D-Bus object asynchronously
* @brief Calls method on the proxied D-Bus object asynchronously
*
* @param[in] methodName Name of the method
* @return A helper object for convenient asynchronous invocation of the method
@@ -223,7 +210,7 @@ namespace sdbus {
[[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName);
/*!
* @brief Registers signal handler for a given signal of the D-Bus object
* @brief Registers signal handler for a given signal of the proxied D-Bus object
*
* @param[in] signalName Name of the signal
* @return A helper object for convenient registration of the signal handler
@@ -243,24 +230,7 @@ namespace sdbus {
[[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);
/*!
* @brief Unregisters signal handler of a given signal of the D-Bus object
*
* @param[in] signalName Name of the signal
* @return A helper object for convenient unregistration of the signal handler
*
* This is a high-level, convenience way of unregistering a D-Bus signal's handler.
*
* Example of use:
* @code
* object_.muteSignal("fooSignal").onInterface("com.kistler.foo");
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] SignalUnsubscriber muteSignal(const std::string& signalName);
/*!
* @brief Gets value of a property of the D-Bus object
* @brief Gets value of a property of the proxied D-Bus object
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient getting of property value
@@ -279,156 +249,28 @@ namespace sdbus {
[[nodiscard]] PropertyGetter getProperty(const std::string& propertyName);
/*!
* @brief Gets value of a property of the D-Bus object asynchronously
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient asynchronous getting of property value
*
* This is a high-level, convenience way of reading D-Bus property values that abstracts
* from the D-Bus message concept.
*
* Example of use:
* @code
* std::future<sdbus::Variant> state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture();
* auto callback = [](const sdbus::Error* err, const sdbus::Variant& value){ ... };
* object.getPropertyAsync("state").onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback));
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] AsyncPropertyGetter getPropertyAsync(const std::string& propertyName);
/*!
* @brief Sets value of a property of the D-Bus object
* @brief Sets value of a property of the proxied D-Bus object
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient setting of property value
*
* This is a high-level, convenience way of writing D-Bus property values that abstracts
* from the D-Bus message concept.
* Setting property value with NoReply flag is also supported.
*
* Example of use:
* @code
* int state = ...;
* object_.setProperty("state").onInterface("com.kistler.foo").toValue(state);
* // Or we can just send the set message call without waiting for the reply
* object_.setProperty("state").onInterface("com.kistler.foo").toValue(state, dont_expect_reply);
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] PropertySetter setProperty(const std::string& propertyName);
/*!
* @brief Sets value of a property of the D-Bus object asynchronously
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient asynchronous setting of property value
*
* This is a high-level, convenience way of writing D-Bus property values that abstracts
* from the D-Bus message concept.
*
* Example of use:
* @code
* int state = ...;
* // We can wait until the set operation finishes by waiting on the future
* std::future<void> res = object_.setPropertyAsync("state").onInterface("com.kistler.foo").toValue(state).getResultAsFuture();
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] AsyncPropertySetter setPropertyAsync(const std::string& propertyName);
/*!
* @brief Gets values of all properties of the D-Bus object
*
* @return A helper object for convenient getting of properties' values
*
* This is a high-level, convenience way of reading D-Bus properties' values that abstracts
* from the D-Bus message concept.
*
* Example of use:
* @code
* auto props = object.getAllProperties().onInterface("com.kistler.foo");
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] AllPropertiesGetter getAllProperties();
/*!
* @brief Gets values of all properties of the D-Bus object asynchronously
*
* @return A helper object for convenient asynchronous getting of properties' values
*
* This is a high-level, convenience way of reading D-Bus properties' values that abstracts
* from the D-Bus message concept.
*
* Example of use:
* @code
* auto callback = [](const sdbus::Error* err, const std::map<std::string, Variant>>& properties){ ... };
* auto props = object.getAllPropertiesAsync().onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback));
* @endcode
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] AsyncAllPropertiesGetter getAllPropertiesAsync();
/*!
* @brief Provides D-Bus connection used by the proxy
*
* @return Reference to the D-Bus connection
*/
virtual sdbus::IConnection& getConnection() const = 0;
/*!
* @brief Returns object path of the underlying DBus object
*/
virtual const std::string& getObjectPath() const = 0;
/*!
* @brief Provides currently processed D-Bus message
*
* This method provides immutable access to the currently processed incoming D-Bus message.
* "Currently processed" means that the registered callback handler(s) for that message
* are being invoked. This method is meant to be called from within a callback handler
* (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is
* guaranteed to return a valid pointer to the D-Bus message for which the handler is called.
* If called from other contexts/threads, it may return a nonzero pointer or a nullptr, depending
* on whether a message was processed at the time of call or not, but the value is nondereferencable,
* since the pointed-to message may have gone in the meantime.
*
* @return A pointer to the currently processed D-Bus message
*/
virtual const Message* getCurrentlyProcessedMessage() const = 0;
/*!
* @brief Calls method on the D-Bus object asynchronously
*
* @param[in] message Message representing an async method call
* @param[in] asyncReplyCallback Handler for the async reply
* @param[in] timeout Timeout for dbus call in microseconds
* @return Cookie for the the pending asynchronous call
*
* The call is non-blocking. It doesn't wait for the reply. Once the reply arrives,
* the provided async reply handler will get invoked from the context of the connection
* I/O event loop thread.
*
* Note: To avoid messing with messages, use higher-level API defined below.
*
* @throws sdbus::Error in case of failure
*/
virtual std::future<MethodReply> callMethod(const MethodCall& message, with_future_t) = 0;
virtual std::future<MethodReply> callMethod(const MethodCall& message, uint64_t timeout, with_future_t) = 0;
/*!
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t)
*/
template <typename _Rep, typename _Period>
std::future<MethodReply> callMethod( const MethodCall& message
, const std::chrono::duration<_Rep, _Period>& timeout
, with_future_t );
};
/********************************************//**
@@ -444,8 +286,6 @@ namespace sdbus {
class PendingAsyncCall
{
public:
PendingAsyncCall() = default;
/*!
* @brief Cancels the delivery of the pending asynchronous call result
*
@@ -489,15 +329,6 @@ namespace sdbus {
return callMethod(message, std::move(asyncReplyCallback), microsecs.count());
}
template <typename _Rep, typename _Period>
inline std::future<MethodReply> IProxy::callMethod( const MethodCall& message
, const std::chrono::duration<_Rep, _Period>& timeout
, with_future_t )
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethod(message, microsecs.count(), with_future);
}
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
{
return MethodInvoker(*this, methodName);
@@ -513,41 +344,16 @@ namespace sdbus {
return SignalSubscriber(*this, signalName);
}
inline SignalUnsubscriber IProxy::muteSignal(const std::string& signalName)
{
return SignalUnsubscriber(*this, signalName);
}
inline PropertyGetter IProxy::getProperty(const std::string& propertyName)
{
return PropertyGetter(*this, propertyName);
}
inline AsyncPropertyGetter IProxy::getPropertyAsync(const std::string& propertyName)
{
return AsyncPropertyGetter(*this, propertyName);
}
inline PropertySetter IProxy::setProperty(const std::string& propertyName)
{
return PropertySetter(*this, propertyName);
}
inline AsyncPropertySetter IProxy::setPropertyAsync(const std::string& propertyName)
{
return AsyncPropertySetter(*this, propertyName);
}
inline AllPropertiesGetter IProxy::getAllProperties()
{
return AllPropertiesGetter(*this);
}
inline AsyncAllPropertiesGetter IProxy::getAllPropertiesAsync()
{
return AsyncAllPropertiesGetter(*this);
}
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
*
@@ -562,9 +368,6 @@ namespace sdbus {
* should make sure that an I/O event loop is running on that connection, so the proxy
* may receive incoming signals and asynchronous method replies.
*
* The destination parameter may be an empty string (useful e.g. in case of direct
* D-Bus connections to a custom server bus).
*
* Code example:
* @code
* auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo");
@@ -588,9 +391,6 @@ namespace sdbus {
* upon that connection in a separate internal thread. Handlers for incoming signals and
* asynchronous method replies will be executed in the context of that thread.
*
* The destination parameter may be an empty string (useful e.g. in case of direct
* D-Bus connections to a custom server bus).
*
* Code example:
* @code
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
@@ -600,34 +400,6 @@ namespace sdbus {
, std::string destination
, std::string objectPath );
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
*
* @param[in] connection D-Bus connection to be used by the proxy object
* @param[in] destination Bus name that provides the remote D-Bus object
* @param[in] objectPath Path of the remote D-Bus object
* @return Pointer to the object proxy instance
*
* The provided connection will be used by the proxy to issue calls against the object.
* The Object proxy becomes an exclusive owner of this connection, but will not start
* an event loop thread on this connection. This is cheap construction and is suitable
* for short-lived proxies created just to execute simple synchronous D-Bus calls and
* then destroyed. Such blocking request-reply calls will work without an event loop
* (but signals, async calls, etc. won't).
*
* The destination parameter may be an empty string (useful e.g. in case of direct
* D-Bus connections to a custom server bus).
*
* Code example:
* @code
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread);
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
, std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t );
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
*
@@ -636,7 +408,7 @@ namespace sdbus {
* @return Pointer to the object proxy instance
*
* No D-Bus connection is provided here, so the object proxy will create and manage
* his own connection, and will automatically start an event loop upon that connection
* his own connection, and will automatically start a procesing loop upon that connection
* in a separate internal thread. Handlers for incoming signals and asynchronous
* method replies will be executed in the context of that thread.
*
@@ -648,28 +420,6 @@ namespace sdbus {
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
, std::string objectPath );
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
*
* @param[in] destination Bus name that provides the remote D-Bus object
* @param[in] objectPath Path of the remote D-Bus object
* @return Pointer to the object proxy instance
*
* No D-Bus connection is provided here, so the object proxy will create and manage
* his own connection, but it will not start an event loop thread. This is cheap
* construction and is suitable for short-lived proxies created just to execute simple
* synchronous D-Bus calls and then destroyed. Such blocking request-reply calls
* will work without an event loop (but signals, async calls, etc. won't).
*
* Code example:
* @code
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread );
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t );
}
#include <sdbus-c++/ConvenienceApiClasses.inl>
+77 -303
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Message.h
*
@@ -31,18 +31,12 @@
#include <sdbus-c++/Error.h>
#include <string>
#include <vector>
#include <array>
#if __cplusplus >= 202002L
#include <span>
#endif
#include <map>
#include <unordered_map>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include <functional>
#include <sys/types.h>
#include <algorithm>
// Forward declarations
namespace sdbus {
@@ -54,17 +48,21 @@ namespace sdbus {
class MethodReply;
namespace internal {
class ISdBus;
class IConnection;
}
}
namespace sdbus {
// Assume the caller has already obtained message ownership
struct adopt_message_t { explicit adopt_message_t() = default; };
inline constexpr adopt_message_t adopt_message{};
/********************************************//**
* @class Message
*
* Message represents a D-Bus message, which can be either method call message,
* method reply message, signal message, or a plain message.
* method reply message, signal message, or a plain message serving as a storage
* for serialized data.
*
* Serialization and deserialization functions are provided for types supported
* by D-Bus.
@@ -92,23 +90,6 @@ namespace sdbus {
Message& operator<<(const Signature &item);
Message& operator<<(const UnixFd &item);
template <typename _Element, typename _Allocator>
Message& operator<<(const std::vector<_Element, _Allocator>& items);
template <typename _Element, std::size_t _Size>
Message& operator<<(const std::array<_Element, _Size>& items);
#if __cplusplus >= 202002L
template <typename _Element, std::size_t _Extent>
Message& operator<<(const std::span<_Element, _Extent>& items);
#endif
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
Message& operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items);
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
Message& operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
template <typename... _ValueTypes>
Message& operator<<(const Struct<_ValueTypes...>& item);
template <typename... _ValueTypes>
Message& operator<<(const std::tuple<_ValueTypes...>& item);
Message& operator>>(bool& item);
Message& operator>>(int16_t& item);
Message& operator>>(int32_t& item);
@@ -124,22 +105,6 @@ namespace sdbus {
Message& operator>>(ObjectPath &item);
Message& operator>>(Signature &item);
Message& operator>>(UnixFd &item);
template <typename _Element, typename _Allocator>
Message& operator>>(std::vector<_Element, _Allocator>& items);
template <typename _Element, std::size_t _Size>
Message& operator>>(std::array<_Element, _Size>& items);
#if __cplusplus >= 202002L
template <typename _Element, std::size_t _Extent>
Message& operator>>(std::span<_Element, _Extent>& items);
#endif
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
Message& operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items);
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
Message& operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
template <typename... _ValueTypes>
Message& operator>>(Struct<_ValueTypes...>& item);
template <typename... _ValueTypes>
Message& operator>>(std::tuple<_ValueTypes...>& item);
Message& openContainer(const std::string& signature);
Message& closeContainer();
@@ -159,55 +124,22 @@ namespace sdbus {
Message& enterStruct(const std::string& signature);
Message& exitStruct();
Message& appendArray(char type, const void *ptr, size_t size);
Message& readArray(char type, const void **ptr, size_t *size);
explicit operator bool() const;
void clearFlags();
std::string getInterfaceName() const;
std::string getMemberName() const;
std::string getSender() const;
std::string getPath() const;
std::string getDestination() const;
void peekType(std::string& type, std::string& contents) const;
bool isValid() const;
bool isEmpty() const;
bool isAtEnd(bool complete) const;
void copyTo(Message& destination, bool complete) const;
void seal();
void rewind(bool complete);
pid_t getCredsPid() const;
uid_t getCredsUid() const;
uid_t getCredsEuid() const;
gid_t getCredsGid() const;
gid_t getCredsEgid() const;
std::vector<gid_t> getCredsSupplementaryGids() const;
std::string getSELinuxContext() const;
class Factory;
private:
template <typename _Array>
void serializeArray(const _Array& items);
template <typename _Array>
void deserializeArray(_Array& items);
template <typename _Array>
void deserializeArrayFast(_Array& items);
template <typename _Element, typename _Allocator>
void deserializeArrayFast(std::vector<_Element, _Allocator>& items);
template <typename _Array>
void deserializeArraySlow(_Array& items);
template <typename _Element, typename _Allocator>
void deserializeArraySlow(std::vector<_Element, _Allocator>& items);
template <typename _Dictionary>
void serializeDictionary(const _Dictionary& items);
template <typename _Dictionary>
void deserializeDictionary(_Dictionary& items);
protected:
Message() = default;
explicit Message(internal::ISdBus* sdbus) noexcept;
@@ -229,17 +161,21 @@ namespace sdbus {
mutable bool ok_{true};
};
struct dont_request_slot_t { explicit dont_request_slot_t() = default; };
inline constexpr dont_request_slot_t dont_request_slot{};
class MethodCall : public Message
{
using Message::Message;
friend Factory;
public:
using Slot = std::unique_ptr<void, std::function<void(void*)>>;
MethodCall() = default;
MethodReply send(uint64_t timeout) const;
[[deprecated("Use send overload with floating_slot instead")]] void send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const;
void send(void* callback, void* userData, uint64_t timeout, floating_slot_t) const;
void send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const;
[[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const;
MethodReply createReply() const;
@@ -248,13 +184,9 @@ namespace sdbus {
void dontExpectReply();
bool doesntExpectReply() const;
protected:
MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept;
private:
MethodReply sendWithReply(uint64_t timeout = 0) const;
MethodReply sendWithNoReply() const;
const internal::IConnection* connection_{};
};
class MethodReply : public Message
@@ -274,7 +206,6 @@ namespace sdbus {
public:
Signal() = default;
void setDestination(const std::string& destination);
void send() const;
};
@@ -296,7 +227,6 @@ namespace sdbus {
PropertyGetReply() = default;
};
// Represents any of the above message types, or just a message that serves as a container for data
class PlainMessage : public Message
{
using Message::Message;
@@ -306,90 +236,38 @@ namespace sdbus {
PlainMessage() = default;
};
template <typename _Element, typename _Allocator>
inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
template <typename _Element>
inline Message& operator<<(Message& msg, const std::vector<_Element>& items)
{
serializeArray(items);
msg.openContainer(signature_of<_Element>::str());
return *this;
for (const auto& item : items)
msg << item;
msg.closeContainer();
return msg;
}
template <typename _Element, std::size_t _Size>
inline Message& Message::operator<<(const std::array<_Element, _Size>& items)
template <typename _Key, typename _Value>
inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items)
{
serializeArray(items);
return *this;
}
#if __cplusplus >= 202002L
template <typename _Element, std::size_t _Extent>
inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
{
serializeArray(items);
return *this;
}
#endif
template <typename _Array>
inline void Message::serializeArray(const _Array& items)
{
using ElementType = typename _Array::value_type;
// Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool,
// otherwise use step-by-step serialization of individual elements.
if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
{
appendArray(*signature_of<ElementType>::str().c_str(), items.data(), items.size() * sizeof(ElementType));
}
else
{
openContainer(signature_of<ElementType>::str());
for (const auto& item : items)
*this << item;
closeContainer();
}
}
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
{
serializeDictionary(items);
return *this;
}
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
{
serializeDictionary(items);
return *this;
}
template <typename _Dictionary>
inline void Message::serializeDictionary(const _Dictionary& items)
{
using KeyType = typename _Dictionary::key_type;
using ValueType = typename _Dictionary::mapped_type;
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
openContainer(arraySignature);
msg.openContainer(arraySignature);
for (const auto& item : items)
{
openDictEntry(dictEntrySignature);
*this << item.first;
*this << item.second;
closeDictEntry();
msg.openDictEntry(dictEntrySignature);
msg << item.first;
msg << item.second;
msg.closeDictEntry();
}
closeContainer();
msg.closeContainer();
return msg;
}
namespace detail
@@ -410,182 +288,78 @@ namespace sdbus {
}
template <typename... _ValueTypes>
inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
assert(structSignature.size() > 2);
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size() - 2);
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
openStruct(structContentSignature);
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
closeStruct();
msg.openStruct(structContentSignature);
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
msg.closeStruct();
return *this;
return msg;
}
template <typename... _ValueTypes>
inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item)
inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item)
{
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
return *this;
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
return msg;
}
template <typename _Element, typename _Allocator>
inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
template <typename _Element>
inline Message& operator>>(Message& msg, std::vector<_Element>& items)
{
deserializeArray(items);
return *this;
}
template <typename _Element, std::size_t _Size>
inline Message& Message::operator>>(std::array<_Element, _Size>& items)
{
deserializeArray(items);
return *this;
}
#if __cplusplus >= 202002L
template <typename _Element, std::size_t _Extent>
inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
{
deserializeArray(items);
return *this;
}
#endif
template <typename _Array>
inline void Message::deserializeArray(_Array& items)
{
using ElementType = typename _Array::value_type;
// Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool,
// otherwise use step-by-step deserialization of individual elements.
if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
{
deserializeArrayFast(items);
}
else
{
deserializeArraySlow(items);
}
}
template <typename _Array>
inline void Message::deserializeArrayFast(_Array& items)
{
using ElementType = typename _Array::value_type;
size_t arraySize{};
const ElementType* arrayPtr{};
readArray(*signature_of<ElementType>::str().c_str(), (const void**)&arrayPtr, &arraySize);
size_t elementsInMsg = arraySize / sizeof(ElementType);
bool notEnoughSpace = items.size() < elementsInMsg;
SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL);
std::copy_n(arrayPtr, elementsInMsg, items.begin());
}
template <typename _Element, typename _Allocator>
void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items)
{
size_t arraySize{};
const _Element* arrayPtr{};
readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize);
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
}
template <typename _Array>
inline void Message::deserializeArraySlow(_Array& items)
{
using ElementType = typename _Array::value_type;
if(!enterContainer(signature_of<ElementType>::str()))
return;
for (auto& elem : items)
if (!(*this >> elem))
break; // Keep the rest in the destination sequence untouched
SDBUS_THROW_ERROR_IF(!isAtEnd(false), "Failed to deserialize array: not enough space in destination sequence", EINVAL);
clearFlags();
exitContainer();
}
template <typename _Element, typename _Allocator>
void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
{
if(!enterContainer(signature_of<_Element>::str()))
return;
if(!msg.enterContainer(signature_of<_Element>::str()))
return msg;
while (true)
{
_Element elem;
if (*this >> elem)
if (msg >> elem)
items.emplace_back(std::move(elem));
else
break;
}
clearFlags();
msg.clearFlags();
exitContainer();
msg.exitContainer();
return msg;
}
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
template <typename _Key, typename _Value>
inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items)
{
deserializeDictionary(items);
return *this;
}
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
{
deserializeDictionary(items);
return *this;
}
template <typename _Dictionary>
inline void Message::deserializeDictionary(_Dictionary& items)
{
using KeyType = typename _Dictionary::key_type;
using ValueType = typename _Dictionary::mapped_type;
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
if (!enterContainer(arraySignature))
return;
if (!msg.enterContainer(arraySignature))
return msg;
while (true)
{
if (!enterDictEntry(dictEntrySignature))
if (!msg.enterDictEntry(dictEntrySignature))
break;
KeyType key;
ValueType value;
*this >> key >> value;
_Key key;
_Value value;
msg >> key >> value;
items.emplace(std::move(key), std::move(value));
exitDictEntry();
msg.exitDictEntry();
}
clearFlags();
msg.clearFlags();
exitContainer();
msg.exitContainer();
return msg;
}
namespace detail
@@ -606,27 +380,27 @@ namespace sdbus {
}
template <typename... _ValueTypes>
inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
if (!enterStruct(structContentSignature))
return *this;
if (!msg.enterStruct(structContentSignature))
return msg;
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
exitStruct();
msg.exitStruct();
return *this;
return msg;
}
template <typename... _ValueTypes>
inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item)
inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item)
{
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
return *this;
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
return msg;
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file MethodResult.h
*
@@ -76,7 +76,7 @@ namespace sdbus {
{
assert(call_.isValid());
auto reply = call_.createReply();
(void)(reply << ... << results);
(reply << ... << results);
reply.send();
}
+2 -38
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ProxyInterfaces.h
*
@@ -109,21 +109,6 @@ namespace sdbus {
{
}
/*!
* @brief Creates native-like proxy object instance
*
* @param[in] destination Bus name that provides a D-Bus object
* @param[in] objectPath Path of the D-Bus object
*
* This constructor overload creates a proxy that manages its own D-Bus connection(s).
* For more information on its behavior, consult @ref createProxy(std::string,std::string,sdbus::dont_run_event_loop_thread_t)
*/
ProxyInterfaces(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
, _Interfaces(getProxy())...
{
}
/*!
* @brief Creates native-like proxy object instance
*
@@ -156,22 +141,6 @@ namespace sdbus {
{
}
/*!
* @brief Creates native-like proxy object instance
*
* @param[in] connection D-Bus connection to be used by the proxy object
* @param[in] destination Bus name that provides a D-Bus object
* @param[in] objectPath Path of the D-Bus object
*
* The proxy created this way becomes an owner of the connection.
* For more information on its behavior, consult @ref createProxy(std::unique_ptr<sdbus::IConnection>&&,std::string,std::string,sdbus::dont_run_event_loop_thread_t)
*/
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
, _Interfaces(getProxy())...
{
}
/*!
* @brief Finishes proxy registration and makes the proxy ready for use
*
@@ -206,11 +175,6 @@ namespace sdbus {
protected:
using base_type = ProxyInterfaces;
ProxyInterfaces(const ProxyInterfaces&) = delete;
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
ProxyInterfaces(ProxyInterfaces&&) = default;
ProxyInterfaces& operator=(ProxyInterfaces&&) = default;
~ProxyInterfaces() = default;
};
+38 -162
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file StandardInterfaces.h
*
@@ -43,32 +43,27 @@ namespace sdbus {
protected:
Peer_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
}
Peer_proxy(const Peer_proxy&) = delete;
Peer_proxy& operator=(const Peer_proxy&) = delete;
Peer_proxy(Peer_proxy&&) = default;
Peer_proxy& operator=(Peer_proxy&&) = default;
~Peer_proxy() = default;
public:
void Ping()
{
proxy_->callMethod("Ping").onInterface(INTERFACE_NAME);
proxy_.callMethod("Ping").onInterface(INTERFACE_NAME);
}
std::string GetMachineId()
{
std::string machineUUID;
proxy_->callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
proxy_.callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
return machineUUID;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
// Proxy for introspection
@@ -78,27 +73,22 @@ namespace sdbus {
protected:
Introspectable_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
}
Introspectable_proxy(const Introspectable_proxy&) = delete;
Introspectable_proxy& operator=(const Introspectable_proxy&) = delete;
Introspectable_proxy(Introspectable_proxy&&) = default;
Introspectable_proxy& operator=(Introspectable_proxy&&) = default;
~Introspectable_proxy() = default;
public:
std::string Introspect()
{
std::string xml;
proxy_->callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
proxy_.callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
return xml;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
// Proxy for properties
@@ -108,10 +98,10 @@ namespace sdbus {
protected:
Properties_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
proxy_
->uponSignal("PropertiesChanged")
.uponSignal("PropertiesChanged")
.onInterface(INTERFACE_NAME)
.call([this]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
@@ -121,11 +111,6 @@ namespace sdbus {
});
}
Properties_proxy(const Properties_proxy&) = delete;
Properties_proxy& operator=(const Properties_proxy&) = delete;
Properties_proxy(Properties_proxy&&) = default;
Properties_proxy& operator=(Properties_proxy&&) = default;
~Properties_proxy() = default;
virtual void onPropertiesChanged( const std::string& interfaceName
@@ -135,59 +120,23 @@ namespace sdbus {
public:
sdbus::Variant Get(const std::string& interfaceName, const std::string& propertyName)
{
return proxy_->getProperty(propertyName).onInterface(interfaceName);
}
template <typename _Function>
PendingAsyncCall GetAsync(const std::string& interfaceName, const std::string& propertyName, _Function&& callback)
{
return proxy_->getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
}
std::future<sdbus::Variant> GetAsync(const std::string& interfaceName, const std::string& propertyName, with_future_t)
{
return proxy_->getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
return proxy_.getProperty(propertyName).onInterface(interfaceName);
}
void Set(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value)
{
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value);
}
void Set(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, dont_expect_reply_t)
{
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply);
}
template <typename _Function>
PendingAsyncCall SetAsync(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, _Function&& callback)
{
return proxy_->setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback));
}
std::future<void> SetAsync(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, with_future_t)
{
return proxy_->setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture();
proxy_.setProperty(propertyName).onInterface(interfaceName).toValue(value);
}
std::map<std::string, sdbus::Variant> GetAll(const std::string& interfaceName)
{
return proxy_->getAllProperties().onInterface(interfaceName);
}
template <typename _Function>
PendingAsyncCall GetAllAsync(const std::string& interfaceName, _Function&& callback)
{
return proxy_->getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
}
std::future<std::map<std::string, sdbus::Variant>> GetAllAsync(const std::string& interfaceName, with_future_t)
{
return proxy_->getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture();
std::map<std::string, sdbus::Variant> props;
proxy_.callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
return props;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
// Proxy for object manager
@@ -197,10 +146,10 @@ namespace sdbus {
protected:
ObjectManager_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
proxy_
->uponSignal("InterfacesAdded")
.uponSignal("InterfacesAdded")
.onInterface(INTERFACE_NAME)
.call([this]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
@@ -208,7 +157,8 @@ namespace sdbus {
this->onInterfacesAdded(objectPath, interfacesAndProperties);
});
proxy_->uponSignal("InterfacesRemoved")
proxy_
.uponSignal("InterfacesRemoved")
.onInterface(INTERFACE_NAME)
.call([this]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
@@ -217,11 +167,6 @@ namespace sdbus {
});
}
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
ObjectManager_proxy(ObjectManager_proxy&&) = default;
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default;
~ObjectManager_proxy() = default;
virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath
@@ -233,17 +178,17 @@ namespace sdbus {
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> GetManagedObjects()
{
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
proxy_->callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
proxy_.callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
return objectsInterfacesAndProperties;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
// Adaptors for the above-listed standard D-Bus interfaces are not necessary because the functionality
// is provided by underlying libsystemd implementation. The exception is Properties_adaptor,
// ObjectManager_adaptor and ManagedObject_adaptor, which provide convenience functionality to emit signals.
// is provided by underlying libsystemd implementation. The exception is Properties_adaptor and
// ObjectManager_adaptor, which provide convenience functionality to emit signals.
// Adaptor for properties
class Properties_adaptor
@@ -252,133 +197,64 @@ namespace sdbus {
protected:
Properties_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
}
Properties_adaptor(const Properties_adaptor&) = delete;
Properties_adaptor& operator=(const Properties_adaptor&) = delete;
Properties_adaptor(Properties_adaptor&&) = default;
Properties_adaptor& operator=(Properties_adaptor&&) = default;
~Properties_adaptor() = default;
public:
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& properties)
{
object_->emitPropertiesChangedSignal(interfaceName, properties);
object_.emitPropertiesChangedSignal(interfaceName, properties);
}
void emitPropertiesChangedSignal(const std::string& interfaceName)
{
object_->emitPropertiesChangedSignal(interfaceName);
object_.emitPropertiesChangedSignal(interfaceName);
}
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
/*!
* @brief Object Manager Convenience Adaptor
*
* Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces
* implements the *GetManagedObjects()* method of the [org.freedesktop.DBus.ObjectManager.GetManagedObjects](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
* interface.
*
* Note that there can be multiple object managers in a path hierarchy. InterfacesAdded/InterfacesRemoved
* signals are sent from the closest object manager at either the same path or the closest parent path of an object.
*/
// Adaptor for object manager
class ObjectManager_adaptor
{
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
protected:
explicit ObjectManager_adaptor(sdbus::IObject& object)
: object_(&object)
ObjectManager_adaptor(sdbus::IObject& object)
: object_(object)
{
object_->addObjectManager();
object_.addObjectManager();
}
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor(ObjectManager_adaptor&&) = default;
ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = default;
~ObjectManager_adaptor() = default;
private:
sdbus::IObject* object_;
};
/*!
* @brief Managed Object Convenience Adaptor
*
* Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces
* will extend the resulting object adaptor with emitInterfacesAddedSignal()/emitInterfacesRemovedSignal()
* according to org.freedesktop.DBus.ObjectManager.InterfacesAdded/.InterfacesRemoved.
*
* Note that objects which implement this adaptor require an object manager (e.g via ObjectManager_adaptor) to be
* instantiated on one of it's parent object paths or the same path. InterfacesAdded/InterfacesRemoved
* signals are sent from the closest object manager at either the same path or the closest parent path of an object.
*/
class ManagedObject_adaptor
{
protected:
explicit ManagedObject_adaptor(sdbus::IObject& object)
: object_(&object)
{
}
ManagedObject_adaptor(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor(ManagedObject_adaptor&&) = default;
ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = default;
~ManagedObject_adaptor() = default;
public:
/*!
* @brief Emits InterfacesAdded signal for this object path
*
* See IObject::emitInterfacesAddedSignal().
*/
void emitInterfacesAddedSignal()
{
object_->emitInterfacesAddedSignal();
object_.emitInterfacesAddedSignal();
}
/*!
* @brief Emits InterfacesAdded signal for this object path
*
* See IObject::emitInterfacesAddedSignal().
*/
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
{
object_->emitInterfacesAddedSignal(interfaces);
object_.emitInterfacesAddedSignal(interfaces);
}
/*!
* @brief Emits InterfacesRemoved signal for this object path
*
* See IObject::emitInterfacesRemovedSignal().
*/
void emitInterfacesRemovedSignal()
{
object_->emitInterfacesRemovedSignal();
object_.emitInterfacesRemovedSignal();
}
/*!
* @brief Emits InterfacesRemoved signal for this object path
*
* See IObject::emitInterfacesRemovedSignal().
*/
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
{
object_->emitInterfacesRemovedSignal(interfaces);
object_.emitInterfacesRemovedSignal(interfaces);
}
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}
+6 -141
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TypeTraits.h
*
@@ -30,15 +30,9 @@
#include <type_traits>
#include <string>
#include <vector>
#include <array>
#if __cplusplus >= 202002L
#include <span>
#endif
#include <map>
#include <unordered_map>
#include <cstdint>
#include <functional>
#include <memory>
#include <tuple>
// Forward declarations
@@ -51,7 +45,6 @@ namespace sdbus {
class MethodCall;
class MethodReply;
class Signal;
class Message;
class PropertySetCall;
class PropertyGetReply;
template <typename... _Results> class Result;
@@ -60,49 +53,16 @@ namespace sdbus {
namespace sdbus {
// Callbacks from sdbus-c++
using method_callback = std::function<void(MethodCall msg)>;
using async_reply_handler = std::function<void(MethodReply& reply, const Error* error)>;
using signal_handler = std::function<void(Signal& signal)>;
using message_handler = std::function<void(Message& msg)>;
using property_set_callback = std::function<void(PropertySetCall& msg)>;
using property_get_callback = std::function<void(PropertyGetReply& reply)>;
// Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++
using Slot = std::unique_ptr<void, std::function<void(void*)>>;
// Tag specifying that an owning slot handle shall be returned from the function
struct request_slot_t { explicit request_slot_t() = default; };
inline constexpr request_slot_t request_slot{};
// Tag specifying that the library shall own the slot resulting from the call of the function (so-called floating slot)
struct floating_slot_t { explicit floating_slot_t() = default; };
inline constexpr floating_slot_t floating_slot{};
// Deprecated name for the above -- a floating slot
struct dont_request_slot_t { explicit dont_request_slot_t() = default; };
[[deprecated("Replaced by floating_slot")]] inline constexpr dont_request_slot_t dont_request_slot{};
// Tag denoting the assumption that the caller has already obtained message ownership
struct adopt_message_t { explicit adopt_message_t() = default; };
inline constexpr adopt_message_t adopt_message{};
// Tag denoting the assumption that the caller has already obtained fd ownership
struct adopt_fd_t { explicit adopt_fd_t() = default; };
inline constexpr adopt_fd_t adopt_fd{};
// Tag specifying that the proxy shall not run an event loop thread on its D-Bus connection.
// Such proxies are typically created to carry out a simple synchronous D-Bus call(s) and then are destroyed.
struct dont_run_event_loop_thread_t { explicit dont_run_event_loop_thread_t() = default; };
inline constexpr dont_run_event_loop_thread_t dont_run_event_loop_thread{};
// Tag denoting an asynchronous call that returns std::future as a handle
struct with_future_t { explicit with_future_t() = default; };
inline constexpr with_future_t with_future{};
// Tag denoting a call where the reply shouldn't be waited for
struct dont_expect_reply_t { explicit dont_expect_reply_t() = default; };
inline constexpr dont_expect_reply_t dont_expect_reply{};
// Template specializations for getting D-Bus signatures from C++ types
template <typename _T>
struct signature_of
{
static constexpr bool is_valid = false;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -113,21 +73,10 @@ namespace sdbus {
}
};
template <typename _T>
struct signature_of<const _T>
: public signature_of<_T>
{};
template <typename _T>
struct signature_of<_T&>
: public signature_of<_T>
{};
template <>
struct signature_of<void>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -139,7 +88,6 @@ namespace sdbus {
struct signature_of<bool>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -151,7 +99,6 @@ namespace sdbus {
struct signature_of<uint8_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -163,7 +110,6 @@ namespace sdbus {
struct signature_of<int16_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -175,7 +121,6 @@ namespace sdbus {
struct signature_of<uint16_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -187,7 +132,6 @@ namespace sdbus {
struct signature_of<int32_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -199,7 +143,6 @@ namespace sdbus {
struct signature_of<uint32_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -211,7 +154,6 @@ namespace sdbus {
struct signature_of<int64_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -223,7 +165,6 @@ namespace sdbus {
struct signature_of<uint64_t>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -235,7 +176,6 @@ namespace sdbus {
struct signature_of<double>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = true;
static const std::string str()
{
@@ -247,7 +187,6 @@ namespace sdbus {
struct signature_of<char*>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -259,7 +198,6 @@ namespace sdbus {
struct signature_of<const char*>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -271,7 +209,6 @@ namespace sdbus {
struct signature_of<char[_N]>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -283,7 +220,6 @@ namespace sdbus {
struct signature_of<const char[_N]>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -295,7 +231,6 @@ namespace sdbus {
struct signature_of<std::string>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -307,7 +242,6 @@ namespace sdbus {
struct signature_of<Struct<_ValueTypes...>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -323,7 +257,6 @@ namespace sdbus {
struct signature_of<Variant>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -335,7 +268,6 @@ namespace sdbus {
struct signature_of<ObjectPath>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -347,7 +279,6 @@ namespace sdbus {
struct signature_of<Signature>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -359,7 +290,6 @@ namespace sdbus {
struct signature_of<UnixFd>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -367,11 +297,10 @@ namespace sdbus {
}
};
template <typename _Element, typename _Allocator>
struct signature_of<std::vector<_Element, _Allocator>>
template <typename _Element>
struct signature_of<std::vector<_Element>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -379,49 +308,10 @@ namespace sdbus {
}
};
template <typename _Element, std::size_t _Size>
struct signature_of<std::array<_Element, _Size>>
template <typename _Key, typename _Value>
struct signature_of<std::map<_Key, _Value>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
#if __cplusplus >= 202002L
template <typename _Element, std::size_t _Extent>
struct signature_of<std::span<_Element, _Extent>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
#endif
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
}
};
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
struct signature_of<std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>>
{
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
static const std::string str()
{
@@ -488,14 +378,12 @@ namespace sdbus {
: public function_traits_base<_ReturnType, _Args...>
{
static constexpr bool is_async = false;
static constexpr bool has_error_param = false;
};
template <typename... _Args>
struct function_traits<void(const Error*, _Args...)>
: public function_traits_base<void, _Args...>
{
static constexpr bool has_error_param = true;
};
template <typename... _Args, typename... _Results>
@@ -555,9 +443,6 @@ namespace sdbus {
template <class _Function>
constexpr auto is_async_method_v = function_traits<_Function>::is_async;
template <class _Function>
constexpr auto has_error_param_v = function_traits<_Function>::has_error_param;
template <typename _FunctionType>
using function_arguments_t = typename function_traits<_FunctionType>::arguments_type;
@@ -626,26 +511,6 @@ namespace sdbus {
}
};
template <typename... _Args> struct future_return
{
typedef std::tuple<_Args...> type;
};
template <> struct future_return<>
{
typedef void type;
};
template <typename _Type> struct future_return<_Type>
{
typedef _Type type;
};
template <typename... _Args>
using future_return_t = typename future_return<_Args...>::type;
namespace detail
{
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
+20 -46
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Types.h
*
@@ -34,7 +34,7 @@
#include <typeinfo>
#include <memory>
#include <tuple>
#include <utility>
#include <unistd.h>
namespace sdbus {
@@ -42,7 +42,7 @@ 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
@@ -104,10 +104,6 @@ namespace sdbus {
*
* Representation of struct D-Bus type
*
* Struct implements tuple protocol, i.e. it's a tuple-like class.
* It can be used with std::get<>(), std::tuple_element,
* std::tuple_size and in structured bindings.
*
***********************************************/
template <typename... _ValueTypes>
class Struct
@@ -116,7 +112,7 @@ namespace sdbus {
public:
using std::tuple<_ValueTypes...>::tuple;
// Disable constructor if an older then 7.1.0 version of GCC is used
// Disable constructor if an older then 7.1.0 version of GCC is used
#if !((defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !(__GNUC__ > 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 0)))))
Struct() = default;
@@ -139,9 +135,6 @@ namespace sdbus {
}
};
template <typename... _Elements>
Struct(_Elements...) -> Struct<_Elements...>;
template<typename... _Elements>
constexpr Struct<std::decay_t<_Elements>...>
make_struct(_Elements&&... args)
@@ -162,9 +155,6 @@ namespace sdbus {
using std::string::string;
ObjectPath() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
ObjectPath(const ObjectPath&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
ObjectPath(ObjectPath&&) = default; // Enable move - user-declared copy ctor prevents implicit creation
ObjectPath& operator = (const ObjectPath&) = default; // Fixes gcc 8.3 error (deleted copy assignment)
ObjectPath& operator = (ObjectPath&&) = default; // Enable move - user-declared copy assign prevents implicit creation
ObjectPath(std::string path)
: std::string(std::move(path))
{}
@@ -183,15 +173,15 @@ namespace sdbus {
using std::string::string;
Signature() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
Signature(const Signature&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
Signature(Signature&&) = default; // Enable move - user-declared copy ctor prevents implicit creation
Signature& operator = (const Signature&) = default; // Fixes gcc 8.3 error (deleted copy assignment)
Signature& operator = (Signature&&) = default; // Enable move - user-declared copy assign prevents implicit creation
Signature(std::string path)
: std::string(std::move(path))
{}
using std::string::operator=;
};
struct adopt_fd_t { explicit adopt_fd_t() = default; };
inline constexpr adopt_fd_t adopt_fd{};
/********************************************//**
* @struct UnixFd
*
@@ -209,7 +199,7 @@ namespace sdbus {
UnixFd() = default;
explicit UnixFd(int fd)
: fd_(checkedDup(fd))
: fd_(::dup(fd))
{
}
@@ -225,12 +215,8 @@ namespace sdbus {
UnixFd& operator=(const UnixFd& other)
{
if (this == &other)
{
return *this;
}
close();
fd_ = checkedDup(other.fd_);
fd_ = ::dup(other.fd_);
return *this;
}
@@ -241,12 +227,9 @@ namespace sdbus {
UnixFd& operator=(UnixFd&& other)
{
if (this == &other)
{
return *this;
}
close();
fd_ = std::exchange(other.fd_, -1);
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
@@ -272,7 +255,9 @@ namespace sdbus {
int release()
{
return std::exchange(fd_, -1);
auto fd = fd_;
fd_ = -1;
return fd;
}
bool isValid() const
@@ -281,26 +266,15 @@ namespace sdbus {
}
private:
/// Closes file descriptor, but does not set it to -1.
void close();
/// Returns negative argument unchanged.
/// Otherwise, call ::dup and throw on failure.
static int checkedDup(int fd);
void close()
{
if (fd_ >= 0)
::close(fd_);
}
int fd_ = -1;
};
}
template <size_t _I, typename... _ValueTypes>
struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>>
: std::tuple_element<_I, std::tuple<_ValueTypes...>>
{};
template <typename... _ValueTypes>
struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
: std::tuple_size<std::tuple<_ValueTypes...>>
{};
#endif /* SDBUS_CXX_TYPES_H_ */
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file sdbus-c++.h
*
+1 -1
View File
@@ -5,7 +5,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: C++ library on top of sd-bus, a systemd D-Bus library
Requires@PKGCONFIG_REQS@: @PKGCONFIG_DEPS@
Requires: libsystemd
Version: @SDBUSCPP_VERSION@
Libs: -L${libdir} -l@PROJECT_NAME@
Cflags: -I${includedir}
+47 -294
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Connection.cpp
*
@@ -27,11 +27,10 @@
#include "Connection.h"
#include "SdBus.h"
#include "MessageUtils.h"
#include "Utils.h"
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Error.h>
#include "ScopeGuard.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <unistd.h>
#include <poll.h>
#include <sys/eventfd.h>
@@ -45,11 +44,6 @@ Connection::Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& bu
assert(iface_ != nullptr);
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, default_bus_t)
: Connection(std::move(interface), [this](sd_bus** bus){ return iface_->sd_bus_open(bus); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, system_bus_t)
: Connection(std::move(interface), [this](sd_bus** bus){ return iface_->sd_bus_open_system(bus); })
{
@@ -60,43 +54,11 @@ Connection::Connection(std::unique_ptr<ISdBus>&& interface, session_bus_t)
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, custom_session_bus_t, const std::string& address)
: Connection(std::move(interface), [&](sd_bus** bus) { return iface_->sd_bus_open_user_with_address(bus, address.c_str()); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, remote_system_bus_t, const std::string& host)
: Connection(std::move(interface), [this, &host](sd_bus** bus){ return iface_->sd_bus_open_system_remote(bus, host.c_str()); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, private_bus_t, const std::string& address)
: Connection(std::move(interface), [&](sd_bus** bus) { return iface_->sd_bus_open_direct(bus, address.c_str()); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, private_bus_t, int fd)
: Connection(std::move(interface), [&](sd_bus** bus) { return iface_->sd_bus_open_direct(bus, fd); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, server_bus_t, int fd)
: Connection(std::move(interface), [&](sd_bus** bus) { return iface_->sd_bus_open_server(bus, fd); })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, sdbus_bus_t, sd_bus *bus)
: Connection(std::move(interface), [&](sd_bus** b) { *b = bus; return 0; })
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
: iface_(std::move(interface))
, bus_(openPseudoBus())
{
assert(iface_ != nullptr);
}
Connection::~Connection()
{
Connection::leaveEventLoop();
@@ -104,24 +66,14 @@ Connection::~Connection()
void Connection::requestName(const std::string& name)
{
SDBUS_CHECK_SERVICE_NAME(name);
auto r = iface_->sd_bus_request_name(bus_.get(), name.c_str(), 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
// In some cases we need to explicitly notify the event loop
// to process messages that may have arrived while executing the call.
notifyEventLoop(eventFd_.fd);
}
void Connection::releaseName(const std::string& name)
{
auto r = iface_->sd_bus_release_name(bus_.get(), name.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
// In some cases we need to explicitly notify the event loop
// to process messages that may have arrived while executing the call.
notifyEventLoop(eventFd_.fd);
}
std::string Connection::getUniqueName() const
@@ -135,7 +87,6 @@ std::string Connection::getUniqueName() const
void Connection::enterEventLoop()
{
loopThreadId_ = std::this_thread::get_id();
SCOPE_EXIT{ loopThreadId_ = std::thread::id{}; };
std::lock_guard guard(loopMutex_);
@@ -149,6 +100,8 @@ void Connection::enterEventLoop()
if (!success)
break; // Exit I/O event loop
}
loopThreadId_ = std::thread::id{};
}
void Connection::enterEventLoopAsync()
@@ -165,7 +118,7 @@ void Connection::leaveEventLoop()
Connection::PollData Connection::getEventLoopPollData() const
{
ISdBus::PollData pollData{};
ISdBus::PollData pollData;
auto r = iface_->sd_bus_get_poll_data(bus_.get(), &pollData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
@@ -184,21 +137,16 @@ ISdBus& Connection::getSdBusInterface()
void Connection::addObjectManager(const std::string& objectPath)
{
Connection::addObjectManager(objectPath, floating_slot);
Connection::addObjectManager(objectPath, nullptr);
}
void Connection::addObjectManager(const std::string& objectPath, floating_slot_t)
{
auto r = iface_->sd_bus_add_object_manager(bus_.get(), nullptr, objectPath.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
}
Slot Connection::addObjectManager(const std::string& objectPath, request_slot_t)
SlotPtr Connection::addObjectManager(const std::string& objectPath, void* /*dummy*/)
{
sd_bus_slot *slot{};
auto r = iface_->sd_bus_add_object_manager(bus_.get(), &slot, objectPath.c_str());
auto r = iface_->sd_bus_add_object_manager( bus_.get()
, &slot
, objectPath.c_str() );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
@@ -223,60 +171,10 @@ uint64_t Connection::getMethodCallTimeout() const
return timeout;
}
Slot Connection::addMatch(const std::string& match, message_handler callback)
{
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
auto matchInfo = std::make_unique<MatchInfo>(MatchInfo{std::move(callback), {}, *this, {}});
auto r = iface_->sd_bus_add_match(bus_.get(), &matchInfo->slot, match.c_str(), &Connection::sdbus_match_callback, matchInfo.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add match", -r);
return {matchInfo.release(), [this](void *ptr)
{
auto* matchInfo = static_cast<MatchInfo*>(ptr);
iface_->sd_bus_slot_unref(matchInfo->slot);
std::default_delete<MatchInfo>{}(matchInfo);
}};
}
void Connection::addMatch(const std::string& match, message_handler callback, floating_slot_t)
{
floatingMatchRules_.push_back(addMatch(match, std::move(callback)));
}
Slot Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback)
{
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
sd_bus_message_handler_t sdbusInstallCallback = installCallback ? &Connection::sdbus_match_install_callback : nullptr;
auto matchInfo = std::make_unique<MatchInfo>(MatchInfo{std::move(callback), std::move(installCallback), *this, {}});
auto r = iface_->sd_bus_add_match_async( bus_.get()
, &matchInfo->slot
, match.c_str()
, &Connection::sdbus_match_callback
, sdbusInstallCallback
, matchInfo.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add match", -r);
return {matchInfo.release(), [this](void *ptr)
{
auto* matchInfo = static_cast<MatchInfo*>(ptr);
iface_->sd_bus_slot_unref(matchInfo->slot);
std::default_delete<MatchInfo>{}(matchInfo);
}};
}
void Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t)
{
floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback)));
}
Slot Connection::addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData )
SlotPtr Connection::addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData )
{
sd_bus_slot *slot{};
@@ -312,14 +210,14 @@ MethodCall Connection::createMethodCall( const std::string& destination
auto r = iface_->sd_bus_message_new_method_call( bus_.get()
, &sdbusMsg
, destination.empty() ? nullptr : destination.c_str()
, destination.c_str()
, objectPath.c_str()
, interfaceName.c_str()
, methodName.c_str() );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method call", -r);
return Message::Factory::create<MethodCall>(sdbusMsg, iface_.get(), this, adopt_message);
return Message::Factory::create<MethodCall>(sdbusMsg, iface_.get(), adopt_message);
}
Signal Connection::createSignal( const std::string& objectPath
@@ -391,19 +289,15 @@ void Connection::emitInterfacesRemovedSignal( const std::string& objectPath
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal", -r);
}
Slot Connection::registerSignalHandler( const std::string& sender
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData )
SlotPtr Connection::registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData )
{
sd_bus_slot *slot{};
// Alternatively to our own composeSignalMatchFilter() implementation, we could use sd_bus_match_signal() from
// https://www.freedesktop.org/software/systemd/man/sd_bus_add_match.html .
// But this would require libsystemd v237 or higher.
auto filter = composeSignalMatchFilter(sender, objectPath, interfaceName, signalName);
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
auto r = iface_->sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
@@ -451,23 +345,6 @@ Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
return busPtr;
}
Connection::BusPtr Connection::openPseudoBus()
{
sd_bus* bus{};
int r = iface_->sd_bus_new(&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open pseudo bus", -r);
(void)iface_->sd_bus_start(bus);
// It is expected that sd_bus_start has failed here, returning -EINVAL, due to having
// not set a bus address, but it will leave the bus in an OPENING state, which enables
// us to create plain D-Bus messages as a local data storage (for Variant, for example),
// without dependency on real IPC communication with the D-Bus broker daemon.
SDBUS_THROW_ERROR_IF(r < 0 && r != -EINVAL, "Failed to start pseudo bus", -r);
return {bus, [this](sd_bus* bus){ return iface_->sd_bus_close_unref(bus); }};
}
void Connection::finishHandshake(sd_bus* bus)
{
// Process all requests that are part of the initial handshake,
@@ -481,37 +358,19 @@ void Connection::finishHandshake(sd_bus* bus)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
}
void Connection::notifyEventLoop(int fd) const
void Connection::notifyEventLoopToExit()
{
assert(fd >= 0);
assert(loopExitFd_.fd >= 0);
uint64_t value = 1;
auto r = write(fd, &value, sizeof(value));
auto r = write(loopExitFd_.fd, &value, sizeof(value));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify event loop", -errno);
}
void Connection::notifyEventLoopToExit() const
{
notifyEventLoop(loopExitFd_.fd);
}
void Connection::notifyEventLoopNewTimeout() const
{
// The extra notifications for new timeouts are only needed if calls are made asynchronously to the event loop.
// Are we in the same thread as the event loop? Note that it's ok to fail this check because the event loop isn't yet started.
if (loopThreadId_.load(std::memory_order_relaxed) == std::this_thread::get_id())
return;
// Get the new timeout from sd-bus
auto sdbusPollData = getEventLoopPollData();
if (sdbusPollData.timeout_usec < activeTimeout_.load(std::memory_order_relaxed))
notifyEventLoop(eventFd_.fd);
}
void Connection::clearEventLoopNotification(int fd) const
void Connection::clearExitNotification()
{
uint64_t value{};
auto r = read(fd, &value, sizeof(value));
auto r = read(loopExitFd_.fd, &value, sizeof(value));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
}
@@ -535,18 +394,13 @@ bool Connection::processPendingRequest()
bool Connection::waitForNextRequest()
{
assert(bus_ != nullptr);
assert(eventFd_.fd >= 0);
assert(loopExitFd_.fd != 0);
auto sdbusPollData = getEventLoopPollData();
struct pollfd fds[] = {
{sdbusPollData.fd, sdbusPollData.events, 0},
{eventFd_.fd, POLLIN, 0},
{loopExitFd_.fd, POLLIN, 0}
};
struct pollfd fds[] = {{sdbusPollData.fd, sdbusPollData.events, 0}, {loopExitFd_.fd, POLLIN, 0}};
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
auto timeout = sdbusPollData.getPollTimeout();
activeTimeout_.store(sdbusPollData.timeout_usec, std::memory_order_relaxed);
auto timeout = sdbusPollData.timeout_usec == (uint64_t) -1 ? (uint64_t)-1 : (sdbusPollData.timeout_usec+999)/1000;
auto r = poll(fds, fdsCount, timeout);
if (r < 0 && errno == EINTR)
@@ -554,31 +408,22 @@ bool Connection::waitForNextRequest()
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
// new timeout notification
if (fds[1].revents & POLLIN)
{
clearEventLoopNotification(fds[1].fd);
}
// loop exit notification
if (fds[2].revents & POLLIN)
{
clearEventLoopNotification(fds[2].fd);
clearExitNotification();
return false;
}
return true;
}
std::string Connection::composeSignalMatchFilter( const std::string &sender
, const std::string &objectPath
, const std::string &interfaceName
, const std::string &signalName )
std::string Connection::composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName )
{
std::string filter;
filter += "type='signal',";
if (!sender.empty())
filter += "sender='" + sender + "',";
filter += "interface='" + interfaceName + "',";
filter += "member='" + signalName + "',";
filter += "path='" + objectPath + "'";
@@ -595,65 +440,20 @@ std::vector</*const */char*> Connection::to_strv(const std::vector<std::string>&
return strv;
}
int Connection::sdbus_match_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
Connection::LoopExitEventFd::LoopExitEventFd()
{
auto* matchInfo = static_cast<MatchInfo*>(userData);
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection.getSdBusInterface());
auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->callback(message); }, retError);
return ok ? 0 : -1;
}
int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
{
auto* matchInfo = static_cast<MatchInfo*>(userData);
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection.getSdBusInterface());
auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->installCallback(message); }, retError);
return ok ? 0 : -1;
}
Connection::EventFd::EventFd()
{
fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
fd = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC | EFD_NONBLOCK);
SDBUS_THROW_ERROR_IF(fd < 0, "Failed to create event object", -errno);
}
Connection::EventFd::~EventFd()
Connection::LoopExitEventFd::~LoopExitEventFd()
{
assert(fd >= 0);
close(fd);
}
} // namespace sdbus::internal
namespace sdbus {
std::optional<std::chrono::microseconds> IConnection::PollData::getRelativeTimeout() const
{
constexpr auto zero = std::chrono::microseconds::zero();
if (timeout_usec == 0)
return zero;
else if (timeout_usec == UINT64_MAX)
return std::nullopt;
// We need C so that we use the same clock as the underlying sd-bus lib.
// We use POSIX's clock_gettime in favour of std::chrono::steady_clock to ensure this.
struct timespec ts{};
auto r = clock_gettime(CLOCK_MONOTONIC, &ts);
SDBUS_THROW_ERROR_IF(r < 0, "clock_gettime failed: ", -errno);
auto now = std::chrono::nanoseconds(ts.tv_nsec) + std::chrono::seconds(ts.tv_sec);
auto absTimeout = std::chrono::microseconds(timeout_usec);
auto result = std::chrono::duration_cast<std::chrono::microseconds>(absTimeout - now);
return std::max(result, zero);
}
int IConnection::PollData::getPollTimeout() const
{
auto timeout = getRelativeTimeout();
return timeout ? static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(timeout.value()).count()) : -1;
}
} // namespace sdbus
namespace sdbus::internal {
std::unique_ptr<sdbus::internal::IConnection> createConnection()
@@ -664,18 +464,10 @@ std::unique_ptr<sdbus::internal::IConnection> createConnection()
return std::unique_ptr<sdbus::internal::IConnection>(connectionInternal);
}
std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::pseudo_bus);
}
} // namespace sdbus::internal
namespace sdbus {
using internal::Connection;
std::unique_ptr<sdbus::IConnection> createConnection()
{
return createSystemBusConnection();
@@ -686,23 +478,12 @@ std::unique_ptr<sdbus::IConnection> createConnection(const std::string& name)
return createSystemBusConnection(name);
}
std::unique_ptr<sdbus::IConnection> createDefaultBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::default_bus);
}
std::unique_ptr<sdbus::IConnection> createDefaultBusConnection(const std::string& name)
{
auto conn = createDefaultBusConnection();
conn->requestName(name);
return conn;
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::system_bus);
assert(interface != nullptr);
constexpr sdbus::internal::Connection::system_bus_t system_bus;
return std::make_unique<sdbus::internal::Connection>(std::move(interface), system_bus);
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
@@ -715,7 +496,9 @@ std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string&
std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::session_bus);
assert(interface != nullptr);
constexpr sdbus::internal::Connection::session_bus_t session_bus;
return std::make_unique<sdbus::internal::Connection>(std::move(interface), session_bus);
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)
@@ -725,42 +508,12 @@ std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string
return conn;
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string &address)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::custom_session_bus, address);
}
std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::remote_system_bus, host);
assert(interface != nullptr);
constexpr sdbus::internal::Connection::remote_system_bus_t remote_system_bus;
return std::make_unique<sdbus::internal::Connection>(std::move(interface), remote_system_bus, host);
}
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, address);
}
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, fd);
}
std::unique_ptr<sdbus::IConnection> createServerBus(int fd)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::server_bus, fd);
}
std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus)
{
SDBUS_THROW_ERROR_IF(bus == nullptr, "Invalid bus argument", EINVAL);
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::sdbus_bus, bus);
}
} // namespace sdbus
+25 -73
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Connection.h
*
@@ -32,7 +32,7 @@
#include "IConnection.h"
#include "ScopeGuard.h"
#include "ISdBus.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <memory>
#include <thread>
#include <string>
@@ -43,39 +43,18 @@
namespace sdbus::internal {
class Connection final
: public sdbus::internal::IConnection
: public sdbus::IConnection // External, public interface
, public sdbus::internal::IConnection // Internal, private interface
{
public:
// Bus type tags
struct default_bus_t{};
inline static constexpr default_bus_t default_bus{};
struct system_bus_t{};
inline static constexpr system_bus_t system_bus{};
struct session_bus_t{};
inline static constexpr session_bus_t session_bus{};
struct custom_session_bus_t{};
inline static constexpr custom_session_bus_t custom_session_bus{};
struct remote_system_bus_t{};
inline static constexpr remote_system_bus_t remote_system_bus{};
struct private_bus_t{};
inline static constexpr private_bus_t private_bus{};
struct server_bus_t{};
inline static constexpr server_bus_t server_bus{};
struct sdbus_bus_t{}; // A bus connection created directly from existing sd_bus instance
inline static constexpr sdbus_bus_t sdbus_bus{};
struct pseudo_bus_t{}; // A bus connection that is not really established with D-Bus daemon
inline static constexpr pseudo_bus_t pseudo_bus{};
Connection(std::unique_ptr<ISdBus>&& interface, default_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, system_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, session_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, custom_session_bus_t, const std::string& address);
Connection(std::unique_ptr<ISdBus>&& interface, remote_system_bus_t, const std::string& host);
Connection(std::unique_ptr<ISdBus>&& interface, private_bus_t, const std::string& address);
Connection(std::unique_ptr<ISdBus>&& interface, private_bus_t, int fd);
Connection(std::unique_ptr<ISdBus>&& interface, server_bus_t, int fd);
Connection(std::unique_ptr<ISdBus>&& interface, sdbus_bus_t, sd_bus *bus);
Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t);
~Connection() override;
void requestName(const std::string& name) override;
@@ -88,24 +67,18 @@ namespace sdbus::internal {
bool processPendingRequest() override;
void addObjectManager(const std::string& objectPath) override;
void addObjectManager(const std::string& objectPath, floating_slot_t) override;
Slot addObjectManager(const std::string& objectPath, request_slot_t) override;
SlotPtr addObjectManager(const std::string& objectPath, void* /*dummy*/) override;
void setMethodCallTimeout(uint64_t timeout) override;
uint64_t getMethodCallTimeout() const override;
[[nodiscard]] Slot addMatch(const std::string& match, message_handler callback) override;
void addMatch(const std::string& match, message_handler callback, floating_slot_t) override;
[[nodiscard]] Slot addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) override;
void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) override;
const ISdBus& getSdBusInterface() const override;
ISdBus& getSdBusInterface() override;
Slot addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) override;
SlotPtr addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) override;
PlainMessage createPlainMessage() const override;
MethodCall createMethodCall( const std::string& destination
@@ -126,12 +99,11 @@ namespace sdbus::internal {
void emitInterfacesRemovedSignal( const std::string& objectPath
, const std::vector<std::string>& interfaces ) override;
Slot registerSignalHandler( const std::string& sender
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData ) override;
SlotPtr registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData ) override;
MethodReply tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout) override;
@@ -141,38 +113,21 @@ namespace sdbus::internal {
Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory);
BusPtr openBus(const std::function<int(sd_bus**)>& busFactory);
BusPtr openPseudoBus();
void finishHandshake(sd_bus* bus);
bool waitForNextRequest();
static std::string composeSignalMatchFilter( const std::string &sender
, const std::string &objectPath
, const std::string &interfaceName
, const std::string &signalName);
void notifyEventLoop(int fd) const;
void notifyEventLoopToExit() const;
void clearEventLoopNotification(int fd) const;
void notifyEventLoopNewTimeout() const override;
static std::string composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName );
void notifyEventLoopToExit();
void clearExitNotification();
void joinWithEventLoop();
static std::vector</*const */char*> to_strv(const std::vector<std::string>& strings);
static int sdbus_match_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_match_install_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
private:
struct EventFd
struct LoopExitEventFd
{
EventFd();
~EventFd();
int fd{-1};
};
struct MatchInfo
{
message_handler callback;
message_handler installCallback;
Connection& connection;
sd_bus_slot *slot;
LoopExitEventFd();
~LoopExitEventFd();
int fd;
};
private:
@@ -181,10 +136,7 @@ namespace sdbus::internal {
std::thread asyncLoopThread_;
std::atomic<std::thread::id> loopThreadId_;
std::mutex loopMutex_;
EventFd loopExitFd_;
EventFd eventFd_;
std::atomic<uint64_t> activeTimeout_{};
std::vector<Slot> floatingMatchRules_;
LoopExitEventFd loopExitFd_;
};
}
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Error.cpp
*
@@ -25,7 +25,7 @@
*/
#include <sdbus-c++/Error.h>
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include "ScopeGuard.h"
namespace sdbus
+4 -4
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Flags.cpp
*
@@ -25,7 +25,7 @@
*/
#include <sdbus-c++/Flags.h>
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
namespace sdbus
{
@@ -47,7 +47,7 @@ namespace sdbus
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
sdbusFlags |= 0;
return sdbusFlags;
}
+19 -20
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file IConnection.h
*
@@ -27,8 +27,7 @@
#ifndef SDBUS_CXX_INTERNAL_ICONNECTION_H_
#define SDBUS_CXX_INTERNAL_ICONNECTION_H_
#include <sdbus-c++/IConnection.h>
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <string>
#include <memory>
#include <functional>
@@ -47,19 +46,20 @@ namespace sdbus {
namespace sdbus::internal {
using SlotPtr = std::unique_ptr<void, std::function<void(void*)>>;
class IConnection
: public ::sdbus::IConnection
{
public:
~IConnection() override = default;
virtual ~IConnection() = default;
virtual const ISdBus& getSdBusInterface() const = 0;
virtual ISdBus& getSdBusInterface() = 0;
[[nodiscard]] virtual Slot addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) = 0;
[[nodiscard]] virtual SlotPtr addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) = 0;
virtual PlainMessage createPlainMessage() const = 0;
virtual MethodCall createMethodCall( const std::string& destination
@@ -80,22 +80,21 @@ namespace sdbus::internal {
virtual void emitInterfacesRemovedSignal( const std::string& objectPath
, const std::vector<std::string>& interfaces ) = 0;
using sdbus::IConnection::addObjectManager;
[[nodiscard]] virtual Slot addObjectManager(const std::string& objectPath, request_slot_t) = 0;
[[nodiscard]] virtual SlotPtr addObjectManager(const std::string& objectPath, void* /*dummy*/ = nullptr) = 0;
[[nodiscard]] virtual Slot registerSignalHandler( const std::string& sender
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData ) = 0;
[[nodiscard]] virtual SlotPtr registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData ) = 0;
virtual void enterEventLoopAsync() = 0;
virtual void leaveEventLoop() = 0;
virtual void notifyEventLoopNewTimeout() const = 0;
virtual MethodReply tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout) = 0;
};
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createConnection();
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection();
}
+4 -27
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ISdBus.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -28,7 +28,7 @@
#ifndef SDBUS_CXX_ISDBUS_H
#define SDBUS_CXX_ISDBUS_H
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
namespace sdbus::internal {
@@ -66,45 +66,22 @@ namespace sdbus::internal {
virtual int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) = 0;
virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) = 0;
virtual int sd_bus_open(sd_bus **ret) = 0;
virtual int sd_bus_open_system(sd_bus **ret) = 0;
virtual int sd_bus_open_user(sd_bus **ret) = 0;
virtual int sd_bus_open_user_with_address(sd_bus **ret, const char* address) = 0;
virtual int sd_bus_open_system(sd_bus **ret) = 0;
virtual int sd_bus_open_system_remote(sd_bus **ret, const char* host) = 0;
virtual int sd_bus_open_direct(sd_bus **ret, const char* address) = 0;
virtual int sd_bus_open_direct(sd_bus **ret, int fd) = 0;
virtual int sd_bus_open_server(sd_bus **ret, int fd) = 0;
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) = 0;
virtual int sd_bus_release_name(sd_bus *bus, const char *name) = 0;
virtual int sd_bus_get_unique_name(sd_bus *bus, const char **name) = 0;
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) = 0;
virtual int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) = 0;
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) = 0;
virtual int sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata) = 0;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
virtual int sd_bus_new(sd_bus **ret) = 0;
virtual int sd_bus_start(sd_bus *bus) = 0;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) = 0;
virtual int sd_bus_flush(sd_bus *bus) = 0;
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) = 0;
virtual sd_bus *sd_bus_close_unref(sd_bus *bus) = 0;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) = 0;
virtual int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) = 0;
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) = 0;
virtual int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) = 0;
virtual int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) = 0;
virtual int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *uid) = 0;
virtual int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) = 0;
virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) = 0;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) = 0;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) = 0;
};
}
+10 -231
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Message.cpp
*
@@ -31,7 +31,7 @@
#include "ISdBus.h"
#include "IConnection.h"
#include "ScopeGuard.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <cassert>
namespace sdbus {
@@ -226,13 +226,6 @@ Message& Message::operator<<(const UnixFd &item)
return *this;
}
Message& Message::appendArray(char type, const void *ptr, size_t size)
{
auto r = sd_bus_message_append_array((sd_bus_message*)msg_, type, ptr, size);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an array", -r);
return *this;
}
Message& Message::operator>>(bool& item)
{
@@ -325,17 +318,6 @@ Message& Message::operator>>(uint64_t& item)
return *this;
}
Message& Message::readArray(char type, const void **ptr, size_t *size)
{
auto r = sd_bus_message_read_array((sd_bus_message*)msg_, type, ptr, size);
if (r == 0)
ok_ = false;
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize an array", -r);
return *this;
}
Message& Message::operator>>(double& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
@@ -601,14 +583,12 @@ void Message::rewind(bool complete)
std::string Message::getInterfaceName() const
{
auto interface = sd_bus_message_get_interface((sd_bus_message*)msg_);
return interface != nullptr ? interface : "";
return sd_bus_message_get_interface((sd_bus_message*)msg_);
}
std::string Message::getMemberName() const
{
auto member = sd_bus_message_get_member((sd_bus_message*)msg_);
return member != nullptr ? member : "";
return sd_bus_message_get_member((sd_bus_message*)msg_);
}
std::string Message::getSender() const
@@ -616,18 +596,6 @@ std::string Message::getSender() const
return sd_bus_message_get_sender((sd_bus_message*)msg_);
}
std::string Message::getPath() const
{
auto path = sd_bus_message_get_path((sd_bus_message*)msg_);
return path != nullptr ? path : "";
}
std::string Message::getDestination() const
{
auto destination = sd_bus_message_get_destination((sd_bus_message*)msg_);
return destination != nullptr ? destination : "";
}
void Message::peekType(std::string& type, std::string& contents) const
{
char typeSig;
@@ -635,7 +603,7 @@ void Message::peekType(std::string& type, std::string& contents) const
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSig, &contentsSig);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
type = typeSig;
contents = contentsSig ? contentsSig : "";
contents = contentsSig;
}
bool Message::isValid() const
@@ -648,129 +616,6 @@ bool Message::isEmpty() const
return sd_bus_message_is_empty((sd_bus_message*)msg_) != 0;
}
bool Message::isAtEnd(bool complete) const
{
return sd_bus_message_at_end((sd_bus_message*)msg_, complete) > 0;
}
pid_t Message::getCredsPid() const
{
uint64_t mask = SD_BUS_CREDS_PID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
pid_t pid = 0;
r = sdbus_->sd_bus_creds_get_pid(creds, &pid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred pid", -r);
return pid;
}
uid_t Message::getCredsUid() const
{
uint64_t mask = SD_BUS_CREDS_UID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
uid_t uid = (uid_t)-1;
r = sdbus_->sd_bus_creds_get_uid(creds, &uid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred uid", -r);
return uid;
}
uid_t Message::getCredsEuid() const
{
uint64_t mask = SD_BUS_CREDS_EUID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
uid_t euid = (uid_t)-1;
r = sdbus_->sd_bus_creds_get_euid(creds, &euid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred euid", -r);
return euid;
}
gid_t Message::getCredsGid() const
{
uint64_t mask = SD_BUS_CREDS_GID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
gid_t gid = (gid_t)-1;
r = sdbus_->sd_bus_creds_get_gid(creds, &gid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred gid", -r);
return gid;
}
gid_t Message::getCredsEgid() const
{
uint64_t mask = SD_BUS_CREDS_EGID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
gid_t egid = (gid_t)-1;
r = sdbus_->sd_bus_creds_get_egid(creds, &egid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred egid", -r);
return egid;
}
std::vector<gid_t> Message::getCredsSupplementaryGids() const
{
uint64_t mask = SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
const gid_t *cGids = nullptr;
r = sdbus_->sd_bus_creds_get_supplementary_gids(creds, &cGids);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred supplementary gids", -r);
std::vector<gid_t> gids{};
if (cGids != nullptr)
{
for (int i = 0; i < r; i++)
gids.push_back(cGids[i]);
}
return gids;
}
std::string Message::getSELinuxContext() const
{
uint64_t mask = SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_SELINUX_CONTEXT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
const char *cLabel = nullptr;
r = sdbus_->sd_bus_creds_get_selinux_context(creds, &cLabel);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred selinux context", -r);
return cLabel;
}
MethodCall::MethodCall( void *msg
, internal::ISdBus *sdbus
, const internal::IConnection *connection
, adopt_message_t) noexcept
: Message(msg, sdbus, adopt_message)
, connection_(connection)
{
assert(connection_ != nullptr);
}
void MethodCall::dontExpectReply()
{
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)msg_, 0);
@@ -817,32 +662,19 @@ MethodReply MethodCall::sendWithNoReply() const
}
void MethodCall::send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const
{
MethodCall::send(callback, userData, timeout, floating_slot);
}
void MethodCall::send(void* callback, void* userData, uint64_t timeout, floating_slot_t) const
{
auto r = sdbus_->sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, timeout);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
// Force event loop to re-enter polling with the async call timeout if that is less than the one used in current poll
SDBUS_THROW_ERROR_IF(connection_ == nullptr, "Invalid use of MethodCall API", ENOTSUP);
connection_->notifyEventLoopNewTimeout();
}
Slot MethodCall::send(void* callback, void* userData, uint64_t timeout) const
MethodCall::Slot MethodCall::send(void* callback, void* userData, uint64_t timeout) const
{
sd_bus_slot* slot;
auto r = sdbus_->sd_bus_call_async(nullptr, &slot, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, timeout);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
// Force event loop to re-enter polling with the async call timeout if that is less than the one used in current poll
SDBUS_THROW_ERROR_IF(connection_ == nullptr, "Invalid use of MethodCall API", ENOTSUP);
connection_->notifyEventLoopNewTimeout();
return {slot, [sdbus_ = sdbus_](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
return Slot{slot, [sdbus_ = sdbus_](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
}
MethodReply MethodCall::createReply() const
@@ -879,63 +711,10 @@ void Signal::send() const
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
}
void Signal::setDestination(const std::string& destination)
{
auto r = sdbus_->sd_bus_message_set_destination((sd_bus_message*)msg_, destination.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
}
namespace {
// Pseudo-connection lifetime handling. In standard cases, we could do with simply function-local static pseudo
// connection instance below. However, it may happen that client's sdbus-c++ objects outlive this static connection
// instance (because they are used in global application objects that were created before this connection, and thus
// are destroyed later). This by itself sounds like a smell in client's application design, but it is downright bad
// in sdbus-c++ because it has no control over when client's dependent statics get destroyed. A "Phoenix" pattern
// (see Modern C++ Design - Generic Programming and Design Patterns Applied, by Andrei Alexandrescu) is applied to fix
// this by re-creating the connection again in such cases and keeping it alive until the next exit handler is invoked.
// Please note that the solution is NOT thread-safe.
// Another common solution is global sdbus-c++ startup/shutdown functions, but that would be an intrusive change.
/*constinit (C++20 keyword) */ static bool pseudoConnectionDestroyed{};
std::unique_ptr<sdbus::internal::IConnection, void(*)(sdbus::internal::IConnection*)> createPseudoConnection()
{
auto deleter = [](sdbus::internal::IConnection* con)
{
delete con;
pseudoConnectionDestroyed = true;
};
return {internal::createPseudoConnection().release(), std::move(deleter)};
}
sdbus::internal::IConnection& getPseudoConnectionInstance()
{
static auto connection = createPseudoConnection();
if (pseudoConnectionDestroyed)
{
connection = createPseudoConnection(); // Phoenix rising from the ashes
atexit([](){ connection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
pseudoConnectionDestroyed = false;
}
assert(connection != nullptr);
return *connection;
}
}
PlainMessage createPlainMessage()
{
// Let's create a pseudo connection -- one that does not really connect to the real bus.
// This is a bit of a hack, but it enables use to work with D-Bus message locally without
// the need of D-Bus daemon. This is especially useful in unit tests of both sdbus-c++ and client code.
// Additionally, it's light-weight and fast solution.
auto& connection = getPseudoConnectionInstance();
return connection.createPlainMessage();
static auto connection = internal::createConnection();
return connection->createPlainMessage();
}
}
+2 -8
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file MessageUtils.h
*
@@ -57,12 +57,6 @@ namespace sdbus
{
return _Msg{msg, sdbus, adopt_message};
}
template<typename _Msg>
static _Msg create(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t)
{
return _Msg{msg, sdbus, connection, adopt_message};
}
};
PlainMessage createPlainMessage();
+55 -66
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Object.cpp
*
@@ -31,11 +31,9 @@
#include <sdbus-c++/Error.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/Flags.h>
#include "ScopeGuard.h"
#include "IConnection.h"
#include "Utils.h"
#include "VTableUtils.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <utility>
#include <cassert>
@@ -44,7 +42,6 @@ namespace sdbus::internal {
Object::Object(sdbus::internal::IConnection& connection, std::string objectPath)
: connection_(connection), objectPath_(std::move(objectPath))
{
SDBUS_CHECK_OBJECT_PATH(objectPath_);
}
void Object::registerMethod( const std::string& interfaceName
@@ -73,11 +70,9 @@ void Object::registerMethod( const std::string& interfaceName
, method_callback methodCallback
, Flags flags )
{
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
SDBUS_CHECK_MEMBER_NAME(methodName);
SDBUS_THROW_ERROR_IF(!methodCallback, "Invalid method callback provided", EINVAL);
auto& interface = getInterface(interfaceName);
auto& interface = interfaces_[interfaceName];
InterfaceData::MethodData methodData{ std::move(inputSignature)
, std::move(outputSignature)
, paramNamesToString(inputNames) + paramNamesToString(outputNames)
@@ -102,10 +97,7 @@ void Object::registerSignal( const std::string& interfaceName
, const std::vector<std::string>& paramNames
, Flags flags )
{
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
SDBUS_CHECK_MEMBER_NAME(signalName);
auto& interface = getInterface(interfaceName);
auto& interface = interfaces_[interfaceName];
InterfaceData::SignalData signalData{std::move(signature), paramNamesToString(paramNames), std::move(flags)};
auto inserted = interface.signals.emplace(std::move(signalName), std::move(signalData)).second;
@@ -134,16 +126,14 @@ void Object::registerProperty( const std::string& interfaceName
, property_set_callback setCallback
, Flags flags )
{
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
SDBUS_CHECK_MEMBER_NAME(propertyName);
SDBUS_THROW_ERROR_IF(!getCallback && !setCallback, "Invalid property callbacks provided", EINVAL);
auto& interface = getInterface(interfaceName);
auto& interface = interfaces_[interfaceName];
InterfaceData::PropertyData propertyData{ std::move(signature)
, std::move(getCallback)
, std::move(setCallback)
, std::move(flags) };
, std::move(flags)};
auto inserted = interface.properties.emplace(std::move(propertyName), std::move(propertyData)).second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register property: property already exists", EINVAL);
@@ -151,7 +141,7 @@ void Object::registerProperty( const std::string& interfaceName
void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags)
{
auto& interface = getInterface(interfaceName);
auto& interface = interfaces_[interfaceName];
interface.flags = flags;
}
@@ -217,7 +207,7 @@ void Object::emitInterfacesRemovedSignal(const std::vector<std::string>& interfa
void Object::addObjectManager()
{
objectManagerSlot_ = connection_.addObjectManager(objectPath_, request_slot);
objectManagerSlot_ = connection_.addObjectManager(objectPath_);
}
void Object::removeObjectManager()
@@ -232,7 +222,7 @@ bool Object::hasObjectManager() const
sdbus::IConnection& Object::getConnection() const
{
return connection_;
return dynamic_cast<sdbus::IConnection&>(connection_);
}
const std::string& Object::getObjectPath() const
@@ -240,16 +230,6 @@ const std::string& Object::getObjectPath() const
return objectPath_;
}
const Message* Object::getCurrentlyProcessedMessage() const
{
return m_CurrentlyProcessedMessage.load(std::memory_order_relaxed);
}
Object::InterfaceData& Object::getInterface(const std::string& interfaceName)
{
return interfaces_.emplace(interfaceName, *this).first->second;
}
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
{
auto& vtable = interfaceData.vtable;
@@ -276,7 +256,7 @@ void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::ve
, methodData.outputArgs.c_str()
, methodData.paramNames.c_str()
, &Object::sdbus_method_callback
, methodData.flags.toSdBusMethodFlags() ));
, methodData.flags_.toSdBusMethodFlags() ));
}
}
@@ -319,7 +299,7 @@ void Object::activateInterfaceVTable( const std::string& interfaceName
, InterfaceData& interfaceData
, const std::vector<sd_bus_vtable>& vtable )
{
interfaceData.slot = connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], &interfaceData);
interfaceData.slot = connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], this);
}
std::string Object::paramNamesToString(const std::vector<std::string>& paramNames)
@@ -332,39 +312,40 @@ std::string Object::paramNamesToString(const std::vector<std::string>& paramName
int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
{
auto* interfaceData = static_cast<InterfaceData*>(userData);
assert(interfaceData != nullptr);
auto& object = interfaceData->object;
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &object.connection_.getSdBusInterface());
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &object->connection_.getSdBusInterface());
object.m_CurrentlyProcessedMessage.store(&message, std::memory_order_relaxed);
SCOPE_EXIT
{
object.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
};
auto& callback = interfaceData->methods[message.getMemberName()].callback;
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[message.getInterfaceName()].methods[message.getMemberName()].callback;
assert(callback);
auto ok = invokeHandlerAndCatchErrors([&](){ callback(message); }, retError);
try
{
callback(std::move(message));
}
catch (const sdbus::Error& e)
{
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
}
return ok ? 1 : -1;
return 1;
}
int Object::sdbus_property_get_callback( sd_bus */*bus*/
, const char */*objectPath*/
, const char */*interface*/
, const char *interface
, const char *property
, sd_bus_message *sdbusReply
, void *userData
, sd_bus_error *retError )
{
auto* interfaceData = static_cast<InterfaceData*>(userData);
assert(interfaceData != nullptr);
auto& object = interfaceData->object;
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
auto& callback = interfaceData->properties[property].getCallback;
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[interface].properties[property].getCallback;
// Getter can be empty - the case of "write-only" property
if (!callback)
{
@@ -372,39 +353,47 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
return 1;
}
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &object.connection_.getSdBusInterface());
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &object->connection_.getSdBusInterface());
auto ok = invokeHandlerAndCatchErrors([&](){ callback(reply); }, retError);
try
{
callback(reply);
}
catch (const sdbus::Error& e)
{
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
}
return ok ? 1 : -1;
return 1;
}
int Object::sdbus_property_set_callback( sd_bus */*bus*/
, const char */*objectPath*/
, const char */*interface*/
, const char *interface
, const char *property
, sd_bus_message *sdbusValue
, void *userData
, sd_bus_error *retError )
{
auto* interfaceData = static_cast<InterfaceData*>(userData);
assert(interfaceData != nullptr);
auto& object = interfaceData->object;
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
auto& callback = interfaceData->properties[property].setCallback;
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[interface].properties[property].setCallback;
assert(callback);
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &object.connection_.getSdBusInterface());
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &object->connection_.getSdBusInterface());
object.m_CurrentlyProcessedMessage.store(&value, std::memory_order_relaxed);
SCOPE_EXIT
try
{
object.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
};
callback(value);
}
catch (const sdbus::Error& e)
{
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
}
auto ok = invokeHandlerAndCatchErrors([&](){ callback(value); }, retError);
return ok ? 1 : -1;
return 1;
}
}
+6 -15
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Object.h
*
@@ -29,13 +29,12 @@
#include <sdbus-c++/IObject.h>
#include "IConnection.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <string>
#include <map>
#include <vector>
#include <functional>
#include <memory>
#include <atomic>
#include <cassert>
namespace sdbus::internal {
@@ -103,14 +102,11 @@ namespace sdbus::internal {
sdbus::IConnection& getConnection() const override;
const std::string& getObjectPath() const override;
const Message* getCurrentlyProcessedMessage() const override;
private:
using InterfaceName = std::string;
struct InterfaceData
{
InterfaceData(Object& object) : object(object) {}
using MethodName = std::string;
struct MethodData
{
@@ -118,7 +114,7 @@ namespace sdbus::internal {
const std::string outputArgs;
const std::string paramNames;
method_callback callback;
Flags flags;
Flags flags_;
};
std::map<MethodName, MethodData> methods;
using SignalName = std::string;
@@ -140,14 +136,10 @@ namespace sdbus::internal {
std::map<PropertyName, PropertyData> properties;
std::vector<sd_bus_vtable> vtable;
Flags flags;
Object& object;
// This is intentionally the last member, because it must be destructed first,
// releasing callbacks above before the callbacks themselves are destructed.
Slot slot;
SlotPtr slot;
};
InterfaceData& getInterface(const std::string& interfaceName);
static const std::vector<sd_bus_vtable>& createInterfaceVTable(InterfaceData& interfaceData);
static void registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
static void registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
@@ -177,8 +169,7 @@ namespace sdbus::internal {
sdbus::internal::IConnection& connection_;
std::string objectPath_;
std::map<InterfaceName, InterfaceData> interfaces_;
Slot objectManagerSlot_;
std::atomic<const Message*> m_CurrentlyProcessedMessage{nullptr};
SlotPtr objectManagerSlot_;
};
}
+42 -151
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Proxy.cpp
*
@@ -27,15 +27,14 @@
#include "Proxy.h"
#include "IConnection.h"
#include "MessageUtils.h"
#include "Utils.h"
#include "sdbus-c++/Message.h"
#include "sdbus-c++/IConnection.h"
#include "sdbus-c++/Error.h"
#include "ScopeGuard.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <cassert>
#include <chrono>
#include <utility>
#include <thread>
namespace sdbus::internal {
@@ -44,9 +43,6 @@ Proxy::Proxy(sdbus::internal::IConnection& connection, std::string destination,
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
SDBUS_CHECK_SERVICE_NAME(destination_);
SDBUS_CHECK_OBJECT_PATH(objectPath_);
// The connection is not ours only, it is owned and managed by the user and we just reference
// it here, so we expect the client to manage the event loop upon this connection themselves.
}
@@ -58,29 +54,11 @@ Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
SDBUS_CHECK_SERVICE_NAME(destination_);
SDBUS_CHECK_OBJECT_PATH(objectPath_);
// The connection is ours only, i.e. it's us who has to manage the event loop upon this connection,
// in order that we get and process signals, async call replies, and other messages from D-Bus.
connection_->enterEventLoopAsync();
}
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t )
: connection_(std::move(connection))
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
SDBUS_CHECK_SERVICE_NAME(destination_);
SDBUS_CHECK_OBJECT_PATH(objectPath_);
// Even though the connection is ours only, we don't start an event loop thread.
// This proxy is meant to be created, used for simple synchronous D-Bus call(s) and then dismissed.
}
MethodCall Proxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
{
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
@@ -89,14 +67,14 @@ MethodCall Proxy::createMethodCall(const std::string& interfaceName, const std::
MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout)
{
// Sending method call synchronously is the only operation that blocks, waiting for the method
// reply message among the incoming messages on the sd-bus connection socket. But typically there
// reply message among the incoming message on the sd-bus connection socket. But typically there
// already is somebody that generally handles incoming D-Bus messages -- the connection event loop
// running typically in its own thread. We have to avoid polling on socket from several threads.
// So we have to branch here: either we are within the context of the event loop thread, then we
// can send the message simply via sd_bus_call, which blocks. Or we are in another thread, then
// we can perform the send operation of the method call message from here (because that is thread-
// safe like other sd-bus API accesses), but the incoming reply we have to get through the event
// loop thread, because this is the only rightful listener on the sd-bus connection socket.
// loop thread, because this is be the only rightful listener on the sd-bus connection socket.
// So, technically, we use async means to wait here for reply received by the event loop thread.
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid method call message provided", EINVAL);
@@ -120,39 +98,17 @@ PendingAsyncCall Proxy::callMethod(const MethodCall& message, async_reply_handle
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL);
auto callback = (void*)&Proxy::sdbus_async_reply_handler;
auto callData = std::make_shared<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}, AsyncCalls::CallData::State::RUNNING});
auto callData = std::make_shared<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}});
auto weakData = std::weak_ptr<AsyncCalls::CallData>{callData};
callData->slot = message.send(callback, callData.get(), timeout);
pendingAsyncCalls_.addCall(std::move(callData));
auto slotPtr = callData->slot.get();
pendingAsyncCalls_.addCall(slotPtr, std::move(callData));
return {weakData};
}
std::future<MethodReply> Proxy::callMethod(const MethodCall& message, with_future_t)
{
return Proxy::callMethod(message, {}, with_future);
}
std::future<MethodReply> Proxy::callMethod(const MethodCall& message, uint64_t timeout, with_future_t)
{
auto promise = std::make_shared<std::promise<MethodReply>>();
auto future = promise->get_future();
async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply& reply, const Error* error) noexcept
{
if (error == nullptr)
promise->set_value(reply);
else
promise->set_exception(std::make_exception_ptr(*error));
};
(void)Proxy::callMethod(message, std::move(asyncReplyCallback), timeout);
return future;
}
MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& message, uint64_t timeout)
{
/*thread_local*/ SyncCallReplyData syncCallReplyData;
@@ -162,9 +118,9 @@ MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& messag
syncCallReplyData.sendMethodReplyToWaitingThread(reply, error);
};
auto callback = (void*)&Proxy::sdbus_async_reply_handler;
AsyncCalls::CallData callData{*this, std::move(asyncReplyCallback), {}, AsyncCalls::CallData::State::NOT_ASYNC};
AsyncCalls::CallData callData{*this, std::move(asyncReplyCallback), {}};
message.send(callback, &callData, timeout, floating_slot);
message.send(callback, &callData, timeout, dont_request_slot);
return syncCallReplyData.waitForMethodReply();
}
@@ -200,28 +156,17 @@ void Proxy::registerSignalHandler( const std::string& interfaceName
, const std::string& signalName
, signal_handler signalHandler )
{
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
SDBUS_CHECK_MEMBER_NAME(signalName);
SDBUS_THROW_ERROR_IF(!signalHandler, "Invalid signal handler provided", EINVAL);
auto& interface = interfaces_[interfaceName];
auto signalData = std::make_unique<InterfaceData::SignalData>(*this, std::move(signalHandler), nullptr);
InterfaceData::SignalData signalData{std::move(signalHandler), nullptr};
auto insertionResult = interface.signals_.emplace(signalName, std::move(signalData));
auto inserted = insertionResult.second;
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal handler: handler already exists", EINVAL);
}
void Proxy::unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName )
{
auto it = interfaces_.find(interfaceName);
if (it != interfaces_.end())
it->second.signals_.erase(signalName);
}
void Proxy::finishRegistration()
{
registerSignalHandlers(*connection_);
@@ -237,13 +182,12 @@ void Proxy::registerSignalHandlers(sdbus::internal::IConnection& connection)
for (auto& signalItem : signalsOnInterface)
{
const auto& signalName = signalItem.first;
auto* signalData = signalItem.second.get();
signalData->slot = connection.registerSignalHandler( destination_
, objectPath_
, interfaceName
, signalName
, &Proxy::sdbus_signal_handler
, signalData);
auto& slot = signalItem.second.slot_;
slot = connection.registerSignalHandler( objectPath_
, interfaceName
, signalName
, &Proxy::sdbus_signal_handler
, this );
}
}
}
@@ -254,81 +198,59 @@ void Proxy::unregister()
interfaces_.clear();
}
sdbus::IConnection& Proxy::getConnection() const
{
return *connection_;
}
const std::string& Proxy::getObjectPath() const
{
return objectPath_;
}
const Message* Proxy::getCurrentlyProcessedMessage() const
{
return m_CurrentlyProcessedMessage.load(std::memory_order_relaxed);
}
int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
{
auto* asyncCallData = static_cast<AsyncCalls::CallData*>(userData);
assert(asyncCallData != nullptr);
assert(asyncCallData->callback);
auto& proxy = asyncCallData->proxy;
auto state = asyncCallData->state;
auto slot = asyncCallData->slot.get();
// We are removing the CallData item at the complete scope exit, after the callback has been invoked.
// We can't do it earlier (before callback invocation for example), because CallBack data (slot release)
// is the synchronization point between callback invocation and Proxy::unregister.
SCOPE_EXIT
{
// Remove call meta-data if it's a real async call (a sync call done in terms of async has STATE_NOT_ASYNC)
if (state != AsyncCalls::CallData::State::NOT_ASYNC)
proxy.pendingAsyncCalls_.removeCall(asyncCallData);
// Remove call meta-data if it's a real async call (a sync call done in terms of async has slot == nullptr)
if (slot)
proxy.pendingAsyncCalls_.removeCall(slot);
};
auto message = Message::Factory::create<MethodReply>(sdbusMessage, &proxy.connection_->getSdBusInterface());
proxy.m_CurrentlyProcessedMessage.store(&message, std::memory_order_relaxed);
SCOPE_EXIT
const auto* error = sd_bus_message_get_error(sdbusMessage);
if (error == nullptr)
{
proxy.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
};
auto ok = invokeHandlerAndCatchErrors([&]
asyncCallData->callback(message, nullptr);
}
else
{
const auto* error = sd_bus_message_get_error(sdbusMessage);
if (error == nullptr)
{
asyncCallData->callback(message, nullptr);
}
else
{
Error exception(error->name, error->message);
asyncCallData->callback(message, &exception);
}
}, retError);
sdbus::Error exception(error->name, error->message);
asyncCallData->callback(message, &exception);
}
return ok ? 0 : -1;
return 1;
}
int Proxy::sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
int Proxy::sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
{
auto* signalData = static_cast<InterfaceData::SignalData*>(userData);
assert(signalData != nullptr);
assert(signalData->callback);
auto* proxy = static_cast<Proxy*>(userData);
assert(proxy != nullptr);
auto message = Message::Factory::create<Signal>(sdbusMessage, &signalData->proxy.connection_->getSdBusInterface());
auto message = Message::Factory::create<Signal>(sdbusMessage, &proxy->connection_->getSdBusInterface());
signalData->proxy.m_CurrentlyProcessedMessage.store(&message, std::memory_order_relaxed);
SCOPE_EXIT
{
signalData->proxy.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
};
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = proxy->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
assert(callback);
auto ok = invokeHandlerAndCatchErrors([&](){ signalData->callback(message); }, retError);
callback(message);
return ok ? 0 : -1;
return 0;
}
}
@@ -345,7 +267,7 @@ void PendingAsyncCall::cancel()
if (auto ptr = callData_.lock(); ptr != nullptr)
{
auto* callData = static_cast<internal::Proxy::AsyncCalls::CallData*>(ptr.get());
callData->proxy.pendingAsyncCalls_.removeCall(callData);
callData->proxy.pendingAsyncCalls_.removeCall(callData->slot.get());
// At this point, the callData item is being deleted, leading to the release of the
// sd-bus slot pointer. This release locks the global sd-bus mutex. If the async
@@ -389,22 +311,6 @@ std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& conne
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t )
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
connection.release();
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
}
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
, std::string objectPath )
{
@@ -418,19 +324,4 @@ std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t )
{
auto connection = sdbus::createConnection();
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
assert(sdbusConnection != nullptr);
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
}
}
+14 -48
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Proxy.h
*
@@ -29,13 +29,12 @@
#include <sdbus-c++/IProxy.h>
#include "IConnection.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <string>
#include <memory>
#include <map>
#include <deque>
#include <unordered_map>
#include <mutex>
#include <atomic>
#include <condition_variable>
namespace sdbus::internal {
@@ -50,29 +49,18 @@ namespace sdbus::internal {
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, std::string destination
, std::string objectPath );
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, std::string destination
, std::string objectPath
, dont_run_event_loop_thread_t );
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) override;
std::future<MethodReply> callMethod(const MethodCall& message, with_future_t) override;
std::future<MethodReply> callMethod(const MethodCall& message, uint64_t timeout, with_future_t) override;
void registerSignalHandler( const std::string& interfaceName
, const std::string& signalName
, signal_handler signalHandler ) override;
void unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName ) override;
void finishRegistration() override;
void unregister() override;
sdbus::IConnection& getConnection() const override;
const std::string& getObjectPath() const override;
const Message* getCurrentlyProcessedMessage() const override;
private:
class SyncCallReplyData
@@ -109,20 +97,10 @@ namespace sdbus::internal {
using SignalName = std::string;
struct SignalData
{
SignalData(Proxy& proxy, signal_handler callback, Slot slot)
: proxy(proxy)
, callback(std::move(callback))
, slot(std::move(slot))
{}
Proxy& proxy;
signal_handler callback;
// slot must be listed after callback to ensure that slot is destructed first.
// Destructing the slot will sd_bus_slot_unref() the callback.
// Only after sd_bus_slot_unref(), we can safely delete the callback. The bus mutex (SdBus::sdbusMutex_)
// ensures that sd_bus_slot_unref() and the callback execute sequentially.
Slot slot;
signal_handler callback_;
SlotPtr slot_;
};
std::map<SignalName, std::unique_ptr<SignalData>> signals_;
std::map<SignalName, SignalData> signals_;
};
std::map<InterfaceName, InterfaceData> interfaces_;
@@ -135,16 +113,9 @@ namespace sdbus::internal {
public:
struct CallData
{
enum class State
{ NOT_ASYNC
, RUNNING
, FINISHED
};
Proxy& proxy;
async_reply_handler callback;
Slot slot;
State state;
MethodCall::Slot slot;
};
~AsyncCalls()
@@ -152,20 +123,18 @@ namespace sdbus::internal {
clear();
}
void addCall(std::shared_ptr<CallData> asyncCallData)
bool addCall(void* slot, std::shared_ptr<CallData> asyncCallData)
{
std::lock_guard lock(mutex_);
if (asyncCallData->state != CallData::State::FINISHED) // The call may have finished in the meantime
calls_.emplace_back(std::move(asyncCallData));
return calls_.emplace(slot, std::move(asyncCallData)).second;
}
void removeCall(CallData* data)
void removeCall(void* slot)
{
std::unique_lock lock(mutex_);
data->state = CallData::State::FINISHED;
if (auto it = std::find_if(calls_.begin(), calls_.end(), [data](auto const& entry){ return entry.get() == data; }); it != calls_.end())
if (auto it = calls_.find(slot); it != calls_.end())
{
auto callData = std::move(*it);
auto callData = std::move(it->second);
calls_.erase(it);
lock.unlock();
@@ -180,7 +149,6 @@ namespace sdbus::internal {
{
std::unique_lock lock(mutex_);
auto asyncCallSlots = std::move(calls_);
calls_ = {};
lock.unlock();
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
@@ -190,11 +158,9 @@ namespace sdbus::internal {
}
private:
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
std::mutex mutex_;
std::deque<std::shared_ptr<CallData>> calls_;
} pendingAsyncCalls_;
std::atomic<const Message*> m_CurrentlyProcessedMessage{nullptr};
};
}
+46 -83
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ScopeGuard.h
*
@@ -55,115 +55,78 @@
// return; // exiting scope normally
// }
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::sdbus::internal::ScopeGuardOnExitTag{} + [&]() \
/**/
#define SCOPE_EXIT_NAMED(NAME) \
auto NAME \
= ::sdbus::internal::ScopeGuardOnExitTag{} + [&]() \
/**/
#define SCOPE_EXIT_SUCCESS \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::sdbus::internal::ScopeGuardOnExitSuccessTag{} + [&]() \
/**/
#define SCOPE_EXIT_SUCCESS_NAMED(NAME) \
auto NAME \
= ::sdbus::internal::ScopeGuardOnExitSuccessTag{} + [&]() \
/**/
#define SCOPE_EXIT_FAILURE \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::sdbus::internal::ScopeGuardOnExitFailureTag{} + [&]() \
/**/
#define SCOPE_EXIT_FAILURE_NAMED(NAME) \
auto NAME \
= ::sdbus::internal::ScopeGuardOnExitFailureTag{} + [&]() \
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::skybase::utils::detail::ScopeGuardOnExit() + [&]() \
/**/
namespace sdbus::internal {
#define SCOPE_EXIT_NAMED(NAME) \
auto NAME \
= ::skybase::utils::detail::ScopeGuardOnExit() + [&]() \
/**/
struct ScopeGuardOnExitTag
{
static bool holds(int /*originalExceptions*/)
{
return true; // Always holds
}
};
struct ScopeGuardOnExitSuccessTag
{
static bool holds(int originalExceptions)
{
return originalExceptions == std::uncaught_exceptions(); // Only holds when no exception occurred within the scope
}
};
struct ScopeGuardOnExitFailureTag
{
static bool holds(int originalExceptions)
{
return originalExceptions != std::uncaught_exceptions(); // Only holds when an exception occurred within the scope
}
};
namespace skybase {
namespace utils {
template <class _Fun, typename _Tag>
template <class _Fun>
class ScopeGuard
{
_Fun fnc_;
bool active_;
public:
ScopeGuard(_Fun f) : fnc_(std::move(f))
ScopeGuard(_Fun f)
: fnc_(std::move(f))
, active_(true)
{
}
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs) : fnc_(std::move(rhs.fnc_)), active_(rhs.active_), exceptions_(rhs.exceptions_)
~ScopeGuard()
{
rhs.dismiss();
if (active_)
fnc_();
}
void dismiss()
{
active_ = false;
}
~ScopeGuard()
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs)
: fnc_(std::move(rhs.fnc_))
, active_(rhs.active_)
{
if (active_ && _Tag::holds(exceptions_))
fnc_();
rhs.dismiss();
}
private:
_Fun fnc_;
int exceptions_{std::uncaught_exceptions()};
bool active_{true};
};
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitTag> operator+(ScopeGuardOnExitTag, _Fun&& fnc)
namespace detail
{
return ScopeGuard<_Fun, ScopeGuardOnExitTag>(std::forward<_Fun>(fnc));
enum class ScopeGuardOnExit
{
};
// Helper function to auto-deduce type of the callable entity
template <typename _Fun>
ScopeGuard<_Fun> operator+(ScopeGuardOnExit, _Fun&& fnc)
{
return ScopeGuard<_Fun>(std::forward<_Fun>(fnc));
}
}
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitSuccessTag> operator+(ScopeGuardOnExitSuccessTag, _Fun&& fnc)
{
return ScopeGuard<_Fun, ScopeGuardOnExitSuccessTag>(std::forward<_Fun>(fnc));
}
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitFailureTag> operator+(ScopeGuardOnExitFailureTag, _Fun&& fnc)
{
return ScopeGuard<_Fun, ScopeGuardOnExitFailureTag>(std::forward<_Fun>(fnc));
}
}
}}
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __COUNTER__)
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __COUNTER__) \
/**/
#else
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __LINE__) \
/**/
#endif
#endif /* SDBUS_CPP_INTERNAL_SCOPEGUARD_H_ */
+7 -232
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file SdBus.cpp
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -48,14 +48,7 @@ int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
{
std::lock_guard lock(sdbusMutex_);
auto r = ::sd_bus_send(bus, m, cookie);
if (r < 0)
return r;
// Make sure long messages are not only stored in outgoing queues but also really sent out
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
return r;
return ::sd_bus_send(bus, m, cookie);
}
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
@@ -69,14 +62,7 @@ int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m,
{
std::lock_guard lock(sdbusMutex_);
auto r = ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
if (r < 0)
return r;
// Make sure long messages are not only stored in outgoing queues but also really sent out
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
return r;
return ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
}
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type)
@@ -175,9 +161,9 @@ int SdBus::sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, ch
return ::sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
}
int SdBus::sd_bus_open(sd_bus **ret)
int SdBus::sd_bus_open_user(sd_bus **ret)
{
return ::sd_bus_open(ret);
return ::sd_bus_open_user(ret);
}
int SdBus::sd_bus_open_system(sd_bus **ret)
@@ -185,123 +171,9 @@ int SdBus::sd_bus_open_system(sd_bus **ret)
return ::sd_bus_open_system(ret);
}
int SdBus::sd_bus_open_user(sd_bus **ret)
{
return ::sd_bus_open_user(ret);
}
int SdBus::sd_bus_open_user_with_address(sd_bus **ret, const char* address)
{
sd_bus* bus = nullptr;
int r = ::sd_bus_new(&bus);
if (r < 0)
return r;
r = ::sd_bus_set_address(bus, address);
if (r < 0)
return r;
r = ::sd_bus_set_bus_client(bus, true);
if (r < 0)
return r;
// Copying behavior from
// https://github.com/systemd/systemd/blob/fee6441601c979165ebcbb35472036439f8dad5f/src/libsystemd/sd-bus/sd-bus.c#L1381
// Here, we make the bus as trusted
r = ::sd_bus_set_trusted(bus, true);
if (r < 0)
return r;
r = ::sd_bus_start(bus);
if (r < 0)
return r;
*ret = bus;
return 0;
}
int SdBus::sd_bus_open_direct(sd_bus **ret, const char* address)
{
sd_bus* bus = nullptr;
int r = ::sd_bus_new(&bus);
if (r < 0)
return r;
r = ::sd_bus_set_address(bus, address);
if (r < 0)
return r;
r = ::sd_bus_start(bus);
if (r < 0)
return r;
*ret = bus;
return 0;
}
int SdBus::sd_bus_open_direct(sd_bus **ret, int fd)
{
sd_bus* bus = nullptr;
int r = ::sd_bus_new(&bus);
if (r < 0)
return r;
r = ::sd_bus_set_fd(bus, fd, fd);
if (r < 0)
return r;
r = ::sd_bus_start(bus);
if (r < 0)
return r;
*ret = bus;
return 0;
}
int SdBus::sd_bus_open_server(sd_bus **ret, int fd)
{
sd_bus* bus = nullptr;
int r = ::sd_bus_new(&bus);
if (r < 0)
return r;
r = ::sd_bus_set_fd(bus, fd, fd);
if (r < 0)
return r;
sd_id128_t id;
r = ::sd_id128_randomize(&id);
if (r < 0)
return r;
r = ::sd_bus_set_server(bus, true, id);
if (r < 0)
return r;
r = ::sd_bus_start(bus);
if (r < 0)
return r;
*ret = bus;
return 0;
}
int SdBus::sd_bus_open_system_remote(sd_bus **ret, const char *host)
{
#ifdef SDBUS_basu
// https://git.sr.ht/~emersion/basu/commit/01d33b244eb6
return -EOPNOTSUPP;
#else
return ::sd_bus_open_system_remote(ret, host);
#endif
}
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
@@ -342,14 +214,7 @@ int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match,
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_match(bus, slot, match, callback, userdata);
}
int SdBus::sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_match_async(bus, slot, match, callback, install_callback, userdata);
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
}
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
@@ -359,16 +224,6 @@ sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
return ::sd_bus_slot_unref(slot);
}
int SdBus::sd_bus_new(sd_bus **ret)
{
return ::sd_bus_new(ret);
}
int SdBus::sd_bus_start(sd_bus *bus)
{
return ::sd_bus_start(bus);
}
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
{
std::lock_guard lock(sdbusMutex_);
@@ -405,84 +260,4 @@ sd_bus* SdBus::sd_bus_flush_close_unref(sd_bus *bus)
return ::sd_bus_flush_close_unref(bus);
}
sd_bus* SdBus::sd_bus_close_unref(sd_bus *bus)
{
#if LIBSYSTEMD_VERSION>=241
return ::sd_bus_close_unref(bus);
#else
::sd_bus_close(bus);
return ::sd_bus_unref(bus);
#endif
}
int SdBus::sd_bus_message_set_destination(sd_bus_message *m, const char *destination)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_set_destination(m, destination);
}
int SdBus::sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_query_sender_creds(m, mask, c);
}
sd_bus_creds* SdBus::sd_bus_creds_unref(sd_bus_creds *c)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_unref(c);
}
int SdBus::sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_pid(c, pid);
}
int SdBus::sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_uid(c, uid);
}
int SdBus::sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_euid(c, euid);
}
int SdBus::sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_gid(c, gid);
}
int SdBus::sd_bus_creds_get_egid(sd_bus_creds *c, uid_t *egid)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_egid(c, egid);
}
int SdBus::sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_supplementary_gids(c, gids);
}
int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_selinux_context(c, label);
}
}
+3 -26
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file SdBus.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -58,45 +58,22 @@ public:
virtual int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) override;
virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) override;
virtual int sd_bus_open(sd_bus **ret) override;
virtual int sd_bus_open_system(sd_bus **ret) override;
virtual int sd_bus_open_user(sd_bus **ret) override;
virtual int sd_bus_open_user_with_address(sd_bus **ret, const char* address) override;
virtual int sd_bus_open_system(sd_bus **ret) override;
virtual int sd_bus_open_system_remote(sd_bus **ret, const char* hsot) override;
virtual int sd_bus_open_direct(sd_bus **ret, const char* address) override;
virtual int sd_bus_open_direct(sd_bus **ret, int fd) override;
virtual int sd_bus_open_server(sd_bus **ret, int fd) override;
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
virtual int sd_bus_release_name(sd_bus *bus, const char *name) override;
virtual int sd_bus_get_unique_name(sd_bus *bus, const char **name) override;
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
virtual int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) override;
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
virtual int sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata) override;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
virtual int sd_bus_new(sd_bus **ret) override;
virtual int sd_bus_start(sd_bus *bus) override;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) override;
virtual int sd_bus_flush(sd_bus *bus) override;
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
virtual sd_bus *sd_bus_close_unref(sd_bus *bus) override;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) override;
virtual int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) override;
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) override;
virtual int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) override;
virtual int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) override;
virtual int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) override;
virtual int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) override;
virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) override;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) override;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) override;
private:
std::recursive_mutex sdbusMutex_;
+3 -29
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Types.cpp
*
@@ -27,11 +27,8 @@
#include <sdbus-c++/Types.h>
#include <sdbus-c++/Error.h>
#include "MessageUtils.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <cassert>
#include <cerrno>
#include <system_error>
#include <unistd.h>
namespace sdbus {
@@ -67,27 +64,4 @@ bool Variant::isEmpty() const
return msg_.isEmpty();
}
void UnixFd::close()
{
if (fd_ >= 0)
{
::close(fd_);
}
}
int UnixFd::checkedDup(int fd)
{
if (fd < 0)
{
return fd;
}
int ret = ::dup(fd);
if (ret < 0)
{
throw std::system_error(errno, std::generic_category(), "dup failed");
}
return ret;
}
}
-87
View File
@@ -1,87 +0,0 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Utils.h
*
* Created on: Feb 9, 2022
* 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_INTERNAL_UTILS_H_
#define SDBUS_CXX_INTERNAL_UTILS_H_
#include <sdbus-c++/Error.h>
#include SDBUS_HEADER
#if LIBSYSTEMD_VERSION>=246
#define SDBUS_CHECK_OBJECT_PATH(_PATH) \
SDBUS_THROW_ERROR_IF(!sd_bus_object_path_is_valid(_PATH.c_str()), "Invalid object path '" + _PATH + "' provided", EINVAL) \
/**/
#define SDBUS_CHECK_INTERFACE_NAME(_NAME) \
SDBUS_THROW_ERROR_IF(!sd_bus_interface_name_is_valid(_NAME.c_str()), "Invalid interface name '" + _NAME + "' provided", EINVAL) \
/**/
#define SDBUS_CHECK_SERVICE_NAME(_NAME) \
SDBUS_THROW_ERROR_IF(!_NAME.empty() && !sd_bus_service_name_is_valid(_NAME.c_str()), "Invalid service name '" + _NAME + "' provided", EINVAL) \
/**/
#define SDBUS_CHECK_MEMBER_NAME(_NAME) \
SDBUS_THROW_ERROR_IF(!sd_bus_member_name_is_valid(_NAME.c_str()), "Invalid member name '" + _NAME + "' provided", EINVAL) \
/**/
#else
#define SDBUS_CHECK_OBJECT_PATH(_PATH)
#define SDBUS_CHECK_INTERFACE_NAME(_NAME)
#define SDBUS_CHECK_SERVICE_NAME(_NAME)
#define SDBUS_CHECK_MEMBER_NAME(_NAME)
#endif
namespace sdbus::internal {
template <typename _Callable>
bool invokeHandlerAndCatchErrors(_Callable callable, sd_bus_error *retError)
{
try
{
callable();
}
catch (const Error& e)
{
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
return false;
}
catch (const std::exception& e)
{
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME, e.what());
return false;
}
catch (...)
{
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME, "Unknown error occurred");
return false;
}
return true;
}
// Implementation of the overload pattern for variant visitation
template <class... Ts> struct overload : Ts... { using Ts::operator()...; };
template <class... Ts> overload(Ts...) -> overload<Ts...>;
}
#endif /* SDBUS_CXX_INTERNAL_UTILS_H_ */
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file VTableUtils.c
*
@@ -25,7 +25,7 @@
*/
#include "VTableUtils.h"
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
sd_bus_vtable createVTableStartItem(uint64_t flags)
{
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file VTableUtils.h
*
@@ -27,7 +27,7 @@
#ifndef SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
#define SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
#include SDBUS_HEADER
#include <systemd/sd-bus.h>
#include <stdbool.h>
#ifdef __cplusplus
+34 -59
View File
@@ -2,44 +2,26 @@
# DOWNLOAD AND BUILD OF GOOGLETEST
#-------------------------------
set(GOOGLETEST_VERSION 1.10.0 CACHE STRING "Version of gmock to use")
set(GOOGLETEST_GIT_REPO "https://github.com/google/googletest.git" CACHE STRING "A git repo to clone and build googletest from if gmock is not found in the system")
include(FetchContent)
find_package(GTest ${GOOGLETEST_VERSION} CONFIG)
if (NOT TARGET GTest::gmock)
# Try pkg-config if GTest was not found through CMake config
find_package(PkgConfig)
if (PkgConfig_FOUND)
pkg_check_modules(GMock IMPORTED_TARGET GLOBAL gmock>=${GOOGLETEST_VERSION})
if(TARGET PkgConfig::GMock)
add_library(GTest::gmock ALIAS PkgConfig::GMock)
endif()
endif()
# GTest was not found in the system, build it on our own
if (NOT TARGET GTest::gmock)
include(FetchContent)
message("Fetching googletest...")
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
GIT_SHALLOW 1
UPDATE_COMMAND "")
message("Fetching googletest v${GOOGLETEST_VERSION}...")
FetchContent_Declare(googletest
GIT_REPOSITORY ${GOOGLETEST_GIT_REPO}
GIT_TAG release-${GOOGLETEST_VERSION}
GIT_SHALLOW 1
UPDATE_COMMAND "")
#FetchContent_MakeAvailable(googletest) # Not available in CMake 3.13 :-( Let's do it manually:
FetchContent_GetProperties(googletest)
if(NOT googletest_POPULATED)
FetchContent_Populate(googletest)
set(gtest_force_shared_crt ON CACHE INTERNAL "" FORCE)
set(BUILD_GMOCK ON CACHE INTERNAL "" FORCE)
set(INSTALL_GTEST OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS_BAK ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_BAK})
add_library(GTest::gmock ALIAS gmock)
endif()
endif()
#FetchContent_MakeAvailable(googletest) # Not available in CMake 3.13 :-( Let's do it manually:
FetchContent_GetProperties(googletest)
if(NOT googletest_POPULATED)
FetchContent_Populate(googletest)
set(gtest_force_shared_crt ON CACHE INTERNAL "" FORCE)
set(BUILD_GMOCK ON CACHE INTERNAL "" FORCE)
set(INSTALL_GTEST OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS_BAK ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_BAK})
endif()
#-------------------------------
@@ -104,14 +86,12 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
#----------------------------------
add_executable(sdbus-c++-unit-tests ${UNITTESTS_SRCS})
target_compile_definitions(sdbus-c++-unit-tests PRIVATE
LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION}
SDBUS_HEADER=<${LIBSYSTEMD_IMPL}/sd-bus.h>)
target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib GTest::gmock)
target_compile_definitions(sdbus-c++-unit-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib gmock gmock_main)
add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS})
target_compile_definitions(sdbus-c++-integration-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
target_link_libraries(sdbus-c++-integration-tests sdbus-c++ GTest::gmock)
target_link_libraries(sdbus-c++-integration-tests sdbus-c++ gmock gmock_main)
# Manual performance and stress tests
option(ENABLE_PERF_TESTS "Build and install manual performance tests (default OFF)" OFF)
@@ -140,26 +120,21 @@ endif()
# INSTALLATION
#----------------------------------
option(INSTALL_TESTS "Install tests (default OFF)" OFF)
set(TESTS_INSTALL_PATH "/opt/test/bin" CACHE STRING "Specifies where the test binaries will be installed")
if(INSTALL_TESTS)
include(GNUInstallDirs)
set(TESTS_INSTALL_PATH "tests/${PROJECT_NAME}" CACHE STRING "Specifies where the test binaries will be installed")
install(TARGETS sdbus-c++-unit-tests DESTINATION ${TESTS_INSTALL_PATH})
install(TARGETS sdbus-c++-integration-tests DESTINATION ${TESTS_INSTALL_PATH})
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/org.sdbuscpp.integrationtests.conf DESTINATION /etc/dbus-1/system.d)
install(TARGETS sdbus-c++-unit-tests DESTINATION ${TESTS_INSTALL_PATH} COMPONENT test)
install(TARGETS sdbus-c++-integration-tests DESTINATION ${TESTS_INSTALL_PATH} COMPONENT test)
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/org.sdbuscpp.integrationtests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT test)
if(ENABLE_PERF_TESTS)
install(TARGETS sdbus-c++-perf-tests-client DESTINATION ${TESTS_INSTALL_PATH})
install(TARGETS sdbus-c++-perf-tests-server DESTINATION ${TESTS_INSTALL_PATH})
install(FILES ${PERFTESTS_SOURCE_DIR}/files/org.sdbuscpp.perftests.conf DESTINATION /etc/dbus-1/system.d)
endif()
if(ENABLE_PERF_TESTS)
install(TARGETS sdbus-c++-perf-tests-client DESTINATION ${TESTS_INSTALL_PATH} COMPONENT test)
install(TARGETS sdbus-c++-perf-tests-server DESTINATION ${TESTS_INSTALL_PATH} COMPONENT test)
install(FILES ${PERFTESTS_SOURCE_DIR}/files/org.sdbuscpp.perftests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT test)
endif()
if(ENABLE_STRESS_TESTS)
install(TARGETS sdbus-c++-stress-tests DESTINATION ${TESTS_INSTALL_PATH} COMPONENT test)
install(FILES ${STRESSTESTS_SOURCE_DIR}/files/org.sdbuscpp.stresstests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT test)
endif()
if(ENABLE_STRESS_TESTS)
install(TARGETS sdbus-c++-stress-tests DESTINATION ${TESTS_INSTALL_PATH})
install(FILES ${STRESSTESTS_SOURCE_DIR}/files/org.sdbuscpp.stresstests.conf DESTINATION /etc/dbus-1/system.d)
endif()
#----------------------------------
@@ -169,4 +144,4 @@ endif()
if(NOT CMAKE_CROSSCOMPILING)
add_test(NAME sdbus-c++-unit-tests COMMAND sdbus-c++-unit-tests)
add_test(NAME sdbus-c++-integration-tests COMMAND sdbus-c++-integration-tests)
endif()
endif()
@@ -0,0 +1,19 @@
# Taken from https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
cmake_minimum_required(VERSION 3.6)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
@@ -0,0 +1,703 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorAndProxy_test.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
{
auto connection = sdbus::createConnection();
connection->requestName(INTERFACE_NAME);
ASSERT_NO_THROW(TestAdaptor adaptor(*connection));
ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH));
connection->releaseName(INTERFACE_NAME);
}
// Methods
TEST_F(SdbusTestObject, CallsEmptyMethodSuccesfully)
{
ASSERT_NO_THROW(m_proxy->noArgNoReturn());
}
TEST_F(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully)
{
auto resInt = m_proxy->getInt();
ASSERT_THAT(resInt, Eq(INT32_VALUE));
auto multiplyRes = m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodsWithTuplesSuccesfully)
{
auto resTuple = m_proxy->getTuple();
ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE));
ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodsWithStructSuccesfully)
{
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
auto vectorRes = m_proxy->getInts16FromStruct(a);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE}
};
vectorRes = m_proxy->getInts16FromStruct(b);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
}
TEST_F(SdbusTestObject, CallsMethodWithVariantSuccesfully)
{
sdbus::Variant v{DOUBLE_VALUE};
auto variantRes = m_proxy->processVariant(v);
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
}
TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
{
std::vector<int32_t> x{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
auto mapOfVariants = m_proxy->getMapOfVariants(x, y);
decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}};
ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>()));
ASSERT_THAT(mapOfVariants[0].get<bool>(), Eq(res[0].get<bool>()));
ASSERT_THAT(mapOfVariants[2].get<bool>(), Eq(res[2].get<bool>()));
}
TEST_F(SdbusTestObject, CallsMethodWithStructInStructSuccesfully)
{
auto val = m_proxy->getStructInStruct();
ASSERT_THAT(val.get<0>(), Eq(STRING_VALUE));
ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully)
{
auto val = m_proxy->sumStructItems({1, 2}, {3, 4});
ASSERT_THAT(val, Eq(1 + 2 + 3 + 4));
}
TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
{
auto val = m_proxy->sumVectorItems({1, 7}, {2, 3});
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3));
}
TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
{
auto resSignature = m_proxy->getSignature();
ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithObjectPathSuccesfully)
{
auto resObjectPath = m_proxy->getObjPath();
ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithUnixFdSuccesfully)
{
auto resUnixFd = m_proxy->getUnixFd();
ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
{
auto resComplex = m_proxy->getComplex();
ASSERT_THAT(resComplex.count(0), Eq(1));
}
TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
{
m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE);
ASSERT_TRUE(waitUntil(m_adaptor->m_wasMultiplyCalled));
ASSERT_THAT(m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully)
{
auto res = m_proxy->doOperationWith500msTimeout(20); // The operation will take 20ms, but the timeout is 500ms, so we are fine
ASSERT_THAT(res, Eq(20));
}
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
{
try
{
m_proxy->doOperationWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
{
try
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
future.get();
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
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());
ASSERT_TRUE(waitUntil(m_adaptor->m_wasThrowErrorCalled));
}
TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
{
// Yeah, this is kinda timing-dependent test, but times should be safe...
std::mutex mtx;
std::vector<uint32_t> results;
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
auto call = [&](uint32_t param)
{
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
auto result = proxy.doOperationAsync(param);
std::lock_guard<std::mutex> guard(mtx);
results.push_back(result);
};
std::thread invocations[]{std::thread{call, 1500}, std::thread{call, 1000}, std::thread{call, 500}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
}
TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
{
std::atomic<size_t> resultCount{};
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
auto call = [&]()
{
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
size_t localResultCount{};
for (size_t i = 0; i < 500; ++i)
{
auto result = proxy.doOperationAsync(i % 2);
if (result == (i % 2)) // Correct return value?
localResultCount++;
}
resultCount += localResultCount;
};
std::thread invocations[]{std::thread{call}, std::thread{call}, std::thread{call}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
ASSERT_THAT(resultCount, Eq(1500));
}
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doOperationClientSideAsync(100);
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
{
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
auto call = m_proxy->doOperationClientSideAsync(100);
ASSERT_TRUE(call.isPending());
}
TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_FALSE(call.isPending());
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(0);
(void) future.get(); // Wait for the call to finish
ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); }));
}
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doErroneousOperationClientSideAsync();
ASSERT_THROW(future.get(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingNonexistentMethod)
{
ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface)
{
ASSERT_THROW(m_proxy->callMethodOnNonexistentInterface(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
{
TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
{
TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist");
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
{
m_proxy->emitTwoSimpleSignals();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
}
#if LIBSYSTEMD_VERSION>=240
TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239)
{
s_connection->setMethodCallTimeout(5000000);
ASSERT_THAT(s_connection->getMethodCallTimeout(), Eq(5000000));
}
#else
TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240)
{
ASSERT_THROW(s_connection->setMethodCallTimeout(5000000), sdbus::Error);
ASSERT_THROW(s_connection->getMethodCallTimeout(), sdbus::Error);
}
#endif
// Signals
TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully)
{
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
{
auto proxy1 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
{
m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("zero"));
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one"));
}
TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
{
double d = 3.14;
m_adaptor->emitSignalWithVariant(d);
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant));
ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d));
}
TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
{
m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}});
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithSignature));
ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av"));
}
// Properties
TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
{
ASSERT_THAT(m_proxy->state(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty)
{
ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error);
}
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
{
uint32_t newActionValue = 5678;
m_proxy->action(newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
// Standard D-Bus interfaces
TEST_F(SdbusTestObject, PingsViaPeerInterface)
{
ASSERT_NO_THROW(m_proxy->Ping());
}
TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface)
{
// If /etc/machine-id does not exist in your system (which is very likely because you have
// a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve
// this, you can create /etc/machine-id yourself as symlink to /var/lib/dbus/machine-id,
// and then org.freedesktop.DBus.Peer.GetMachineId() will start to work.
if (::access("/etc/machine-id", F_OK) == -1)
GTEST_SKIP() << "/etc/machine-id file does not exist, GetMachineId() will not work";
ASSERT_NO_THROW(m_proxy->GetMachineId());
}
TEST_F(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface)
{
ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription()));
}
TEST_F(SdbusTestObject, GetsPropertyViaPropertiesInterface)
{
ASSERT_THAT(m_proxy->Get(INTERFACE_NAME, "state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{
uint32_t newActionValue = 2345;
m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
{
const auto properties = m_proxy->GetAll(INTERFACE_NAME);
ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& /*invalidatedProperties*/ )
{
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1));
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(!DEFAULT_BLOCKING_VALUE));
signalReceived = true;
};
m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
m_proxy->action(DEFAULT_ACTION_VALUE*2);
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties )
{
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1));
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
ASSERT_THAT(invalidatedProperties, SizeIs(1));
EXPECT_THAT(invalidatedProperties[0], Eq("action"));
signalReceived = true;
};
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME);
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
{
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
}
TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully)
{
auto subObject1 = sdbus::createObject(*s_connection, "/sub/path1");
subObject1->registerProperty("aProperty1").onInterface("org.sdbuscpp.integrationtests.iface1").withGetter([]{return uint8_t{123};});
subObject1->finishRegistration();
auto subObject2 = sdbus::createObject(*s_connection, "/sub/path2");
subObject2->registerProperty("aProperty2").onInterface("org.sdbuscpp.integrationtests.iface2").withGetter([]{return "hi";});
subObject2->finishRegistration();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path1").at("org.sdbuscpp.integrationtests.iface1").at("aProperty1").get<uint8_t>(), Eq(123));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path2").at("org.sdbuscpp.integrationtests.iface2").at("aProperty2").get<std::string>(), Eq("hi"));
}
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(1));
EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1));
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
m_adaptor->emitInterfacesAddedSignal();
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(1));
EXPECT_THAT(interfaces[0], Eq(INTERFACE_NAME));
signalReceived = true;
};
m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
signalReceived = true;
};
m_adaptor->emitInterfacesRemovedSignal();
ASSERT_TRUE(waitUntil(signalReceived));
}
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusAsyncMethodsTests.cpp
*
@@ -42,7 +42,6 @@
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::Le;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
@@ -57,7 +56,6 @@ using SdbusTestObject = TestFixture;
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
{
std::chrono::time_point<std::chrono::steady_clock> start;
try
{
std::promise<uint32_t> promise;
@@ -70,8 +68,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
promise.set_exception(std::make_exception_ptr(*err));
});
start = std::chrono::steady_clock::now();
m_proxy->doOperationClientSideAsyncWithTimeout(1us, 1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
m_proxy->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
future.get();
FAIL() << "Expected sdbus::Error exception";
@@ -80,8 +77,6 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
auto measuredTimeout = std::chrono::steady_clock::now() - start;
ASSERT_THAT(measuredTimeout, Le(50ms));
}
catch(...)
{
@@ -98,7 +93,7 @@ TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
std::atomic<int> startedCount{};
auto call = [&](uint32_t param)
{
TestProxy proxy{BUS_NAME, OBJECT_PATH};
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
auto result = proxy.doOperationAsync(param);
@@ -121,7 +116,7 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
std::atomic<int> startedCount{};
auto call = [&]()
{
TestProxy proxy{BUS_NAME, OBJECT_PATH};
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
@@ -161,24 +156,6 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFuture)
{
auto future = m_proxy->doOperationClientSideAsync(100, sdbus::with_future);
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutureOnBasicAPILevel)
{
auto future = m_proxy->doOperationClientSideAsyncOnBasicAPILevel(100);
auto methodReply = future.get();
uint32_t returnValue{};
methodReply >> returnValue;
ASSERT_THAT(returnValue, Eq(100));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
{
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
@@ -224,23 +201,7 @@ TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); }));
}
TEST_F(SdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending)
{
sdbus::PendingAsyncCall call;
ASSERT_FALSE(call.isPending());
}
TEST_F(SdbusTestObject, SupportsAsyncCallCopyAssignment)
{
sdbus::PendingAsyncCall call;
call = m_proxy->doOperationClientSideAsync(100);
ASSERT_TRUE(call.isPending());
}
TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
@@ -256,10 +217,3 @@ TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
ASSERT_THROW(future.get(), sdbus::Error);
}
TEST_F(SdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithFutureFails)
{
auto future = m_proxy->doErroneousOperationClientSideAsync(sdbus::with_future);
ASSERT_THROW(future.get(), sdbus::Error);
}
+8 -49
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusConnectionTests.cpp
*
@@ -37,11 +37,9 @@
// STL
#include <thread>
#include <chrono>
using ::testing::Eq;
using namespace sdbus::test;
using namespace std::chrono_literals;
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -56,8 +54,8 @@ TEST(Connection, CanRequestRegisteredDbusName)
{
auto connection = sdbus::createConnection();
ASSERT_NO_THROW(connection->requestName(BUS_NAME))
<< "Perhaps you've forgotten to copy `org.sdbuscpp.integrationtests.conf` file to `/etc/dbus-1/system.d` directory before running the tests?";
ASSERT_NO_THROW(connection->requestName(INTERFACE_NAME));
connection->releaseName(INTERFACE_NAME);
}
TEST(Connection, CannotRequestNonregisteredDbusName)
@@ -70,8 +68,8 @@ TEST(Connection, CanReleasedRequestedName)
{
auto connection = sdbus::createConnection();
connection->requestName(BUS_NAME);
ASSERT_NO_THROW(connection->releaseName(BUS_NAME));
connection->requestName(INTERFACE_NAME);
ASSERT_NO_THROW(connection->releaseName(INTERFACE_NAME));
}
TEST(Connection, CannotReleaseNonrequestedName)
@@ -83,51 +81,12 @@ TEST(Connection, CannotReleaseNonrequestedName)
TEST(Connection, CanEnterAndLeaveEventLoop)
{
auto connection = sdbus::createConnection();
connection->requestName(BUS_NAME);
connection->requestName(INTERFACE_NAME);
std::thread t([&](){ connection->enterEventLoop(); });
connection->leaveEventLoop();
t.join();
}
TEST(Connection, PollDataGetZeroTimeout)
{
sdbus::IConnection::PollData pd{};
pd.timeout_usec = 0;
ASSERT_TRUE(pd.getRelativeTimeout().has_value());
EXPECT_THAT(pd.getRelativeTimeout().value(), Eq(std::chrono::microseconds::zero()));
EXPECT_THAT(pd.getPollTimeout(), Eq(0));
}
TEST(Connection, PollDataGetInfiniteTimeout)
{
sdbus::IConnection::PollData pd{};
pd.timeout_usec = UINT64_MAX;
ASSERT_FALSE(pd.getRelativeTimeout().has_value());
EXPECT_THAT(pd.getPollTimeout(), Eq(-1));
}
TEST(Connection, PollDataGetZeroRelativeTimeoutForPast)
{
sdbus::IConnection::PollData pd{};
auto past = std::chrono::steady_clock::now() - 10s;
pd.timeout_usec = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch()).count();
ASSERT_TRUE(pd.getRelativeTimeout().has_value());
EXPECT_THAT(pd.getRelativeTimeout().value(), Eq(0us));
EXPECT_THAT(pd.getPollTimeout(), Eq(0));
}
TEST(Connection, PollDataGetRelativeTimeoutInTolerance)
{
sdbus::IConnection::PollData pd{};
constexpr auto TIMEOUT = 1s;
constexpr auto TOLERANCE = 100ms;
auto future = std::chrono::steady_clock::now() + TIMEOUT;
pd.timeout_usec = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch()).count();
ASSERT_TRUE(pd.getRelativeTimeout().has_value());
EXPECT_GE(pd.getRelativeTimeout().value(), TIMEOUT - TOLERANCE);
EXPECT_LE(pd.getRelativeTimeout().value(), TIMEOUT + TOLERANCE);
EXPECT_GE(pd.getPollTimeout(), 900);
EXPECT_LE(pd.getPollTimeout(), 1100);
connection->releaseName(INTERFACE_NAME);
}
+6 -131
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusGeneralTests.cpp
*
@@ -26,7 +26,6 @@
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "TestFixture.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
@@ -38,16 +37,9 @@
#include <fstream>
#include <future>
#include <unistd.h>
#include <variant>
using ::testing::ElementsAre;
using ::testing::Eq;
using namespace std::chrono_literals;
using namespace sdbus::test;
using AConnection = TestFixture;
using ADirectConnection = TestFixtureWithDirectConnection;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
@@ -55,127 +47,10 @@ using ADirectConnection = TestFixtureWithDirectConnection;
TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
{
auto connection = sdbus::createConnection();
connection->requestName(BUS_NAME);
connection->requestName(INTERFACE_NAME);
ASSERT_NO_THROW(TestAdaptor adaptor(*connection, OBJECT_PATH));
ASSERT_NO_THROW(TestProxy proxy(BUS_NAME, OBJECT_PATH));
}
ASSERT_NO_THROW(TestAdaptor adaptor(*connection));
ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH));
TEST(AProxy, SupportsMoveSemantics)
{
static_assert(std::is_move_constructible_v<DummyTestProxy>);
static_assert(std::is_move_assignable_v<DummyTestProxy>);
}
TEST(AnAdaptor, SupportsMoveSemantics)
{
static_assert(std::is_move_constructible_v<DummyTestAdaptor>);
static_assert(std::is_move_assignable_v<DummyTestAdaptor>);
}
TEST_F(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
{
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
});
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(matchingMessageReceived));
}
TEST_F(AConnection, CanInstallMatchRuleAsynchronously)
{
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
std::atomic<bool> matchRuleInstalled{false};
auto slot = s_proxyConnection->addMatchAsync( matchRule
, [&](sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
}
, [&](sdbus::Message& /*msg*/)
{
matchRuleInstalled = true;
} );
EXPECT_TRUE(waitUntil(matchRuleInstalled));
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(matchingMessageReceived));
}
TEST_F(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot)
{
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
});
slot.reset();
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s));
}
TEST_F(AConnection, CanAddFloatingMatchRule)
{
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
auto con = sdbus::createSystemBusConnection();
con->enterEventLoopAsync();
auto callback = [&](sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
};
con->addMatch(matchRule, std::move(callback), sdbus::floating_slot);
m_adaptor->emitSimpleSignal();
[[maybe_unused]] auto gotMessage = waitUntil(matchingMessageReceived, 2s);
assert(gotMessage);
matchingMessageReceived = false;
con.reset();
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s));
}
TEST_F(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule)
{
auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'";
std::atomic<size_t> numberOfMatchingMessages{};
auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
{
if(msg.getMemberName() == "simpleSignal")
numberOfMatchingMessages++;
});
auto adaptor2 = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH_2);
m_adaptor->emitSignalWithMap({});
adaptor2->emitSimpleSignal();
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil([&](){ return numberOfMatchingMessages == 2; }));
ASSERT_FALSE(waitUntil([&](){ return numberOfMatchingMessages > 2; }, 1s));
}
// A simple direct connection test similar in nature to https://github.com/systemd/systemd/blob/main/src/libsystemd/sd-bus/test-bus-server.c
TEST_F(ADirectConnection, CanBeUsedBetweenClientAndServer)
{
auto val = m_proxy->sumArrayItems({1, 7}, {2, 3, 4});
m_adaptor->emitSimpleSignal();
// Make sure method call passes and emitted signal is received
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3 + 4));
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
connection->releaseName(INTERFACE_NAME);
}
+13 -49
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusMethodsTests.cpp
*
@@ -42,11 +42,9 @@
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::Le;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -103,9 +101,7 @@ TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
std::vector<int32_t> x{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
auto mapOfVariants = m_proxy->getMapOfVariants(x, y);
decltype(mapOfVariants) res{ {sdbus::Variant{-2}, sdbus::Variant{false}}
, {sdbus::Variant{0}, sdbus::Variant{false}}
, {sdbus::Variant{2}, sdbus::Variant{true}}};
decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}};
ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>()));
ASSERT_THAT(mapOfVariants[0].get<bool>(), Eq(res[0].get<bool>()));
@@ -127,8 +123,8 @@ TEST_F(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully)
TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
{
auto val = m_proxy->sumArrayItems({1, 7}, {2, 3, 4});
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3 + 4));
auto val = m_proxy->sumVectorItems({1, 7}, {2, 3});
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3));
}
TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
@@ -165,24 +161,21 @@ TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
TEST_F(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully)
{
auto res = m_proxy->doOperationWithTimeout(500ms, 20); // The operation will take 20ms, but the timeout is 500ms, so we are fine
auto res = m_proxy->doOperationWith500msTimeout(20); // The operation will take 20ms, but the timeout is 500ms, so we are fine
ASSERT_THAT(res, Eq(20));
}
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
{
auto start = std::chrono::steady_clock::now();
try
{
m_proxy->doOperationWithTimeout(1us, 1000); // The operation will take 1s, but the timeout is 1us, so we should time out
m_proxy->doOperationWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Operation timed out", "Method call timed out"));
auto measuredTimeout = std::chrono::steady_clock::now() - start;
ASSERT_THAT(measuredTimeout, Le(50ms));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
}
catch(...)
{
@@ -233,7 +226,7 @@ TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
{
TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist");
TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist");
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
@@ -245,45 +238,16 @@ TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
}
TEST_F(SdbusTestObject, CanAccessAssociatedMethodCallMessageInMethodCallHandler)
{
m_proxy->doOperation(10); // This will save pointer to method call message on server side
ASSERT_THAT(m_adaptor->m_methodCallMsg, NotNull());
ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperation"));
}
TEST_F(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCallHandler)
{
m_proxy->doOperationAsync(10); // This will save pointer to method call message on server side
ASSERT_THAT(m_adaptor->m_methodCallMsg, NotNull());
ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperationAsync"));
}
#if LIBSYSTEMD_VERSION>=240
TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239)
{
s_adaptorConnection->setMethodCallTimeout(5000000);
ASSERT_THAT(s_adaptorConnection->getMethodCallTimeout(), Eq(5000000));
s_connection->setMethodCallTimeout(5000000);
ASSERT_THAT(s_connection->getMethodCallTimeout(), Eq(5000000));
}
#else
TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240)
{
ASSERT_THROW(s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error);
ASSERT_THROW(s_adaptorConnection->getMethodCallTimeout(), sdbus::Error);
ASSERT_THROW(s_connection->setMethodCallTimeout(5000000), sdbus::Error);
ASSERT_THROW(s_connection->getMethodCallTimeout(), sdbus::Error);
}
#endif
TEST_F(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
{
#if defined(__clang__) && defined(__FreeBSD__)
GTEST_SKIP() << "https://github.com/Kistler-Group/sdbus-cpp/issues/359";
#endif
auto proxy = std::make_unique<TestProxy>(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
auto multiplyRes = proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
}
+2 -13
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusPropertiesTests.cpp
*
@@ -45,9 +45,6 @@ using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using ::testing::Not;
using ::testing::IsEmpty;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -75,11 +72,3 @@ TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHandler)
{
m_proxy->blocking(true); // This will save pointer to property get message on server side
ASSERT_THAT(m_adaptor->m_propertySetMsg, NotNull());
ASSERT_THAT(m_adaptor->m_propertySetSender, Not(IsEmpty()));
}
+5 -80
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorAndProxy_test.cpp
*
@@ -32,7 +32,6 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <chrono>
using ::testing::Eq;
using ::testing::DoubleEq;
@@ -40,7 +39,6 @@ using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -59,8 +57,8 @@ TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully)
TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
{
auto proxy1 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy1 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
m_adaptor->emitSimpleSignal();
@@ -69,17 +67,6 @@ TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
{
auto otherBusName = BUS_NAME + "2";
auto connection2 = sdbus::createConnection(otherBusName);
auto adaptor2 = std::make_unique<TestAdaptor>(*connection2, OBJECT_PATH);
adaptor2->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s));
}
TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
{
m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
@@ -89,22 +76,10 @@ TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one"));
}
TEST_F(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully)
{
std::map<int32_t, std::string> largeMap;
for (int32_t i = 0; i < 20'000; ++i)
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1));
m_adaptor->emitSignalWithMap(largeMap);
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1"));
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2"));
}
TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
{
double d = 3.14;
m_adaptor->emitSignalWithVariant(sdbus::Variant{d});
m_adaptor->emitSignalWithVariant(d);
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant));
ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d));
@@ -117,53 +92,3 @@ TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithSignature));
ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av"));
}
TEST_F(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
{
m_adaptor->emitSimpleSignal();
waitUntil(m_proxy->m_gotSimpleSignal);
ASSERT_THAT(m_proxy->m_signalMsg, NotNull());
ASSERT_THAT(m_proxy->m_signalMemberName, Eq("simpleSignal"));
}
TEST_F(SdbusTestObject, UnregistersSignalHandler)
{
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s));
}
TEST_F(SdbusTestObject, UnregistersSignalHandlerForSomeProxies)
{
auto proxy1 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s));
}
TEST_F(SdbusTestObject, ReRegistersSignalHandler)
{
// unregister simple-signal handler
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s));
// re-register simple-signal handler
ASSERT_NO_THROW(m_proxy->reRegisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
}
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusStandardInterfacesTests.cpp
*
@@ -61,9 +61,12 @@ TEST_F(SdbusTestObject, PingsViaPeerInterface)
TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface)
{
if (::access("/etc/machine-id", F_OK) == -1 &&
::access("/var/lib/dbus/machine-id", F_OK) == -1)
GTEST_SKIP() << "/etc/machine-id and /var/lib/dbus/machine-id files do not exist, GetMachineId() will not work";
// If /etc/machine-id does not exist in your system (which is very likely because you have
// a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve
// this, you can create /etc/machine-id yourself as symlink to /var/lib/dbus/machine-id,
// and then org.freedesktop.DBus.Peer.GetMachineId() will start to work.
if (::access("/etc/machine-id", F_OK) == -1)
GTEST_SKIP() << "/etc/machine-id file does not exist, GetMachineId() will not work";
ASSERT_NO_THROW(m_proxy->GetMachineId());
}
@@ -79,66 +82,15 @@ TEST_F(SdbusTestObject, GetsPropertyViaPropertiesInterface)
ASSERT_THAT(m_proxy->Get(INTERFACE_NAME, "state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterface)
{
std::promise<std::string> promise;
auto future = promise.get_future();
m_proxy->GetAsync(INTERFACE_NAME, "state", [&](const sdbus::Error* err, sdbus::Variant value)
{
if (err == nullptr)
promise.set_value(value.get<std::string>());
else
promise.set_exception(std::make_exception_ptr(*err));
});
ASSERT_THAT(future.get(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture)
{
auto future = m_proxy->GetAsync(INTERFACE_NAME, "state", sdbus::with_future);
ASSERT_THAT(future.get().get<std::string>(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{
uint32_t newActionValue = 2345;
m_proxy->Set(INTERFACE_NAME, "action", sdbus::Variant{newActionValue});
m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface)
{
uint32_t newActionValue = 2346;
std::promise<void> promise;
auto future = promise.get_future();
m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, [&](const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value();
else
promise.set_exception(std::make_exception_ptr(*err));
});
ASSERT_NO_THROW(future.get());
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture)
{
uint32_t newActionValue = 2347;
auto future = m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, sdbus::with_future);
ASSERT_NO_THROW(future.get());
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
{
const auto properties = m_proxy->GetAll(INTERFACE_NAME);
@@ -149,38 +101,6 @@ TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
TEST_F(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterface)
{
std::promise<std::map<std::string, sdbus::Variant>> promise;
auto future = promise.get_future();
m_proxy->GetAllAsync(INTERFACE_NAME, [&](const sdbus::Error* err, std::map<std::string, sdbus::Variant> value)
{
if (err == nullptr)
promise.set_value(std::move(value));
else
promise.set_exception(std::make_exception_ptr(*err));
});
const auto properties = future.get();
ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
TEST_F(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfaceWithFuture)
{
auto future = m_proxy->GetAllAsync(INTERFACE_NAME, sdbus::with_future);
auto properties = future.get();
ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
{
std::atomic<bool> signalReceived{false};
@@ -223,31 +143,32 @@ TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
{
m_adaptor.reset();
const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
}
TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully)
{
auto adaptor2 = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH_2);
const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects();
auto subObject1 = sdbus::createObject(*s_connection, "/sub/path1");
subObject1->registerProperty("aProperty1").onInterface("org.sdbuscpp.integrationtests.iface1").withGetter([]{return uint8_t{123};});
subObject1->finishRegistration();
auto subObject2 = sdbus::createObject(*s_connection, "/sub/path2");
subObject2->registerProperty("aProperty2").onInterface("org.sdbuscpp.integrationtests.iface2").withGetter([]{return "hi";});
subObject2->finishRegistration();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH)
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2)
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path1").at("org.sdbuscpp.integrationtests.iface1").at("aProperty1").get<uint8_t>(), Eq(123));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path2").at("org.sdbuscpp.integrationtests.iface2").at("aProperty2").get<std::string>(), Eq("hi"));
}
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(1));
@@ -277,17 +198,11 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
#if LIBSYSTEMD_VERSION<=250
EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
#else
// Since systemd v251, ObjectManager standard interface is not listed among the interfaces
// if the object does not have object manager functionality explicitly enabled.
EXPECT_THAT(interfacesAndProperties, SizeIs(4)); // INTERFACE_NAME + 3 standard interfaces
#endif
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
@@ -313,8 +228,8 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(1));
@@ -330,17 +245,11 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
#if LIBSYSTEMD_VERSION<=250
ASSERT_THAT(interfaces, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
#else
// Since systemd v251, ObjectManager standard interface is not listed among the interfaces
// if the object does not have object manager functionality explicitly enabled.
ASSERT_THAT(interfaces, SizeIs(4)); // INTERFACE_NAME + 3 standard interfaces
#endif
signalReceived = true;
};
+3 -23
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Defs.h
*
@@ -28,19 +28,11 @@
#define SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_
#include "sdbus-c++/Types.h"
#include <chrono>
#include <ostream>
#include <filesystem>
namespace sdbus { namespace test {
const std::string INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
const std::string BUS_NAME = INTERFACE_NAME;
const std::string EMPTY_DESTINATION;
const std::string MANAGER_PATH {"/org/sdbuscpp/integrationtests"};
const std::string OBJECT_PATH {"/org/sdbuscpp/integrationtests/ObjectA1"};
const std::string OBJECT_PATH_2{"/org/sdbuscpp/integrationtests/ObjectB1"};
const std::string DIRECT_CONNECTION_SOCKET_PATH{std::filesystem::temp_directory_path() / "sdbus-cpp-direct-connection-test"};
const std::string OBJECT_PATH{"/"};
constexpr const uint8_t UINT8_VALUE{1};
constexpr const int16_t INT16_VALUE{21};
@@ -61,16 +53,4 @@ constexpr const double DOUBLE_VALUE{3.24L};
}}
namespace testing::internal {
// Printer for std::chrono::duration types.
// This is a workaround, since it's not a good thing to add this to std namespace.
template< class Rep, class Period >
void PrintTo(const ::std::chrono::duration<Rep, Period>& d, ::std::ostream* os) {
auto seconds = std::chrono::duration_cast<std::chrono::duration<double>>(d);
*os << seconds.count() << "s";
}
}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */
+11 -21
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
@@ -30,9 +30,9 @@
#include <atomic>
namespace sdbus { namespace test {
TestAdaptor::TestAdaptor(sdbus::IConnection& connection, const std::string& path) :
AdaptorInterfaces(connection, path)
TestAdaptor::TestAdaptor(sdbus::IConnection& connection) :
AdaptorInterfaces(connection, OBJECT_PATH)
{
registerAdaptor();
}
@@ -77,7 +77,7 @@ std::vector<int16_t> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_
sdbus::Variant TestAdaptor::processVariant(const sdbus::Variant& v)
{
sdbus::Variant res{static_cast<int32_t>(v.get<double>())};
sdbus::Variant res = static_cast<int32_t>(v.get<double>());
return res;
}
@@ -93,7 +93,7 @@ std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vecto
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> TestAdaptor::getStructInStruct()
{
return sdbus::Struct{STRING_VALUE, sdbus::Struct{std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}}};
return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}));
}
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
@@ -104,7 +104,7 @@ int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, c
return res;
}
uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& a, const std::array<uint64_t, 3>& b)
uint32_t TestAdaptor::sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b)
{
uint32_t res{0};
for (auto x : a)
@@ -121,18 +121,11 @@ uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& a, const std::a
uint32_t TestAdaptor::doOperation(const uint32_t& param)
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
m_methodCallMsg = getObject().getCurrentlyProcessedMessage();
m_methodCallMemberName = m_methodCallMsg->getMemberName();
return param;
}
void TestAdaptor::doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t param)
{
m_methodCallMsg = getObject().getCurrentlyProcessedMessage();
m_methodCallMemberName = m_methodCallMsg->getMemberName();
if (param == 0)
{
// Don't sleep and return the result from this thread
@@ -162,9 +155,9 @@ sdbus::UnixFd TestAdaptor::getUnixFd()
return sdbus::UnixFd{UNIX_FD_VALUE};
}
std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> TestAdaptor::getComplex()
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> TestAdaptor::getComplex()
{
return { // unordered_map
return { // map
{
0, // uint_64_t
{ // struct
@@ -234,9 +227,6 @@ bool TestAdaptor::blocking()
void TestAdaptor::blocking(const bool& value)
{
m_propertySetMsg = getObject().getCurrentlyProcessedMessage();
m_propertySetSender = m_propertySetMsg->getSender();
m_blocking = value;
}
@@ -390,7 +380,7 @@ R"delimiter(
<arg type="(ix)" direction="in"/>
<arg type="i" direction="out"/>
</method>
<method name="sumArrayItems">
<method name="sumVectorItems">
<arg type="aq" direction="in"/>
<arg type="at" direction="in"/>
<arg type="u" direction="out"/>
+6 -64
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.h
*
@@ -32,31 +32,15 @@
#include <thread>
#include <chrono>
#include <atomic>
#include <utility>
namespace sdbus { namespace test {
class ObjectManagerTestAdaptor final : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
{
public:
ObjectManagerTestAdaptor(sdbus::IConnection& connection, std::string path) :
AdaptorInterfaces(connection, std::move(path))
{
registerAdaptor();
}
~ObjectManagerTestAdaptor()
{
unregisterAdaptor();
}
};
class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integrationtests_adaptor
, sdbus::Properties_adaptor
, sdbus::ManagedObject_adaptor >
, sdbus::ObjectManager_adaptor >
{
public:
TestAdaptor(sdbus::IConnection& connection, const std::string& path);
TestAdaptor(sdbus::IConnection& connection);
~TestAdaptor();
protected:
@@ -70,13 +54,13 @@ protected:
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) override;
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override;
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) override;
uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1) override;
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1) override;
uint32_t doOperation(const uint32_t& arg0) override;
void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) override;
sdbus::Signature getSignature() override;
sdbus::ObjectPath getObjPath() override;
sdbus::UnixFd getUnixFd() override;
std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() override;
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() override;
void throwError() override;
void throwErrorWithNoReply() override;
void doPrivilegedStuff() override;
@@ -102,48 +86,6 @@ public: // for tests
mutable std::atomic<bool> m_wasMultiplyCalled{false};
mutable double m_multiplyResult{};
mutable std::atomic<bool> m_wasThrowErrorCalled{false};
const Message* m_methodCallMsg{};
std::string m_methodCallMemberName;
const Message* m_propertySetMsg{};
std::string m_propertySetSender;
};
class DummyTestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integrationtests_adaptor
, sdbus::Properties_adaptor
, sdbus::ManagedObject_adaptor >
{
public:
DummyTestAdaptor(sdbus::IConnection& connection, const std::string& path) : AdaptorInterfaces(connection, path) {}
protected:
void noArgNoReturn() override {}
int32_t getInt() override { return {}; }
std::tuple<uint32_t, std::string> getTuple() override { return {}; }
double multiply(const int64_t&, const double&) override { return {}; }
void multiplyWithNoReply(const int64_t&, const double&) override {}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>&) override { return {}; }
sdbus::Variant processVariant(const sdbus::Variant&) override { return {}; }
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>&, const sdbus::Struct<sdbus::Variant, sdbus::Variant>&) override { return {}; }
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override { return {}; }
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>&, const sdbus::Struct<int32_t, int64_t>&) override { return {}; }
uint32_t sumArrayItems(const std::vector<uint16_t>&, const std::array<uint64_t, 3>&) override { return {}; }
uint32_t doOperation(const uint32_t&) override { return {}; }
void doOperationAsync(sdbus::Result<uint32_t>&&, uint32_t) override {}
sdbus::Signature getSignature() override { return {}; }
sdbus::ObjectPath getObjPath() override { return {}; }
sdbus::UnixFd getUnixFd() override { return {}; }
std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() override { return {}; }
void throwError() override {}
void throwErrorWithNoReply() override {}
void doPrivilegedStuff() override {}
void emitTwoSimpleSignals() override {}
uint32_t action() override { return {}; }
void action(const uint32_t&) override {}
bool blocking() override { return {}; }
void blocking(const bool&) override {}
std::string state() override { return {}; }
};
}}
+4 -5
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
@@ -27,8 +27,7 @@
#include "TestFixture.h"
namespace sdbus { namespace test {
std::unique_ptr<sdbus::IConnection> TestFixture::s_adaptorConnection = sdbus::createSystemBusConnection();
std::unique_ptr<sdbus::IConnection> TestFixture::s_proxyConnection = sdbus::createSystemBusConnection();
std::unique_ptr<sdbus::IConnection> TestFixture::s_connection = sdbus::createSystemBusConnection();
}}
+33 -118
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.h
*
@@ -39,11 +39,6 @@
#include <atomic>
#include <chrono>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
namespace sdbus { namespace test {
class TestFixture : public ::testing::Test
@@ -51,27 +46,44 @@ class TestFixture : public ::testing::Test
public:
static void SetUpTestCase()
{
s_proxyConnection->enterEventLoopAsync();
s_adaptorConnection->requestName(BUS_NAME);
s_adaptorConnection->enterEventLoopAsync();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
s_connection->requestName(INTERFACE_NAME);
s_connection->enterEventLoopAsync();
}
static void TearDownTestCase()
{
s_adaptorConnection->releaseName(BUS_NAME);
s_adaptorConnection->leaveEventLoop();
s_proxyConnection->leaveEventLoop();
s_connection->leaveEventLoop();
s_connection->releaseName(INTERFACE_NAME);
}
template <typename _Fnc>
static bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
using namespace std::chrono_literals;
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
return false;
} while (!fnc());
return true;
}
static bool waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
return waitUntil([&flag]() -> bool { return flag; }, timeout);
}
private:
void SetUp() override
{
m_objectManagerProxy = std::make_unique<ObjectManagerTestProxy>(*s_proxyConnection, BUS_NAME, MANAGER_PATH);
m_proxy = std::make_unique<TestProxy>(*s_proxyConnection, BUS_NAME, OBJECT_PATH);
m_objectManagerAdaptor = std::make_unique<ObjectManagerTestAdaptor>(*s_adaptorConnection, MANAGER_PATH);
m_adaptor = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH);
m_adaptor = std::make_unique<TestAdaptor>(*s_connection);
m_proxy = std::make_unique<TestProxy>(INTERFACE_NAME, OBJECT_PATH);
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy to start listening to signals
}
void TearDown() override
@@ -81,109 +93,12 @@ private:
}
public:
static std::unique_ptr<sdbus::IConnection> s_adaptorConnection;
static std::unique_ptr<sdbus::IConnection> s_proxyConnection;
std::unique_ptr<ObjectManagerTestAdaptor> m_objectManagerAdaptor;
std::unique_ptr<ObjectManagerTestProxy> m_objectManagerProxy;
static std::unique_ptr<sdbus::IConnection> s_connection;
std::unique_ptr<TestAdaptor> m_adaptor;
std::unique_ptr<TestProxy> m_proxy;
};
class TestFixtureWithDirectConnection : public ::testing::Test
{
private:
void SetUp() override
{
int sock = openUnixSocket();
createClientAndServerConnections(sock);
createAdaptorAndProxyObjects();
}
void TearDown() override
{
m_proxy.reset();
m_adaptor.reset();
m_proxyConnection->leaveEventLoop();
m_adaptorConnection->leaveEventLoop();
}
static int openUnixSocket()
{
int sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
assert(sock >= 0);
sockaddr_un sa;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", DIRECT_CONNECTION_SOCKET_PATH.c_str());
unlink(DIRECT_CONNECTION_SOCKET_PATH.c_str());
umask(0000);
[[maybe_unused]] int r = bind(sock, (const sockaddr*) &sa, sizeof(sa.sun_path));
assert(r >= 0);
r = listen(sock, 5);
assert(r >= 0);
return sock;
}
void createClientAndServerConnections(int sock)
{
std::thread t([&]()
{
auto fd = accept4(sock, NULL, NULL, /*SOCK_NONBLOCK|*/SOCK_CLOEXEC);
m_adaptorConnection = sdbus::createServerBus(fd);
// This is necessary so that createDirectBusConnection() below does not block
m_adaptorConnection->enterEventLoopAsync();
});
m_proxyConnection = sdbus::createDirectBusConnection("unix:path=" + DIRECT_CONNECTION_SOCKET_PATH);
m_proxyConnection->enterEventLoopAsync();
t.join();
}
void createAdaptorAndProxyObjects()
{
assert(m_adaptorConnection != nullptr);
assert(m_proxyConnection != nullptr);
m_adaptor = std::make_unique<TestAdaptor>(*m_adaptorConnection, OBJECT_PATH);
// Destination parameter can be empty in case of direct connections
m_proxy = std::make_unique<TestProxy>(*m_proxyConnection, EMPTY_DESTINATION, OBJECT_PATH);
}
public:
std::unique_ptr<sdbus::IConnection> m_adaptorConnection;
std::unique_ptr<sdbus::IConnection> m_proxyConnection;
std::unique_ptr<TestAdaptor> m_adaptor;
std::unique_ptr<TestProxy> m_proxy;
};
template <typename _Fnc>
inline bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
using namespace std::chrono_literals;
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
return false;
} while (!fnc());
return true;
}
inline bool waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
return waitUntil([&flag]() -> bool { return flag; }, timeout);
}
}}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */
+19 -40
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
@@ -30,7 +30,7 @@
#include <atomic>
namespace sdbus { namespace test {
TestProxy::TestProxy(std::string destination, std::string objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
@@ -39,13 +39,6 @@ TestProxy::TestProxy(std::string destination, std::string objectPath)
registerProxy();
}
TestProxy::TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
: ProxyInterfaces(std::move(destination), std::move(objectPath), dont_run_event_loop_thread)
{
// It doesn't make sense to register any signals here since proxy upon a D-Bus connection with no event loop thread
// will not receive any incoming messages except replies to synchronous D-Bus calls.
}
TestProxy::TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
{
@@ -61,9 +54,6 @@ TestProxy::~TestProxy()
void TestProxy::onSimpleSignal()
{
m_signalMsg = getProxy().getCurrentlyProcessedMessage();
m_signalMemberName = m_signalMsg->getMemberName();
m_gotSimpleSignal = true;
}
@@ -99,16 +89,28 @@ void TestProxy::onPropertiesChanged( const std::string& interfaceName
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
}
void TestProxy::onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties)
{
if (m_onInterfacesAddedHandler)
m_onInterfacesAddedHandler(objectPath, interfacesAndProperties);
}
void TestProxy::onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces)
{
if (m_onInterfacesRemovedHandler)
m_onInterfacesRemovedHandler(objectPath, interfaces);
}
void TestProxy::installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler)
{
m_DoOperationClientSideAsyncReplyHandler = std::move(handler);
}
uint32_t TestProxy::doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
uint32_t TestProxy::doOperationWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
uint32_t result;
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(timeout).withArguments(param).storeResultsTo(result);
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(500000us).withArguments(param).storeResultsTo(result);
return result;
}
@@ -123,22 +125,6 @@ sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
});
}
std::future<uint32_t> TestProxy::doOperationClientSideAsync(uint32_t param, with_future_t)
{
return getProxy().callMethodAsync("doOperation")
.onInterface(sdbus::test::INTERFACE_NAME)
.withArguments(param)
.getResultAsFuture<uint32_t>();
}
std::future<MethodReply> TestProxy::doOperationClientSideAsyncOnBasicAPILevel(uint32_t param)
{
auto methodCall = getProxy().createMethodCall(sdbus::test::INTERFACE_NAME, "doOperation");
methodCall << param;
return getProxy().callMethod(methodCall, sdbus::with_future);
}
void TestProxy::doErroneousOperationClientSideAsync()
{
getProxy().callMethodAsync("throwError")
@@ -149,19 +135,12 @@ void TestProxy::doErroneousOperationClientSideAsync()
});
}
std::future<void> TestProxy::doErroneousOperationClientSideAsync(with_future_t)
{
return getProxy().callMethodAsync("throwError")
.onInterface(sdbus::test::INTERFACE_NAME)
.getResultAsFuture<>();
}
void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
void TestProxy::doOperationClientSideAsyncWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
getProxy().callMethodAsync("doOperation")
.onInterface(sdbus::test::INTERFACE_NAME)
.withTimeout(timeout)
.withTimeout(500000us)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
+11 -67
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.h
*
@@ -32,49 +32,17 @@
#include <thread>
#include <chrono>
#include <atomic>
#include <future>
namespace sdbus { namespace test {
class ObjectManagerTestProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
{
public:
ObjectManagerTestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
{
registerProxy();
}
~ObjectManagerTestProxy()
{
unregisterProxy();
}
protected:
void onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
{
if (m_onInterfacesAddedHandler)
m_onInterfacesAddedHandler(objectPath, interfacesAndProperties);
}
void onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces) override
{
if (m_onInterfacesRemovedHandler)
m_onInterfacesRemovedHandler(objectPath, interfaces);
}
public: // for tests
std::function<void(const sdbus::ObjectPath&, const std::map<std::string, std::map<std::string, sdbus::Variant>>&)> m_onInterfacesAddedHandler;
std::function<void(const sdbus::ObjectPath&, const std::vector<std::string>&)> m_onInterfacesRemovedHandler;
};
class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
, sdbus::Peer_proxy
, sdbus::Introspectable_proxy
, sdbus::Properties_proxy >
, sdbus::Properties_proxy
, sdbus::ObjectManager_proxy >
{
public:
TestProxy(std::string destination, std::string objectPath);
TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t);
TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath);
~TestProxy();
@@ -90,16 +58,16 @@ protected:
void onPropertiesChanged( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties ) override;
void onInterfacesAdded( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override;
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces) override;
public:
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler);
uint32_t doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
uint32_t doOperationWith500msTimeout(uint32_t param);
sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param);
std::future<uint32_t> doOperationClientSideAsync(uint32_t param, with_future_t);
std::future<MethodReply> doOperationClientSideAsyncOnBasicAPILevel(uint32_t param);
std::future<void> doErroneousOperationClientSideAsync(with_future_t);
void doErroneousOperationClientSideAsync();
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
void doOperationClientSideAsyncWith500msTimeout(uint32_t param);
int32_t callNonexistentMethod();
int32_t callMethodOnNonexistentInterface();
void setStateProperty(const std::string& value);
@@ -117,32 +85,8 @@ public: // for tests
std::function<void(uint32_t res, const sdbus::Error* err)> m_DoOperationClientSideAsyncReplyHandler;
std::function<void(const std::string&, const std::map<std::string, sdbus::Variant>&, const std::vector<std::string>&)> m_onPropertiesChangedHandler;
const Message* m_signalMsg{};
std::string m_signalMemberName;
};
class DummyTestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
, sdbus::Peer_proxy
, sdbus::Introspectable_proxy
, sdbus::Properties_proxy >
{
public:
DummyTestProxy(std::string destination, std::string objectPath)
: ProxyInterfaces(destination, objectPath)
{
}
protected:
void onSimpleSignal() override {}
void onSignalWithMap(const std::map<int32_t, std::string>&) override {}
void onSignalWithVariant(const sdbus::Variant&) override {}
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>&) {}
void onDoOperationReply(uint32_t, const sdbus::Error*) {}
// Signals of standard D-Bus interfaces
void onPropertiesChanged( const std::string&, const std::map<std::string, sdbus::Variant>&, const std::vector<std::string>& ) override {}
std::function<void(const sdbus::ObjectPath&, const std::map<std::string, std::map<std::string, sdbus::Variant>>&)> m_onInterfacesAddedHandler;
std::function<void(const sdbus::ObjectPath&, const std::vector<std::string>&)> m_onInterfacesRemovedHandler;
};
}}
@@ -11,9 +11,6 @@
<allow own="org.sdbuscpp.integrationtests"/>
<allow send_destination="org.sdbuscpp.integrationtests"/>
<allow send_interface="org.sdbuscpp.integrationtests"/>
<allow own="org.sdbuscpp.integrationtests2"/>
<allow send_destination="org.sdbuscpp.integrationtests2"/>
</policy>
</busconfig>
@@ -20,59 +20,54 @@ public:
protected:
integrationtests_adaptor(sdbus::IObject& object)
: object_(&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).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
object_->registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
object_->registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
object_->registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
object_->registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
object_->registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); });
object_->registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
object_->registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
object_->registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
object_->registerMethod("sumArrayItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1){ return this->sumArrayItems(arg0, arg1); });
object_->registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
object_->registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
object_->registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
object_->registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
object_->registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
object_->registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").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](){ return this->throwErrorWithNoReply(); }).withNoReply();
object_->registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
object_->registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
object_->registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
object_->registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
object_->registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
object_->registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
object_->registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
object_->registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
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).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); });
object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1){ return this->sumVectorItems(arg0, arg1); });
object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
object_.registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").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](){ return this->throwErrorWithNoReply(); }).withNoReply();
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
object_.registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
}
integrationtests_adaptor(const integrationtests_adaptor&) = delete;
integrationtests_adaptor& operator=(const integrationtests_adaptor&) = delete;
integrationtests_adaptor(integrationtests_adaptor&&) = default;
integrationtests_adaptor& operator=(integrationtests_adaptor&&) = default;
~integrationtests_adaptor() = default;
public:
void emitSimpleSignal()
{
object_->emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
}
void emitSignalWithMap(const std::map<int32_t, std::string>& aMap)
{
object_->emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
}
void emitSignalWithVariant(const sdbus::Variant& aVariant)
{
object_->emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
}
private:
@@ -86,13 +81,13 @@ private:
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) = 0;
virtual sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() = 0;
virtual int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) = 0;
virtual uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1) = 0;
virtual uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1) = 0;
virtual uint32_t doOperation(const uint32_t& arg0) = 0;
virtual void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) = 0;
virtual sdbus::Signature getSignature() = 0;
virtual sdbus::ObjectPath getObjPath() = 0;
virtual sdbus::UnixFd getUnixFd() = 0;
virtual std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() = 0;
virtual std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() = 0;
virtual void throwError() = 0;
virtual void throwErrorWithNoReply() = 0;
virtual void doPrivilegedStuff() = 0;
@@ -106,7 +101,7 @@ private:
virtual std::string state() = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}} // namespaces
+34 -50
View File
@@ -20,18 +20,13 @@ public:
protected:
integrationtests_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
proxy_->uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
proxy_->uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
proxy_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
proxy_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
}
integrationtests_proxy(const integrationtests_proxy&) = delete;
integrationtests_proxy& operator=(const integrationtests_proxy&) = delete;
integrationtests_proxy(integrationtests_proxy&&) = default;
integrationtests_proxy& operator=(integrationtests_proxy&&) = default;
~integrationtests_proxy() = default;
virtual void onSimpleSignal() = 0;
@@ -41,178 +36,167 @@ protected:
public:
void noArgNoReturn()
{
proxy_->callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
proxy_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
}
int32_t getInt()
{
int32_t result;
proxy_->callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::tuple<uint32_t, std::string> getTuple()
{
std::tuple<uint32_t, std::string> result;
proxy_->callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
double multiply(const int64_t& a, const double& b)
{
double result;
proxy_->callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
proxy_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
return result;
}
void multiplyWithNoReply(const int64_t& a, const double& b)
{
proxy_->callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
proxy_.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>>& arg0)
{
std::vector<int16_t> result;
proxy_->callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
proxy_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
sdbus::Variant processVariant(const sdbus::Variant& variant)
{
sdbus::Variant result;
proxy_->callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
proxy_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
return result;
}
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
{
std::map<int32_t, sdbus::Variant> result;
proxy_->callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
proxy_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
return result;
}
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct()
{
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> result;
proxy_->callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1)
{
int32_t result;
proxy_->callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
proxy_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
return result;
}
uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1)
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1)
{
uint32_t result;
proxy_->callMethod("sumArrayItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
proxy_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
return result;
}
uint32_t doOperation(const uint32_t& arg0)
{
uint32_t result;
proxy_->callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
proxy_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
uint32_t doOperationAsync(const uint32_t& arg0)
{
uint32_t result;
proxy_->callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
proxy_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
sdbus::Signature getSignature()
{
sdbus::Signature result;
proxy_->callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::ObjectPath getObjPath()
{
sdbus::ObjectPath result;
proxy_->callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::UnixFd getUnixFd()
{
sdbus::UnixFd result;
proxy_->callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::unordered_map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex()
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex()
{
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::unordered_map<int32_t, std::string>>>>, sdbus::Signature, std::string>> result;
proxy_->callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> result;
proxy_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void throwError()
{
proxy_->callMethod("throwError").onInterface(INTERFACE_NAME);
proxy_.callMethod("throwError").onInterface(INTERFACE_NAME);
}
void throwErrorWithNoReply()
{
proxy_->callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
proxy_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
}
void doPrivilegedStuff()
{
proxy_->callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
proxy_.callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
}
void emitTwoSimpleSignals()
{
proxy_->callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
}
void unregisterSimpleSignalHandler()
{
proxy_->muteSignal("simpleSignal").onInterface(INTERFACE_NAME);
}
void reRegisterSimpleSignalHandler()
{
proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
proxy_->finishRegistration();
proxy_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
}
public:
uint32_t action()
{
return proxy_->getProperty("action").onInterface(INTERFACE_NAME);
return proxy_.getProperty("action").onInterface(INTERFACE_NAME);
}
void action(const uint32_t& value)
{
proxy_->setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
proxy_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
}
bool blocking()
{
return proxy_->getProperty("blocking").onInterface(INTERFACE_NAME);
return proxy_.getProperty("blocking").onInterface(INTERFACE_NAME);
}
void blocking(const bool& value)
{
proxy_->setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
proxy_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
}
std::string state()
{
return proxy_->getProperty("state").onInterface(INTERFACE_NAME);
return proxy_.getProperty("state").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}} // namespaces
@@ -45,7 +45,7 @@
<arg type="(ix)" direction="in" />
<arg type="i" direction="out" />
</method>
<method name="sumArrayItems">
<method name="sumVectorItems">
<arg type="aq" direction="in" />
<arg type="at" direction="in" />
<arg type="u" direction="out" />
@@ -82,7 +82,7 @@
</method>
<method name="emitTwoSimpleSignals">
</method>
<signal name="simpleSignal">
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
</signal>
@@ -102,4 +102,4 @@
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
</node>
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file sdbus-c++-integration-tests.cpp
*
+6 -11
View File
@@ -20,24 +20,19 @@ public:
protected:
perftests_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
object_->registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); });
object_->registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); });
object_->registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("data");
object_.registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); });
object_.registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); });
object_.registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("data");
}
perftests_adaptor(const perftests_adaptor&) = delete;
perftests_adaptor& operator=(const perftests_adaptor&) = delete;
perftests_adaptor(perftests_adaptor&&) = default;
perftests_adaptor& operator=(perftests_adaptor&&) = default;
~perftests_adaptor() = default;
public:
void emitDataSignal(const std::string& data)
{
object_->emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
object_.emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
}
private:
@@ -45,7 +40,7 @@ private:
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}} // namespaces
+5 -10
View File
@@ -20,16 +20,11 @@ public:
protected:
perftests_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
proxy_->uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
proxy_.uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
}
perftests_proxy(const perftests_proxy&) = delete;
perftests_proxy& operator=(const perftests_proxy&) = delete;
perftests_proxy(perftests_proxy&&) = default;
perftests_proxy& operator=(perftests_proxy&&) = default;
~perftests_proxy() = default;
virtual void onDataSignal(const std::string& data) = 0;
@@ -37,18 +32,18 @@ protected:
public:
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize)
{
proxy_->callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
proxy_.callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
}
std::string concatenateTwoStrings(const std::string& string1, const std::string& string2)
{
std::string result;
proxy_->callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
proxy_.callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
return result;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}} // namespaces
@@ -22,23 +22,18 @@ public:
protected:
thermometer_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
}
thermometer_adaptor(const thermometer_adaptor&) = delete;
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
thermometer_adaptor(thermometer_adaptor&&) = default;
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
~thermometer_adaptor() = default;
private:
virtual uint32_t getCurrentTemperature() = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}}}} // namespaces
@@ -22,27 +22,22 @@ public:
protected:
thermometer_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
}
thermometer_proxy(const thermometer_proxy&) = delete;
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
thermometer_proxy(thermometer_proxy&&) = default;
thermometer_proxy& operator=(thermometer_proxy&&) = default;
~thermometer_proxy() = default;
public:
uint32_t getCurrentTemperature()
{
uint32_t result;
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}}}} // namespaces
+5 -10
View File
@@ -21,30 +21,25 @@ public:
protected:
concatenator_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); });
object_->registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); });
object_.registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
}
concatenator_adaptor(const concatenator_adaptor&) = delete;
concatenator_adaptor& operator=(const concatenator_adaptor&) = delete;
concatenator_adaptor(concatenator_adaptor&&) = default;
concatenator_adaptor& operator=(concatenator_adaptor&&) = default;
~concatenator_adaptor() = default;
public:
void emitConcatenatedSignal(const std::string& concatenatedString)
{
object_->emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
object_.emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
}
private:
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}}} // namespaces
+4 -9
View File
@@ -21,16 +21,11 @@ public:
protected:
concatenator_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
proxy_->uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
proxy_.uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
}
concatenator_proxy(const concatenator_proxy&) = delete;
concatenator_proxy& operator=(const concatenator_proxy&) = delete;
concatenator_proxy(concatenator_proxy&&) = default;
concatenator_proxy& operator=(concatenator_proxy&&) = default;
~concatenator_proxy() = default;
virtual void onConcatenatedSignal(const std::string& concatenatedString) = 0;
@@ -40,11 +35,11 @@ protected:
public:
sdbus::PendingAsyncCall concatenate(const std::map<std::string, sdbus::Variant>& params)
{
return proxy_->callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
return proxy_.callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}}} // namespaces
@@ -22,23 +22,18 @@ public:
protected:
thermometer_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
}
thermometer_adaptor(const thermometer_adaptor&) = delete;
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
thermometer_adaptor(thermometer_adaptor&&) = default;
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
~thermometer_adaptor() = default;
private:
virtual uint32_t getCurrentTemperature() = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}}}} // namespaces
@@ -56,17 +51,12 @@ public:
protected:
factory_adaptor(sdbus::IObject& object)
: object_(&object)
: object_(object)
{
object_->registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); });
object_->registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply();
object_.registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); });
object_.registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply();
}
factory_adaptor(const factory_adaptor&) = delete;
factory_adaptor& operator=(const factory_adaptor&) = delete;
factory_adaptor(factory_adaptor&&) = default;
factory_adaptor& operator=(factory_adaptor&&) = default;
~factory_adaptor() = default;
private:
@@ -74,7 +64,7 @@ private:
virtual void destroyDelegateObject(sdbus::Result<>&& result, sdbus::ObjectPath delegate) = 0;
private:
sdbus::IObject* object_;
sdbus::IObject& object_;
};
}}}}} // namespaces
@@ -22,27 +22,22 @@ public:
protected:
thermometer_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
}
thermometer_proxy(const thermometer_proxy&) = delete;
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
thermometer_proxy(thermometer_proxy&&) = default;
thermometer_proxy& operator=(thermometer_proxy&&) = default;
~thermometer_proxy() = default;
public:
uint32_t getCurrentTemperature()
{
uint32_t result;
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}}}} // namespaces
@@ -60,32 +55,27 @@ public:
protected:
factory_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
: proxy_(proxy)
{
}
factory_proxy(const factory_proxy&) = delete;
factory_proxy& operator=(const factory_proxy&) = delete;
factory_proxy(factory_proxy&&) = default;
factory_proxy& operator=(factory_proxy&&) = default;
~factory_proxy() = default;
public:
sdbus::ObjectPath createDelegateObject()
{
sdbus::ObjectPath result;
proxy_->callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
proxy_.callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void destroyDelegateObject(const sdbus::ObjectPath& delegate)
{
proxy_->callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
proxy_.callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
}
private:
sdbus::IProxy* proxy_;
sdbus::IProxy& proxy_;
};
}}}}} // namespaces
@@ -12,7 +12,7 @@
<allow send_destination="org.sdbuscpp.stresstests.service1"/>
<allow send_interface="org.sdbuscpp.stresstests.service1"/>
</policy>
<policy context="default">
<allow own="org.sdbuscpp.stresstests.service2"/>
<allow send_destination="org.sdbuscpp.stresstests.service2"/>
+3 -3
View File
@@ -427,8 +427,8 @@ int main(int argc, char *argv[])
while (!stopClients)
{
std::map<std::string, sdbus::Variant> param;
param["key1"] = sdbus::Variant{"sdbus-c++-stress-tests"};
param["key2"] = sdbus::Variant{++localCounter};
param["key1"] = "sdbus-c++-stress-tests";
param["key2"] = ++localCounter;
concatenator.concatenate(param);
@@ -509,6 +509,6 @@ int main(int argc, char *argv[])
exitLogger = true;
loggerThread.join();
return 0;
}
+17 -63
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Connection_test.cpp
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -35,7 +35,10 @@ using ::testing::DoAll;
using ::testing::SetArgPointee;
using ::testing::Return;
using ::testing::NiceMock;
using ::sdbus::internal::Connection;
using sdbus::internal::Connection;
constexpr sdbus::internal::Connection::system_bus_t system_bus;
constexpr sdbus::internal::Connection::session_bus_t session_bus;
constexpr sdbus::internal::Connection::remote_system_bus_t remote_system_bus;
class ConnectionCreationTest : public ::testing::Test
{
@@ -46,89 +49,61 @@ protected:
sd_bus* fakeBusPtr_ = reinterpret_cast<sd_bus*>(1);
};
using ADefaultBusConnection = ConnectionCreationTest;
using ASystemBusConnection = ConnectionCreationTest;
using ASessionBusConnection = ConnectionCreationTest;
TEST_F(ADefaultBusConnection, OpensAndFlushesBusWhenCreated)
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::default_bus);
}
TEST_F(ASystemBusConnection, OpensAndFlushesBusWhenCreated)
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::system_bus);
Connection(std::move(sdBusIntfMock_), system_bus);
}
TEST_F(ASessionBusConnection, OpensAndFlushesBusWhenCreated)
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::session_bus);
}
TEST_F(ADefaultBusConnection, ClosesAndUnrefsBusWhenDestructed)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::default_bus);
Connection(std::move(sdBusIntfMock_), session_bus);
}
TEST_F(ASystemBusConnection, ClosesAndUnrefsBusWhenDestructed)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::system_bus);
Connection(std::move(sdBusIntfMock_), session_bus);
}
TEST_F(ASessionBusConnection, ClosesAndUnrefsBusWhenDestructed)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1);
Connection(std::move(sdBusIntfMock_), Connection::session_bus);
}
TEST_F(ADefaultBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1)));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::default_bus), sdbus::Error);
Connection(std::move(sdBusIntfMock_), session_bus);
}
TEST_F(ASystemBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1)));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::system_bus), sdbus::Error);
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), system_bus), sdbus::Error);
}
TEST_F(ASessionBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1)));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::session_bus), sdbus::Error);
}
TEST_F(ADefaultBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::default_bus), sdbus::Error);
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), session_bus), sdbus::Error);
}
TEST_F(ASystemBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::system_bus), sdbus::Error);
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), system_bus), sdbus::Error);
}
TEST_F(ASessionBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction)
{
ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1));
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::session_bus), sdbus::Error);
ASSERT_THROW(Connection(std::move(sdBusIntfMock_), session_bus), sdbus::Error);
}
namespace
@@ -153,10 +128,6 @@ protected:
std::unique_ptr<Connection> con_;
};
template<> void AConnectionNameRequest<Connection::default_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
}
template<> void AConnectionNameRequest<Connection::system_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
@@ -165,40 +136,23 @@ template<> void AConnectionNameRequest<Connection::session_bus_t>::setUpBusOpenE
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
}
template<> void AConnectionNameRequest<Connection::custom_session_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user_with_address(_, _)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
}
template<> void AConnectionNameRequest<Connection::remote_system_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system_remote(_, _)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
}
template<> void AConnectionNameRequest<Connection::pseudo_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_new(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
// `sd_bus_start` for pseudo connection shall return an error value, remember this is a fake connection...
EXPECT_CALL(*sdBusIntfMock_, sd_bus_start(fakeBusPtr_)).WillOnce(Return(-EINVAL));
}
template <typename _BusTypeTag>
std::unique_ptr<Connection> AConnectionNameRequest<_BusTypeTag>::makeConnection()
{
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), _BusTypeTag{});
}
template<> std::unique_ptr<Connection> AConnectionNameRequest<Connection::custom_session_bus_t>::makeConnection()
{
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), Connection::custom_session_bus, "custom session bus");
}
template<> std::unique_ptr<Connection> AConnectionNameRequest<Connection::remote_system_bus_t>::makeConnection()
{
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), Connection::remote_system_bus, "some host");
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), remote_system_bus, "some host");
}
typedef ::testing::Types< Connection::default_bus_t
, Connection::system_bus_t
typedef ::testing::Types< Connection::system_bus_t
, Connection::session_bus_t
, Connection::custom_session_bus_t
, Connection::remote_system_bus_t
, Connection::pseudo_bus_t
> BusTypeTags;
TYPED_TEST_SUITE(AConnectionNameRequest, BusTypeTags);
+9 -254
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Message_test.cpp
*
@@ -29,7 +29,6 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <cstdint>
#include <list>
using ::testing::Eq;
using ::testing::Gt;
@@ -46,82 +45,6 @@ namespace
}
}
namespace sdbus {
template <typename _ElementType>
sdbus::Message& operator<<(sdbus::Message& msg, const std::list<_ElementType>& items)
{
msg.openContainer(sdbus::signature_of<_ElementType>::str());
for (const auto& item : items)
msg << item;
msg.closeContainer();
return msg;
}
template <typename _ElementType>
sdbus::Message& operator>>(sdbus::Message& msg, std::list<_ElementType>& items)
{
if(!msg.enterContainer(sdbus::signature_of<_ElementType>::str()))
return msg;
while (true)
{
_ElementType elem;
if (msg >> elem)
items.emplace_back(std::move(elem));
else
break;
}
msg.clearFlags();
msg.exitContainer();
return msg;
}
}
template <typename _Element, typename _Allocator>
struct sdbus::signature_of<std::list<_Element, _Allocator>>
: sdbus::signature_of<std::vector<_Element, _Allocator>>
{};
namespace my {
struct Struct
{
int i;
std::string s;
std::list<double> l;
};
bool operator==(const Struct& lhs, const Struct& rhs)
{
return lhs.i == rhs.i && lhs.s == rhs.s && lhs.l == rhs.l;
}
sdbus::Message& operator<<(sdbus::Message& msg, const Struct& items)
{
return msg << sdbus::Struct{std::forward_as_tuple(items.i, items.s, items.l)};
}
sdbus::Message& operator>>(sdbus::Message& msg, Struct& items)
{
sdbus::Struct s{std::forward_as_tuple(items.i, items.s, items.l)};
return msg >> s;
}
}
template <>
struct sdbus::signature_of<my::Struct>
: sdbus::signature_of<sdbus::Struct<int, std::string, std::list<double>>>
{};
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
@@ -193,7 +116,7 @@ TEST(AMessage, CanCarryASimpleInteger)
{
auto msg = sdbus::createPlainMessage();
const int dataWritten = 5;
int dataWritten = 5;
msg << dataWritten;
msg.seal();
@@ -208,7 +131,7 @@ TEST(AMessage, CanCarryAUnixFd)
{
auto msg = sdbus::createPlainMessage();
const sdbus::UnixFd dataWritten{0};
sdbus::UnixFd dataWritten{0};
msg << dataWritten;
msg.seal();
@@ -223,7 +146,7 @@ TEST(AMessage, CanCarryAVariant)
{
auto msg = sdbus::createPlainMessage();
const auto dataWritten = sdbus::Variant((double)3.14);
auto dataWritten = sdbus::Variant((double)3.14);
msg << dataWritten;
msg.seal();
@@ -238,8 +161,8 @@ TEST(AMessage, CanCarryACollectionOfEmbeddedVariants)
{
auto msg = sdbus::createPlainMessage();
std::vector<sdbus::Variant> value{sdbus::Variant{"hello"s}, sdbus::Variant{(double)3.14}};
const auto dataWritten = sdbus::Variant{value};
auto value = std::vector<sdbus::Variant>{"hello"s, (double)3.14};
auto dataWritten = sdbus::Variant{value};
msg << dataWritten;
msg.seal();
@@ -251,11 +174,11 @@ TEST(AMessage, CanCarryACollectionOfEmbeddedVariants)
ASSERT_THAT(dataRead.get<decltype(value)>()[1].get<double>(), Eq(value[1].get<double>()));
}
TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdVector)
TEST(AMessage, CanCarryAnArray)
{
auto msg = sdbus::createPlainMessage();
const std::vector<int64_t> dataWritten{3545342, 43643532, 324325};
std::vector<int64_t> dataWritten{3545342, 43643532, 324325};
msg << dataWritten;
msg.seal();
@@ -266,116 +189,6 @@ TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdVector)
ASSERT_THAT(dataRead, Eq(dataWritten));
}
TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdVector)
{
auto msg = sdbus::createPlainMessage();
const std::vector<sdbus::Signature> dataWritten{"s", "u", "b"};
msg << dataWritten;
msg.seal();
std::vector<sdbus::Signature> dataRead;
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
}
TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdArray)
{
auto msg = sdbus::createPlainMessage();
const std::array<int, 3> dataWritten{3545342, 43643532, 324325};
msg << dataWritten;
msg.seal();
std::array<int, 3> dataRead;
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
}
TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdArray)
{
auto msg = sdbus::createPlainMessage();
const std::array<sdbus::Signature, 3> dataWritten{"s", "u", "b"};
msg << dataWritten;
msg.seal();
std::array<sdbus::Signature, 3> dataRead;
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
}
#if __cplusplus >= 202002L
TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdSpan)
{
auto msg = sdbus::createPlainMessage();
const std::array<int, 3> sourceArray{3545342, 43643532, 324325};
const std::span dataWritten{sourceArray};
msg << dataWritten;
msg.seal();
std::array<int, 3> destinationArray;
std::span dataRead{destinationArray};
msg >> dataRead;
ASSERT_THAT(std::vector(dataRead.begin(), dataRead.end()), Eq(std::vector(dataWritten.begin(), dataWritten.end())));
}
TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdSpan)
{
auto msg = sdbus::createPlainMessage();
const std::array<sdbus::Signature, 3> sourceArray{"s", "u", "b"};
const std::span dataWritten{sourceArray};
msg << dataWritten;
msg.seal();
std::array<sdbus::Signature, 3> destinationArray;
std::span dataRead{destinationArray};
msg >> dataRead;
ASSERT_THAT(std::vector(dataRead.begin(), dataRead.end()), Eq(std::vector(dataWritten.begin(), dataWritten.end())));
}
#endif
TEST(AMessage, ThrowsWhenDestinationStdArrayIsTooSmallDuringDeserialization)
{
auto msg = sdbus::createPlainMessage();
const std::vector<int> dataWritten{3545342, 43643532, 324325, 89789, 15343};
msg << dataWritten;
msg.seal();
std::array<int, 3> dataRead;
ASSERT_THROW(msg >> dataRead, sdbus::Error);
}
#if __cplusplus >= 202002L
TEST(AMessage, ThrowsWhenDestinationStdSpanIsTooSmallDuringDeserialization)
{
auto msg = sdbus::createPlainMessage();
const std::array<int, 3> dataWritten{3545342, 43643532, 324325};
msg << dataWritten;
msg.seal();
std::array<int, 2> destinationArray;
std::span dataRead{destinationArray};
ASSERT_THROW(msg >> dataRead, sdbus::Error);
}
#endif
TEST(AMessage, CanCarryADictionary)
{
auto msg = sdbus::createPlainMessage();
@@ -425,61 +238,3 @@ TEST(AMessage, CanCarryAComplexType)
ASSERT_THAT(dataRead, Eq(dataWritten));
}
TEST(AMessage, CanPeekASimpleType)
{
auto msg = sdbus::createPlainMessage();
msg << 123;
msg.seal();
std::string type;
std::string contents;
msg.peekType(type, contents);
ASSERT_THAT(type, "i");
ASSERT_THAT(contents, "");
}
TEST(AMessage, CanPeekContainerContents)
{
auto msg = sdbus::createPlainMessage();
msg << std::map<int, std::string>{{1, "one"}, {2, "two"}};
msg.seal();
std::string type;
std::string contents;
msg.peekType(type, contents);
ASSERT_THAT(type, "a");
ASSERT_THAT(contents, "{is}");
}
TEST(AMessage, CanCarryDBusArrayGivenAsCustomType)
{
auto msg = sdbus::createPlainMessage();
const std::list<int64_t> dataWritten{3545342, 43643532, 324325};
//custom::MyType t;
msg << dataWritten;
// msg << t;
msg.seal();
std::list<int64_t> dataRead;
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
}
TEST(AMessage, CanCarryDBusStructGivenAsCustomType)
{
auto msg = sdbus::createPlainMessage();
const my::Struct dataWritten{3545342, "hello"s, {3.14, 2.4568546}};
msg << dataWritten;
msg.seal();
my::Struct dataRead;
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
}
+4 -15
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TypeTraits_test.cpp
*
@@ -77,12 +77,7 @@ namespace
TYPE(sdbus::Struct<bool>)HAS_DBUS_TYPE_SIGNATURE("(b)")
TYPE(sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>)HAS_DBUS_TYPE_SIGNATURE("(qdsv)")
TYPE(std::vector<int16_t>)HAS_DBUS_TYPE_SIGNATURE("an")
TYPE(std::array<int16_t, 3>)HAS_DBUS_TYPE_SIGNATURE("an")
#if __cplusplus >= 202002L
TYPE(std::span<int16_t>)HAS_DBUS_TYPE_SIGNATURE("ao")
#endif
TYPE(std::map<int32_t, int64_t>)HAS_DBUS_TYPE_SIGNATURE("a{ix}")
TYPE(std::unordered_map<int32_t, int64_t>)HAS_DBUS_TYPE_SIGNATURE("a{ix}")
using ComplexType = std::map<
uint64_t,
sdbus::Struct<
@@ -91,10 +86,9 @@ namespace
std::vector<
sdbus::Struct<
sdbus::ObjectPath,
std::array<int16_t, 3>,
bool,
sdbus::Variant,
std::unordered_map<int, std::string>
std::map<int, std::string>
>
>
>,
@@ -103,7 +97,7 @@ namespace
const char*
>
>;
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(oanbva{is})}ghs)}")
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(obva{is})}ghs)}")
typedef ::testing::Types< bool
, uint8_t
@@ -123,12 +117,7 @@ namespace
, sdbus::Struct<bool>
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
, std::vector<int16_t>
, std::array<int16_t, 3>
#if __cplusplus >= 202002L
, std::span<int16_t>
#endif
, std::map<int32_t, int64_t>
, std::unordered_map<int32_t, int64_t>
, ComplexType
> DBusSupportedTypes;
+11 -73
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Types_test.cpp
*
@@ -67,7 +67,7 @@ TEST(AVariant, CanBeConstructedFromASimpleValue)
TEST(AVariant, CanBeConstructedFromAComplexValue)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} };
ASSERT_NO_THROW(sdbus::Variant{value});
}
@@ -103,7 +103,7 @@ TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} };
sdbus::Variant variant(value);
@@ -123,7 +123,7 @@ TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
TEST(AVariant, ReturnsTrueWhenAskedIfItContainsTheTypeItReallyContains)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} };
sdbus::Variant variant(value);
@@ -143,8 +143,8 @@ TEST(AVariant, CanContainOtherEmbeddedVariants)
{
using TypeWithVariants = std::vector<sdbus::Struct<sdbus::Variant, double>>;
TypeWithVariants value;
value.push_back({sdbus::Variant("a string"), ANY_DOUBLE});
value.push_back({sdbus::Variant(ANY_UINT64), ANY_DOUBLE});
value.emplace_back(sdbus::make_struct(sdbus::Variant("a string"), ANY_DOUBLE));
value.emplace_back(sdbus::make_struct(sdbus::Variant(ANY_UINT64), ANY_DOUBLE));
sdbus::Variant variant(value);
@@ -172,7 +172,7 @@ TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} };
sdbus::Variant variant(value);
auto msg = sdbus::createPlainMessage();
@@ -187,7 +187,7 @@ TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} };
sdbus::Variant variant(value);
auto variantCopy1{variant};
auto variantCopy2 = variant;
@@ -207,41 +207,15 @@ TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
ASSERT_THAT(receivedVariant3.get<decltype(value)>(), Eq(value));
}
TEST(AStruct, CanBeCreatedFromStdTuple)
TEST(AStruct, CreatesStructFromTuple)
{
std::tuple<int32_t, std::string> value{1234, "abcd"};
sdbus::Struct valueStruct{value};
ASSERT_THAT(valueStruct.get<0>(), Eq(std::get<0>(value)));
ASSERT_THAT(valueStruct.get<1>(), Eq(std::get<1>(value)));
}
TEST(AStruct, CanProvideItsDataThroughStdGet)
{
std::tuple<int32_t, std::string> value{1234, "abcd"};
sdbus::Struct valueStruct{value};
sdbus::Struct<int32_t, std::string> valueStruct{value};
ASSERT_THAT(std::get<0>(valueStruct), Eq(std::get<0>(value)));
ASSERT_THAT(std::get<1>(valueStruct), Eq(std::get<1>(value)));
}
TEST(AStruct, CanBeUsedLikeStdTupleType)
{
using StructType = sdbus::Struct<int, std::string, bool>;
static_assert(std::tuple_size_v<StructType> == 3);
static_assert(std::is_same_v<std::tuple_element_t<1, StructType>, std::string>);
}
TEST(AStruct, CanBeUsedInStructuredBinding)
{
sdbus::Struct valueStruct(1234, "abcd", true);
auto [first, second, third] = valueStruct;
ASSERT_THAT(std::tie(first, second, third), Eq(std::tuple{1234, "abcd", true}));
}
TEST(AnObjectPath, CanBeConstructedFromCString)
{
const char* aPath = "/some/path";
@@ -256,15 +230,6 @@ TEST(AnObjectPath, CanBeConstructedFromStdString)
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
}
TEST(AnObjectPath, CanBeMovedLikeAStdString)
{
std::string aPath{"/some/very/long/path/longer/than/sso"};
sdbus::ObjectPath oPath{aPath};
ASSERT_THAT(sdbus::ObjectPath{std::move(oPath)}, Eq(sdbus::ObjectPath(std::move(aPath))));
ASSERT_THAT(std::string(oPath), Eq(aPath));
}
TEST(ASignature, CanBeConstructedFromCString)
{
const char* aSignature = "us";
@@ -279,15 +244,6 @@ TEST(ASignature, CanBeConstructedFromStdString)
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
}
TEST(ASignature, CanBeMovedLikeAStdString)
{
std::string aSignature{"us"};
sdbus::Signature oSignature{aSignature};
ASSERT_THAT(sdbus::Signature{std::move(oSignature)}, Eq(sdbus::Signature(std::move(aSignature))));
ASSERT_THAT(std::string(oSignature), Eq(aSignature));
}
TEST(AUnixFd, DuplicatesAndOwnsFdUponStandardConstruction)
{
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
@@ -388,21 +344,3 @@ TEST(AUnixFd, TakesOverNewFdAndClosesOriginalFdOnAdoptingReset)
EXPECT_THAT(unixFd.get(), Eq(newFd));
EXPECT_THAT(::close(fd), Eq(-1));
}
TEST(AnError, CanBeConstructedFromANameAndAMessage)
{
auto error = sdbus::Error("name", "message");
EXPECT_THAT(error.getName(), Eq<std::string>("name"));
EXPECT_THAT(error.getMessage(), Eq<std::string>("message"));
}
TEST(AnError, CanBeConstructedFromANameOnly)
{
auto error1 = sdbus::Error("name");
auto error2 = sdbus::Error("name", nullptr);
EXPECT_THAT(error1.getName(), Eq<std::string>("name"));
EXPECT_THAT(error2.getName(), Eq<std::string>("name"));
EXPECT_THAT(error1.getMessage(), Eq<std::string>(""));
EXPECT_THAT(error2.getMessage(), Eq<std::string>(""));
}
+3 -26
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file SdBusMock.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -57,45 +57,22 @@ public:
MOCK_METHOD3(sd_bus_emit_interfaces_added_strv, int(sd_bus *bus, const char *path, char **interfaces));
MOCK_METHOD3(sd_bus_emit_interfaces_removed_strv, int(sd_bus *bus, const char *path, char **interfaces));
MOCK_METHOD1(sd_bus_open, int(sd_bus **ret));
MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret));
MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret));
MOCK_METHOD2(sd_bus_open_user_with_address, int(sd_bus **ret, const char* address));
MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret));
MOCK_METHOD2(sd_bus_open_system_remote, int(sd_bus **ret, const char *host));
MOCK_METHOD2(sd_bus_open_direct, int(sd_bus **ret, const char* address));
MOCK_METHOD2(sd_bus_open_direct, int(sd_bus **ret, int fd));
MOCK_METHOD2(sd_bus_open_server, int(sd_bus **ret, int fd));
MOCK_METHOD3(sd_bus_request_name, int(sd_bus *bus, const char *name, uint64_t flags));
MOCK_METHOD2(sd_bus_release_name, int(sd_bus *bus, const char *name));
MOCK_METHOD2(sd_bus_get_unique_name, int(sd_bus *bus, const char **name));
MOCK_METHOD6(sd_bus_add_object_vtable, int(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata));
MOCK_METHOD3(sd_bus_add_object_manager, int(sd_bus *bus, sd_bus_slot **slot, const char *path));
MOCK_METHOD5(sd_bus_add_match, int(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata));
MOCK_METHOD6(sd_bus_add_match_async, int(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata));
MOCK_METHOD1(sd_bus_slot_unref, sd_bus_slot*(sd_bus_slot *slot));
MOCK_METHOD1(sd_bus_new, int(sd_bus **ret));
MOCK_METHOD1(sd_bus_start, int(sd_bus *bus));
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
MOCK_METHOD2(sd_bus_get_poll_data, int(sd_bus *bus, PollData* data));
MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
MOCK_METHOD1(sd_bus_flush_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD1(sd_bus_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD2(sd_bus_message_set_destination, int(sd_bus_message *m, const char *destination));
MOCK_METHOD3(sd_bus_query_sender_creds, int(sd_bus_message *, uint64_t, sd_bus_creds **));
MOCK_METHOD1(sd_bus_creds_unref, sd_bus_creds*(sd_bus_creds *));
MOCK_METHOD2(sd_bus_creds_get_pid, int(sd_bus_creds *, pid_t *));
MOCK_METHOD2(sd_bus_creds_get_uid, int(sd_bus_creds *, uid_t *));
MOCK_METHOD2(sd_bus_creds_get_euid, int(sd_bus_creds *, uid_t *));
MOCK_METHOD2(sd_bus_creds_get_gid, int(sd_bus_creds *, gid_t *));
MOCK_METHOD2(sd_bus_creds_get_egid, int(sd_bus_creds *, gid_t *));
MOCK_METHOD2(sd_bus_creds_get_supplementary_gids, int(sd_bus_creds *, const gid_t **));
MOCK_METHOD2(sd_bus_creds_get_selinux_context, int(sd_bus_creds *, const char **));
};
#endif //SDBUS_CXX_SDBUS_MOCK_H
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file sdbus-c++-unit-tests.cpp
*
+2 -26
View File
@@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.5)
project(sdbus-c++-tools VERSION 1.5.0)
project(sdbus-c++-tools)
include(GNUInstallDirs)
@@ -43,33 +43,9 @@ set(CMAKE_CXX_STANDARD 14)
add_executable(sdbus-c++-xml2cpp ${SDBUSCPP_XML2CPP_SRCS})
target_link_libraries (sdbus-c++-xml2cpp ${EXPAT_LIBRARIES})
target_include_directories(sdbus-c++-xml2cpp PRIVATE ${EXPAT_INCLUDE_DIRS})
#----------------------------------
# INSTALLATION
#----------------------------------
install(TARGETS sdbus-c++-xml2cpp EXPORT sdbus-c++-tools-targets DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT dev)
#----------------------------------
# CMAKE CONFIG & PACKAGE CONFIG
#----------------------------------
include(CMakePackageConfigHelpers)
install(EXPORT sdbus-c++-tools-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++-tools
NAMESPACE SDBusCpp::
COMPONENT dev)
configure_package_config_file(cmake/sdbus-c++-tools-config.cmake.in cmake/sdbus-c++-tools-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++)
write_basic_package_version_file(cmake/sdbus-c++-tools-config-version.cmake COMPATIBILITY SameMajorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-tools-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-tools-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++-tools
COMPONENT dev)
configure_file(pkgconfig/sdbus-c++-tools.pc.in pkgconfig/sdbus-c++-tools.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/sdbus-c++-tools.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)
install(TARGETS sdbus-c++-xml2cpp EXPORT sdbus-c++-xml2cpp DESTINATION ${CMAKE_INSTALL_BINDIR})
@@ -1,4 +0,0 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
check_required_components("sdbus-c++-xml2cpp")
-8
View File
@@ -1,8 +0,0 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: Stub generator tool for sdbus-c++ library
Version: @SDBUSCPP_VERSION@
+10 -16
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorGenerator.cpp
*
@@ -85,7 +85,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
<< "protected:" << endl
<< tab << className << "(sdbus::IObject& object)" << endl
<< tab << tab << ": object_(&object)" << endl;
<< tab << tab << ": object_(object)" << endl;
Nodes methods = interface["method"];
Nodes signals = interface["signal"];
@@ -111,7 +111,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
if(!annotationRegistration.empty())
{
std::stringstream str;
str << tab << tab << "object_->setInterfaceFlags(INTERFACE_NAME)" << annotationRegistration << ";" << endl;
str << tab << tab << "object_.setInterfaceFlags(INTERFACE_NAME)" << annotationRegistration << ";" << endl;
annotationRegistration = str.str();
}
@@ -131,12 +131,6 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
<< propertyRegistration
<< tab << "}" << endl << endl;
// Rule of Five
body << tab << className << "(const " << className << "&) = delete;" << endl;
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
body << tab << className << "(" << className << "&&) = default;" << endl;
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
body << tab << "~" << className << "() = default;" << endl << endl;
if (!signalMethods.empty())
@@ -155,7 +149,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
}
body << "private:" << endl
<< tab << "sdbus::IObject* object_;" << endl
<< tab << "sdbus::IObject& object_;" << endl
<< "};" << endl << endl
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
@@ -192,7 +186,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
}
else if (annotationName == "org.freedesktop.DBus.Method.Async")
{
if (annotationValue == "server" || annotationValue == "clientserver" || annotationValue == "client-server")
if (annotationValue == "server" || annotationValue == "clientserver")
async = true;
}
else if (annotationName == "org.freedesktop.systemd1.Privileged")
@@ -217,7 +211,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
using namespace std::string_literals;
registrationSS << tab << tab << "object_->registerMethod(\""
registrationSS << tab << tab << "object_.registerMethod(\""
<< methodName << "\")"
<< ".onInterface(INTERFACE_NAME)"
<< (!argStringsStr.empty() ? (".withInputParamNames(" + argStringsStr + ")") : "")
@@ -273,7 +267,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
std::tie(argStr, argTypeStr, typeStr, argStringsStr) = argsToNamesAndTypes(args);
signalRegistrationSS << tab << tab
<< "object_->registerSignal(\"" << name << "\")"
<< "object_.registerSignal(\"" << name << "\")"
".onInterface(INTERFACE_NAME)";
if (args.size() > 0)
@@ -290,7 +284,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
signalMethodSS << tab << "void emit" << nameWithCapFirstLetter << "(" << argTypeStr << ")" << endl
<< tab << "{" << endl
<< tab << tab << "object_->emitSignal(\"" << name << "\")"
<< tab << tab << "object_.emitSignal(\"" << name << "\")"
".onInterface(INTERFACE_NAME)";
if (!argStr.empty())
@@ -339,7 +333,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
}
registrationSS << tab << tab << "object_->registerProperty(\""
registrationSS << tab << tab << "object_.registerProperty(\""
<< propertyName << "\")"
<< ".onInterface(INTERFACE_NAME)";
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorGenerator.h
*
+3 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file BaseGenerator.cpp
*
@@ -182,3 +182,4 @@ std::string BaseGenerator::outArgsToType(const Nodes& args, bool bareList) const
return retTypeSS.str();
}
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file BaseGenerator.h
*
+31 -142
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ProxyGenerator.cpp
*
@@ -33,7 +33,6 @@
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <regex>
using std::endl;
@@ -84,7 +83,7 @@ std::string ProxyGenerator::processInterface(Node& interface) const
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
<< "protected:" << endl
<< tab << className << "(sdbus::IProxy& proxy)" << endl
<< tab << tab << ": proxy_(&proxy)" << endl;
<< tab << tab << ": proxy_(proxy)" << endl;
Nodes methods = interface["method"];
Nodes signals = interface["signal"];
@@ -97,29 +96,17 @@ std::string ProxyGenerator::processInterface(Node& interface) const
<< registration
<< tab << "}" << endl << endl;
// Rule of Five
body << tab << className << "(const " << className << "&) = delete;" << endl;
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
body << tab << className << "(" << className << "&&) = default;" << endl;
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
body << tab << "~" << className << "() = default;" << endl << endl;
if (!declaration.empty())
body << declaration << endl;
std::string methodDefinitions, asyncDeclarationsMethods;
std::tie(methodDefinitions, asyncDeclarationsMethods) = processMethods(methods);
std::string propertyDefinitions, asyncDeclarationsProperties;
std::tie(propertyDefinitions, asyncDeclarationsProperties) = processProperties(properties);
std::string methodDefinitions, asyncDeclarations;
std::tie(methodDefinitions, asyncDeclarations) = processMethods(methods);
if (!asyncDeclarationsMethods.empty())
if (!asyncDeclarations.empty())
{
body << asyncDeclarationsMethods << endl;
}
if (!asyncDeclarationsProperties.empty())
{
body << asyncDeclarationsProperties << endl;
body << asyncDeclarations << endl;
}
if (!methodDefinitions.empty())
@@ -127,13 +114,14 @@ std::string ProxyGenerator::processInterface(Node& interface) const
body << "public:" << endl << methodDefinitions;
}
std::string propertyDefinitions = processProperties(properties);
if (!propertyDefinitions.empty())
{
body << "public:" << endl << propertyDefinitions;
}
body << "private:" << endl
<< tab << "sdbus::IProxy* proxy_;" << endl
<< tab << "sdbus::IProxy& proxy_;" << endl
<< "};" << endl << endl
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
@@ -142,8 +130,6 @@ std::string ProxyGenerator::processInterface(Node& interface) const
std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes& methods) const
{
const std::regex patternTimeout{R"(^(\d+)(min|s|ms|us)?$)"};
std::ostringstream definitionSS, asyncDeclarationSS;
for (const auto& method : methods)
@@ -156,30 +142,18 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
bool dontExpectReply{false};
bool async{false};
bool future{false}; // Async methods implemented by means of either std::future or callbacks
std::string timeoutValue;
std::smatch smTimeout;
Nodes annotations = (*method)["annotation"];
for (const auto& annotation : annotations)
{
const auto annotationName = annotation->get("name");
const auto annotationValue = annotation->get("value");
if (annotationName == "org.freedesktop.DBus.Method.NoReply" && annotationValue == "true")
if (annotation->get("name") == "org.freedesktop.DBus.Method.NoReply" && annotation->get("value") == "true")
dontExpectReply = true;
else
{
if (annotationName == "org.freedesktop.DBus.Method.Async"
&& (annotationValue == "client" || annotationValue == "clientserver" || annotationValue == "client-server"))
async = true;
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && annotationValue == "callback")
future = false;
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
future = true;
}
if (annotationName == "org.freedesktop.DBus.Method.Timeout")
timeoutValue = annotationValue;
else if (annotation->get("name") == "org.freedesktop.DBus.Method.Async"
&& (annotation->get("value") == "client" || annotation->get("value") == "clientserver"))
async = true;
if (annotation->get("name") == "org.freedesktop.DBus.Method.Timeout")
timeoutValue = annotation->get("value");
}
if (dontExpectReply && outArgs.size() > 0)
{
@@ -194,21 +168,13 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
timeoutValue.clear();
}
if (!timeoutValue.empty() && !std::regex_match(timeoutValue, smTimeout, patternTimeout))
{
std::cerr << "Function: " << name << ": ";
std::cerr << "Option 'org.freedesktop.DBus.Method.Timeout' has unsupported timeout value! Option ignored..." << std::endl;
timeoutValue.clear();
}
auto retType = outArgsToType(outArgs);
auto retTypeBare = outArgsToType(outArgs, true);
std::string inArgStr, inArgTypeStr;
std::tie(inArgStr, inArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(inArgs);
std::string outArgStr, outArgTypeStr;
std::tie(outArgStr, outArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(outArgs);
const std::string realRetType = (async && !dontExpectReply ? (future ? "std::future<" + retType + ">" : "sdbus::PendingAsyncCall") : async ? "void" : retType);
const std::string realRetType = (async && !dontExpectReply ? "sdbus::PendingAsyncCall" : async ? "void" : retType);
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
<< tab << "{" << endl;
@@ -223,13 +189,11 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
}
definitionSS << tab << tab << (async && !dontExpectReply ? "return " : "")
<< "proxy_->callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
<< "proxy_.callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
if (!timeoutValue.empty())
{
const auto val = smTimeout.str(1);
const auto unit = smTimeout.str(2);
definitionSS << ".withTimeout(" << val << (unit.empty() ? "us" : unit) << ")";
definitionSS << ".withTimeout(" << timeoutValue << "us)";
}
if (inArgs.size() > 0)
@@ -242,18 +206,11 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
auto nameBigFirst = name;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (future) // Async methods implemented through future
{
definitionSS << ".getResultAsFuture<" << retTypeBare << ">()";
}
else // Async methods implemented through callbacks
{
definitionSS << ".uponReplyInvoke([this](const sdbus::Error* error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "error); })";
definitionSS << ".uponReplyInvoke([this](const sdbus::Error* error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "error); })";
asyncDeclarationSS << tab << "virtual void on" << nameBigFirst << "Reply("
<< outArgTypeStr << (outArgTypeStr.empty() ? "" : ", ") << "const sdbus::Error* error) = 0;" << endl;
}
asyncDeclarationSS << tab << "virtual void on" << nameBigFirst << "Reply("
<< outArgTypeStr << (outArgTypeStr.empty() ? "" : ", ") << "const sdbus::Error* error) = 0;" << endl;
}
else if (outArgs.size() > 0)
{
@@ -287,7 +244,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes&
std::tie(argStr, argTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(args);
registrationSS << tab << tab << "proxy_"
"->uponSignal(\"" << name << "\")"
".uponSignal(\"" << name << "\")"
".onInterface(INTERFACE_NAME)"
".call([this](" << argTypeStr << ")"
"{ this->on" << nameBigFirst << "(" << argStr << "); });" << endl;
@@ -298,9 +255,9 @@ std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes&
return std::make_tuple(registrationSS.str(), declarationSS.str());
}
std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nodes& properties) const
std::string ProxyGenerator::processProperties(const Nodes& properties) const
{
std::ostringstream propertySS, asyncDeclarationSS;
std::ostringstream propertySS;
for (const auto& property : properties)
{
auto propertyName = property->get("name");
@@ -312,93 +269,25 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
auto propertyArg = std::string("value");
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
bool asyncGet{false};
bool futureGet{false}; // Async property getter implemented by means of either std::future or callbacks
bool asyncSet{false};
bool futureSet{false}; // Async property setter implemented by means of either std::future or callbacks
Nodes annotations = (*property)["annotation"];
for (const auto& annotation : annotations)
{
const auto annotationName = annotation->get("name");
const auto annotationValue = annotation->get("value");
if (annotationName == "org.freedesktop.DBus.Property.Get.Async" && annotationValue == "client") // Server-side not supported (may be in the future)
asyncGet = true;
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && annotationValue == "callback")
futureGet = false;
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
futureGet = true;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async" && annotationValue == "client") // Server-side not supported (may be in the future)
asyncSet = true;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && annotationValue == "callback")
futureSet = false;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
futureSet = true;
}
if (propertyAccess == "read" || propertyAccess == "readwrite")
{
const std::string realRetType = (asyncGet ? (futureGet ? "std::future<sdbus::Variant>" : "sdbus::PendingAsyncCall") : propertyType);
propertySS << tab << realRetType << " " << propertyNameSafe << "()" << endl
propertySS << tab << propertyType << " " << propertyNameSafe << "()" << endl
<< tab << "{" << endl;
propertySS << tab << tab << "return proxy_->getProperty" << (asyncGet ? "Async" : "") << "(\"" << propertyName << "\")"
propertySS << tab << tab << "return proxy_.getProperty(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)";
if (asyncGet)
{
auto nameBigFirst = propertyName;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (futureGet) // Async methods implemented through future
{
propertySS << ".getResultAsFuture()";
}
else // Async methods implemented through callbacks
{
propertySS << ".uponReplyInvoke([this](const sdbus::Error* error, const sdbus::Variant& value)"
"{ this->on" << nameBigFirst << "PropertyGetReply(value.get<" << propertyType << ">(), error); })";
asyncDeclarationSS << tab << "virtual void on" << nameBigFirst << "PropertyGetReply("
<< "const " << propertyType << "& value, const sdbus::Error* error) = 0;" << endl;
}
}
propertySS << ";" << endl << tab << "}" << endl << endl;
}
if (propertyAccess == "readwrite" || propertyAccess == "write")
{
const std::string realRetType = (asyncSet ? (futureSet ? "std::future<void>" : "sdbus::PendingAsyncCall") : "void");
propertySS << tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
<< tab << "{" << endl;
propertySS << tab << tab << (asyncSet ? "return " : "") << "proxy_->setProperty" << (asyncSet ? "Async" : "")
<< "(\"" << propertyName << "\")"
propertySS << tab << "void " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
<< tab << "{" << endl;
propertySS << tab << tab << "proxy_.setProperty(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)"
".toValue(" << propertyArg << ")";
if (asyncSet)
{
auto nameBigFirst = propertyName;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (futureSet) // Async methods implemented through future
{
propertySS << ".getResultAsFuture()";
}
else // Async methods implemented through callbacks
{
propertySS << ".uponReplyInvoke([this](const sdbus::Error* error)"
"{ this->on" << nameBigFirst << "PropertySetReply(error); })";
asyncDeclarationSS << tab << "virtual void on" << nameBigFirst << "PropertySetReply("
<< "const sdbus::Error* error) = 0;" << endl;
}
}
propertySS << ";" << endl << tab << "}" << endl << endl;
}
}
return std::make_tuple(propertySS.str(), asyncDeclarationSS.str());
return propertySS.str();
}
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file ProxyGenerator.h
*
@@ -73,7 +73,7 @@ private:
* @param properties
* @return source code
*/
std::tuple<std::string, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
std::string processProperties(const sdbuscpp::xml::Nodes& properties) const;
};

Some files were not shown because too many files have changed in this diff Show More