forked from Kistler-Group/sdbus-cpp
Compare commits
15 Commits
fix_parser
...
temp/all
Author | SHA1 | Date | |
---|---|---|---|
7589ed1d83 | |||
3acd20c2fd | |||
f332f46087 | |||
c9e157e3e1 | |||
8ca3fdd5ce | |||
55c306ce05 | |||
6c5e72326c | |||
8bbeeeb4ce | |||
7a09e9bcc8 | |||
c812d03bc7 | |||
e7d4e07926 | |||
031f4687ca | |||
aeae79003a | |||
74d849d933 | |||
f336811fc7 |
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
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
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
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.
|
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-18.04, ubuntu-20.04]
|
||||
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04]
|
||||
compiler: [g++, clang]
|
||||
build: [shared-libsystemd]
|
||||
include:
|
||||
@ -20,7 +20,7 @@ jobs:
|
||||
compiler: g++
|
||||
build: embedded-static-libsystemd
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: install-libsystemd-toolchain
|
||||
if: matrix.build == 'embedded-static-libsystemd'
|
||||
run: |
|
||||
@ -39,33 +39,37 @@ 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: configure-debug
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-18.04'
|
||||
- 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: |
|
||||
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
|
||||
sudo apt-get install -y libgmock-dev
|
||||
- name: configure-debug
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -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 ..
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -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-18.04' || matrix.os == 'ubuntu-22.04')
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -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 -DBUILD_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 -DCMAKE_VERBOSE_MAKEFILE=ON -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 . -j2
|
||||
cmake --build . -j4
|
||||
- name: verify
|
||||
run: |
|
||||
cd build
|
||||
sudo cmake --build . --target install
|
||||
ctest
|
||||
ctest --output-on-failure
|
||||
- name: pack
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
@ -73,7 +77,7 @@ jobs:
|
||||
cpack -G DEB
|
||||
- name: 'Upload Artifact'
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04' && matrix.compiler == 'g++'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "debian-packages-${{ matrix.os }}-${{ matrix.compiler }}"
|
||||
path: |
|
||||
|
@ -140,7 +140,7 @@ endif()
|
||||
install(TARGETS ${EXPORT_SET}
|
||||
EXPORT sdbus-c++-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT dev
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SDBUSCPP_INCLUDE_SUBDIR} COMPONENT dev)
|
||||
|
||||
|
@ -97,7 +97,7 @@ 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/docs/dbus-specification.html)
|
||||
* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
|
||||
* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
|
||||
|
||||
Contributing
|
||||
|
242
backup/CMakeLists.txt
Normal file
242
backup/CMakeLists.txt
Normal file
@ -0,0 +1,242 @@
|
||||
#-------------------------------
|
||||
# PROJECT INFORMATION
|
||||
#-------------------------------
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(sdbus-c++ VERSION 1.2.0 LANGUAGES C CXX)
|
||||
|
||||
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
|
||||
|
||||
#-------------------------------
|
||||
# PERFORMING CHECKS & PREPARING THE DEPENDENCIES
|
||||
#-------------------------------
|
||||
|
||||
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(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++)")
|
||||
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}")
|
||||
else()
|
||||
# Build static libsystemd library as an external project
|
||||
include(cmake/LibsystemdExternalProject.cmake)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(SDBUSCPP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(SDBUSCPP_INCLUDE_SUBDIR sdbus-c++)
|
||||
set(SDBUSCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/${SDBUSCPP_INCLUDE_SUBDIR})
|
||||
|
||||
set(SDBUSCPP_CPP_SRCS
|
||||
${SDBUSCPP_SOURCE_DIR}/Connection.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Error.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Message.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Object.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Proxy.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Types.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Flags.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/VTableUtils.c
|
||||
${SDBUSCPP_SOURCE_DIR}/SdBus.cpp)
|
||||
|
||||
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
|
||||
${SDBUSCPP_SOURCE_DIR}/VTableUtils.h
|
||||
${SDBUSCPP_SOURCE_DIR}/SdBus.h
|
||||
${SDBUSCPP_SOURCE_DIR}/ISdBus.h)
|
||||
|
||||
set(SDBUSCPP_PUBLIC_HDRS
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.inl
|
||||
${SDBUSCPP_INCLUDE_DIR}/Error.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IConnection.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/AdaptorInterfaces.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/ProxyInterfaces.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/StandardInterfaces.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IObject.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IProxy.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Message.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/MethodResult.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Types.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Flags.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h)
|
||||
|
||||
set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS})
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
#----------------------------------
|
||||
# LIBRARY BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
set(SDBUSCPP_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
|
||||
|
||||
# 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})
|
||||
target_include_directories(sdbus-c++-objlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
|
||||
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)
|
||||
|
||||
add_library(sdbus-c++)
|
||||
target_include_directories(sdbus-c++ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
set_target_properties(sdbus-c++
|
||||
PROPERTIES PUBLIC_HEADER "${SDBUSCPP_PUBLIC_HDRS}"
|
||||
VERSION "${SDBUSCPP_VERSION}"
|
||||
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "sdbus-c++")
|
||||
target_link_libraries(sdbus-c++ PRIVATE sdbus-c++-objlib)
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
set(EXPORT_SET sdbus-c++)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
list(APPEND EXPORT_SET "sdbus-c++-objlib")
|
||||
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
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SDBUSCPP_INCLUDE_SUBDIR} COMPONENT dev)
|
||||
|
||||
#----------------------------------
|
||||
# TESTS
|
||||
#----------------------------------
|
||||
|
||||
option(BUILD_TESTS "Build and install tests (default OFF)" OFF)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
message(STATUS "Building with tests")
|
||||
enable_testing()
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# UTILS
|
||||
#----------------------------------
|
||||
|
||||
option(BUILD_CODE_GEN "Build and install interface stub code generator (default OFF)" OFF)
|
||||
|
||||
if(BUILD_CODE_GEN)
|
||||
message(STATUS "Building with code generator tool")
|
||||
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
|
||||
#----------------------------------
|
||||
|
||||
option(BUILD_DOC "Build documentation for sdbus-c++" ON)
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# CMAKE CONFIG & PACKAGE CONFIG
|
||||
#----------------------------------
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(EXPORT sdbus-c++-targets
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++
|
||||
NAMESPACE SDBusCpp::
|
||||
COMPONENT dev)
|
||||
|
||||
configure_package_config_file(cmake/sdbus-c++-config.cmake.in cmake/sdbus-c++-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++)
|
||||
write_basic_package_version_file(cmake/sdbus-c++-config-version.cmake COMPATIBILITY SameMajorVersion)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-config-version.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()
|
||||
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)
|
29
backup/docs/CMakeLists.txt
Normal file
29
backup/docs/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
# Building doxygen documentation
|
||||
|
||||
find_package(Doxygen)
|
||||
|
||||
if(BUILD_DOXYGEN_DOC)
|
||||
if(DOXYGEN_FOUND)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
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)
|
||||
else()
|
||||
message(WARNING "Documentation enabled, but Doxygen cannot be found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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)
|
2496
backup/docs/Doxyfile.in
Normal file
2496
backup/docs/Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
BIN
backup/docs/sdbus-c++-class-diagram.png
Normal file
BIN
backup/docs/sdbus-c++-class-diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
63
backup/docs/sdbus-c++-class-diagram.uml
Normal file
63
backup/docs/sdbus-c++-class-diagram.uml
Normal file
@ -0,0 +1,63 @@
|
||||
@startuml
|
||||
|
||||
package "Public API" <<frame>> #DDDDDD {
|
||||
interface IConnection {
|
||||
+requestName()
|
||||
+enterProcessLoop()
|
||||
+leaveProcessLoop()
|
||||
}
|
||||
|
||||
interface IObject {
|
||||
+registerMethod()
|
||||
+emitSignal()
|
||||
}
|
||||
|
||||
interface IProxy {
|
||||
+callMethod()
|
||||
+subscribeToSignal()
|
||||
+get/setProperty()
|
||||
}
|
||||
|
||||
class Message {
|
||||
+serialize(...)
|
||||
+deserialize(...)
|
||||
+send()
|
||||
Type msgType
|
||||
}
|
||||
}
|
||||
|
||||
interface IConnectionInternal {
|
||||
+addObjectVTable()
|
||||
+createMethodCall()
|
||||
+createSignal()
|
||||
}
|
||||
|
||||
class Connection {
|
||||
}
|
||||
|
||||
class Object {
|
||||
IConnectionInternal& connection
|
||||
string objectPath
|
||||
List interfaces
|
||||
List methods
|
||||
List signals
|
||||
List properties
|
||||
}
|
||||
|
||||
class Proxy {
|
||||
IConnectionInternal& connection
|
||||
string destination
|
||||
string objectPath
|
||||
List signalHandlers
|
||||
}
|
||||
|
||||
IConnection <|-- Connection
|
||||
IConnectionInternal <|- Connection
|
||||
IObject <|-- Object
|
||||
IProxy <|-- Proxy
|
||||
Connection <-- Object : "use"
|
||||
Connection <-- Proxy : "use"
|
||||
Message <.. Object : "send/receive"
|
||||
Message <.. Proxy : "send/receive"
|
||||
|
||||
@enduml
|
50
backup/docs/systemd-dbus-config.md
Normal file
50
backup/docs/systemd-dbus-config.md
Normal file
@ -0,0 +1,50 @@
|
||||
Systemd and D-Bus configuration
|
||||
=======================
|
||||
|
||||
**Table of contents**
|
||||
|
||||
1. [Introduction](#introduction)
|
||||
2. [Systemd configuration](#systemd-configuration)
|
||||
3. [Dbus configuration](#dbus-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.
|
||||
|
||||
|
||||
Systemd configuration
|
||||
---------------------------------------
|
||||
|
||||
Filename should use `.service` extension. It also must be placed in configuration directory (/etc/systemd/system in Ubuntu 18.04.1 LTS)
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=nameOfService
|
||||
|
||||
[Service]
|
||||
ExecStart=/path/to/executable
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
D-Bus 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:
|
||||
|
||||
```
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="org.sdbuscpp.concatenator"/>
|
||||
<allow send_destination="org.sdbuscpp.concatenator"/>
|
||||
<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`.
|
1351
backup/docs/using-sdbus-c++.md
Normal file
1351
backup/docs/using-sdbus-c++.md
Normal file
File diff suppressed because it is too large
Load Diff
154
backup/include/sdbus-c++/AdaptorInterfaces.h
Normal file
154
backup/include/sdbus-c++/AdaptorInterfaces.h
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file AdaptorInterfaces.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_ADAPTORINTERFACES_H_
|
||||
#define SDBUS_CXX_ADAPTORINTERFACES_H_
|
||||
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class IConnection;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class ObjectHolder
|
||||
*
|
||||
* ObjectHolder is a helper that simply owns and provides
|
||||
* access to an object to other classes in the inheritance
|
||||
* hierarchy of an object based on generated interface classes.
|
||||
*
|
||||
***********************************************/
|
||||
class ObjectHolder
|
||||
{
|
||||
protected:
|
||||
ObjectHolder(std::unique_ptr<IObject>&& object)
|
||||
: object_(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
const IObject& getObject() const
|
||||
{
|
||||
assert(object_ != nullptr);
|
||||
return *object_;
|
||||
}
|
||||
|
||||
IObject& getObject()
|
||||
{
|
||||
assert(object_ != nullptr);
|
||||
return *object_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<IObject> object_;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class AdaptorInterfaces
|
||||
*
|
||||
* AdaptorInterfaces is a helper template class that joins all interface classes of a remote
|
||||
* D-Bus object generated by sdbus-c++-xml2cpp to be used on the server (the adaptor) side,
|
||||
* including some auxiliary classes. AdaptorInterfaces is the class that native-like object
|
||||
* implementation classes written by users should inherit from and implement all pure virtual
|
||||
* methods. So the _Interfaces template parameter is a list of sdbus-c++-xml2cpp-generated
|
||||
* adaptor-side interface classes representing interfaces (with methods, signals and properties)
|
||||
* of the D-Bus object.
|
||||
*
|
||||
* In the final adaptor class inherited from AdaptorInterfaces, it is necessary to finish
|
||||
* adaptor registration in class constructor (finishRegistration();`), and, conversely,
|
||||
* unregister the adaptor in class destructor (`unregister();`).
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _Interfaces>
|
||||
class AdaptorInterfaces
|
||||
: protected ObjectHolder
|
||||
, public _Interfaces...
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* @brief Creates object instance
|
||||
*
|
||||
* @param[in] connection D-Bus connection where the object will publish itself
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* For more information, consult @ref createObject(sdbus::IConnection&,std::string)
|
||||
*/
|
||||
AdaptorInterfaces(IConnection& connection, std::string objectPath)
|
||||
: ObjectHolder(createObject(connection, std::move(objectPath)))
|
||||
, _Interfaces(getObject())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Finishes adaptor API registration and publishes the adaptor on the bus
|
||||
*
|
||||
* This function must be called in the constructor of the final adaptor class that implements AdaptorInterfaces.
|
||||
*
|
||||
* For more information, see underlying @ref IObject::finishRegistration()
|
||||
*/
|
||||
void registerAdaptor()
|
||||
{
|
||||
getObject().finishRegistration();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Unregisters adaptors's API and removes it from the bus
|
||||
*
|
||||
* This function must be called in the destructor of the final adaptor class that implements AdaptorInterfaces.
|
||||
*
|
||||
* For more information, see underlying @ref IObject::unregister()
|
||||
*/
|
||||
void unregisterAdaptor()
|
||||
{
|
||||
getObject().unregister();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
*/
|
||||
const std::string& getObjectPath() const
|
||||
{
|
||||
return getObject().getObjectPath();
|
||||
}
|
||||
|
||||
protected:
|
||||
using base_type = AdaptorInterfaces;
|
||||
|
||||
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces(AdaptorInterfaces&&) = default;
|
||||
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = default;
|
||||
~AdaptorInterfaces() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_ADAPTORINTERFACES_H_ */
|
257
backup/include/sdbus-c++/ConvenienceApiClasses.h
Normal file
257
backup/include/sdbus-c++/ConvenienceApiClasses.h
Normal file
@ -0,0 +1,257 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ConvenienceApiClasses.h
|
||||
*
|
||||
* Created on: Jan 19, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_CONVENIENCEAPICLASSES_H_
|
||||
#define SDBUS_CXX_CONVENIENCEAPICLASSES_H_
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class IObject;
|
||||
class IProxy;
|
||||
class Variant;
|
||||
class Error;
|
||||
class PendingAsyncCall;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
class MethodRegistrator
|
||||
{
|
||||
public:
|
||||
MethodRegistrator(IObject& object, const std::string& methodName);
|
||||
MethodRegistrator(MethodRegistrator&& other) = default;
|
||||
~MethodRegistrator() noexcept(false);
|
||||
|
||||
MethodRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename _Function> MethodRegistrator& implementedAs(_Function&& callback);
|
||||
MethodRegistrator& withInputParamNames(std::vector<std::string> paramNames);
|
||||
template <typename... _String> MethodRegistrator& withInputParamNames(_String... paramNames);
|
||||
MethodRegistrator& withOutputParamNames(std::vector<std::string> paramNames);
|
||||
template <typename... _String> MethodRegistrator& withOutputParamNames(_String... paramNames);
|
||||
MethodRegistrator& markAsDeprecated();
|
||||
MethodRegistrator& markAsPrivileged();
|
||||
MethodRegistrator& withNoReply();
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& methodName_;
|
||||
std::string interfaceName_;
|
||||
std::string inputSignature_;
|
||||
std::vector<std::string> inputParamNames_;
|
||||
std::string outputSignature_;
|
||||
std::vector<std::string> outputParamNames_;
|
||||
method_callback methodCallback_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
class SignalRegistrator
|
||||
{
|
||||
public:
|
||||
SignalRegistrator(IObject& object, const std::string& signalName);
|
||||
SignalRegistrator(SignalRegistrator&& other) = default;
|
||||
~SignalRegistrator() noexcept(false);
|
||||
|
||||
SignalRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename... _Args> SignalRegistrator& withParameters();
|
||||
template <typename... _Args> SignalRegistrator& withParameters(std::vector<std::string> paramNames);
|
||||
template <typename... _Args, typename... _String> SignalRegistrator& withParameters(_String... paramNames);
|
||||
SignalRegistrator& markAsDeprecated();
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& signalName_;
|
||||
std::string interfaceName_;
|
||||
std::string signalSignature_;
|
||||
std::vector<std::string> paramNames_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
class PropertyRegistrator
|
||||
{
|
||||
public:
|
||||
PropertyRegistrator(IObject& object, const std::string& propertyName);
|
||||
PropertyRegistrator(PropertyRegistrator&& other) = default;
|
||||
~PropertyRegistrator() noexcept(false);
|
||||
|
||||
PropertyRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename _Function> PropertyRegistrator& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyRegistrator& withSetter(_Function&& callback);
|
||||
PropertyRegistrator& markAsDeprecated();
|
||||
PropertyRegistrator& markAsPrivileged();
|
||||
PropertyRegistrator& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& propertyName_;
|
||||
std::string interfaceName_;
|
||||
std::string propertySignature_;
|
||||
property_get_callback getter_;
|
||||
property_set_callback setter_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
|
||||
};
|
||||
|
||||
class InterfaceFlagsSetter
|
||||
{
|
||||
public:
|
||||
InterfaceFlagsSetter(IObject& object, const std::string& interfaceName);
|
||||
InterfaceFlagsSetter(InterfaceFlagsSetter&& other) = default;
|
||||
~InterfaceFlagsSetter() noexcept(false);
|
||||
|
||||
InterfaceFlagsSetter& markAsDeprecated();
|
||||
InterfaceFlagsSetter& markAsPrivileged();
|
||||
InterfaceFlagsSetter& withNoReplyMethods();
|
||||
InterfaceFlagsSetter& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& interfaceName_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when InterfaceFlagsSetter is constructed
|
||||
};
|
||||
|
||||
class SignalEmitter
|
||||
{
|
||||
public:
|
||||
SignalEmitter(IObject& object, const std::string& signalName);
|
||||
SignalEmitter(SignalEmitter&& other) = default;
|
||||
~SignalEmitter() noexcept(false);
|
||||
SignalEmitter& onInterface(const std::string& interfaceName);
|
||||
template <typename... _Args> void withArguments(_Args&&... args);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& signalName_;
|
||||
Signal signal_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed
|
||||
};
|
||||
|
||||
class MethodInvoker
|
||||
{
|
||||
public:
|
||||
MethodInvoker(IProxy& proxy, const std::string& methodName);
|
||||
MethodInvoker(MethodInvoker&& other) = default;
|
||||
~MethodInvoker() noexcept(false);
|
||||
|
||||
MethodInvoker& onInterface(const std::string& interfaceName);
|
||||
MethodInvoker& withTimeout(uint64_t usec);
|
||||
template <typename _Rep, typename _Period>
|
||||
MethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
||||
template <typename... _Args> MethodInvoker& withArguments(_Args&&... args);
|
||||
template <typename... _Args> void storeResultsTo(_Args&... args);
|
||||
|
||||
void dontExpectReply();
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& methodName_;
|
||||
uint64_t timeout_{};
|
||||
MethodCall method_;
|
||||
int exceptions_{}; // Number of active exceptions when MethodInvoker is constructed
|
||||
bool methodCalled_{};
|
||||
};
|
||||
|
||||
class AsyncMethodInvoker
|
||||
{
|
||||
public:
|
||||
AsyncMethodInvoker(IProxy& proxy, const std::string& methodName);
|
||||
AsyncMethodInvoker& onInterface(const std::string& interfaceName);
|
||||
AsyncMethodInvoker& withTimeout(uint64_t usec);
|
||||
template <typename _Rep, typename _Period>
|
||||
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
||||
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
|
||||
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& methodName_;
|
||||
uint64_t timeout_{};
|
||||
MethodCall method_;
|
||||
};
|
||||
|
||||
class SignalSubscriber
|
||||
{
|
||||
public:
|
||||
SignalSubscriber(IProxy& proxy, const std::string& signalName);
|
||||
SignalSubscriber& onInterface(std::string interfaceName);
|
||||
template <typename _Function> void call(_Function&& callback);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& signalName_;
|
||||
std::string interfaceName_;
|
||||
};
|
||||
|
||||
class SignalUnsubscriber
|
||||
{
|
||||
public:
|
||||
SignalUnsubscriber(IProxy& proxy, const std::string& signalName);
|
||||
void onInterface(std::string interfaceName);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& signalName_;
|
||||
};
|
||||
|
||||
class PropertyGetter
|
||||
{
|
||||
public:
|
||||
PropertyGetter(IProxy& proxy, const std::string& propertyName);
|
||||
sdbus::Variant onInterface(const std::string& interfaceName);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
};
|
||||
|
||||
class PropertySetter
|
||||
{
|
||||
public:
|
||||
PropertySetter(IProxy& proxy, const std::string& propertyName);
|
||||
PropertySetter& onInterface(std::string interfaceName);
|
||||
template <typename _Value> void toValue(const _Value& value);
|
||||
void toValue(const sdbus::Variant& value);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
std::string interfaceName_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_CONVENIENCEAPICLASSES_H_ */
|
745
backup/include/sdbus-c++/ConvenienceApiClasses.inl
Normal file
745
backup/include/sdbus-c++/ConvenienceApiClasses.inl
Normal file
@ -0,0 +1,745 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ConvenienceApiClasses.inl
|
||||
*
|
||||
* Created on: Dec 19, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_CONVENIENCEAPICLASSES_INL_
|
||||
#define SDBUS_CPP_CONVENIENCEAPICLASSES_INL_
|
||||
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/*** ----------------- ***/
|
||||
/*** MethodRegistrator ***/
|
||||
/*** ----------------- ***/
|
||||
|
||||
inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
|
||||
: object_(object)
|
||||
, methodName_(methodName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the method if MethodRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(methodCallback_); // implementedAs() must be placed/called prior to this function
|
||||
|
||||
// registerMethod() can throw. But as the MethodRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerMethod() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerMethod( interfaceName_
|
||||
, std::move(methodName_)
|
||||
, std::move(inputSignature_)
|
||||
, std::move(inputParamNames_)
|
||||
, std::move(outputSignature_)
|
||||
, std::move(outputParamNames_)
|
||||
, std::move(methodCallback_)
|
||||
, std::move(flags_));
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
MethodRegistrator& MethodRegistrator::implementedAs(_Function&& callback)
|
||||
{
|
||||
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
methodCallback_ = [callback = std::forward<_Function>(callback)](MethodCall call)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<_Function> inputArgs;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple.
|
||||
call >> inputArgs;
|
||||
|
||||
if constexpr (!is_async_method_v<_Function>)
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
auto ret = sdbus::apply(callback, inputArgs);
|
||||
|
||||
// Store output arguments to the reply message and send it back.
|
||||
auto reply = call.createReply();
|
||||
reply << ret;
|
||||
reply.send();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple and with result object to be set later
|
||||
using AsyncResult = typename function_traits<_Function>::async_result_t;
|
||||
sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs));
|
||||
}
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withInputParamNames(std::vector<std::string> paramNames)
|
||||
{
|
||||
inputParamNames_ = std::move(paramNames);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodRegistrator& MethodRegistrator::withInputParamNames(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withInputParamNames({paramNames...});
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withOutputParamNames(std::vector<std::string> paramNames)
|
||||
{
|
||||
outputParamNames_ = std::move(paramNames);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodRegistrator& MethodRegistrator::withOutputParamNames(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withOutputParamNames({paramNames...});
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withNoReply()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** ----------------- ***/
|
||||
/*** SignalRegistrator ***/
|
||||
/*** ----------------- ***/
|
||||
|
||||
inline SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName)
|
||||
: object_(object)
|
||||
, signalName_(signalName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the signal if SignalRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
// registerSignal() can throw. But as the SignalRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerSignal() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerSignal( interfaceName_
|
||||
, std::move(signalName_)
|
||||
, std::move(signalSignature_)
|
||||
, std::move(paramNames_)
|
||||
, std::move(flags_) );
|
||||
}
|
||||
|
||||
inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters()
|
||||
{
|
||||
signalSignature_ = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters(std::vector<std::string> paramNames)
|
||||
{
|
||||
paramNames_ = std::move(paramNames);
|
||||
|
||||
return withParameters<_Args...>();
|
||||
}
|
||||
|
||||
template <typename... _Args, typename... _String>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
static_assert(sizeof...(_Args) == sizeof...(_String), "Numbers of signal parameters and their names don't match");
|
||||
|
||||
return withParameters<_Args...>({paramNames...});
|
||||
}
|
||||
|
||||
inline SignalRegistrator& SignalRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** ------------------- ***/
|
||||
/*** PropertyRegistrator ***/
|
||||
/*** ------------------- ***/
|
||||
|
||||
inline PropertyRegistrator::PropertyRegistrator(IObject& object, const std::string& propertyName)
|
||||
: object_(object)
|
||||
, propertyName_(propertyName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the property if PropertyRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
// registerProperty() can throw. But as the PropertyRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerProperty() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerProperty( interfaceName_
|
||||
, propertyName_
|
||||
, propertySignature_
|
||||
, std::move(getter_)
|
||||
, std::move(setter_)
|
||||
, flags_ );
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyRegistrator& PropertyRegistrator::withGetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_traits<_Function>::arity == 0, "Property getter function must not take any arguments");
|
||||
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
|
||||
|
||||
if (propertySignature_.empty())
|
||||
propertySignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
|
||||
getter_ = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
|
||||
{
|
||||
// Get the propety value and serialize it into the pre-constructed reply message
|
||||
reply << callback();
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyRegistrator& PropertyRegistrator::withSetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_traits<_Function>::arity == 1, "Property setter function must take one parameter - the property value");
|
||||
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
|
||||
|
||||
if (propertySignature_.empty())
|
||||
propertySignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
|
||||
setter_ = [callback = std::forward<_Function>(callback)](PropertySetCall& call)
|
||||
{
|
||||
// Default-construct property value
|
||||
using property_type = function_argument_t<_Function, 0>;
|
||||
std::decay_t<property_type> property;
|
||||
|
||||
// Deserialize property value from the incoming call message
|
||||
call >> property;
|
||||
|
||||
// Invoke setter with the value
|
||||
callback(property);
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** InterfaceFlagsSetter ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
inline InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
|
||||
: object_(object)
|
||||
, interfaceName_(interfaceName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't set any flags if InterfaceFlagsSetter threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow setInterfaceFlags() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.setInterfaceFlags(interfaceName_, std::move(flags_));
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withNoReplyMethods()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** ------------- ***/
|
||||
/*** SignalEmitter ***/
|
||||
/*** ------------- ***/
|
||||
|
||||
inline SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName)
|
||||
: object_(object)
|
||||
, signalName_(signalName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalEmitter::~SignalEmitter() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't emit the signal if SignalEmitter threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
// emitSignal() can throw. But as the SignalEmitter shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow emitSignal() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.emitSignal(signal_);
|
||||
}
|
||||
|
||||
inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
signal_ = object_.createSignal(interfaceName, signalName_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline void SignalEmitter::withArguments(_Args&&... args)
|
||||
{
|
||||
assert(signal_.isValid()); // onInterface() must be placed/called prior to withArguments()
|
||||
|
||||
detail::serialize_pack(signal_, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
/*** ------------- ***/
|
||||
/*** MethodInvoker ***/
|
||||
/*** ------------- ***/
|
||||
|
||||
inline MethodInvoker::MethodInvoker(IProxy& proxy, const std::string& methodName)
|
||||
: proxy_(proxy)
|
||||
, methodName_(methodName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline MethodInvoker::~MethodInvoker() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't call the method if it has been called already or if MethodInvoker
|
||||
// threw an exception in one of its methods
|
||||
if (methodCalled_ || std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
// callMethod() can throw. But as the MethodInvoker shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow callMethod() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
proxy_.callMethod(method_, timeout_);
|
||||
}
|
||||
|
||||
inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
method_ = proxy_.createMethodCall(interfaceName, methodName_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodInvoker& MethodInvoker::withTimeout(uint64_t usec)
|
||||
{
|
||||
timeout_ = usec;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline MethodInvoker& MethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return withTimeout(microsecs.count());
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args)
|
||||
{
|
||||
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
detail::serialize_pack(method_, std::forward<_Args>(args)...);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline void MethodInvoker::storeResultsTo(_Args&... args)
|
||||
{
|
||||
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
auto reply = proxy_.callMethod(method_, timeout_);
|
||||
methodCalled_ = true;
|
||||
|
||||
detail::deserialize_pack(reply, args...);
|
||||
}
|
||||
|
||||
inline void MethodInvoker::dontExpectReply()
|
||||
{
|
||||
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
method_.dontExpectReply();
|
||||
}
|
||||
|
||||
/*** ------------------ ***/
|
||||
/*** AsyncMethodInvoker ***/
|
||||
/*** ------------------ ***/
|
||||
|
||||
inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const std::string& methodName)
|
||||
: proxy_(proxy)
|
||||
, methodName_(methodName)
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
method_ = proxy_.createMethodCall(interfaceName, methodName_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(uint64_t usec)
|
||||
{
|
||||
timeout_ = usec;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return withTimeout(microsecs.count());
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::withArguments(_Args&&... args)
|
||||
{
|
||||
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
detail::serialize_pack(method_, std::forward<_Args>(args)...);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
PendingAsyncCall AsyncMethodInvoker::uponReplyInvoke(_Function&& callback)
|
||||
{
|
||||
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
auto asyncReplyHandler = [callback = std::forward<_Function>(callback)](MethodReply& reply, const Error* error)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<_Function> args;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple (if no error occurred).
|
||||
if (error == nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
reply >> args;
|
||||
}
|
||||
catch (const Error& e)
|
||||
{
|
||||
// Catch message unpack exceptions and pass them to the callback
|
||||
// in the expected manner to avoid propagating them up the call
|
||||
// stack to the event loop.
|
||||
sdbus::apply(callback, &e, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
sdbus::apply(callback, error, args);
|
||||
};
|
||||
|
||||
return proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
|
||||
}
|
||||
|
||||
/*** ---------------- ***/
|
||||
/*** SignalSubscriber ***/
|
||||
/*** ---------------- ***/
|
||||
|
||||
inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const std::string& signalName)
|
||||
: proxy_(proxy)
|
||||
, signalName_(signalName)
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalSubscriber& SignalSubscriber::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline void SignalSubscriber::call(_Function&& callback)
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
proxy_.registerSignalHandler( interfaceName_
|
||||
, signalName_
|
||||
, [callback = std::forward<_Function>(callback)](Signal& signal)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the signal message.
|
||||
tuple_of_function_input_arg_types_t<_Function> signalArgs;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Invoke callback with error argument and input arguments from the tuple.
|
||||
sdbus::apply(callback, &e, 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*** ------------------ ***/
|
||||
/*** SignalUnsubscriber ***/
|
||||
/*** ------------------ ***/
|
||||
|
||||
inline SignalUnsubscriber::SignalUnsubscriber(IProxy& proxy, const std::string& signalName)
|
||||
: proxy_(proxy)
|
||||
, signalName_(signalName)
|
||||
{
|
||||
}
|
||||
|
||||
inline void SignalUnsubscriber::onInterface(std::string interfaceName)
|
||||
{
|
||||
proxy_.unregisterSignalHandler(interfaceName, signalName_);
|
||||
}
|
||||
|
||||
/*** -------------- ***/
|
||||
/*** PropertyGetter ***/
|
||||
/*** -------------- ***/
|
||||
|
||||
inline PropertyGetter::PropertyGetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline sdbus::Variant PropertyGetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
sdbus::Variant var;
|
||||
proxy_
|
||||
.callMethod("Get")
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(interfaceName, propertyName_)
|
||||
.storeResultsTo(var);
|
||||
return var;
|
||||
}
|
||||
|
||||
/*** -------------- ***/
|
||||
/*** PropertySetter ***/
|
||||
/*** -------------- ***/
|
||||
|
||||
inline PropertySetter::PropertySetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline PropertySetter& PropertySetter::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Value>
|
||||
inline void PropertySetter::toValue(const _Value& value)
|
||||
{
|
||||
PropertySetter::toValue(sdbus::Variant{value});
|
||||
}
|
||||
|
||||
inline void PropertySetter::toValue(const sdbus::Variant& value)
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
proxy_
|
||||
.callMethod("Set")
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(interfaceName_, propertyName_, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ */
|
89
backup/include/sdbus-c++/Error.h
Normal file
89
backup/include/sdbus-c++/Error.h
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Error.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_ERROR_H_
|
||||
#define SDBUS_CXX_ERROR_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class Error
|
||||
*
|
||||
* Represents a common sdbus-c++ exception.
|
||||
*
|
||||
***********************************************/
|
||||
class Error
|
||||
: 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)
|
||||
, message_(message)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& getName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string& getMessage() const
|
||||
{
|
||||
return message_;
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return !getName().empty();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
sdbus::Error createError(int errNo, const std::string& customMsg);
|
||||
}
|
||||
|
||||
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
|
||||
throw sdbus::createError((_ERRNO), (_MSG)) \
|
||||
/**/
|
||||
|
||||
#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
|
||||
if (!(_COND)) ; else SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
|
||||
/**/
|
||||
|
||||
#endif /* SDBUS_CXX_ERROR_H_ */
|
99
backup/include/sdbus-c++/Flags.h
Normal file
99
backup/include/sdbus-c++/Flags.h
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Flags.h
|
||||
*
|
||||
* Created on: Dec 31, 2018
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_FLAGS_H_
|
||||
#define SDBUS_CXX_FLAGS_H_
|
||||
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
// D-Bus interface, method, signal or property flags
|
||||
class Flags
|
||||
{
|
||||
public:
|
||||
enum GeneralFlags : uint8_t
|
||||
{ DEPRECATED = 0
|
||||
, METHOD_NO_REPLY = 1
|
||||
, PRIVILEGED = 2
|
||||
};
|
||||
|
||||
enum PropertyUpdateBehaviorFlags : uint8_t
|
||||
{ EMITS_CHANGE_SIGNAL = 3
|
||||
, EMITS_INVALIDATION_SIGNAL = 4
|
||||
, EMITS_NO_SIGNAL = 5
|
||||
, CONST_PROPERTY_VALUE = 6
|
||||
};
|
||||
|
||||
enum : uint8_t
|
||||
{ FLAG_COUNT = 7
|
||||
};
|
||||
|
||||
Flags()
|
||||
{
|
||||
// EMITS_CHANGE_SIGNAL is on by default
|
||||
flags_.set(EMITS_CHANGE_SIGNAL, true);
|
||||
}
|
||||
|
||||
void set(GeneralFlags flag, bool value = true)
|
||||
{
|
||||
flags_.set(flag, value);
|
||||
}
|
||||
|
||||
void set(PropertyUpdateBehaviorFlags flag, bool value = true)
|
||||
{
|
||||
flags_.set(EMITS_CHANGE_SIGNAL, false);
|
||||
flags_.set(EMITS_INVALIDATION_SIGNAL, false);
|
||||
flags_.set(EMITS_NO_SIGNAL, false);
|
||||
flags_.set(CONST_PROPERTY_VALUE, false);
|
||||
|
||||
flags_.set(flag, value);
|
||||
}
|
||||
|
||||
bool test(GeneralFlags flag) const
|
||||
{
|
||||
return flags_.test(flag);
|
||||
}
|
||||
|
||||
bool test(PropertyUpdateBehaviorFlags flag) const
|
||||
{
|
||||
return flags_.test(flag);
|
||||
}
|
||||
|
||||
uint64_t toSdBusInterfaceFlags() const;
|
||||
uint64_t toSdBusMethodFlags() const;
|
||||
uint64_t toSdBusSignalFlags() const;
|
||||
uint64_t toSdBusPropertyFlags() const;
|
||||
uint64_t toSdBusWritablePropertyFlags() const;
|
||||
|
||||
private:
|
||||
std::bitset<FLAG_COUNT> flags_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_FLAGS_H_ */
|
504
backup/include/sdbus-c++/IConnection.h
Normal file
504
backup/include/sdbus-c++/IConnection.h
Normal file
@ -0,0 +1,504 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IConnection.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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>
|
||||
#include <thread>
|
||||
|
||||
struct sd_event;
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class IConnection
|
||||
*
|
||||
* An interface to D-Bus bus connection. Incorporates implementation
|
||||
* of both synchronous and asynchronous D-Bus I/O event loop.
|
||||
*
|
||||
* All methods throw sdbus::Error in case of failure. All methods in
|
||||
* this class are thread-aware, but not thread-safe.
|
||||
*
|
||||
***********************************************/
|
||||
class IConnection
|
||||
{
|
||||
public:
|
||||
struct PollData;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
|
||||
/*!
|
||||
* @brief Requests D-Bus name on the connection
|
||||
*
|
||||
* @param[in] name Name to request
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void requestName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Releases D-Bus name on the connection
|
||||
*
|
||||
* @param[in] name Name to release
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void releaseName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Retrieves the unique name of a connection. E.g. ":1.xx"
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::string getUniqueName() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Enters I/O event loop on this bus connection
|
||||
*
|
||||
* The incoming D-Bus messages are processed in the loop. The method
|
||||
* blocks indefinitely, until unblocked through leaveEventLoop().
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void enterEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Enters I/O event loop on this bus connection in a separate thread
|
||||
*
|
||||
* The same as enterEventLoop, except that it doesn't block
|
||||
* because it runs the loop in a separate, internally managed thread.
|
||||
*/
|
||||
virtual void enterEventLoopAsync() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Leaves the I/O event loop running on this bus connection
|
||||
*
|
||||
* This causes the loop to exit and frees the thread serving the loop
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void leaveEventLoop() = 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
|
||||
*/
|
||||
[[deprecated("Use one of other addObjectManager overloads")]] virtual void addObjectManager(const std::string& objectPath) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Returns fd's, I/O events and timeout data to be used in an external event loop
|
||||
*
|
||||
* This function is useful to hook up a bus connection object with an
|
||||
* external (like GMainLoop, boost::asio, etc.) or manual event loop
|
||||
* involving poll() or a similar I/O polling call.
|
||||
*
|
||||
* Before **each** invocation of the I/O polling call, this function
|
||||
* should be invoked. Returned PollData::fd file descriptor should
|
||||
* be polled for the events indicated by PollData::events, and the I/O
|
||||
* call should block for that up to the returned PollData::timeout.
|
||||
*
|
||||
* Additionally, returned PollData::eventFd should be polled for POLLIN
|
||||
* events.
|
||||
*
|
||||
* After each I/O polling call the bus connection needs to process
|
||||
* incoming or outgoing data, by invoking processPendingEvent().
|
||||
*
|
||||
* Note that the returned timeout should be considered only a maximum
|
||||
* sleeping time. It is permissible (and even expected) that shorter
|
||||
* timeouts are used by the calling program, in case other event sources
|
||||
* are polled in the same event loop. Note that the returned time-value
|
||||
* is absolute, based of CLOCK_MONOTONIC and specified in microseconds.
|
||||
* Use PollData::getPollTimeout() to have the timeout value converted
|
||||
* in a form that can be passed to poll(2).
|
||||
*
|
||||
* The bus connection conveniently integrates sd-event event loop.
|
||||
* To attach the bus connection to an sd-event event loop, use
|
||||
* attachSdEventLoop() function.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual PollData getEventLoopPollData() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Processes a pending event
|
||||
*
|
||||
* @returns True if an event was processed, false if no operations were pending
|
||||
*
|
||||
* This function drives the D-Bus connection. It processes pending I/O events.
|
||||
* Queued outgoing messages (or parts thereof) are sent out. Queued incoming
|
||||
* messages are dispatched to registered callbacks. Timeouts are recalculated.
|
||||
*
|
||||
* It returns false when no operations were pending and true if a message was
|
||||
* processed. When false is returned the caller should synchronously poll for
|
||||
* I/O events before calling into processPendingEvent() again.
|
||||
* Don't forget to call getEventLoopPollData() each time before the next poll.
|
||||
*
|
||||
* You don't need to directly call this method or getEventLoopPollData() method
|
||||
* when using convenient, internal bus connection event loops through
|
||||
* enterEventLoop() or enterEventLoopAsync() calls, or when the bus is
|
||||
* connected to an sd-event event loop through attachSdEventLoop().
|
||||
* It is invoked automatically when necessary.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual bool processPendingEvent() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets general method call timeout
|
||||
*
|
||||
* @param[in] timeout Timeout value in microseconds
|
||||
*
|
||||
* General method call timeout is used for all method calls upon this connection.
|
||||
* Method call-specific timeout overrides this general setting.
|
||||
*
|
||||
* Supported by libsystemd>=v240.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void setMethodCallTimeout(uint64_t timeout) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::setMethodCallTimeout(uint64_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
void setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
||||
|
||||
/*!
|
||||
* @brief Gets general method call timeout
|
||||
*
|
||||
* @return Timeout value in microseconds
|
||||
*
|
||||
* Supported by libsystemd>=v240.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
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 Adds a match rule for incoming message dispatching
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon incoming 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 Adds a floating match rule for incoming message dispatching
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon incoming 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 Attaches the bus connection to an sd-event event loop
|
||||
*
|
||||
* @param[in] event sd-event event loop object
|
||||
* @param[in] priority Specified priority
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*
|
||||
* See `man sd_bus_attach_event'.
|
||||
*/
|
||||
virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Detaches the bus connection from an sd-event event loop
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void detachSdEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Gets current sd-event event loop for the bus connection
|
||||
*
|
||||
* @return Pointer to event loop object if attached, nullptr otherwise
|
||||
*/
|
||||
virtual sd_event *getSdEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::enterEventLoop()
|
||||
*
|
||||
* @deprecated This function has been replaced by enterEventLoop()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by enterEventLoop()")]] void enterProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::enterEventLoopAsync()
|
||||
*
|
||||
* @deprecated This function has been replaced by enterEventLoopAsync()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by enterEventLoopAsync()")]] void enterProcessingLoopAsync();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::leaveEventLoop()
|
||||
*
|
||||
* @deprecated This function has been replaced by leaveEventLoop()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by leaveEventLoop()")]] void leaveProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::getEventLoopPollData()
|
||||
*
|
||||
* @deprecated This function has been replaced by getEventLoopPollData()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by getEventLoopPollData()")]] PollData getProcessLoopPollData() const;
|
||||
|
||||
/*!
|
||||
* @struct PollData
|
||||
*
|
||||
* Carries poll data needed for integration with external event loop implementations.
|
||||
*
|
||||
* See getEventLoopPollData() for more info.
|
||||
*/
|
||||
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 microseconds, based of CLOCK_MONOTONIC.
|
||||
*
|
||||
* Call getPollTimeout() to get timeout recalculated to relative timeout that can be passed to poll(2).
|
||||
*/
|
||||
std::chrono::microseconds timeout;
|
||||
|
||||
/*!
|
||||
* An additional event fd to be monitored by the event loop for POLLIN events.
|
||||
*/
|
||||
int eventFd;
|
||||
|
||||
/*!
|
||||
* Returns the timeout as relative value from now.
|
||||
*
|
||||
* Returned value is std::chrono::microseconds::max() if the timeout is indefinite.
|
||||
*
|
||||
* @return Relative timeout as a time duration
|
||||
*/
|
||||
[[nodiscard]] std::chrono::microseconds getRelativeTimeout() const;
|
||||
|
||||
/*!
|
||||
* Returns relative timeout in the form 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 milliseconds otherwise.
|
||||
*/
|
||||
[[nodiscard]] int getPollTimeout() const;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline void IConnection::setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return setMethodCallTimeout(microsecs.count());
|
||||
}
|
||||
|
||||
inline void IConnection::enterProcessingLoop()
|
||||
{
|
||||
enterEventLoop();
|
||||
}
|
||||
|
||||
inline void IConnection::enterProcessingLoopAsync()
|
||||
{
|
||||
enterEventLoopAsync();
|
||||
}
|
||||
|
||||
inline void IConnection::leaveProcessingLoop()
|
||||
{
|
||||
leaveEventLoop();
|
||||
}
|
||||
|
||||
inline IConnection::PollData IConnection::getProcessLoopPollData() const
|
||||
{
|
||||
return getEventLoopPollData();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system bus connection
|
||||
*
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createConnection();
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system bus connection with a name
|
||||
*
|
||||
* @param[in] name Name to request on the connection after its opening
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[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
|
||||
*
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection();
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system bus connection with a name
|
||||
*
|
||||
* @param[in] name Name to request on the connection after its opening
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name);
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus session bus connection
|
||||
*
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection();
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus session bus connection with a name
|
||||
*
|
||||
* @param[in] name Name to request on the connection after its opening
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[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
|
||||
*
|
||||
* @param[in] host Name of the host to connect
|
||||
* @return Connection instance
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host);
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_ICONNECTION_H_ */
|
512
backup/include/sdbus-c++/IObject.h
Normal file
512
backup/include/sdbus-c++/IObject.h
Normal file
@ -0,0 +1,512 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IObject.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_IOBJECT_H_
|
||||
#define SDBUS_CXX_IOBJECT_H_
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class Signal;
|
||||
class IConnection;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class IObject
|
||||
*
|
||||
* IObject class represents a D-Bus object instance identified by a specific object path.
|
||||
* D-Bus object provides its interfaces, methods, signals and properties on a bus
|
||||
* identified by a specific bus name.
|
||||
*
|
||||
* All IObject member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error.
|
||||
* The IObject class has been designed as thread-aware. However, the operation of
|
||||
* creating and sending asynchronous method replies, as well as creating and emitting
|
||||
* signals, is thread-safe by design.
|
||||
*
|
||||
***********************************************/
|
||||
class IObject
|
||||
{
|
||||
public:
|
||||
virtual ~IObject() = default;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the method will belong to
|
||||
* @param[in] methodName Name of the method
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] methodCallback Callback that implements the body of the method
|
||||
* @param[in] flags D-Bus method flags (privileged, deprecated, or no reply)
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the method will belong to
|
||||
* @param[in] methodName Name of the method
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] inputNames Names of input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] outputNames Names of output parameters
|
||||
* @param[in] methodCallback Callback that implements the body of the method
|
||||
* @param[in] flags D-Bus method flags (privileged, deprecated, or no reply)
|
||||
*
|
||||
* Provided names of input and output parameters will be included in the introspection
|
||||
* description (given that at least version 242 of underlying libsystemd library is
|
||||
* used; otherwise, names of parameters are ignored). This usually helps better describe
|
||||
* the API to the introspector.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, method_callback methodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will emit on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal will fall under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signature D-Bus signature of signal parameters
|
||||
* @param[in] flags D-Bus signal flags (deprecated)
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will emit on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal will fall under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signature D-Bus signature of signal parameters
|
||||
* @param[in] paramNames Names of parameters of the signal
|
||||
* @param[in] flags D-Bus signal flags (deprecated)
|
||||
*
|
||||
* Provided names of signal output parameters will be included in the introspection
|
||||
* description (given that at least version 242 of underlying libsystemd library is
|
||||
* used; otherwise, names of parameters are ignored). This usually helps better describe
|
||||
* the API to the introspector.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers read-only property that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the property will fall under
|
||||
* @param[in] propertyName Name of the property
|
||||
* @param[in] signature D-Bus signature of property parameters
|
||||
* @param[in] getCallback Callback that implements the body of the property getter
|
||||
* @param[in] flags D-Bus property flags (deprecated, property update behavior)
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers read/write property that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the property will fall under
|
||||
* @param[in] propertyName Name of the property
|
||||
* @param[in] signature D-Bus signature of property parameters
|
||||
* @param[in] getCallback Callback that implements the body of the property getter
|
||||
* @param[in] setCallback Callback that implements the body of the property setter
|
||||
* @param[in] flags D-Bus property flags (deprecated, property update behavior)
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets flags for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @param[in] flags Flags to be set
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void setInterfaceFlags(const std::string& interfaceName, Flags flags) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Finishes object API registration and publishes the object on the bus
|
||||
*
|
||||
* The method exports all up to now registered methods, signals and properties on D-Bus.
|
||||
* Must be called after all methods, signals and properties have been registered.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void finishRegistration() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters object's API and removes object from the bus
|
||||
*
|
||||
* This method unregisters the object, its interfaces, methods, signals and properties
|
||||
* from the bus. Unregistration is done automatically also in object's destructor. This
|
||||
* method makes sense if, in the process of object removal, we need to make sure that
|
||||
* callbacks are unregistered explicitly before the final destruction of the object instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregister() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Creates a signal message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A signal message
|
||||
*
|
||||
* Serialize signal arguments into the returned message and emit the signal by passing
|
||||
* the message with serialized arguments to the @c emitSignal function.
|
||||
* Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual Signal createSignal(const std::string& interfaceName, const std::string& signalName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits signal for this object path
|
||||
*
|
||||
* @param[in] message Signal message to be sent out
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitSignal(const sdbus::Signal& message) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits PropertyChanged signal for specified properties under a given interface of this object path
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that properties belong to
|
||||
* @param[in] propNames Names of properties that will be included in the PropertiesChanged signal
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits PropertyChanged signal for all properties on a given interface of this object path
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const std::string& interfaceName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesAdded signal on this object path
|
||||
*
|
||||
* This emits an InterfacesAdded signal on this object path, by iterating all registered
|
||||
* interfaces on the path. All properties are queried and included in the signal.
|
||||
* This call is equivalent to emitInterfacesAddedSignal() with an explicit list of
|
||||
* registered interfaces. However, unlike emitInterfacesAddedSignal(interfaces), this
|
||||
* call can figure out the list of supported interfaces itself. Furthermore, it properly
|
||||
* adds the builtin org.freedesktop.DBus.* interfaces.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesAddedSignal() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesAdded signal on this object path
|
||||
*
|
||||
* This emits an InterfacesAdded signal on this object path with explicitly provided list
|
||||
* of registered interfaces. As sdbus-c++ does currently not supported adding/removing
|
||||
* interfaces of an existing object at run time (an object has a fixed set of interfaces
|
||||
* registered by the time of invoking finishRegistration()), emitInterfacesAddedSignal(void)
|
||||
* is probably what you are looking for.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesRemoved signal on this object path
|
||||
*
|
||||
* This is like sd_bus_emit_object_added(), but emits an InterfacesRemoved signal on this
|
||||
* object path. This only includes any registered interfaces but skips the properties.
|
||||
* This function shall be called (just) before destroying the object.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesRemovedSignal() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesRemoved signal on this object path
|
||||
*
|
||||
* This emits an InterfacesRemoved signal on the given path with explicitly provided list
|
||||
* of registered interfaces. As sdbus-c++ does currently not supported adding/removing
|
||||
* interfaces of an existing object at run time (an object has a fixed set of interfaces
|
||||
* registered by the time of invoking finishRegistration()), emitInterfacesRemovedSignal(void)
|
||||
* is probably what you are looking for.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds an ObjectManager interface at the path of this D-Bus object
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addObjectManager() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Removes an ObjectManager interface from the path of this D-Bus object
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void removeObjectManager() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Tests whether ObjectManager interface is added at the path of this D-Bus object
|
||||
* @return True if ObjectManager interface is there, false otherwise
|
||||
*/
|
||||
virtual bool hasObjectManager() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Provides D-Bus connection used by the object
|
||||
*
|
||||
* @return Reference to the D-Bus connection
|
||||
*/
|
||||
virtual sdbus::IConnection& getConnection() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A helper object for convenient registration of the method
|
||||
*
|
||||
* This is a high-level, convenience way of registering D-Bus methods that abstracts
|
||||
* from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the parameters and return type
|
||||
* of the provided native method implementation callback.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object.registerMethod("doFoo").onInterface("com.kistler.foo").implementedAs([this](int value){ return this->doFoo(value); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] MethodRegistrator registerMethod(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A helper object for convenient registration of the signal
|
||||
*
|
||||
* This is a high-level, convenience way of registering D-Bus signals that abstracts
|
||||
* from the D-Bus message concept. Signal arguments are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native parameters.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object.registerSignal("paramChange").onInterface("com.kistler.foo").withParameters<std::map<int32_t, std::string>>();
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalRegistrator registerSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @brief Registers property that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] propertyName Name of the property
|
||||
* @return A helper object for convenient registration of the property
|
||||
*
|
||||
* This is a high-level, convenience way of registering D-Bus properties that abstracts
|
||||
* from the D-Bus message concept. Property arguments are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native callbacks.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.registerProperty("state").onInterface("com.kistler.foo").withGetter([this](){ return this->state(); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertyRegistrator registerProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets flags (annotations) for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @return A helper object for convenient setting of Interface flags
|
||||
*
|
||||
* This is a high-level, convenience alternative to the other setInterfaceFlags overload.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.setInterfaceFlags("com.kistler.foo").markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] InterfaceFlagsSetter setInterfaceFlags(const std::string& interfaceName);
|
||||
|
||||
/*!
|
||||
* @brief Emits signal on D-Bus
|
||||
*
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A helper object for convenient emission of signals
|
||||
*
|
||||
* This is a high-level, convenience way of emitting D-Bus signals that abstracts
|
||||
* from the D-Bus message concept. Signal arguments are automatically serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native arguments.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* int arg1 = ...;
|
||||
* double arg2 = ...;
|
||||
* object_.emitSignal("fooSignal").onInterface("com.kistler.foo").withArguments(arg1, arg2);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalEmitter emitSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @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
|
||||
|
||||
inline MethodRegistrator IObject::registerMethod(const std::string& methodName)
|
||||
{
|
||||
return MethodRegistrator(*this, methodName);
|
||||
}
|
||||
|
||||
inline SignalRegistrator IObject::registerSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalRegistrator(*this, signalName);
|
||||
}
|
||||
|
||||
inline PropertyRegistrator IObject::registerProperty(const std::string& propertyName)
|
||||
{
|
||||
return PropertyRegistrator(*this, propertyName);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter IObject::setInterfaceFlags(const std::string& interfaceName)
|
||||
{
|
||||
return InterfaceFlagsSetter(*this, interfaceName);
|
||||
}
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalEmitter(*this, signalName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates instance representing a D-Bus object
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
* @return Pointer to the object representation instance
|
||||
*
|
||||
* The provided connection will be used by the object to export methods,
|
||||
* issue signals and provide properties.
|
||||
*
|
||||
* Creating a D-Bus object instance is (thread-)safe even upon the connection
|
||||
* which is already running its I/O event loop.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, std::string objectPath);
|
||||
|
||||
}
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl>
|
||||
|
||||
#endif /* SDBUS_CXX_IOBJECT_H_ */
|
545
backup/include/sdbus-c++/IProxy.h
Normal file
545
backup/include/sdbus-c++/IProxy.h
Normal file
@ -0,0 +1,545 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IProxy.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_IPROXY_H_
|
||||
#define SDBUS_CXX_IPROXY_H_
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class MethodCall;
|
||||
class MethodReply;
|
||||
class IConnection;
|
||||
class PendingAsyncCall;
|
||||
namespace internal {
|
||||
class Proxy;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class IProxy
|
||||
*
|
||||
* IProxy class represents a proxy object, which is a convenient local object created
|
||||
* to represent a remote D-Bus object in another process.
|
||||
* The proxy enables calling methods on remote objects, receiving signals from remote
|
||||
* objects, and getting/setting properties of remote objects.
|
||||
*
|
||||
* All IProxy member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error.
|
||||
* The IProxy class has been designed as thread-aware. However, the operation of
|
||||
* creating and sending method calls (both synchronously and asynchronously) is
|
||||
* thread-safe by design.
|
||||
*
|
||||
***********************************************/
|
||||
class IProxy
|
||||
{
|
||||
public:
|
||||
virtual ~IProxy() = default;
|
||||
|
||||
/*!
|
||||
* @brief Creates a method call message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that provides a given method
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A method call message
|
||||
*
|
||||
* Serialize method arguments into the returned message and invoke the method by passing
|
||||
* the message with serialized arguments to the @c callMethod function.
|
||||
* Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return A method reply message
|
||||
*
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply, or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. Slim proxies created with `dont_run_event_loop_thread` tag are
|
||||
* designed for exactly that purpose.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
MethodReply callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout);
|
||||
|
||||
/*!
|
||||
* @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
|
||||
* @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 bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
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 proxied D-Bus object
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief 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
|
||||
*
|
||||
* The method physically subscribes to the desired signals.
|
||||
* Must be called only once, after all signals have been registered already.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void finishRegistration() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters proxy's signal handlers and stops receving replies to pending async calls
|
||||
*
|
||||
* Unregistration is done automatically also in proxy's destructor. This method makes
|
||||
* sense if, in the process of proxy removal, we need to make sure that callbacks
|
||||
* are unregistered explicitly before the final destruction of the proxy instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregister() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the proxied D-Bus object
|
||||
*
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A helper object for convenient invocation of the method
|
||||
*
|
||||
* This is a high-level, convenience way of calling D-Bus methods that abstracts
|
||||
* from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native arguments
|
||||
* and return values.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* int result, a = ..., b = ...;
|
||||
* object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] MethodInvoker callMethod(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @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
|
||||
*
|
||||
* This is a high-level, convenience way of calling D-Bus methods that abstracts
|
||||
* from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native arguments
|
||||
* and return values.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* int a = ..., b = ...;
|
||||
* object_.callMethodAsync("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result)
|
||||
* {
|
||||
* std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl;
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @brief Registers signal handler for a given signal of the proxied D-Bus object
|
||||
*
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A helper object for convenient registration of the signal handler
|
||||
*
|
||||
* This is a high-level, convenience way of registering to D-Bus signals that abstracts
|
||||
* from the D-Bus message concept. Signal arguments are automatically serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the parameters
|
||||
* of the provided native signal callback.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @brief Unregisters signal handler of a given signal of the proxied 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 proxied D-Bus object
|
||||
*
|
||||
* @param[in] propertyName Name of the property
|
||||
* @return A helper object for convenient getting of property value
|
||||
*
|
||||
* This is a high-level, convenience way of reading D-Bus property values that abstracts
|
||||
* from the D-Bus message concept. sdbus::Variant is returned which shall then be converted
|
||||
* to the real property type (implicit conversion is supported).
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* int state = object.getProperty("state").onInterface("com.kistler.foo");
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertyGetter getProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets value of a property of the proxied D-Bus object
|
||||
*
|
||||
* @param[in] propertyName Name of the property
|
||||
* @return A helper object for convenient setting of property value
|
||||
*
|
||||
* This is a high-level, convenience way of writing D-Bus property values that abstracts
|
||||
* from the D-Bus message concept.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* int state = ...;
|
||||
* object_.setProperty("state").onInterface("com.kistler.foo").toValue(state);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertySetter setProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @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;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class PendingAsyncCall
|
||||
*
|
||||
* PendingAsyncCall represents a simple handle type to cancel the delivery
|
||||
* of the asynchronous D-Bus call result to the application.
|
||||
*
|
||||
* The handle is lifetime-independent from the originating Proxy object.
|
||||
* It's safe to call its methods even after the Proxy has gone.
|
||||
*
|
||||
***********************************************/
|
||||
class PendingAsyncCall
|
||||
{
|
||||
public:
|
||||
PendingAsyncCall() = default;
|
||||
|
||||
/*!
|
||||
* @brief Cancels the delivery of the pending asynchronous call result
|
||||
*
|
||||
* This function effectively removes the callback handler registered to the
|
||||
* async D-Bus method call result delivery. Does nothing if the call was
|
||||
* completed already, or if the originating Proxy object has gone meanwhile.
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/*!
|
||||
* @brief Answers whether the asynchronous call is still pending
|
||||
*
|
||||
* @return True if the call is pending, false if the call has been fully completed
|
||||
*
|
||||
* Pending call in this context means a call whose results have not arrived, or
|
||||
* have arrived and are currently being processed by the callback handler.
|
||||
*/
|
||||
bool isPending() const;
|
||||
|
||||
private:
|
||||
friend internal::Proxy;
|
||||
PendingAsyncCall(std::weak_ptr<void> callData);
|
||||
|
||||
private:
|
||||
std::weak_ptr<void> callData_;
|
||||
};
|
||||
|
||||
// Out-of-line member definitions
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return callMethod(message, microsecs.count());
|
||||
}
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline PendingAsyncCall IProxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return callMethod(message, std::move(asyncReplyCallback), microsecs.count());
|
||||
}
|
||||
|
||||
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
|
||||
{
|
||||
return MethodInvoker(*this, methodName);
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker IProxy::callMethodAsync(const std::string& methodName)
|
||||
{
|
||||
return AsyncMethodInvoker(*this, methodName);
|
||||
}
|
||||
|
||||
inline SignalSubscriber IProxy::uponSignal(const std::string& signalName)
|
||||
{
|
||||
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 PropertySetter IProxy::setProperty(const std::string& propertyName)
|
||||
{
|
||||
return PropertySetter(*this, propertyName);
|
||||
}
|
||||
|
||||
// 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{};
|
||||
|
||||
/*!
|
||||
* @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 proxy object instance
|
||||
*
|
||||
* The provided connection will be used by the proxy to issue calls against the object,
|
||||
* and signals, if any, will be subscribed to on this connection. The caller still
|
||||
* remains the owner of the connection (the proxy just keeps a reference to it), and
|
||||
* 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.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( sdbus::IConnection& connection
|
||||
, 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,
|
||||
* and signals, if any, will be subscribed to on this connection. The Object proxy becomes
|
||||
* an exclusive owner of this 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.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
|
||||
, 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).
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @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, and will automatically start an event 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.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[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>
|
||||
|
||||
#endif /* SDBUS_CXX_IPROXY_H_ */
|
414
backup/include/sdbus-c++/Message.h
Normal file
414
backup/include/sdbus-c++/Message.h
Normal file
@ -0,0 +1,414 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message.h
|
||||
*
|
||||
* Created on: Nov 9, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_MESSAGE_H_
|
||||
#define SDBUS_CXX_MESSAGE_H_
|
||||
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class Variant;
|
||||
class ObjectPath;
|
||||
class Signature;
|
||||
template <typename... _ValueTypes> class Struct;
|
||||
class UnixFd;
|
||||
class MethodReply;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class Message
|
||||
*
|
||||
* Message represents a D-Bus message, which can be either method call message,
|
||||
* method reply message, signal message, or a plain message.
|
||||
*
|
||||
* Serialization and deserialization functions are provided for types supported
|
||||
* by D-Bus.
|
||||
*
|
||||
* You don't need to work with this class directly if you use high-level APIs
|
||||
* of @c IObject and @c IProxy.
|
||||
*
|
||||
***********************************************/
|
||||
class [[nodiscard]] Message
|
||||
{
|
||||
public:
|
||||
Message& operator<<(bool item);
|
||||
Message& operator<<(int16_t item);
|
||||
Message& operator<<(int32_t item);
|
||||
Message& operator<<(int64_t item);
|
||||
Message& operator<<(uint8_t item);
|
||||
Message& operator<<(uint16_t item);
|
||||
Message& operator<<(uint32_t item);
|
||||
Message& operator<<(uint64_t item);
|
||||
Message& operator<<(double item);
|
||||
Message& operator<<(const char *item);
|
||||
Message& operator<<(const std::string &item);
|
||||
Message& operator<<(const Variant &item);
|
||||
Message& operator<<(const ObjectPath &item);
|
||||
Message& operator<<(const Signature &item);
|
||||
Message& operator<<(const UnixFd &item);
|
||||
|
||||
Message& operator>>(bool& item);
|
||||
Message& operator>>(int16_t& item);
|
||||
Message& operator>>(int32_t& item);
|
||||
Message& operator>>(int64_t& item);
|
||||
Message& operator>>(uint8_t& item);
|
||||
Message& operator>>(uint16_t& item);
|
||||
Message& operator>>(uint32_t& item);
|
||||
Message& operator>>(uint64_t& item);
|
||||
Message& operator>>(double& item);
|
||||
Message& operator>>(char*& item);
|
||||
Message& operator>>(std::string &item);
|
||||
Message& operator>>(Variant &item);
|
||||
Message& operator>>(ObjectPath &item);
|
||||
Message& operator>>(Signature &item);
|
||||
Message& operator>>(UnixFd &item);
|
||||
|
||||
Message& openContainer(const std::string& signature);
|
||||
Message& closeContainer();
|
||||
Message& openDictEntry(const std::string& signature);
|
||||
Message& closeDictEntry();
|
||||
Message& openVariant(const std::string& signature);
|
||||
Message& closeVariant();
|
||||
Message& openStruct(const std::string& signature);
|
||||
Message& closeStruct();
|
||||
|
||||
Message& enterContainer(const std::string& signature);
|
||||
Message& exitContainer();
|
||||
Message& enterDictEntry(const std::string& signature);
|
||||
Message& exitDictEntry();
|
||||
Message& enterVariant(const std::string& signature);
|
||||
Message& exitVariant();
|
||||
Message& enterStruct(const std::string& signature);
|
||||
Message& exitStruct();
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
Message() = default;
|
||||
explicit Message(internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
Message(const Message&) noexcept;
|
||||
Message& operator=(const Message&) noexcept;
|
||||
Message(Message&& other) noexcept;
|
||||
Message& operator=(Message&& other) noexcept;
|
||||
|
||||
~Message();
|
||||
|
||||
friend Factory;
|
||||
|
||||
protected:
|
||||
void* msg_{};
|
||||
internal::ISdBus* sdbus_{};
|
||||
mutable bool ok_{true};
|
||||
};
|
||||
|
||||
class MethodCall : public Message
|
||||
{
|
||||
using Message::Message;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
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;
|
||||
[[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const;
|
||||
|
||||
MethodReply createReply() const;
|
||||
MethodReply createErrorReply(const sdbus::Error& error) const;
|
||||
|
||||
void dontExpectReply();
|
||||
bool doesntExpectReply() const;
|
||||
|
||||
protected:
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
private:
|
||||
MethodReply sendWithReply(uint64_t timeout = 0) const;
|
||||
MethodReply sendWithNoReply() const;
|
||||
};
|
||||
|
||||
class MethodReply : public Message
|
||||
{
|
||||
using Message::Message;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
MethodReply() = default;
|
||||
void send() const;
|
||||
};
|
||||
|
||||
class Signal : public Message
|
||||
{
|
||||
using Message::Message;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
Signal() = default;
|
||||
void setDestination(const std::string& destination);
|
||||
void send() const;
|
||||
};
|
||||
|
||||
class PropertySetCall : public Message
|
||||
{
|
||||
using Message::Message;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
PropertySetCall() = default;
|
||||
};
|
||||
|
||||
class PropertyGetReply : public Message
|
||||
{
|
||||
using Message::Message;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
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;
|
||||
friend Factory;
|
||||
|
||||
public:
|
||||
PlainMessage() = default;
|
||||
};
|
||||
|
||||
template <typename _Element>
|
||||
inline Message& operator<<(Message& msg, const std::vector<_Element>& items)
|
||||
{
|
||||
msg.openContainer(signature_of<_Element>::str());
|
||||
|
||||
for (const auto& item : items)
|
||||
msg << item;
|
||||
|
||||
msg.closeContainer();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value>
|
||||
inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items)
|
||||
{
|
||||
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
msg.openContainer(arraySignature);
|
||||
|
||||
for (const auto& item : items)
|
||||
{
|
||||
msg.openDictEntry(dictEntrySignature);
|
||||
msg << item.first;
|
||||
msg << item.second;
|
||||
msg.closeDictEntry();
|
||||
}
|
||||
|
||||
msg.closeContainer();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... _Args>
|
||||
void serialize_pack(Message& msg, _Args&&... args)
|
||||
{
|
||||
(void)(msg << ... << args);
|
||||
}
|
||||
|
||||
template <class _Tuple, std::size_t... _Is>
|
||||
void serialize_tuple( Message& msg
|
||||
, const _Tuple& t
|
||||
, std::index_sequence<_Is...>)
|
||||
{
|
||||
serialize_pack(msg, std::get<_Is>(t)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
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);
|
||||
|
||||
msg.openStruct(structContentSignature);
|
||||
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
msg.closeStruct();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item)
|
||||
{
|
||||
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
template <typename _Element>
|
||||
inline Message& operator>>(Message& msg, std::vector<_Element>& items)
|
||||
{
|
||||
if(!msg.enterContainer(signature_of<_Element>::str()))
|
||||
return msg;
|
||||
|
||||
while (true)
|
||||
{
|
||||
_Element elem;
|
||||
if (msg >> elem)
|
||||
items.emplace_back(std::move(elem));
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
msg.clearFlags();
|
||||
|
||||
msg.exitContainer();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value>
|
||||
inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items)
|
||||
{
|
||||
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
if (!msg.enterContainer(arraySignature))
|
||||
return msg;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!msg.enterDictEntry(dictEntrySignature))
|
||||
break;
|
||||
|
||||
_Key key;
|
||||
_Value value;
|
||||
msg >> key >> value;
|
||||
|
||||
items.emplace(std::move(key), std::move(value));
|
||||
|
||||
msg.exitDictEntry();
|
||||
}
|
||||
|
||||
msg.clearFlags();
|
||||
|
||||
msg.exitContainer();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... _Args>
|
||||
void deserialize_pack(Message& msg, _Args&... args)
|
||||
{
|
||||
(void)(msg >> ... >> args);
|
||||
}
|
||||
|
||||
template <class _Tuple, std::size_t... _Is>
|
||||
void deserialize_tuple( Message& msg
|
||||
, _Tuple& t
|
||||
, std::index_sequence<_Is...> )
|
||||
{
|
||||
deserialize_pack(msg, std::get<_Is>(t)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
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 (!msg.enterStruct(structContentSignature))
|
||||
return msg;
|
||||
|
||||
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
|
||||
msg.exitStruct();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item)
|
||||
{
|
||||
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_MESSAGE_H_ */
|
92
backup/include/sdbus-c++/MethodResult.h
Normal file
92
backup/include/sdbus-c++/MethodResult.h
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file MethodResult.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_METHODRESULT_H_
|
||||
#define SDBUS_CXX_METHODRESULT_H_
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <cassert>
|
||||
|
||||
// Forward declaration
|
||||
namespace sdbus {
|
||||
class Error;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class Result
|
||||
*
|
||||
* Represents result of an asynchronous server-side method.
|
||||
* An instance is provided to the method and shall be set
|
||||
* by the method to either method return value or an error.
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _Results>
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
Result() = default;
|
||||
Result(MethodCall call);
|
||||
|
||||
Result(const Result&) = delete;
|
||||
Result& operator=(const Result&) = delete;
|
||||
|
||||
Result(Result&& other) = default;
|
||||
Result& operator=(Result&& other) = default;
|
||||
|
||||
void returnResults(const _Results&... results) const;
|
||||
void returnError(const Error& error) const;
|
||||
|
||||
private:
|
||||
MethodCall call_;
|
||||
};
|
||||
|
||||
template <typename... _Results>
|
||||
inline Result<_Results...>::Result(MethodCall call)
|
||||
: call_(std::move(call))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnResults(const _Results&... results) const
|
||||
{
|
||||
assert(call_.isValid());
|
||||
auto reply = call_.createReply();
|
||||
(reply << ... << results);
|
||||
reply.send();
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnError(const Error& error) const
|
||||
{
|
||||
auto reply = call_.createErrorReply(error);
|
||||
reply.send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_METHODRESULT_H_ */
|
219
backup/include/sdbus-c++/ProxyInterfaces.h
Normal file
219
backup/include/sdbus-c++/ProxyInterfaces.h
Normal file
@ -0,0 +1,219 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ProxyInterfaces.h
|
||||
*
|
||||
* Created on: Apr 8, 2019
|
||||
* 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_PROXYINTERFACES_H_
|
||||
#define SDBUS_CXX_PROXYINTERFACES_H_
|
||||
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class IConnection;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class ProxyObjectHolder
|
||||
*
|
||||
* ProxyObjectHolder is a helper that simply owns and provides
|
||||
* access to a proxy object to other classes in the inheritance
|
||||
* hierarchy of a native-like proxy object based on generated
|
||||
* interface classes.
|
||||
*
|
||||
***********************************************/
|
||||
class ProxyObjectHolder
|
||||
{
|
||||
protected:
|
||||
ProxyObjectHolder(std::unique_ptr<IProxy>&& proxy)
|
||||
: proxy_(std::move(proxy))
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
}
|
||||
|
||||
const IProxy& getProxy() const
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
return *proxy_;
|
||||
}
|
||||
|
||||
IProxy& getProxy()
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
return *proxy_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<IProxy> proxy_;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class ProxyInterfaces
|
||||
*
|
||||
* ProxyInterfaces is a helper template class that joins all interface classes of a remote
|
||||
* D-Bus object generated by sdbus-c++-xml2cpp to be used on the client (the proxy) side,
|
||||
* including some auxiliary classes. ProxyInterfaces is the class that native-like proxy
|
||||
* implementation classes written by users should inherit from and implement all pure virtual
|
||||
* methods. So the _Interfaces template parameter is a list of sdbus-c++-xml2cpp-generated
|
||||
* proxy-side interface classes representing interfaces of the corresponding remote D-Bus object.
|
||||
*
|
||||
* In the final proxy class inherited from ProxyInterfaces, it is necessary to finish proxy
|
||||
* registration in class constructor (`finishRegistration();`), and, conversely, unregister
|
||||
* the proxy in class destructor (`unregister();`).
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _Interfaces>
|
||||
class ProxyInterfaces
|
||||
: protected ProxyObjectHolder
|
||||
, public _Interfaces...
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* @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)
|
||||
*/
|
||||
ProxyInterfaces(std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @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
|
||||
*
|
||||
* @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 just references a D-Bus connection owned and managed by the user.
|
||||
* For more information on its behavior, consult @ref createProxy(IConnection&,std::string,std::string)
|
||||
*/
|
||||
ProxyInterfaces(IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(connection, std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @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)
|
||||
*/
|
||||
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @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
|
||||
*
|
||||
* This function must be called in the constructor of the final proxy class that implements ProxyInterfaces.
|
||||
*
|
||||
* For more information, see underlying @ref IProxy::finishRegistration()
|
||||
*/
|
||||
void registerProxy()
|
||||
{
|
||||
getProxy().finishRegistration();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Unregisters the proxy so it no more receives signals and async call replies
|
||||
*
|
||||
* This function must be called in the destructor of the final proxy class that implements ProxyInterfaces.
|
||||
*
|
||||
* See underlying @ref IProxy::unregister()
|
||||
*/
|
||||
void unregisterProxy()
|
||||
{
|
||||
getProxy().unregister();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
*/
|
||||
const std::string& getObjectPath() const
|
||||
{
|
||||
return getProxy().getObjectPath();
|
||||
}
|
||||
|
||||
protected:
|
||||
using base_type = ProxyInterfaces;
|
||||
|
||||
ProxyInterfaces(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces(ProxyInterfaces&&) = default;
|
||||
ProxyInterfaces& operator=(ProxyInterfaces&&) = default;
|
||||
~ProxyInterfaces() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERFACES_H_ */
|
350
backup/include/sdbus-c++/StandardInterfaces.h
Normal file
350
backup/include/sdbus-c++/StandardInterfaces.h
Normal file
@ -0,0 +1,350 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file StandardInterfaces.h
|
||||
*
|
||||
* Created on: Dec 13, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_STANDARDINTERFACES_H_
|
||||
#define SDBUS_CXX_STANDARDINTERFACES_H_
|
||||
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
// Proxy for peer
|
||||
class Peer_proxy
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Peer";
|
||||
|
||||
protected:
|
||||
Peer_proxy(sdbus::IProxy& 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);
|
||||
}
|
||||
|
||||
std::string GetMachineId()
|
||||
{
|
||||
std::string machineUUID;
|
||||
proxy_->callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
|
||||
return machineUUID;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for introspection
|
||||
class Introspectable_proxy
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
|
||||
|
||||
protected:
|
||||
Introspectable_proxy(sdbus::IProxy& 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);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for properties
|
||||
class Properties_proxy
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
Properties_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_
|
||||
->uponSignal("PropertiesChanged")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties )
|
||||
{
|
||||
this->onPropertiesChanged(interfaceName, changedProperties, invalidatedProperties);
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties ) = 0;
|
||||
|
||||
public:
|
||||
sdbus::Variant Get(const std::string& interfaceName, const std::string& propertyName)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> GetAll(const std::string& interfaceName)
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> props;
|
||||
proxy_->callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
|
||||
return props;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for object manager
|
||||
class ObjectManager_proxy
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
|
||||
protected:
|
||||
ObjectManager_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_
|
||||
->uponSignal("InterfacesAdded")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
{
|
||||
this->onInterfacesAdded(objectPath, interfacesAndProperties);
|
||||
});
|
||||
|
||||
proxy_->uponSignal("InterfacesRemoved")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
this->onInterfacesRemoved(objectPath, interfaces);
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) = 0;
|
||||
virtual void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
public:
|
||||
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);
|
||||
return objectsInterfacesAndProperties;
|
||||
}
|
||||
|
||||
private:
|
||||
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.
|
||||
|
||||
// Adaptor for properties
|
||||
class Properties_adaptor
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
Properties_adaptor(sdbus::IObject& 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);
|
||||
}
|
||||
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName)
|
||||
{
|
||||
object_->emitPropertiesChangedSignal(interfaceName);
|
||||
}
|
||||
|
||||
private:
|
||||
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.
|
||||
*/
|
||||
class ObjectManager_adaptor
|
||||
{
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesAdded signal for this object path
|
||||
*
|
||||
* See IObject::emitInterfacesAddedSignal().
|
||||
*/
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
object_->emitInterfacesAddedSignal(interfaces);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesRemoved signal for this object path
|
||||
*
|
||||
* See IObject::emitInterfacesRemovedSignal().
|
||||
*/
|
||||
void 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);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_STANDARDINTERFACES_H_ */
|
610
backup/include/sdbus-c++/TypeTraits.h
Normal file
610
backup/include/sdbus-c++/TypeTraits.h
Normal file
@ -0,0 +1,610 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TypeTraits.h
|
||||
*
|
||||
* Created on: Nov 9, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_TYPETRAITS_H_
|
||||
#define SDBUS_CXX_TYPETRAITS_H_
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class Variant;
|
||||
template <typename... _ValueTypes> class Struct;
|
||||
class ObjectPath;
|
||||
class Signature;
|
||||
class UnixFd;
|
||||
class MethodCall;
|
||||
class MethodReply;
|
||||
class Signal;
|
||||
class Message;
|
||||
class PropertySetCall;
|
||||
class PropertyGetReply;
|
||||
template <typename... _Results> class Result;
|
||||
class Error;
|
||||
}
|
||||
|
||||
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{};
|
||||
|
||||
// Template specializations for getting D-Bus signatures from C++ types
|
||||
template <typename _T>
|
||||
struct signature_of
|
||||
{
|
||||
static constexpr bool is_valid = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
// sizeof(_T) < 0 is here to make compiler not being able to figure out
|
||||
// the assertion expression before the template instantiation takes place.
|
||||
static_assert(sizeof(_T) < 0, "Unknown DBus type");
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<void>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<bool>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "b";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint8_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "y";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int16_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "n";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint16_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "q";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int32_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "i";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint32_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "u";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int64_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "x";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint64_t>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "t";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<double>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "d";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<char*>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<const char*>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<char[_N]>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<const char[_N]>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<std::string>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
struct signature_of<Struct<_ValueTypes...>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
std::string signature;
|
||||
signature += "(";
|
||||
(signature += ... += signature_of<_ValueTypes>::str());
|
||||
signature += ")";
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<Variant>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "v";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<ObjectPath>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "o";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<Signature>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "g";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<UnixFd>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "h";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Element>
|
||||
struct signature_of<std::vector<_Element>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a" + signature_of<_Element>::str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Key, typename _Value>
|
||||
struct signature_of<std::map<_Key, _Value>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Function traits implementation inspired by (c) kennytm,
|
||||
// https://github.com/kennytm/utils/blob/master/traits.hpp
|
||||
template <typename _Type>
|
||||
struct function_traits
|
||||
: public function_traits<decltype(&_Type::operator())>
|
||||
{};
|
||||
|
||||
template <typename _Type>
|
||||
struct function_traits<const _Type>
|
||||
: public function_traits<_Type>
|
||||
{};
|
||||
|
||||
template <typename _Type>
|
||||
struct function_traits<_Type&>
|
||||
: public function_traits<_Type>
|
||||
{};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits_base
|
||||
{
|
||||
typedef _ReturnType result_type;
|
||||
typedef std::tuple<_Args...> arguments_type;
|
||||
typedef std::tuple<std::decay_t<_Args>...> decayed_arguments_type;
|
||||
|
||||
typedef _ReturnType function_type(_Args...);
|
||||
|
||||
static constexpr std::size_t arity = sizeof...(_Args);
|
||||
|
||||
// template <size_t _Idx, typename _Enabled = void>
|
||||
// struct arg;
|
||||
//
|
||||
// template <size_t _Idx>
|
||||
// struct arg<_Idx, std::enable_if_t<(_Idx < arity)>>
|
||||
// {
|
||||
// typedef std::tuple_element_t<_Idx, arguments_type> type;
|
||||
// };
|
||||
//
|
||||
// template <size_t _Idx>
|
||||
// struct arg<_Idx, std::enable_if_t<!(_Idx < arity)>>
|
||||
// {
|
||||
// typedef void type;
|
||||
// };
|
||||
|
||||
template <size_t _Idx>
|
||||
struct arg
|
||||
{
|
||||
typedef std::tuple_element_t<_Idx, std::tuple<_Args...>> type;
|
||||
};
|
||||
|
||||
template <size_t _Idx>
|
||||
using arg_t = typename arg<_Idx>::type;
|
||||
};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_Args...)>
|
||||
: 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>
|
||||
struct function_traits<void(Result<_Results...>, _Args...)>
|
||||
: public function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = true;
|
||||
using async_result_t = Result<_Results...>;
|
||||
};
|
||||
|
||||
template <typename... _Args, typename... _Results>
|
||||
struct function_traits<void(Result<_Results...>&&, _Args...)>
|
||||
: public function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = true;
|
||||
using async_result_t = Result<_Results...>;
|
||||
};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(*)(_Args...)>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
{};
|
||||
|
||||
template <typename _ClassType, typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...)>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
{
|
||||
typedef _ClassType& owner_type;
|
||||
};
|
||||
|
||||
template <typename _ClassType, typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
{
|
||||
typedef const _ClassType& owner_type;
|
||||
};
|
||||
|
||||
template <typename _ClassType, typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
{
|
||||
typedef volatile _ClassType& owner_type;
|
||||
};
|
||||
|
||||
template <typename _ClassType, typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
{
|
||||
typedef const volatile _ClassType& owner_type;
|
||||
};
|
||||
|
||||
template <typename FunctionType>
|
||||
struct function_traits<std::function<FunctionType>>
|
||||
: public function_traits<FunctionType>
|
||||
{};
|
||||
|
||||
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;
|
||||
|
||||
template <typename _FunctionType, size_t _Idx>
|
||||
using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>;
|
||||
|
||||
template <typename _FunctionType>
|
||||
constexpr auto function_argument_count_v = function_traits<_FunctionType>::arity;
|
||||
|
||||
template <typename _FunctionType>
|
||||
using function_result_t = typename function_traits<_FunctionType>::result_type;
|
||||
|
||||
template <typename _Function>
|
||||
struct tuple_of_function_input_arg_types
|
||||
{
|
||||
typedef typename function_traits<_Function>::decayed_arguments_type type;
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<_Function>::type;
|
||||
|
||||
template <typename _Function>
|
||||
struct tuple_of_function_output_arg_types
|
||||
{
|
||||
typedef typename function_traits<_Function>::result_type type;
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type;
|
||||
|
||||
template <typename _Type>
|
||||
struct aggregate_signature
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
return signature_of<std::decay_t<_Type>>::str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... _Types>
|
||||
struct aggregate_signature<std::tuple<_Types...>>
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
std::string signature;
|
||||
(void)(signature += ... += signature_of<std::decay_t<_Types>>::str());
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
struct signature_of_function_input_arguments
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
return aggregate_signature<tuple_of_function_input_arg_types_t<_Function>>::str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
struct signature_of_function_output_arguments
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
return aggregate_signature<tuple_of_function_output_arg_types_t<_Function>>::str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
||||
constexpr decltype(auto) apply_impl( _Function&& f
|
||||
, Result<_Args...>&& r
|
||||
, _Tuple&& t
|
||||
, std::index_sequence<_I...> )
|
||||
{
|
||||
return std::forward<_Function>(f)(std::move(r), std::get<_I>(std::forward<_Tuple>(t))...);
|
||||
}
|
||||
|
||||
template <class _Function, class _Tuple, std::size_t... _I>
|
||||
constexpr decltype(auto) apply_impl( _Function&& f
|
||||
, const Error* e
|
||||
, _Tuple&& t
|
||||
, std::index_sequence<_I...> )
|
||||
{
|
||||
return std::forward<_Function>(f)(e, std::get<_I>(std::forward<_Tuple>(t))...);
|
||||
}
|
||||
|
||||
// For non-void returning functions, apply_impl simply returns function return value (a tuple of values).
|
||||
// For void-returning functions, apply_impl returns an empty tuple.
|
||||
template <class _Function, class _Tuple, std::size_t... _I>
|
||||
constexpr decltype(auto) apply_impl( _Function&& f
|
||||
, _Tuple&& t
|
||||
, std::index_sequence<_I...> )
|
||||
{
|
||||
if constexpr (!std::is_void_v<function_result_t<_Function>>)
|
||||
return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...);
|
||||
else
|
||||
return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...), std::tuple<>{};
|
||||
}
|
||||
}
|
||||
|
||||
// Convert tuple `t' of values into a list of arguments
|
||||
// and invoke function `f' with those arguments.
|
||||
template <class _Function, class _Tuple>
|
||||
constexpr decltype(auto) apply(_Function&& f, _Tuple&& t)
|
||||
{
|
||||
return detail::apply_impl( std::forward<_Function>(f)
|
||||
, std::forward<_Tuple>(t)
|
||||
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
|
||||
}
|
||||
|
||||
// Convert tuple `t' of values into a list of arguments
|
||||
// and invoke function `f' with those arguments.
|
||||
template <class _Function, class _Tuple, typename... _Args>
|
||||
constexpr decltype(auto) apply(_Function&& f, Result<_Args...>&& r, _Tuple&& t)
|
||||
{
|
||||
return detail::apply_impl( std::forward<_Function>(f)
|
||||
, std::move(r)
|
||||
, std::forward<_Tuple>(t)
|
||||
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
|
||||
}
|
||||
|
||||
// Convert tuple `t' of values into a list of arguments
|
||||
// and invoke function `f' with those arguments.
|
||||
template <class _Function, class _Tuple>
|
||||
constexpr decltype(auto) apply(_Function&& f, const Error* e, _Tuple&& t)
|
||||
{
|
||||
return detail::apply_impl( std::forward<_Function>(f)
|
||||
, e
|
||||
, std::forward<_Tuple>(t)
|
||||
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_TYPETRAITS_H_ */
|
283
backup/include/sdbus-c++/Types.h
Normal file
283
backup/include/sdbus-c++/Types.h
Normal file
@ -0,0 +1,283 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types.h
|
||||
*
|
||||
* Created on: Nov 23, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_TYPES_H_
|
||||
#define SDBUS_CXX_TYPES_H_
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
* @class Variant
|
||||
*
|
||||
* Variant can hold value of any D-Bus-supported type.
|
||||
*
|
||||
* Note: Even though thread-aware, Variant objects are not thread-safe.
|
||||
* Some const methods are conceptually const, but not physically const,
|
||||
* thus are not thread-safe. This is by design: normally, clients
|
||||
* should process a single Variant object in a single thread at a time.
|
||||
* Otherwise they need to take care of synchronization by themselves.
|
||||
*
|
||||
***********************************************/
|
||||
class Variant
|
||||
{
|
||||
public:
|
||||
Variant();
|
||||
|
||||
template <typename _ValueType>
|
||||
Variant(const _ValueType& value)
|
||||
: Variant()
|
||||
{
|
||||
msg_.openVariant(signature_of<_ValueType>::str());
|
||||
msg_ << value;
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename _ValueType>
|
||||
_ValueType get() const
|
||||
{
|
||||
_ValueType val;
|
||||
msg_.rewind(false);
|
||||
msg_.enterVariant(signature_of<_ValueType>::str());
|
||||
msg_ >> val;
|
||||
msg_.exitVariant();
|
||||
return val;
|
||||
}
|
||||
|
||||
// Only allow conversion operator for true D-Bus type representations in C++
|
||||
template <typename _ValueType, typename = std::enable_if_t<signature_of<_ValueType>::is_valid>>
|
||||
operator _ValueType() const
|
||||
{
|
||||
return get<_ValueType>();
|
||||
}
|
||||
|
||||
template <typename _Type>
|
||||
bool containsValueOfType() const
|
||||
{
|
||||
return signature_of<_Type>::str() == peekValueType();
|
||||
}
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
void serializeTo(Message& msg) const;
|
||||
void deserializeFrom(Message& msg);
|
||||
std::string peekValueType() const;
|
||||
|
||||
private:
|
||||
mutable PlainMessage msg_{};
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class Struct
|
||||
*
|
||||
* Representation of struct D-Bus type
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _ValueTypes>
|
||||
class Struct
|
||||
: public std::tuple<_ValueTypes...>
|
||||
{
|
||||
public:
|
||||
using std::tuple<_ValueTypes...>::tuple;
|
||||
|
||||
// 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;
|
||||
|
||||
explicit Struct(const std::tuple<_ValueTypes...>& t)
|
||||
: std::tuple<_ValueTypes...>(t)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
template <std::size_t _I>
|
||||
auto& get()
|
||||
{
|
||||
return std::get<_I>(*this);
|
||||
}
|
||||
|
||||
template <std::size_t _I>
|
||||
const auto& get() const
|
||||
{
|
||||
return std::get<_I>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... _Elements>
|
||||
constexpr Struct<std::decay_t<_Elements>...>
|
||||
make_struct(_Elements&&... args)
|
||||
{
|
||||
typedef Struct<std::decay_t<_Elements>...> result_type;
|
||||
return result_type(std::forward<_Elements>(args)...);
|
||||
}
|
||||
|
||||
/********************************************//**
|
||||
* @class ObjectPath
|
||||
*
|
||||
* Representation of object path D-Bus type
|
||||
*
|
||||
***********************************************/
|
||||
class ObjectPath : public std::string
|
||||
{
|
||||
public:
|
||||
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))
|
||||
{}
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class Signature
|
||||
*
|
||||
* Representation of Signature D-Bus type
|
||||
*
|
||||
***********************************************/
|
||||
class Signature : public std::string
|
||||
{
|
||||
public:
|
||||
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 UnixFd
|
||||
*
|
||||
* UnixFd is a representation of file descriptor D-Bus type that owns
|
||||
* the underlying fd, provides access to it, and closes the fd when
|
||||
* the UnixFd goes out of scope.
|
||||
*
|
||||
* UnixFd can be default constructed (owning invalid fd), or constructed from
|
||||
* an explicitly provided fd by either duplicating or adopting that fd as-is.
|
||||
*
|
||||
***********************************************/
|
||||
class UnixFd
|
||||
{
|
||||
public:
|
||||
UnixFd() = default;
|
||||
|
||||
explicit UnixFd(int fd)
|
||||
: fd_(::dup(fd))
|
||||
{
|
||||
}
|
||||
|
||||
UnixFd(int fd, adopt_fd_t)
|
||||
: fd_(fd)
|
||||
{
|
||||
}
|
||||
|
||||
UnixFd(const UnixFd& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
UnixFd& operator=(const UnixFd& other)
|
||||
{
|
||||
close();
|
||||
fd_ = ::dup(other.fd_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnixFd(UnixFd&& other)
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
UnixFd& operator=(UnixFd&& other)
|
||||
{
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~UnixFd()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
int get() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
|
||||
void reset(int fd = -1)
|
||||
{
|
||||
*this = UnixFd{fd};
|
||||
}
|
||||
|
||||
void reset(int fd, adopt_fd_t)
|
||||
{
|
||||
*this = UnixFd{fd, adopt_fd};
|
||||
}
|
||||
|
||||
int release()
|
||||
{
|
||||
auto fd = fd_;
|
||||
fd_ = -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return fd_ >= 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void close()
|
||||
{
|
||||
if (fd_ >= 0)
|
||||
::close(fd_);
|
||||
}
|
||||
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_TYPES_H_ */
|
38
backup/include/sdbus-c++/sdbus-c++.h
Normal file
38
backup/include/sdbus-c++/sdbus-c++.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file sdbus-c++.h
|
||||
*
|
||||
* Created on: Jan 19, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/AdaptorInterfaces.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/StandardInterfaces.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/Flags.h>
|
843
backup/src/Connection.cpp
Normal file
843
backup/src/Connection.cpp
Normal file
@ -0,0 +1,843 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection.cpp
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory)
|
||||
: sdbus_(std::move(interface))
|
||||
, bus_(openBus(busFactory))
|
||||
{
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, default_bus_t)
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return sdbus_->sd_bus_open(bus); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, system_bus_t)
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return sdbus_->sd_bus_open_system(bus); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, session_bus_t)
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return sdbus_->sd_bus_open_user(bus); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, custom_session_bus_t, const std::string& address)
|
||||
: Connection(std::move(interface), [&](sd_bus** bus) { return sdbus_->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 sdbus_->sd_bus_open_system_remote(bus, host.c_str()); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
|
||||
: sdbus_(std::move(interface))
|
||||
, bus_(openPseudoBus())
|
||||
{
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
Connection::leaveEventLoop();
|
||||
}
|
||||
|
||||
void Connection::requestName(const std::string& name)
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(name);
|
||||
|
||||
auto r = sdbus_->sd_bus_request_name(bus_.get(), name.c_str(), 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
|
||||
}
|
||||
|
||||
void Connection::releaseName(const std::string& name)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_release_name(bus_.get(), name.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
|
||||
}
|
||||
|
||||
std::string Connection::getUniqueName() const
|
||||
{
|
||||
const char* unique = nullptr;
|
||||
auto r = sdbus_->sd_bus_get_unique_name(bus_.get(), &unique);
|
||||
SDBUS_THROW_ERROR_IF(r < 0 || unique == nullptr, "Failed to get unique bus name", -r);
|
||||
return unique;
|
||||
}
|
||||
|
||||
void Connection::enterEventLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Process one pending event
|
||||
(void)processPendingEvent();
|
||||
|
||||
// And go to poll(), which wakes us up right away
|
||||
// if there's another pending event, or sleeps otherwise.
|
||||
auto success = waitForNextEvent();
|
||||
if (!success)
|
||||
break; // Exit I/O event loop
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::enterEventLoopAsync()
|
||||
{
|
||||
if (!asyncLoopThread_.joinable())
|
||||
asyncLoopThread_ = std::thread([this](){ enterEventLoop(); });
|
||||
}
|
||||
|
||||
void Connection::leaveEventLoop()
|
||||
{
|
||||
notifyEventLoopToExit();
|
||||
joinWithEventLoop();
|
||||
}
|
||||
|
||||
Connection::PollData Connection::getEventLoopPollData() const
|
||||
{
|
||||
ISdBus::PollData pollData{};
|
||||
auto r = sdbus_->sd_bus_get_poll_data(bus_.get(), &pollData);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
|
||||
|
||||
assert(eventFd_.fd >= 0);
|
||||
|
||||
auto timeout = pollData.timeout_usec == UINT64_MAX ? std::chrono::microseconds::max() : std::chrono::microseconds(pollData.timeout_usec);
|
||||
|
||||
return {pollData.fd, pollData.events, timeout, eventFd_.fd};
|
||||
}
|
||||
|
||||
const ISdBus& Connection::getSdBusInterface() const
|
||||
{
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
ISdBus& Connection::getSdBusInterface()
|
||||
{
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
void Connection::addObjectManager(const std::string& objectPath)
|
||||
{
|
||||
Connection::addObjectManager(objectPath, floating_slot);
|
||||
}
|
||||
|
||||
void Connection::addObjectManager(const std::string& objectPath, floating_slot_t)
|
||||
{
|
||||
auto r = sdbus_->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)
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = sdbus_->sd_bus_add_object_manager(bus_.get(), &slot, objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
|
||||
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
void Connection::setMethodCallTimeout(uint64_t timeout)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_set_method_call_timeout(bus_.get(), timeout);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set method call timeout", -r);
|
||||
}
|
||||
|
||||
uint64_t Connection::getMethodCallTimeout() const
|
||||
{
|
||||
uint64_t timeout;
|
||||
|
||||
auto r = sdbus_->sd_bus_get_method_call_timeout(bus_.get(), &timeout);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get method call timeout", -r);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
Slot Connection::addMatch(const std::string& match, message_handler callback)
|
||||
{
|
||||
auto matchInfo = std::make_unique<MatchInfo>(MatchInfo{std::move(callback), *this, {}});
|
||||
|
||||
auto messageHandler = [](sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/) -> int
|
||||
{
|
||||
auto* matchInfo = static_cast<MatchInfo*>(userData);
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection.getSdBusInterface());
|
||||
matchInfo->callback(message);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto r = sdbus_->sd_bus_add_match(bus_.get(), &matchInfo->slot, match.c_str(), std::move(messageHandler), 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);
|
||||
sdbus_->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)));
|
||||
}
|
||||
|
||||
void Connection::attachSdEventLoop(sd_event *event, int priority)
|
||||
{
|
||||
// Get default event if no event is provided by the caller
|
||||
if (event != nullptr)
|
||||
event = sd_event_ref(event);
|
||||
else
|
||||
(void)sd_event_default(&event);
|
||||
SDBUS_THROW_ERROR_IF(!event, "Invalid sd_event handle", EINVAL);
|
||||
Slot sdEvent{event, [](void* event){ sd_event_unref((sd_event*)event); }};
|
||||
// TODO: auto sdEvent = createSdEventSlot(...);
|
||||
|
||||
sd_event_source *timeEventSource{};
|
||||
auto r = sd_event_add_time(event, &timeEventSource, CLOCK_MONOTONIC, 0, 0, onSdTimerEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add timer event", -r);
|
||||
Slot sdTimeEventSource{timeEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
r = sd_event_source_set_priority(timeEventSource, priority); // TODO maybe use custom EventSourceSlot with custom type? Then we can use slot.get() here
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event priority", -r);
|
||||
|
||||
r = sd_event_source_set_description(timeEventSource, "bus-time");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event description", -r);
|
||||
// TODO: auto sdTimeEventSource = createSdTimeEventSourceSlot(...);
|
||||
|
||||
auto pollData = getEventLoopPollData();
|
||||
|
||||
sd_event_source *ioEventSource{};
|
||||
r = sd_event_add_io(event, &ioEventSource, pollData.fd, 0, onSdIoEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add io event", -r);
|
||||
Slot sdIoEventSource{ioEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
r = sd_event_source_set_prepare(ioEventSource, onSdEventPrepare);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for IO event", -r);
|
||||
|
||||
r = sd_event_source_set_priority(ioEventSource, priority);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
|
||||
r = sd_event_source_set_description(ioEventSource, "bus-input");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
// TODO: auto sdIoEventSource = createSdIoEventSourceSlot(...);
|
||||
|
||||
sd_event_source *internalEventSource{};
|
||||
r = sd_event_add_io(event, &internalEventSource, pollData.eventFd, 0, onSdInternalEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add internal event", -r);
|
||||
Slot sdInternalEventSource{internalEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
// sd-event loop calls prepare callbacks for all event sources, not just for the one that fired now.
|
||||
// So since onSdEventPrepare is already registered on ioEventSource, we don't need to duplicate it here.
|
||||
//r = sd_event_source_set_prepare(internalEventSource, onSdEventPrepare);
|
||||
//SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for internal event", -r);
|
||||
|
||||
r = sd_event_source_set_priority(internalEventSource, priority);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for internal event", -r);
|
||||
|
||||
r = sd_event_source_set_description(internalEventSource, "internal-event");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
// TODO: auto sdInternalEventSource = createSdInternalEventSourceSlot(...);
|
||||
|
||||
sdEvent_ = std::make_unique<SdEvent>(SdEvent{ std::move(sdEvent)
|
||||
, std::move(sdTimeEventSource)
|
||||
, std::move(sdIoEventSource)
|
||||
, std::move(sdInternalEventSource) });
|
||||
}
|
||||
|
||||
void Connection::detachSdEventLoop()
|
||||
{
|
||||
sdEvent_.reset();
|
||||
}
|
||||
|
||||
sd_event *Connection::getSdEventLoop()
|
||||
{
|
||||
return sdEvent_ ? static_cast<sd_event*>(sdEvent_->sdEvent.get()) : nullptr;
|
||||
}
|
||||
|
||||
int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
(void)connection->processPendingEvent();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
(void)connection->processPendingEvent();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdInternalEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
// It's not really necessary to processPendingEvent() here. We just clear the event fd.
|
||||
// The sd-event loop will before the next poll call prepare callbacks for all event sources,
|
||||
// including I/O bus fd. This will get up-to-date poll timeout, which will be zero if there
|
||||
// are pending D-Bus messages in the read queue, which will immediately wake up next poll
|
||||
// and go to onSdIoEvent() handler, which calls processPendingEvent(). Viola.
|
||||
// For external event loops that only have access to public sdbus-c++ API, processPendingEvent()
|
||||
// is the only option to clear event fd (it comes at a little extra cost but on the other hand
|
||||
// the solution is simpler for clients -- we don't provide an extra method for just clearing
|
||||
// the event fd. There is one method for both fd's -- and that's processPendingEvent().
|
||||
|
||||
// Kept here so that potential readers know what to do in their custom external event loops.
|
||||
//(void)connection->processPendingEvent();
|
||||
|
||||
connection->eventFd_.clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
auto sdbusPollData = connection->getEventLoopPollData();
|
||||
|
||||
// Set poll events to watch out for on I/O fd
|
||||
auto* sdIoEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdIoEventSource.get());
|
||||
auto r = sd_event_source_set_io_events(sdIoEventSource, sdbusPollData.events);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for IO event source", -r);
|
||||
|
||||
// Set poll events to watch out for on internal event fd
|
||||
auto* sdInternalEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdInternalEventSource.get());
|
||||
r = sd_event_source_set_io_events(sdInternalEventSource, POLLIN);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for internal event source", -r);
|
||||
|
||||
// Set current timeout to the time event source (it may be zero if there are messages in the sd-bus queues to be processed)
|
||||
auto* sdTimeEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdTimeEventSource.get());
|
||||
r = sd_event_source_set_time(sdTimeEventSource, static_cast<uint64_t>(sdbusPollData.timeout.count()));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set timeout for time event source", -r);
|
||||
r = sd_event_source_set_enabled(sdTimeEventSource, SD_EVENT_ON);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enable time event source", -r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData )
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = sdbus_->sd_bus_add_object_vtable(bus_.get()
|
||||
, &slot
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, vtable
|
||||
, userData );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register object vtable", -r);
|
||||
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
PlainMessage Connection::createPlainMessage() const
|
||||
{
|
||||
sd_bus_message* sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new(bus_.get(), &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a plain message", -r);
|
||||
|
||||
return Message::Factory::create<PlainMessage>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
MethodCall Connection::createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_method_call(bus_.get()
|
||||
, &sdbusMsg
|
||||
, 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, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
Signal Connection::createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_signal(bus_.get()
|
||||
, &sdbusMsg
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, signalName.c_str() );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
|
||||
|
||||
return Message::Factory::create<Signal>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
MethodReply Connection::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
// If the call expects reply, this call will block the bus connection from
|
||||
// serving other messages until the reply arrives or the call times out.
|
||||
auto reply = message.send(timeout);
|
||||
|
||||
// Some messages may have arrived while waiting for the call reply. They were set aside while waiting.
|
||||
// In case an event loop is inside a poll in another thread, or an external event loop polls in the
|
||||
// same thread but as an unrelated event source, then we need to wake up the poll explicitly so the
|
||||
// event loop 1. processes all messages in the read queue, 2. updates poll timeout before next poll.
|
||||
if (arePendingMessagesInReadQueue())
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
message.send(callback, userData, timeout, floating_slot);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
}
|
||||
|
||||
Slot Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
auto slot = message.send(callback, userData, timeout);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames )
|
||||
{
|
||||
auto names = to_strv(propNames);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_properties_changed_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, propNames.empty() ? nullptr : &names[0] );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit PropertiesChanged signal", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesAddedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_emit_object_added(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal for all registered interfaces", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_added_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesRemovedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_emit_object_removed(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal for all registered interfaces", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
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 )
|
||||
{
|
||||
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 r = sdbus_->sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
|
||||
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
|
||||
{
|
||||
sd_bus* bus{};
|
||||
int r = busFactory(&bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
|
||||
|
||||
BusPtr busPtr{bus, [this](sd_bus* bus){ return sdbus_->sd_bus_flush_close_unref(bus); }};
|
||||
finishHandshake(busPtr.get());
|
||||
return busPtr;
|
||||
}
|
||||
|
||||
Connection::BusPtr Connection::openPseudoBus()
|
||||
{
|
||||
sd_bus* bus{};
|
||||
|
||||
int r = sdbus_->sd_bus_new(&bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open pseudo bus", -r);
|
||||
|
||||
(void)sdbus_->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 sdbus_->sd_bus_close_unref(bus); }};
|
||||
}
|
||||
|
||||
void Connection::finishHandshake(sd_bus* bus)
|
||||
{
|
||||
// Process all requests that are part of the initial handshake,
|
||||
// like processing the Hello message response, authentication etc.,
|
||||
// to avoid connection authentication timeout in dbus daemon.
|
||||
|
||||
assert(bus != nullptr);
|
||||
|
||||
auto r = sdbus_->sd_bus_flush(bus);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
|
||||
}
|
||||
|
||||
void Connection::notifyEventLoopToExit()
|
||||
{
|
||||
loopExitFd_.notify();
|
||||
}
|
||||
|
||||
void Connection::notifyEventLoopToWakeUpFromPoll()
|
||||
{
|
||||
eventFd_.notify();
|
||||
}
|
||||
|
||||
void Connection::joinWithEventLoop()
|
||||
{
|
||||
if (asyncLoopThread_.joinable())
|
||||
asyncLoopThread_.join();
|
||||
}
|
||||
|
||||
bool Connection::processPendingEvent()
|
||||
{
|
||||
auto bus = bus_.get();
|
||||
assert(bus != nullptr);
|
||||
|
||||
int r = sdbus_->sd_bus_process(bus, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
|
||||
|
||||
// In correct use of sdbus-c++ API, r can be 0 only when processPendingEvent()
|
||||
// is called from an external event loop as a reaction to event fd being signalled.
|
||||
// If there are no more D-Bus messages to process, we know we have to clear event fd.
|
||||
if (r == 0)
|
||||
eventFd_.clear();
|
||||
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
bool Connection::waitForNextEvent()
|
||||
{
|
||||
assert(bus_ != nullptr);
|
||||
assert(loopExitFd_.fd >= 0);
|
||||
assert(eventFd_.fd >= 0);
|
||||
|
||||
auto sdbusPollData = getEventLoopPollData();
|
||||
struct pollfd fds[] = { {sdbusPollData.fd, sdbusPollData.events, 0}
|
||||
, {eventFd_.fd, POLLIN, 0}
|
||||
, {loopExitFd_.fd, POLLIN, 0} };
|
||||
constexpr auto fdsCount = sizeof(fds)/sizeof(fds[0]);
|
||||
|
||||
auto timeout = sdbusPollData.getPollTimeout();
|
||||
auto r = poll(fds, fdsCount, timeout);
|
||||
|
||||
if (r < 0 && errno == EINTR)
|
||||
return true; // Try again
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
|
||||
|
||||
// Wake up notification, in order that we re-enter poll with freshly read PollData (namely, new poll timeout thereof)
|
||||
if (fds[1].revents & POLLIN)
|
||||
{
|
||||
auto cleared = eventFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the event descriptor", -errno);
|
||||
// Go poll() again, but with up-to-date timeout (which will wake poll() up right away if there are messages to process)
|
||||
return waitForNextEvent();
|
||||
}
|
||||
// Loop exit notification
|
||||
if (fds[2].revents & POLLIN)
|
||||
{
|
||||
auto cleared = loopExitFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the loop exit descriptor", -errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::arePendingMessagesInReadQueue() const
|
||||
{
|
||||
uint64_t readQueueSize{};
|
||||
|
||||
auto r = sdbus_->sd_bus_get_n_queued_read(bus_.get(), &readQueueSize);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get number of pending messages in read queue", -r);
|
||||
|
||||
return readQueueSize > 0;
|
||||
}
|
||||
|
||||
std::string Connection::composeSignalMatchFilter( const std::string &sender
|
||||
, const std::string &objectPath
|
||||
, const std::string &interfaceName
|
||||
, const std::string &signalName )
|
||||
{
|
||||
std::string filter;
|
||||
|
||||
filter += "type='signal',";
|
||||
filter += "sender='" + sender + "',";
|
||||
filter += "interface='" + interfaceName + "',";
|
||||
filter += "member='" + signalName + "',";
|
||||
filter += "path='" + objectPath + "'";
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
std::vector</*const */char*> Connection::to_strv(const std::vector<std::string>& strings)
|
||||
{
|
||||
std::vector</*const */char*> strv;
|
||||
for (auto& str : strings)
|
||||
strv.push_back(const_cast<char*>(str.c_str()));
|
||||
strv.push_back(nullptr);
|
||||
return strv;
|
||||
}
|
||||
|
||||
Connection::EventFd::EventFd()
|
||||
{
|
||||
fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
SDBUS_THROW_ERROR_IF(fd < 0, "Failed to create event object", -errno);
|
||||
}
|
||||
|
||||
Connection::EventFd::~EventFd()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void Connection::EventFd::notify()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
auto r = eventfd_write(fd, 1);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify event descriptor", -errno);
|
||||
}
|
||||
|
||||
bool Connection::EventFd::clear()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
|
||||
uint64_t value{};
|
||||
auto r = eventfd_read(fd, &value);
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::chrono::microseconds IConnection::PollData::getRelativeTimeout() const
|
||||
{
|
||||
constexpr auto zero = std::chrono::microseconds::zero();
|
||||
constexpr auto max = std::chrono::microseconds::max();
|
||||
using internal::now;
|
||||
|
||||
if (timeout == zero)
|
||||
return zero;
|
||||
else if (timeout == max)
|
||||
return max;
|
||||
else
|
||||
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
|
||||
}
|
||||
|
||||
int IConnection::PollData::getPollTimeout() const
|
||||
{
|
||||
const auto relativeTimeout = getRelativeTimeout();
|
||||
|
||||
if (relativeTimeout == decltype(relativeTimeout)::max())
|
||||
return -1;
|
||||
else
|
||||
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
std::unique_ptr<sdbus::internal::IConnection> createConnection()
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
SCOPE_EXIT{ connection.release(); };
|
||||
auto connectionInternal = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
|
||||
{
|
||||
auto conn = createSystemBusConnection();
|
||||
conn->requestName(name);
|
||||
return conn;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)
|
||||
{
|
||||
auto conn = createSessionBusConnection();
|
||||
conn->requestName(name);
|
||||
return conn;
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string &address)
|
||||
{
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
assert(interface != nullptr);
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
197
backup/src/Connection.h
Normal file
197
backup/src/Connection.h
Normal file
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_CONNECTION_H_
|
||||
#define SDBUS_CXX_INTERNAL_CONNECTION_H_
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include "IConnection.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "ISdBus.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class Connection final
|
||||
: public sdbus::internal::IConnection
|
||||
{
|
||||
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 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, pseudo_bus_t);
|
||||
~Connection() override;
|
||||
|
||||
void requestName(const std::string& name) override;
|
||||
void releaseName(const std::string& name) override;
|
||||
std::string getUniqueName() const override;
|
||||
void enterEventLoop() override;
|
||||
void enterEventLoopAsync() override;
|
||||
void leaveEventLoop() override;
|
||||
PollData getEventLoopPollData() const override;
|
||||
bool processPendingEvent() 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;
|
||||
|
||||
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;
|
||||
|
||||
void attachSdEventLoop(sd_event *event, int priority) override;
|
||||
void detachSdEventLoop() override;
|
||||
sd_event *getSdEventLoop() 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;
|
||||
|
||||
PlainMessage createPlainMessage() const override;
|
||||
MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const override;
|
||||
Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const override;
|
||||
|
||||
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
||||
void callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t) override;
|
||||
Slot callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout) override;
|
||||
|
||||
void emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames ) override;
|
||||
void emitInterfacesAddedSignal(const std::string& objectPath) override;
|
||||
void emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) override;
|
||||
void emitInterfacesRemovedSignal(const std::string& objectPath) override;
|
||||
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;
|
||||
|
||||
private:
|
||||
using BusFactory = std::function<int(sd_bus**)>;
|
||||
using BusPtr = std::unique_ptr<sd_bus, std::function<sd_bus*(sd_bus*)>>;
|
||||
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 waitForNextEvent();
|
||||
|
||||
bool arePendingMessagesInReadQueue() const;
|
||||
static std::string composeSignalMatchFilter( const std::string &sender
|
||||
, const std::string &objectPath
|
||||
, const std::string &interfaceName
|
||||
, const std::string &signalName);
|
||||
|
||||
void notifyEventLoopToExit();
|
||||
void notifyEventLoopToWakeUpFromPoll();
|
||||
void joinWithEventLoop();
|
||||
|
||||
static std::vector</*const */char*> to_strv(const std::vector<std::string>& strings);
|
||||
|
||||
static int onSdTimerEvent(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
static int onSdIoEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata);
|
||||
static int onSdInternalEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata);
|
||||
static int onSdEventPrepare(sd_event_source *s, void *userdata);
|
||||
|
||||
struct EventFd
|
||||
{
|
||||
EventFd();
|
||||
~EventFd();
|
||||
void notify();
|
||||
bool clear();
|
||||
|
||||
int fd{-1};
|
||||
};
|
||||
|
||||
struct MatchInfo
|
||||
{
|
||||
message_handler callback;
|
||||
Connection& connection;
|
||||
sd_bus_slot *slot;
|
||||
};
|
||||
|
||||
// sd-event integration
|
||||
struct SdEvent
|
||||
{
|
||||
Slot sdEvent;
|
||||
Slot sdTimeEventSource;
|
||||
Slot sdIoEventSource;
|
||||
Slot sdInternalEventSource;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<ISdBus> sdbus_;
|
||||
BusPtr bus_;
|
||||
std::thread asyncLoopThread_;
|
||||
EventFd loopExitFd_; // To wake up event loop I/O polling to exit
|
||||
EventFd eventFd_; // To wake up event loop I/O polling to re-enter poll with fresh PollData values
|
||||
std::vector<Slot> floatingMatchRules_;
|
||||
std::unique_ptr<SdEvent> sdEvent_; // Integration of systemd sd-event event loop implementation
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_CONNECTION_H_ */
|
43
backup/src/Error.cpp
Normal file
43
backup/src/Error.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Error.cpp
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
sdbus::Error createError(int errNo, const std::string& customMsg)
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
sd_bus_error_set_errno(&sdbusError, errNo);
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
std::string name(sdbusError.name);
|
||||
std::string message(customMsg + " (" + sdbusError.message + ")");
|
||||
return sdbus::Error(name, message);
|
||||
}
|
||||
}
|
112
backup/src/Flags.cpp
Normal file
112
backup/src/Flags.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Flags.cpp
|
||||
*
|
||||
* Created on: Dec 31, 2018
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
uint64_t Flags::toSdBusInterfaceFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
|
||||
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
|
||||
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
|
||||
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
|
||||
sdbusFlags |= 0;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusMethodFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
if (flags_.test(Flags::METHOD_NO_REPLY))
|
||||
sdbusFlags |= SD_BUS_VTABLE_METHOD_NO_REPLY;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusSignalFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusPropertyFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
//if (!flags_.test(Flags::PRIVILEGED))
|
||||
// sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
|
||||
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
|
||||
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
|
||||
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
|
||||
sdbusFlags |= 0;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusWritablePropertyFlags() const
|
||||
{
|
||||
auto sdbusFlags = toSdBusPropertyFlags();
|
||||
|
||||
using namespace sdbus;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
}
|
104
backup/src/IConnection.h
Normal file
104
backup/src/IConnection.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IConnection.h
|
||||
*
|
||||
* Created on: Nov 9, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_ICONNECTION_H_
|
||||
#define SDBUS_CXX_INTERNAL_ICONNECTION_H_
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
// Forward declaration
|
||||
namespace sdbus {
|
||||
class MethodCall;
|
||||
class MethodReply;
|
||||
class Signal;
|
||||
class PlainMessage;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class IConnection
|
||||
: public ::sdbus::IConnection
|
||||
{
|
||||
public:
|
||||
~IConnection() override = 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;
|
||||
|
||||
virtual PlainMessage createPlainMessage() const = 0;
|
||||
virtual MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const = 0;
|
||||
virtual Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const = 0;
|
||||
|
||||
virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout) = 0;
|
||||
virtual void callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t) = 0;
|
||||
virtual Slot callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout) = 0;
|
||||
|
||||
virtual void emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames ) = 0;
|
||||
virtual void emitInterfacesAddedSignal(const std::string& objectPath) = 0;
|
||||
virtual void emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) = 0;
|
||||
virtual void emitInterfacesRemovedSignal(const std::string& objectPath) = 0;
|
||||
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 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]] std::unique_ptr<sdbus::internal::IConnection> createConnection();
|
||||
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection();
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_ICONNECTION_H_ */
|
108
backup/src/ISdBus.h
Normal file
108
backup/src/ISdBus.h
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ISdBus.h
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
*
|
||||
* Created on: Mar 12, 2019
|
||||
* 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_ISDBUS_H
|
||||
#define SDBUS_CXX_ISDBUS_H
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class ISdBus
|
||||
{
|
||||
public:
|
||||
struct PollData
|
||||
{
|
||||
int fd;
|
||||
short int events;
|
||||
uint64_t timeout_usec;
|
||||
};
|
||||
|
||||
virtual ~ISdBus() = default;
|
||||
|
||||
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) = 0;
|
||||
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
|
||||
|
||||
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) = 0;
|
||||
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) = 0;
|
||||
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) = 0;
|
||||
|
||||
virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) = 0;
|
||||
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0;
|
||||
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0;
|
||||
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) = 0;
|
||||
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) = 0;
|
||||
|
||||
virtual int sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec) = 0;
|
||||
virtual int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) = 0;
|
||||
|
||||
virtual int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names) = 0;
|
||||
virtual int sd_bus_emit_object_added(sd_bus *bus, const char *path) = 0;
|
||||
virtual int sd_bus_emit_object_removed(sd_bus *bus, const char *path) = 0;
|
||||
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_remote(sd_bus **ret, const char* host) = 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 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_get_n_queued_read(sd_bus *bus, uint64_t *ret) = 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SDBUS_CXX_ISDBUS_H
|
865
backup/src/Message.cpp
Normal file
865
backup/src/Message.cpp
Normal file
@ -0,0 +1,865 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message.cpp
|
||||
*
|
||||
* Created on: Nov 9, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include "MessageUtils.h"
|
||||
#include "ISdBus.h"
|
||||
#include "IConnection.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
Message::Message(internal::ISdBus* sdbus) noexcept
|
||||
: sdbus_(sdbus)
|
||||
{
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus) noexcept
|
||||
: msg_(msg)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept
|
||||
: msg_(msg)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(const Message& other) noexcept
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Message& Message::operator=(const Message& other) noexcept
|
||||
{
|
||||
if (msg_)
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
sdbus_ = other.sdbus_;
|
||||
ok_ = other.ok_;
|
||||
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message::Message(Message&& other) noexcept
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
Message& Message::operator=(Message&& other) noexcept
|
||||
{
|
||||
if (msg_)
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
other.msg_ = nullptr;
|
||||
sdbus_ = other.sdbus_;
|
||||
other.sdbus_ = nullptr;
|
||||
ok_ = other.ok_;
|
||||
other.ok_ = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message::~Message()
|
||||
{
|
||||
if (msg_)
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message& Message::operator<<(bool item)
|
||||
{
|
||||
int intItem = item;
|
||||
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a bool value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(int16_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int16_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(int32_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int32_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(int64_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int64_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(uint8_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a byte value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(uint16_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint16_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(uint32_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint32_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(uint64_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint64_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(double item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a double value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const char* item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a C-string value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const std::string& item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a string value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const Variant &item)
|
||||
{
|
||||
item.serializeTo(*this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const ObjectPath &item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, item.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an ObjectPath value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const Signature &item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, item.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a Signature value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const UnixFd &item)
|
||||
{
|
||||
auto fd = item.get();
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a UnixFd value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Message& Message::operator>>(bool& item)
|
||||
{
|
||||
int intItem;
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a bool value", -r);
|
||||
|
||||
item = static_cast<bool>(intItem);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(int16_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a int16_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(int32_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a int32_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(int64_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a bool value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(uint8_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a byte value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(uint16_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint16_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(uint32_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint32_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(uint64_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint64_t value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(double& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a double value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(char*& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a string value", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(std::string& item)
|
||||
{
|
||||
char* str{};
|
||||
(*this) >> str;
|
||||
|
||||
if (str != nullptr)
|
||||
item = str;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(Variant &item)
|
||||
{
|
||||
item.deserializeFrom(*this);
|
||||
|
||||
// Empty variant is normally prohibited. Users cannot send empty variants.
|
||||
// Therefore in this context an empty variant means that we are at the end
|
||||
// of deserializing a container, and thus we shall set ok_ flag to false.
|
||||
if (item.isEmpty())
|
||||
ok_ = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(ObjectPath &item)
|
||||
{
|
||||
char* str{};
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, &str);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize an ObjectPath value", -r);
|
||||
|
||||
if (str != nullptr)
|
||||
item = str;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(Signature &item)
|
||||
{
|
||||
char* str{};
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, &str);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a Signature value", -r);
|
||||
|
||||
if (str != nullptr)
|
||||
item = str;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator>>(UnixFd &item)
|
||||
{
|
||||
int fd = -1;
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a UnixFd value", -r);
|
||||
|
||||
item.reset(fd);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Message& Message::openContainer(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::closeContainer()
|
||||
{
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openDictEntry(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::closeDictEntry()
|
||||
{
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openVariant(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::closeVariant()
|
||||
{
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openStruct(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a struct", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::closeStruct()
|
||||
{
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a struct", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Message& Message::enterContainer(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::exitContainer()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterDictEntry(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::exitDictEntry()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterVariant(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::exitVariant()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterStruct(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a struct", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::exitStruct()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a struct", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Message::operator bool() const
|
||||
{
|
||||
return ok_;
|
||||
}
|
||||
|
||||
void Message::clearFlags()
|
||||
{
|
||||
ok_ = true;
|
||||
}
|
||||
|
||||
void Message::copyTo(Message& destination, bool complete) const
|
||||
{
|
||||
auto r = sd_bus_message_copy((sd_bus_message*)destination.msg_, (sd_bus_message*)msg_, complete);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to copy the message", -r);
|
||||
}
|
||||
|
||||
void Message::seal()
|
||||
{
|
||||
const auto messageCookie = 1;
|
||||
const auto sealTimeout = 0;
|
||||
auto r = sd_bus_message_seal((sd_bus_message*)msg_, messageCookie, sealTimeout);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to seal the message", -r);
|
||||
}
|
||||
|
||||
void Message::rewind(bool complete)
|
||||
{
|
||||
auto r = sd_bus_message_rewind((sd_bus_message*)msg_, complete);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
|
||||
}
|
||||
|
||||
std::string Message::getInterfaceName() const
|
||||
{
|
||||
auto interface = sd_bus_message_get_interface((sd_bus_message*)msg_);
|
||||
return interface != nullptr ? interface : "";
|
||||
}
|
||||
|
||||
std::string Message::getMemberName() const
|
||||
{
|
||||
auto member = sd_bus_message_get_member((sd_bus_message*)msg_);
|
||||
return member != nullptr ? member : "";
|
||||
}
|
||||
|
||||
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;
|
||||
const char* contentsSig;
|
||||
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 : "";
|
||||
}
|
||||
|
||||
bool Message::isValid() const
|
||||
{
|
||||
return msg_ != nullptr && sdbus_ != nullptr;
|
||||
}
|
||||
|
||||
bool Message::isEmpty() const
|
||||
{
|
||||
return sd_bus_message_is_empty((sd_bus_message*)msg_) != 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
|
||||
, adopt_message_t) noexcept
|
||||
: Message(msg, sdbus, adopt_message)
|
||||
{
|
||||
}
|
||||
|
||||
void MethodCall::dontExpectReply()
|
||||
{
|
||||
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)msg_, 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
|
||||
}
|
||||
|
||||
bool MethodCall::doesntExpectReply() const
|
||||
{
|
||||
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
MethodReply MethodCall::send(uint64_t timeout) const
|
||||
{
|
||||
if (!doesntExpectReply())
|
||||
return sendWithReply(timeout);
|
||||
else
|
||||
return sendWithNoReply();
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithReply(uint64_t timeout) const
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_call(nullptr, (sd_bus_message*)msg_, timeout, &sdbusError, &sdbusReply);
|
||||
|
||||
if (sd_bus_error_is_set(&sdbusError))
|
||||
throw sdbus::Error(sdbusError.name, sdbusError.message);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithNoReply() const
|
||||
{
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(); // No reply
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return {slot, [sdbus_ = sdbus_](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createReply() const
|
||||
{
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_return((sd_bus_message*)msg_, &sdbusReply);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createErrorReply(const Error& error) const
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
sd_bus_error_set(&sdbusError, error.getName().c_str(), error.getMessage().c_str());
|
||||
|
||||
sd_bus_message* sdbusErrorReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_error((sd_bus_message*)msg_, &sdbusErrorReply, &sdbusError);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method error reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusErrorReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
void MethodReply::send() const
|
||||
{
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send reply", -r);
|
||||
}
|
||||
|
||||
void Signal::send() const
|
||||
{
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
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);
|
||||
}
|
||||
|
||||
PlainMessage createPlainMessage()
|
||||
{
|
||||
//static auto connection = internal::createConnection();
|
||||
// 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.
|
||||
static auto connection = internal::createPseudoConnection();
|
||||
return connection->createPlainMessage();
|
||||
}
|
||||
|
||||
}
|
65
backup/src/MessageUtils.h
Normal file
65
backup/src/MessageUtils.h
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file MessageUtils.h
|
||||
*
|
||||
* Created on: Dec 5, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_MESSAGEUTILS_H_
|
||||
#define SDBUS_CXX_INTERNAL_MESSAGEUTILS_H_
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
class Message::Factory
|
||||
{
|
||||
public:
|
||||
template<typename _Msg>
|
||||
static _Msg create()
|
||||
{
|
||||
return _Msg{};
|
||||
}
|
||||
|
||||
template<typename _Msg>
|
||||
static _Msg create(void *msg)
|
||||
{
|
||||
return _Msg{msg};
|
||||
}
|
||||
|
||||
template<typename _Msg>
|
||||
static _Msg create(void *msg, internal::ISdBus* sdbus)
|
||||
{
|
||||
return _Msg{msg, sdbus};
|
||||
}
|
||||
|
||||
template<typename _Msg>
|
||||
static _Msg create(void *msg, internal::ISdBus* sdbus, adopt_message_t)
|
||||
{
|
||||
return _Msg{msg, sdbus, adopt_message};
|
||||
}
|
||||
};
|
||||
|
||||
PlainMessage createPlainMessage();
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_MESSAGEUTILS_H_ */
|
443
backup/src/Object.cpp
Normal file
443
backup/src/Object.cpp
Normal file
@ -0,0 +1,443 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Object.cpp
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "MessageUtils.h"
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#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 <systemd/sd-bus.h>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
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
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags )
|
||||
{
|
||||
registerMethod( interfaceName
|
||||
, std::move(methodName)
|
||||
, std::move(inputSignature)
|
||||
, {}
|
||||
, std::move(outputSignature)
|
||||
, {}
|
||||
, std::move(methodCallback)
|
||||
, std::move(flags) );
|
||||
}
|
||||
|
||||
void Object::registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, 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);
|
||||
InterfaceData::MethodData methodData{ std::move(inputSignature)
|
||||
, std::move(outputSignature)
|
||||
, paramNamesToString(inputNames) + paramNamesToString(outputNames)
|
||||
, std::move(methodCallback)
|
||||
, std::move(flags) };
|
||||
auto inserted = interface.methods.emplace(std::move(methodName), std::move(methodData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
|
||||
}
|
||||
|
||||
void Object::registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags )
|
||||
{
|
||||
registerSignal(interfaceName, std::move(signalName), std::move(signature), {}, std::move(flags));
|
||||
}
|
||||
|
||||
void Object::registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
SDBUS_CHECK_MEMBER_NAME(signalName);
|
||||
|
||||
auto& interface = getInterface(interfaceName);
|
||||
|
||||
InterfaceData::SignalData signalData{std::move(signature), paramNamesToString(paramNames), std::move(flags)};
|
||||
auto inserted = interface.signals.emplace(std::move(signalName), std::move(signalData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal: signal already exists", EINVAL);
|
||||
}
|
||||
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags )
|
||||
{
|
||||
registerProperty( interfaceName
|
||||
, std::move(propertyName)
|
||||
, std::move(signature)
|
||||
, std::move(getCallback)
|
||||
, {}
|
||||
, std::move(flags) );
|
||||
}
|
||||
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, 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);
|
||||
|
||||
InterfaceData::PropertyData propertyData{ std::move(signature)
|
||||
, std::move(getCallback)
|
||||
, std::move(setCallback)
|
||||
, 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);
|
||||
}
|
||||
|
||||
void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags)
|
||||
{
|
||||
auto& interface = getInterface(interfaceName);
|
||||
interface.flags = flags;
|
||||
}
|
||||
|
||||
void Object::finishRegistration()
|
||||
{
|
||||
for (auto& item : interfaces_)
|
||||
{
|
||||
const auto& interfaceName = item.first;
|
||||
auto& interfaceData = item.second;
|
||||
|
||||
const auto& vtable = createInterfaceVTable(interfaceData);
|
||||
activateInterfaceVTable(interfaceName, interfaceData, vtable);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::unregister()
|
||||
{
|
||||
interfaces_.clear();
|
||||
removeObjectManager();
|
||||
}
|
||||
|
||||
sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::string& signalName)
|
||||
{
|
||||
return connection_.createSignal(objectPath_, interfaceName, signalName);
|
||||
}
|
||||
|
||||
void Object::emitSignal(const sdbus::Signal& message)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid signal message provided", EINVAL);
|
||||
|
||||
message.send();
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames)
|
||||
{
|
||||
connection_.emitPropertiesChangedSignal(objectPath_, interfaceName, propNames);
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const std::string& interfaceName)
|
||||
{
|
||||
Object::emitPropertiesChangedSignal(interfaceName, {});
|
||||
}
|
||||
|
||||
void Object::emitInterfacesAddedSignal()
|
||||
{
|
||||
connection_.emitInterfacesAddedSignal(objectPath_);
|
||||
}
|
||||
|
||||
void Object::emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
connection_.emitInterfacesAddedSignal(objectPath_, interfaces);
|
||||
}
|
||||
|
||||
void Object::emitInterfacesRemovedSignal()
|
||||
{
|
||||
connection_.emitInterfacesRemovedSignal(objectPath_);
|
||||
}
|
||||
|
||||
void Object::emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
connection_.emitInterfacesRemovedSignal(objectPath_, interfaces);
|
||||
}
|
||||
|
||||
void Object::addObjectManager()
|
||||
{
|
||||
objectManagerSlot_ = connection_.addObjectManager(objectPath_, request_slot);
|
||||
}
|
||||
|
||||
void Object::removeObjectManager()
|
||||
{
|
||||
objectManagerSlot_.reset();
|
||||
}
|
||||
|
||||
bool Object::hasObjectManager() const
|
||||
{
|
||||
return objectManagerSlot_ != nullptr;
|
||||
}
|
||||
|
||||
sdbus::IConnection& Object::getConnection() const
|
||||
{
|
||||
return connection_;
|
||||
}
|
||||
|
||||
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;
|
||||
assert(vtable.empty());
|
||||
|
||||
vtable.push_back(createVTableStartItem(interfaceData.flags.toSdBusInterfaceFlags()));
|
||||
registerMethodsToVTable(interfaceData, vtable);
|
||||
registerSignalsToVTable(interfaceData, vtable);
|
||||
registerPropertiesToVTable(interfaceData, vtable);
|
||||
vtable.push_back(createVTableEndItem());
|
||||
|
||||
return vtable;
|
||||
}
|
||||
|
||||
void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
for (const auto& item : interfaceData.methods)
|
||||
{
|
||||
const auto& methodName = item.first;
|
||||
const auto& methodData = item.second;
|
||||
|
||||
vtable.push_back(createVTableMethodItem( methodName.c_str()
|
||||
, methodData.inputArgs.c_str()
|
||||
, methodData.outputArgs.c_str()
|
||||
, methodData.paramNames.c_str()
|
||||
, &Object::sdbus_method_callback
|
||||
, methodData.flags.toSdBusMethodFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
for (const auto& item : interfaceData.signals)
|
||||
{
|
||||
const auto& signalName = item.first;
|
||||
const auto& signalData = item.second;
|
||||
|
||||
vtable.push_back(createVTableSignalItem( signalName.c_str()
|
||||
, signalData.signature.c_str()
|
||||
, signalData.paramNames.c_str()
|
||||
, signalData.flags.toSdBusSignalFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
for (const auto& item : interfaceData.properties)
|
||||
{
|
||||
const auto& propertyName = item.first;
|
||||
const auto& propertyData = item.second;
|
||||
|
||||
if (!propertyData.setCallback)
|
||||
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, propertyData.flags.toSdBusPropertyFlags() ));
|
||||
else
|
||||
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, &Object::sdbus_property_set_callback
|
||||
, propertyData.flags.toSdBusWritablePropertyFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::string Object::paramNamesToString(const std::vector<std::string>& paramNames)
|
||||
{
|
||||
std::string names;
|
||||
for (const auto& name : paramNames)
|
||||
names += name + '\0';
|
||||
return names;
|
||||
}
|
||||
|
||||
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 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;
|
||||
assert(callback);
|
||||
|
||||
try
|
||||
{
|
||||
callback(message);
|
||||
}
|
||||
catch (const Error& e)
|
||||
{
|
||||
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
, const char */*objectPath*/
|
||||
, 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& callback = interfaceData->properties[property].getCallback;
|
||||
// Getter can be empty - the case of "write-only" property
|
||||
if (!callback)
|
||||
{
|
||||
sd_bus_error_set(retError, "org.freedesktop.DBus.Error.Failed", "Cannot read property as it is write-only");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &object.connection_.getSdBusInterface());
|
||||
|
||||
try
|
||||
{
|
||||
callback(reply);
|
||||
}
|
||||
catch (const Error& e)
|
||||
{
|
||||
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Object::sdbus_property_set_callback( sd_bus */*bus*/
|
||||
, const char */*objectPath*/
|
||||
, 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& callback = interfaceData->properties[property].setCallback;
|
||||
assert(callback);
|
||||
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &object.connection_.getSdBusInterface());
|
||||
|
||||
object.m_CurrentlyProcessedMessage.store(&value, std::memory_order_relaxed);
|
||||
SCOPE_EXIT
|
||||
{
|
||||
object.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
callback(value);
|
||||
}
|
||||
catch (const Error& e)
|
||||
{
|
||||
sd_bus_error_set(retError, e.getName().c_str(), e.getMessage().c_str());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, std::string objectPath)
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
return std::make_unique<sdbus::internal::Object>(*sdbusConnection, std::move(objectPath));
|
||||
}
|
||||
|
||||
}
|
186
backup/src/Object.h
Normal file
186
backup/src/Object.h
Normal file
@ -0,0 +1,186 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Object.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_OBJECT_H_
|
||||
#define SDBUS_CXX_INTERNAL_OBJECT_H_
|
||||
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include "IConnection.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class Object
|
||||
: public IObject
|
||||
{
|
||||
public:
|
||||
Object(sdbus::internal::IConnection& connection, std::string objectPath);
|
||||
|
||||
void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags ) override;
|
||||
void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, method_callback methodCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags ) override;
|
||||
void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags ) override;
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void setInterfaceFlags(const std::string& interfaceName, Flags flags) override;
|
||||
|
||||
void finishRegistration() override;
|
||||
void unregister() override;
|
||||
|
||||
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
||||
void emitSignal(const sdbus::Signal& message) override;
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames) override;
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName) override;
|
||||
void emitInterfacesAddedSignal() override;
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces) override;
|
||||
void emitInterfacesRemovedSignal() override;
|
||||
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces) override;
|
||||
|
||||
void addObjectManager() override;
|
||||
void removeObjectManager() override;
|
||||
bool hasObjectManager() const override;
|
||||
|
||||
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
|
||||
{
|
||||
const std::string inputArgs;
|
||||
const std::string outputArgs;
|
||||
const std::string paramNames;
|
||||
method_callback callback;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<MethodName, MethodData> methods;
|
||||
using SignalName = std::string;
|
||||
struct SignalData
|
||||
{
|
||||
const std::string signature;
|
||||
const std::string paramNames;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<SignalName, SignalData> signals;
|
||||
using PropertyName = std::string;
|
||||
struct PropertyData
|
||||
{
|
||||
const std::string signature;
|
||||
property_get_callback getCallback;
|
||||
property_set_callback setCallback;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<PropertyName, PropertyData> properties;
|
||||
std::vector<sd_bus_vtable> vtable;
|
||||
Flags flags;
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
static void registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
|
||||
void activateInterfaceVTable( const std::string& interfaceName
|
||||
, InterfaceData& interfaceData
|
||||
, const std::vector<sd_bus_vtable>& vtable );
|
||||
static std::string paramNamesToString(const std::vector<std::string>& paramNames);
|
||||
|
||||
static int sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
static int sdbus_property_get_callback( sd_bus *bus
|
||||
, const char *objectPath
|
||||
, const char *interface
|
||||
, const char *property
|
||||
, sd_bus_message *sdbusReply
|
||||
, void *userData
|
||||
, sd_bus_error *retError );
|
||||
static int sdbus_property_set_callback( sd_bus *bus
|
||||
, const char *objectPath
|
||||
, const char *interface
|
||||
, const char *property
|
||||
, sd_bus_message *sdbusValue
|
||||
, void *userData
|
||||
, sd_bus_error *retError );
|
||||
|
||||
private:
|
||||
sdbus::internal::IConnection& connection_;
|
||||
std::string objectPath_;
|
||||
std::map<InterfaceName, InterfaceData> interfaces_;
|
||||
Slot objectManagerSlot_;
|
||||
std::atomic<const Message*> m_CurrentlyProcessedMessage{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_OBJECT_H_ */
|
361
backup/src/Proxy.cpp
Normal file
361
backup/src/Proxy.cpp
Normal file
@ -0,0 +1,361 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Proxy.cpp
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
Proxy::Proxy(sdbus::internal::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
|
||||
, 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.
|
||||
}
|
||||
|
||||
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
: connection_(std::move(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);
|
||||
}
|
||||
|
||||
MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid method call message provided", EINVAL);
|
||||
|
||||
return connection_->callMethod(message, timeout);
|
||||
}
|
||||
|
||||
PendingAsyncCall Proxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout)
|
||||
{
|
||||
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), {}});
|
||||
auto weakData = std::weak_ptr<AsyncCalls::CallData>{callData};
|
||||
|
||||
callData->slot = connection_->callMethod(message, callback, callData.get(), timeout);
|
||||
|
||||
auto slotPtr = callData->slot.get();
|
||||
pendingAsyncCalls_.addCall(slotPtr, std::move(callData));
|
||||
|
||||
// TODO: Instead of PendingAsyncCall consider using Slot implementation for simplicity and consistency
|
||||
return {weakData};
|
||||
}
|
||||
|
||||
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);
|
||||
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_);
|
||||
}
|
||||
|
||||
void Proxy::registerSignalHandlers(sdbus::internal::IConnection& connection)
|
||||
{
|
||||
for (auto& interfaceItem : interfaces_)
|
||||
{
|
||||
const auto& interfaceName = interfaceItem.first;
|
||||
auto& signalsOnInterface = interfaceItem.second.signals_;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Proxy::unregister()
|
||||
{
|
||||
pendingAsyncCalls_.clear();
|
||||
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*/)
|
||||
{
|
||||
auto* asyncCallData = static_cast<AsyncCalls::CallData*>(userData);
|
||||
assert(asyncCallData != nullptr);
|
||||
assert(asyncCallData->callback);
|
||||
auto& proxy = asyncCallData->proxy;
|
||||
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 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
|
||||
{
|
||||
proxy.m_CurrentlyProcessedMessage.store(nullptr, std::memory_order_relaxed);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (const Error&)
|
||||
{
|
||||
// Intentionally left blank -- sdbus-c++ exceptions shall not bubble up to the underlying C sd-bus library
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 message = Message::Factory::create<Signal>(sdbusMessage, &signalData->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);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
signalData->callback(message);
|
||||
}
|
||||
catch (const Error&)
|
||||
{
|
||||
// Intentionally left blank -- sdbus-c++ exceptions shall not bubble up to the underlying C sd-bus library
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
PendingAsyncCall::PendingAsyncCall(std::weak_ptr<void> callData)
|
||||
: callData_(std::move(callData))
|
||||
{
|
||||
}
|
||||
|
||||
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->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
|
||||
// callback is currently being processed, the sd-bus mutex is locked by the event
|
||||
// loop thread, thus access to the callData item is synchronized and thread-safe.
|
||||
}
|
||||
}
|
||||
|
||||
bool PendingAsyncCall::isPending() const
|
||||
{
|
||||
return !callData_.expired();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( IConnection& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
return std::make_unique<sdbus::internal::Proxy>( *sdbusConnection
|
||||
, std::move(destination)
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
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) );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
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) );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
}
|
176
backup/src/Proxy.h
Normal file
176
backup/src/Proxy.h
Normal file
@ -0,0 +1,176 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Proxy.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_PROXY_H_
|
||||
#define SDBUS_CXX_INTERNAL_PROXY_H_
|
||||
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include "IConnection.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class Proxy
|
||||
: public IProxy
|
||||
{
|
||||
public:
|
||||
Proxy( sdbus::internal::IConnection& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
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;
|
||||
|
||||
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:
|
||||
void registerSignalHandlers(sdbus::internal::IConnection& connection);
|
||||
static int sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
static int sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
|
||||
private:
|
||||
friend PendingAsyncCall;
|
||||
|
||||
std::unique_ptr< sdbus::internal::IConnection
|
||||
, std::function<void(sdbus::internal::IConnection*)>
|
||||
> connection_;
|
||||
std::string destination_;
|
||||
std::string objectPath_;
|
||||
|
||||
using InterfaceName = std::string;
|
||||
struct InterfaceData
|
||||
{
|
||||
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;
|
||||
};
|
||||
std::map<SignalName, std::unique_ptr<SignalData>> signals_;
|
||||
};
|
||||
std::map<InterfaceName, InterfaceData> interfaces_;
|
||||
|
||||
// We need to keep track of pending async calls. When the proxy is being destructed, we must
|
||||
// remove all slots of these pending calls, otherwise in case when the connection outlives
|
||||
// the proxy, we might get async reply handlers invoked for pending async calls after the proxy
|
||||
// has been destroyed, which is a free ticket into the realm of undefined behavior.
|
||||
class AsyncCalls
|
||||
{
|
||||
public:
|
||||
struct CallData
|
||||
{
|
||||
Proxy& proxy;
|
||||
async_reply_handler callback;
|
||||
Slot slot;
|
||||
};
|
||||
|
||||
~AsyncCalls()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool addCall(void* slot, std::shared_ptr<CallData> asyncCallData)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return calls_.emplace(slot, std::move(asyncCallData)).second;
|
||||
}
|
||||
|
||||
void removeCall(void* slot)
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
if (auto it = calls_.find(slot); it != calls_.end())
|
||||
{
|
||||
auto callData = std::move(it->second);
|
||||
calls_.erase(it);
|
||||
lock.unlock();
|
||||
|
||||
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
|
||||
// out of the `mutex_' critical section here, because if the `removeCall` is called by some
|
||||
// thread and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
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
|
||||
// out of the `mutex_' critical section here, because if the `clear` is called by some thread
|
||||
// and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
|
||||
} pendingAsyncCalls_;
|
||||
|
||||
std::atomic<const Message*> m_CurrentlyProcessedMessage{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_PROXY_H_ */
|
131
backup/src/ScopeGuard.h
Normal file
131
backup/src/ScopeGuard.h
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ScopeGuard.h
|
||||
*
|
||||
* Created on: Apr 29, 2015
|
||||
* 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_CPP_INTERNAL_SCOPEGUARD_H_
|
||||
#define SDBUS_CPP_INTERNAL_SCOPEGUARD_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
// Straightforward, modern, easy-to-use RAII utility to perform work on scope exit in an exception-safe manner.
|
||||
//
|
||||
// The utility helps providing basic exception safety guarantee by ensuring that the resources are always
|
||||
// released in face of an exception and released or kept when exiting the scope normally.
|
||||
//
|
||||
// Use SCOPE_EXIT if you'd like to perform an (mostly clean-up) operation when the scope ends, either due
|
||||
// to an exception or because it just ends normally.
|
||||
// Use SCOPE_EXIT_NAMED if you'd like to conditionally deactivate given scope-exit operation. This is useful
|
||||
// if, for example, we want the operation to be executed only in face of an exception.
|
||||
//
|
||||
// Example usage (maybe a bit contrived):
|
||||
// SqlDb* g_pDb = nullptr;
|
||||
// void fnc() {
|
||||
// auto* pDb = open_database(...); // Resource to be released when scope exits due to whatever reason
|
||||
// SCOPE_EXIT{ close_database(pDb); }; // Executes body when exiting the scope due to whatever reason
|
||||
// g_pDb = open_database(...); // Resource to be released only in face of an exception
|
||||
// SCOPE_EXIT_NAMED(releaseGlobalDbOnException) // Executes body when exiting the scope in face of an exception
|
||||
// {
|
||||
// close_database(g_pDb);
|
||||
// g_pDb = nullptr;
|
||||
// };
|
||||
// //... do operations (that may or may not possibly throw) on the database here
|
||||
// releaseGlobalDbOnException.dismiss(); // Don't release global DB on normal scope exit
|
||||
// return; // exiting scope normally
|
||||
// }
|
||||
|
||||
#define SCOPE_EXIT \
|
||||
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
|
||||
= ::sdbus::internal::detail::ScopeGuardOnExit() + [&]() \
|
||||
/**/
|
||||
|
||||
#define SCOPE_EXIT_NAMED(NAME) \
|
||||
auto NAME \
|
||||
= ::sdbus::internal::detail::ScopeGuardOnExit() + [&]() \
|
||||
/**/
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
template <class _Fun>
|
||||
class ScopeGuard
|
||||
{
|
||||
_Fun fnc_;
|
||||
bool active_;
|
||||
|
||||
public:
|
||||
ScopeGuard(_Fun f)
|
||||
: fnc_(std::move(f))
|
||||
, active_(true)
|
||||
{
|
||||
}
|
||||
~ScopeGuard()
|
||||
{
|
||||
if (active_)
|
||||
fnc_();
|
||||
}
|
||||
void dismiss()
|
||||
{
|
||||
active_ = false;
|
||||
}
|
||||
ScopeGuard() = delete;
|
||||
ScopeGuard(const ScopeGuard&) = delete;
|
||||
ScopeGuard& operator=(const ScopeGuard&) = delete;
|
||||
ScopeGuard(ScopeGuard&& rhs)
|
||||
: fnc_(std::move(rhs.fnc_))
|
||||
, active_(rhs.active_)
|
||||
{
|
||||
rhs.dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define CONCATENATE_IMPL(s1, s2) s1##s2
|
||||
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define ANONYMOUS_VARIABLE(str) \
|
||||
CONCATENATE(str, __COUNTER__) \
|
||||
/**/
|
||||
#else
|
||||
#define ANONYMOUS_VARIABLE(str) \
|
||||
CONCATENATE(str, __LINE__) \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#endif /* SDBUS_CPP_INTERNAL_SCOPEGUARD_H_ */
|
415
backup/src/SdBus.cpp
Normal file
415
backup/src/SdBus.cpp
Normal file
@ -0,0 +1,415 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file SdBus.cpp
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
*
|
||||
* Created on: Mar 3, 2019
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SdBus.h"
|
||||
#include <sdbus-c++/Error.h>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *m)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_ref(m);
|
||||
}
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_unref(m);
|
||||
}
|
||||
|
||||
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
|
||||
// TODO: This is a workaround. We should not block here until everything is physically sent out.
|
||||
// Refactor: if sd_bus_get_n_queued_write() > 0 then wake up event loop through event fd
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_call(bus, m, usec, ret_error, reply);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec)
|
||||
{
|
||||
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
|
||||
// TODO: This is a workaround. We should not block here until everything is physically sent out.
|
||||
// Refactor: if sd_bus_get_n_queued_write() > 0 then wake up event loop through event fd
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new(bus, m, type);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_signal(bus, m, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_return(call, m);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_error(call, m, e);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec)
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_set_method_call_timeout(bus, usec);
|
||||
#else
|
||||
(void)bus;
|
||||
(void)usec;
|
||||
throw sdbus::Error(SD_BUS_ERROR_NOT_SUPPORTED, "Setting general method call timeout not supported by underlying version of libsystemd");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret)
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_get_method_call_timeout(bus, ret);
|
||||
#else
|
||||
(void)bus;
|
||||
(void)ret;
|
||||
throw sdbus::Error(SD_BUS_ERROR_NOT_SUPPORTED, "Getting general method call timeout not supported by underlying version of libsystemd");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_properties_changed_strv(bus, path, interface, names);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_object_added(sd_bus *bus, const char *path)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_object_added(bus, path);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_object_removed(sd_bus *bus, const char *path)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_object_removed(bus, path);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_open(sd_bus **ret)
|
||||
{
|
||||
return ::sd_bus_open(ret);
|
||||
}
|
||||
|
||||
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_system_remote(sd_bus **ret, const char *host)
|
||||
{
|
||||
return ::sd_bus_open_system_remote(ret, host);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_request_name(bus, name, flags);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_release_name(bus, name);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_unique_name(sd_bus *bus, const char **name)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
return ::sd_bus_get_unique_name(bus, name);
|
||||
}
|
||||
|
||||
int SdBus::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)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_add_object_manager(bus, slot, path);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
|
||||
}
|
||||
|
||||
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
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_);
|
||||
|
||||
return ::sd_bus_process(bus, r);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_poll_data(sd_bus *bus, PollData* data)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
auto r = ::sd_bus_get_fd(bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
data->fd = r;
|
||||
|
||||
r = ::sd_bus_get_events(bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
data->events = static_cast<short int>(r);
|
||||
|
||||
r = ::sd_bus_get_timeout(bus, &data->timeout_usec);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_get_n_queued_read(bus, ret);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_flush(sd_bus *bus)
|
||||
{
|
||||
return ::sd_bus_flush(bus);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
103
backup/src/SdBus.h
Normal file
103
backup/src/SdBus.h
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file SdBus.h
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
*
|
||||
* Created on: Mar 3, 2019
|
||||
* 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_SDBUS_H
|
||||
#define SDBUS_CXX_SDBUS_H
|
||||
|
||||
#include "ISdBus.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class SdBus final : public ISdBus
|
||||
{
|
||||
public:
|
||||
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) override;
|
||||
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
|
||||
|
||||
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) override;
|
||||
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) override;
|
||||
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) override;
|
||||
|
||||
virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) override;
|
||||
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override;
|
||||
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
|
||||
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) override;
|
||||
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) override;
|
||||
|
||||
virtual int sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec) override;
|
||||
virtual int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) override;
|
||||
|
||||
virtual int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names) override;
|
||||
virtual int sd_bus_emit_object_added(sd_bus *bus, const char *path) override;
|
||||
virtual int sd_bus_emit_object_removed(sd_bus *bus, const char *path) override;
|
||||
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_remote(sd_bus **ret, const char* hsot) 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 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_get_n_queued_read(sd_bus *bus, uint64_t *ret) 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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SDBUS_C_SDBUS_H
|
67
backup/src/Types.cpp
Normal file
67
backup/src/Types.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types.cpp
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include "MessageUtils.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
Variant::Variant()
|
||||
: msg_(createPlainMessage())
|
||||
{
|
||||
}
|
||||
|
||||
void Variant::serializeTo(Message& msg) const
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(isEmpty(), "Empty variant is not allowed", EINVAL);
|
||||
msg_.rewind(true);
|
||||
msg_.copyTo(msg, true);
|
||||
}
|
||||
|
||||
void Variant::deserializeFrom(Message& msg)
|
||||
{
|
||||
msg.copyTo(msg_, false);
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
std::string Variant::peekValueType() const
|
||||
{
|
||||
msg_.rewind(false);
|
||||
std::string type;
|
||||
std::string contents;
|
||||
msg_.peekType(type, contents);
|
||||
return contents;
|
||||
}
|
||||
|
||||
bool Variant::isEmpty() const
|
||||
{
|
||||
return msg_.isEmpty();
|
||||
}
|
||||
|
||||
}
|
68
backup/src/Utils.h
Normal file
68
backup/src/Utils.h
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* (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 <systemd/sd-bus.h>
|
||||
|
||||
#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(!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 {
|
||||
|
||||
// Returns time since epoch based of POSIX CLOCK_MONOTONIC,
|
||||
// so we use the very same clock as underlying sd-bus library.
|
||||
[[nodiscard]] inline auto now()
|
||||
{
|
||||
struct timespec ts{};
|
||||
auto r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "clock_gettime failed: ", -errno);
|
||||
|
||||
return std::chrono::nanoseconds(ts.tv_nsec) + std::chrono::seconds(ts.tv_sec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_UTILS_H_ */
|
105
backup/src/VTableUtils.c
Normal file
105
backup/src/VTableUtils.c
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableUtils.c
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VTableUtils.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags)
|
||||
{
|
||||
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(flags);
|
||||
return vtableStart;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags )
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
// We have to expand macro SD_BUS_METHOD_WITH_NAMES manually here, because the macro expects literal char strings
|
||||
/*struct sd_bus_vtable vtableItem = SD_BUS_METHOD_WITH_NAMES(member, signature, innames, result, outnames, handler, flags);*/
|
||||
struct sd_bus_vtable vtableItem =
|
||||
{
|
||||
.type = _SD_BUS_VTABLE_METHOD,
|
||||
.flags = flags,
|
||||
.x = {
|
||||
.method = {
|
||||
.member = member,
|
||||
.signature = signature,
|
||||
.result = result,
|
||||
.handler = handler,
|
||||
.offset = 0,
|
||||
.names = paramNames,
|
||||
},
|
||||
},
|
||||
};
|
||||
#else
|
||||
(void)paramNames;
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, flags);
|
||||
#endif
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags )
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL_WITH_NAMES(member, signature, outnames, flags);
|
||||
#else
|
||||
(void)outnames;
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, flags);
|
||||
#endif
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableEndItem()
|
||||
{
|
||||
struct sd_bus_vtable vtableEnd = SD_BUS_VTABLE_END;
|
||||
return vtableEnd;
|
||||
}
|
63
backup/src/VTableUtils.h
Normal file
63
backup/src/VTableUtils.h
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableUtils.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
|
||||
#define SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags);
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableEndItem();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_VTABLEUTILS_H_ */
|
167
backup/tests/CMakeLists.txt
Normal file
167
backup/tests/CMakeLists.txt
Normal file
@ -0,0 +1,167 @@
|
||||
#-------------------------------
|
||||
# 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")
|
||||
|
||||
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 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()
|
||||
endif()
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(UNITTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/unittests)
|
||||
set(UNITTESTS_SRCS
|
||||
${UNITTESTS_SOURCE_DIR}/sdbus-c++-unit-tests.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/Message_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/PollData_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/Types_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/TypeTraits_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/Connection_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/mocks/SdBusMock.h)
|
||||
|
||||
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
|
||||
set(INTEGRATIONTESTS_SRCS
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusConnectionTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusGeneralTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusMethodsTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusAsyncMethodsTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusSignalsTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusPropertiesTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/DBusStandardInterfacesTests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/Defs.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-adaptor.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-proxy.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp)
|
||||
|
||||
set(PERFTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/perftests)
|
||||
set(STRESSTESTS_CLIENT_SRCS
|
||||
${PERFTESTS_SOURCE_DIR}/client.cpp
|
||||
${PERFTESTS_SOURCE_DIR}/perftests-proxy.h)
|
||||
set(STRESSTESTS_SERVER_SRCS
|
||||
${PERFTESTS_SOURCE_DIR}/server.cpp
|
||||
${PERFTESTS_SOURCE_DIR}/perftests-adaptor.h)
|
||||
|
||||
set(STRESSTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/stresstests)
|
||||
set(STRESSTESTS_SRCS
|
||||
${STRESSTESTS_SOURCE_DIR}/sdbus-c++-stress-tests.cpp
|
||||
${STRESSTESTS_SOURCE_DIR}/fahrenheit-thermometer-adaptor.h
|
||||
${STRESSTESTS_SOURCE_DIR}/fahrenheit-thermometer-proxy.h
|
||||
${STRESSTESTS_SOURCE_DIR}/celsius-thermometer-adaptor.h
|
||||
${STRESSTESTS_SOURCE_DIR}/celsius-thermometer-proxy.h
|
||||
${STRESSTESTS_SOURCE_DIR}/concatenator-adaptor.h
|
||||
${STRESSTESTS_SOURCE_DIR}/concatenator-proxy.h)
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
#----------------------------------
|
||||
# BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
add_executable(sdbus-c++-unit-tests ${UNITTESTS_SRCS})
|
||||
target_compile_definitions(sdbus-c++-unit-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
|
||||
target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib GTest::gmock)
|
||||
|
||||
add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS})
|
||||
target_compile_definitions(sdbus-c++-integration-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
|
||||
# Systemd::Libsystemd is included because integration tests use sd-event. Otherwise sdbus-c++ encapsulates and hides libsystemd.
|
||||
target_link_libraries(sdbus-c++-integration-tests sdbus-c++ Systemd::Libsystemd GTest::gmock)
|
||||
|
||||
# Manual performance and stress tests
|
||||
option(ENABLE_PERF_TESTS "Build and install manual performance tests (default OFF)" OFF)
|
||||
option(ENABLE_STRESS_TESTS "Build and install manual stress tests (default OFF)" OFF)
|
||||
|
||||
if(ENABLE_PERF_TESTS OR ENABLE_STRESS_TESTS)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(ENABLE_PERF_TESTS)
|
||||
message(STATUS "Building with performance tests")
|
||||
add_executable(sdbus-c++-perf-tests-client ${STRESSTESTS_CLIENT_SRCS})
|
||||
target_link_libraries(sdbus-c++-perf-tests-client sdbus-c++ Threads::Threads)
|
||||
add_executable(sdbus-c++-perf-tests-server ${STRESSTESTS_SERVER_SRCS})
|
||||
target_link_libraries(sdbus-c++-perf-tests-server sdbus-c++ Threads::Threads)
|
||||
endif()
|
||||
|
||||
if(ENABLE_STRESS_TESTS)
|
||||
message(STATUS "Building with stress tests")
|
||||
add_executable(sdbus-c++-stress-tests ${STRESSTESTS_SRCS})
|
||||
target_link_libraries(sdbus-c++-stress-tests sdbus-c++ Threads::Threads)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
set(TESTS_INSTALL_PATH "/opt/test/bin" CACHE STRING "Specifies where the test binaries will be installed")
|
||||
|
||||
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 /etc/dbus-1/system.d COMPONENT test)
|
||||
|
||||
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 /etc/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 /etc/dbus-1/system.d COMPONENT test)
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# RUNNING THE TESTS UPON BUILD
|
||||
#----------------------------------
|
||||
|
||||
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()
|
238
backup/tests/integrationtests/DBusAsyncMethodsTests.cpp
Normal file
238
backup/tests/integrationtests/DBusAsyncMethodsTests.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusAsyncMethodsTests.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::Le;
|
||||
using ::testing::AnyOf;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::SizeIs;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
|
||||
{
|
||||
std::chrono::time_point<std::chrono::steady_clock> start;
|
||||
try
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->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));
|
||||
});
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
this->m_proxy->doOperationClientSideAsyncWithTimeout(1us, (1s).count()); // The operation will take 1s, but the timeout is 1us, 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"));
|
||||
auto measuredTimeout = std::chrono::steady_clock::now() - start;
|
||||
ASSERT_THAT(measuredTimeout, Le(50ms));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
FAIL() << "Expected sdbus::Error exception";
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, 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{BUS_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));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
|
||||
{
|
||||
std::atomic<size_t> resultCount{};
|
||||
std::atomic<bool> invoke{};
|
||||
std::atomic<int> startedCount{};
|
||||
auto call = [&]()
|
||||
{
|
||||
TestProxy proxy{BUS_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));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->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));
|
||||
});
|
||||
|
||||
this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
ASSERT_THAT(future.get(), Eq(100));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
|
||||
{
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
|
||||
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
ASSERT_TRUE(call.isPending());
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
call.cancel();
|
||||
|
||||
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
call.cancel();
|
||||
|
||||
ASSERT_FALSE(call.isPending());
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
|
||||
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(0);
|
||||
(void) future.get(); // Wait for the call to finish
|
||||
|
||||
ASSERT_TRUE(this->waitUntil([&call](){ return !call.isPending(); }));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending)
|
||||
{
|
||||
sdbus::PendingAsyncCall call;
|
||||
|
||||
ASSERT_FALSE(call.isPending());
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, SupportsAsyncCallCopyAssignment)
|
||||
{
|
||||
sdbus::PendingAsyncCall call;
|
||||
|
||||
call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
ASSERT_TRUE(call.isPending());
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->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));
|
||||
});
|
||||
|
||||
this->m_proxy->doErroneousOperationClientSideAsync();
|
||||
|
||||
ASSERT_THROW(future.get(), sdbus::Error);
|
||||
}
|
91
backup/tests/integrationtests/DBusConnectionTests.cpp
Normal file
91
backup/tests/integrationtests/DBusConnectionTests.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusConnectionTests.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/>.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "Defs.h"
|
||||
|
||||
// sdbus
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
|
||||
// gmock
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
// STL
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using ::testing::Eq;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(Connection, CanBeDefaultConstructed)
|
||||
{
|
||||
ASSERT_NO_THROW(auto con = sdbus::createConnection());
|
||||
}
|
||||
|
||||
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?";
|
||||
}
|
||||
|
||||
TEST(Connection, CannotRequestNonregisteredDbusName)
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
ASSERT_THROW(connection->requestName("some.random.not.supported.dbus.name"), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(Connection, CanReleasedRequestedName)
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
|
||||
connection->requestName(BUS_NAME);
|
||||
ASSERT_NO_THROW(connection->releaseName(BUS_NAME));
|
||||
}
|
||||
|
||||
TEST(Connection, CannotReleaseNonrequestedName)
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
ASSERT_THROW(connection->releaseName("some.random.nonrequested.name"), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(Connection, CanEnterAndLeaveInternalEventLoop)
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
connection->requestName(BUS_NAME);
|
||||
|
||||
std::thread t([&](){ connection->enterEventLoop(); });
|
||||
connection->leaveEventLoop();
|
||||
|
||||
t.join();
|
||||
}
|
144
backup/tests/integrationtests/DBusGeneralTests.cpp
Normal file
144
backup/tests/integrationtests/DBusGeneralTests.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusGeneralTests.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 "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "TestFixture.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>
|
||||
#include <variant>
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
connection->requestName(BUS_NAME);
|
||||
|
||||
ASSERT_NO_THROW(TestAdaptor adaptor(*connection, OBJECT_PATH));
|
||||
ASSERT_NO_THROW(TestProxy proxy(BUS_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>);
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
|
||||
{
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
});
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(matchingMessageReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot)
|
||||
{
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
});
|
||||
slot.reset();
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_FALSE(this->waitUntil(matchingMessageReceived, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(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);
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
[[maybe_unused]] auto gotMessage = this->waitUntil(matchingMessageReceived, 2s);
|
||||
assert(gotMessage);
|
||||
matchingMessageReceived = false;
|
||||
|
||||
con.reset();
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_FALSE(this->waitUntil(matchingMessageReceived, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule)
|
||||
{
|
||||
auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'";
|
||||
std::atomic<size_t> numberOfMatchingMessages{};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
|
||||
{
|
||||
if(msg.getMemberName() == "simpleSignal")
|
||||
numberOfMatchingMessages++;
|
||||
});
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
|
||||
this->m_adaptor->emitSignalWithMap({});
|
||||
adaptor2->emitSimpleSignal();
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil([&](){ return numberOfMatchingMessages == 2; }));
|
||||
ASSERT_FALSE(this->waitUntil([&](){ return numberOfMatchingMessages > 2; }, 1s));
|
||||
}
|
281
backup/tests/integrationtests/DBusMethodsTests.cpp
Normal file
281
backup/tests/integrationtests/DBusMethodsTests.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusMethodsTests.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::Le;
|
||||
using ::testing::AnyOf;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::NotNull;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsEmptyMethodSuccesfully)
|
||||
{
|
||||
ASSERT_NO_THROW(this->m_proxy->noArgNoReturn());
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully)
|
||||
{
|
||||
auto resInt = this->m_proxy->getInt();
|
||||
ASSERT_THAT(resInt, Eq(INT32_VALUE));
|
||||
|
||||
auto multiplyRes = this->m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
|
||||
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithTuplesSuccesfully)
|
||||
{
|
||||
auto resTuple = this->m_proxy->getTuple();
|
||||
ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE));
|
||||
ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccesfully)
|
||||
{
|
||||
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
|
||||
auto vectorRes = this->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 = this->m_proxy->getInts16FromStruct(b);
|
||||
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccesfully)
|
||||
{
|
||||
sdbus::Variant v{DOUBLE_VALUE};
|
||||
sdbus::Variant variantRes = this->m_proxy->processVariant(v);
|
||||
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
|
||||
{
|
||||
std::vector<int32_t> x{-2, 0, 2};
|
||||
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
|
||||
std::map<int32_t, sdbus::Variant> mapOfVariants = this->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>()));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStructInStructSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->getStructInStruct();
|
||||
ASSERT_THAT(val.template get<0>(), Eq(STRING_VALUE));
|
||||
ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->sumStructItems({1, 2}, {3, 4});
|
||||
ASSERT_THAT(val, Eq(1 + 2 + 3 + 4));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->sumVectorItems({1, 7}, {2, 3});
|
||||
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
|
||||
{
|
||||
auto resSignature = this->m_proxy->getSignature();
|
||||
ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithObjectPathSuccesfully)
|
||||
{
|
||||
auto resObjectPath = this->m_proxy->getObjPath();
|
||||
ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithUnixFdSuccesfully)
|
||||
{
|
||||
auto resUnixFd = this->m_proxy->getUnixFd();
|
||||
ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
|
||||
{
|
||||
auto resComplex = this->m_proxy->getComplex();
|
||||
ASSERT_THAT(resComplex.count(0), Eq(1));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
|
||||
{
|
||||
this->m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE);
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_adaptor->m_wasMultiplyCalled));
|
||||
ASSERT_THAT(this->m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully)
|
||||
{
|
||||
auto res = this->m_proxy->doOperationWithTimeout(500ms, (20ms).count()); // The operation will take 20ms, but the timeout is 500ms, so we are fine
|
||||
ASSERT_THAT(res, Eq(20));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
try
|
||||
{
|
||||
this->m_proxy->doOperationWithTimeout(1us, (1s).count()); // The operation will take 1s, but the timeout is 1us, 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"));
|
||||
auto measuredTimeout = std::chrono::steady_clock::now() - start;
|
||||
ASSERT_THAT(measuredTimeout, Le(50ms));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
FAIL() << "Expected sdbus::Error exception";
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodThatThrowsError)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->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";
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet)
|
||||
{
|
||||
ASSERT_NO_THROW(this->m_proxy->throwErrorWithNoReply());
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_adaptor->m_wasThrowErrorCalled));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingNonexistentMethod)
|
||||
{
|
||||
ASSERT_THROW(this->m_proxy->callNonexistentMethod(), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentInterface)
|
||||
{
|
||||
ASSERT_THROW(this->m_proxy->callMethodOnNonexistentInterface(), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
|
||||
{
|
||||
TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
|
||||
ASSERT_THROW(proxy.getInt(), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
|
||||
{
|
||||
TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist");
|
||||
ASSERT_THROW(proxy.getInt(), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
|
||||
{
|
||||
this->m_proxy->emitTwoSimpleSignals();
|
||||
|
||||
EXPECT_TRUE(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
|
||||
EXPECT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInMethodCallHandler)
|
||||
{
|
||||
this->m_proxy->doOperation(10); // This will save pointer to method call message on server side
|
||||
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperation"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCallHandler)
|
||||
{
|
||||
this->m_proxy->doOperationAsync(10); // This will save pointer to method call message on server side
|
||||
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperationAsync"));
|
||||
}
|
||||
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
TYPED_TEST(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239)
|
||||
{
|
||||
this->s_adaptorConnection->setMethodCallTimeout(5000000);
|
||||
ASSERT_THAT(this->s_adaptorConnection->getMethodCallTimeout(), Eq(5000000));
|
||||
}
|
||||
#else
|
||||
TYPED_TEST(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240)
|
||||
{
|
||||
ASSERT_THROW(this->s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error);
|
||||
ASSERT_THROW(this->s_adaptorConnection->getMethodCallTimeout(), sdbus::Error);
|
||||
}
|
||||
#endif
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
{
|
||||
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));
|
||||
}
|
83
backup/tests/integrationtests/DBusPropertiesTests.cpp
Normal file
83
backup/tests/integrationtests/DBusPropertiesTests.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusPropertiesTests.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 ::testing::NotNull;
|
||||
using ::testing::Not;
|
||||
using ::testing::IsEmpty;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
|
||||
{
|
||||
ASSERT_THAT(this->m_proxy->state(), Eq(DEFAULT_STATE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsWritingToReadOnlyProperty)
|
||||
{
|
||||
ASSERT_THROW(this->m_proxy->setStateProperty("new_value"), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
|
||||
{
|
||||
uint32_t newActionValue = 5678;
|
||||
|
||||
this->m_proxy->action(newActionValue);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHandler)
|
||||
{
|
||||
this->m_proxy->blocking(true); // This will save pointer to property get message on server side
|
||||
|
||||
ASSERT_THAT(this->m_adaptor->m_propertySetMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_propertySetSender, Not(IsEmpty()));
|
||||
}
|
167
backup/tests/integrationtests/DBusSignalsTests.cpp
Normal file
167
backup/tests/integrationtests/DBusSignalsTests.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.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 <chrono>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::DoubleEq;
|
||||
using ::testing::Gt;
|
||||
using ::testing::AnyOf;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::NotNull;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
|
||||
{
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
|
||||
ASSERT_TRUE(this->waitUntil(proxy1->m_gotSimpleSignal));
|
||||
ASSERT_TRUE(this->waitUntil(proxy2->m_gotSimpleSignal));
|
||||
}
|
||||
|
||||
TYPED_TEST(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(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithMapSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("zero"));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("one"));
|
||||
}
|
||||
|
||||
TYPED_TEST(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));
|
||||
this->m_adaptor->emitSignalWithMap(largeMap);
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1"));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
|
||||
{
|
||||
double d = 3.14;
|
||||
this->m_adaptor->emitSignalWithVariant(d);
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithVariant));
|
||||
ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(d));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}});
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithSignature));
|
||||
ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq("av"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
|
||||
{
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
this->waitUntil(this->m_proxy->m_gotSimpleSignal);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->m_signalMsg, NotNull());
|
||||
ASSERT_THAT(this->m_proxy->m_signalMemberName, Eq("simpleSignal"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, UnregistersSignalHandler)
|
||||
{
|
||||
ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler());
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_FALSE(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, UnregistersSignalHandlerForSomeProxies)
|
||||
{
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler());
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(proxy1->m_gotSimpleSignal));
|
||||
ASSERT_TRUE(this->waitUntil(proxy2->m_gotSimpleSignal));
|
||||
ASSERT_FALSE(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ReRegistersSignalHandler)
|
||||
{
|
||||
// unregister simple-signal handler
|
||||
ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler());
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_FALSE(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 1s));
|
||||
|
||||
// re-register simple-signal handler
|
||||
ASSERT_NO_THROW(this->m_proxy->reRegisterSimpleSignalHandler());
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
|
||||
}
|
268
backup/tests/integrationtests/DBusStandardInterfacesTests.cpp
Normal file
268
backup/tests/integrationtests/DBusStandardInterfacesTests.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusStandardInterfacesTests.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;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, PingsViaPeerInterface)
|
||||
{
|
||||
ASSERT_NO_THROW(this->m_proxy->Ping());
|
||||
}
|
||||
|
||||
TYPED_TEST(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(this->m_proxy->GetMachineId());
|
||||
}
|
||||
|
||||
// TODO: Adjust expected xml and uncomment this test
|
||||
//TYPED_TEST(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface)
|
||||
//{
|
||||
// ASSERT_THAT(this->m_proxy->Introspect(), Eq(this->m_adaptor->getExpectedXmlApiDescription()));
|
||||
//}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsPropertyViaPropertiesInterface)
|
||||
{
|
||||
ASSERT_THAT(this->m_proxy->Get(INTERFACE_NAME, "state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
|
||||
{
|
||||
uint32_t newActionValue = 2345;
|
||||
|
||||
this->m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
|
||||
{
|
||||
const auto properties = this->m_proxy->GetAll(INTERFACE_NAME);
|
||||
|
||||
ASSERT_THAT(properties, SizeIs(3));
|
||||
EXPECT_THAT(properties.at("state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at("blocking").template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->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;
|
||||
};
|
||||
|
||||
this->m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
|
||||
this->m_proxy->action(DEFAULT_ACTION_VALUE*2);
|
||||
this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"});
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->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;
|
||||
};
|
||||
|
||||
this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME);
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
|
||||
{
|
||||
this->m_adaptor.reset();
|
||||
const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects();
|
||||
|
||||
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsManagedObjectsSuccessfully)
|
||||
{
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects();
|
||||
|
||||
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
|
||||
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH)
|
||||
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
|
||||
.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2)
|
||||
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
|
||||
.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->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;
|
||||
};
|
||||
|
||||
this->m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME});
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->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));
|
||||
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;
|
||||
};
|
||||
|
||||
this->m_adaptor->emitInterfacesAddedSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->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;
|
||||
};
|
||||
|
||||
this->m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME});
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
|
||||
{
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->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;
|
||||
};
|
||||
|
||||
this->m_adaptor->emitInterfacesRemovedSignal();
|
||||
|
||||
ASSERT_TRUE(this->waitUntil(signalReceived));
|
||||
}
|
73
backup/tests/integrationtests/Defs.h
Normal file
73
backup/tests/integrationtests/Defs.h
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Defs.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_
|
||||
#define SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_
|
||||
|
||||
#include "sdbus-c++/Types.h"
|
||||
#include <chrono>
|
||||
#include <ostream>
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
const std::string INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
|
||||
const std::string BUS_NAME = INTERFACE_NAME;
|
||||
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"};
|
||||
|
||||
constexpr const uint8_t UINT8_VALUE{1};
|
||||
constexpr const int16_t INT16_VALUE{21};
|
||||
constexpr const uint32_t UINT32_VALUE{42};
|
||||
constexpr const int32_t INT32_VALUE{-42};
|
||||
constexpr const int32_t INT64_VALUE{-1024};
|
||||
|
||||
const std::string STRING_VALUE{"sdbus-c++-testing"};
|
||||
const sdbus::Signature SIGNATURE_VALUE{"a{is}"};
|
||||
const sdbus::ObjectPath OBJECT_PATH_VALUE{"/"};
|
||||
const int UNIX_FD_VALUE = 0;
|
||||
|
||||
const std::string DEFAULT_STATE_VALUE{"default-state-value"};
|
||||
const uint32_t DEFAULT_ACTION_VALUE{999};
|
||||
const bool DEFAULT_BLOCKING_VALUE{true};
|
||||
|
||||
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_ */
|
426
backup/tests/integrationtests/TestAdaptor.cpp
Normal file
426
backup/tests/integrationtests/TestAdaptor.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestAdaptor.cpp
|
||||
*
|
||||
* Created on: May 23, 2020
|
||||
* 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 "TestAdaptor.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
TestAdaptor::TestAdaptor(sdbus::IConnection& connection, const std::string& path) :
|
||||
AdaptorInterfaces(connection, path)
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
TestAdaptor::~TestAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
void TestAdaptor::noArgNoReturn()
|
||||
{
|
||||
}
|
||||
|
||||
int32_t TestAdaptor::getInt()
|
||||
{
|
||||
return INT32_VALUE;
|
||||
}
|
||||
|
||||
std::tuple<uint32_t, std::string> TestAdaptor::getTuple()
|
||||
{
|
||||
return std::make_tuple(UINT32_VALUE, STRING_VALUE);
|
||||
}
|
||||
|
||||
double TestAdaptor::multiply(const int64_t& a, const double& b)
|
||||
{
|
||||
return a * b;
|
||||
}
|
||||
|
||||
void TestAdaptor::multiplyWithNoReply(const int64_t& a, const double& b)
|
||||
{
|
||||
m_multiplyResult = a * b;
|
||||
m_wasMultiplyCalled = true;
|
||||
}
|
||||
|
||||
std::vector<int16_t> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
|
||||
{
|
||||
std::vector<int16_t> res{x.get<1>()};
|
||||
auto y = std::get<std::vector<int16_t>>(x);
|
||||
res.insert(res.end(), y.begin(), y.end());
|
||||
return res;
|
||||
}
|
||||
|
||||
sdbus::Variant TestAdaptor::processVariant(const sdbus::Variant& v)
|
||||
{
|
||||
sdbus::Variant res = static_cast<int32_t>(v.get<double>());
|
||||
return res;
|
||||
}
|
||||
|
||||
std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
|
||||
{
|
||||
std::map<int32_t, sdbus::Variant> res;
|
||||
for (auto item : x)
|
||||
{
|
||||
res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> TestAdaptor::getStructInStruct()
|
||||
{
|
||||
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)
|
||||
{
|
||||
int32_t res{0};
|
||||
res += std::get<0>(a) + std::get<1>(a);
|
||||
res += std::get<0>(b) + std::get<1>(b);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t TestAdaptor::sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b)
|
||||
{
|
||||
uint32_t res{0};
|
||||
for (auto x : a)
|
||||
{
|
||||
res += x;
|
||||
}
|
||||
for (auto x : b)
|
||||
{
|
||||
res += x;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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
|
||||
result.returnResults(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process asynchronously in another thread and return the result from there
|
||||
std::thread([param, result = std::move(result)]()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(param));
|
||||
result.returnResults(param);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
sdbus::Signature TestAdaptor::getSignature()
|
||||
{
|
||||
return SIGNATURE_VALUE;
|
||||
}
|
||||
sdbus::ObjectPath TestAdaptor::getObjPath()
|
||||
{
|
||||
return OBJECT_PATH_VALUE;
|
||||
}
|
||||
sdbus::UnixFd TestAdaptor::getUnixFd()
|
||||
{
|
||||
return sdbus::UnixFd{UNIX_FD_VALUE};
|
||||
}
|
||||
|
||||
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 { // map
|
||||
{
|
||||
0, // uint_64_t
|
||||
{ // struct
|
||||
{ // map
|
||||
{
|
||||
23, // uint8_t
|
||||
{ // vector
|
||||
{ // struct
|
||||
"/object/path", // object path
|
||||
false,
|
||||
Variant{3.14},
|
||||
{ // map
|
||||
{0, "zero"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"a{t(a{ya(obva{is})}gs)}", // signature
|
||||
std::string{}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void TestAdaptor::throwError()
|
||||
{
|
||||
m_wasThrowErrorCalled = true;
|
||||
throw sdbus::createError(1, "A test error occurred");
|
||||
}
|
||||
|
||||
void TestAdaptor::throwErrorWithNoReply()
|
||||
{
|
||||
TestAdaptor::throwError();
|
||||
}
|
||||
|
||||
void TestAdaptor::doPrivilegedStuff()
|
||||
{
|
||||
// Intentionally left blank
|
||||
}
|
||||
|
||||
void TestAdaptor::emitTwoSimpleSignals()
|
||||
{
|
||||
emitSimpleSignal();
|
||||
emitSignalWithMap({});
|
||||
}
|
||||
|
||||
std::string TestAdaptor::state()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
uint32_t TestAdaptor::action()
|
||||
{
|
||||
return m_action;
|
||||
}
|
||||
|
||||
void TestAdaptor::action(const uint32_t& value)
|
||||
{
|
||||
m_action = value;
|
||||
}
|
||||
|
||||
bool TestAdaptor::blocking()
|
||||
{
|
||||
return m_blocking;
|
||||
}
|
||||
|
||||
void TestAdaptor::blocking(const bool& value)
|
||||
{
|
||||
m_propertySetMsg = getObject().getCurrentlyProcessedMessage();
|
||||
m_propertySetSender = m_propertySetMsg->getSender();
|
||||
|
||||
m_blocking = value;
|
||||
}
|
||||
|
||||
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
|
||||
{
|
||||
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(s);
|
||||
}
|
||||
|
||||
std::string TestAdaptor::getExpectedXmlApiDescription() const
|
||||
{
|
||||
return
|
||||
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Peer">
|
||||
<method name="Ping"/>
|
||||
<method name="GetMachineId">
|
||||
<arg type="s" name="machine_uuid" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="data" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="out" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="properties" direction="out" type="a{sv}"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="in" type="v"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg type="s" name="interface"/>
|
||||
<arg type="a{sv}" name="changed_properties"/>
|
||||
<arg type="as" name="invalidated_properties"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.ObjectManager">
|
||||
<method name="GetManagedObjects">
|
||||
<arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
|
||||
</method>
|
||||
<signal name="InterfacesAdded">
|
||||
<arg type="o" name="object_path"/>
|
||||
<arg type="a{sa{sv}}" name="interfaces_and_properties"/>
|
||||
</signal>
|
||||
<signal name="InterfacesRemoved">
|
||||
<arg type="o" name="object_path"/>
|
||||
<arg type="as" name="interfaces"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.sdbuscpp.integrationtests">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<method name="doOperation">
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="doOperationAsync">
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="doPrivilegedStuff">
|
||||
<annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
|
||||
</method>
|
||||
<method name="emitTwoSimpleSignals">
|
||||
</method>
|
||||
<method name="getComplex">
|
||||
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</method>
|
||||
<method name="getInt">)delimiter"
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
R"delimiter(
|
||||
<arg type="i" name="anInt" direction="out"/>)delimiter"
|
||||
#else
|
||||
R"delimiter(
|
||||
<arg type="i" direction="out"/>)delimiter"
|
||||
#endif
|
||||
R"delimiter(
|
||||
</method>
|
||||
<method name="getInts16FromStruct">
|
||||
<arg type="(yndsan)" direction="in"/>
|
||||
<arg type="an" direction="out"/>
|
||||
</method>
|
||||
<method name="getMapOfVariants">)delimiter"
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
R"delimiter(
|
||||
<arg type="ai" name="x" direction="in"/>
|
||||
<arg type="(vv)" name="y" direction="in"/>
|
||||
<arg type="a{iv}" name="aMapOfVariants" direction="out"/>)delimiter"
|
||||
#else
|
||||
R"delimiter(
|
||||
<arg type="ai" direction="in"/>
|
||||
<arg type="(vv)" direction="in"/>
|
||||
<arg type="a{iv}" direction="out"/>)delimiter"
|
||||
#endif
|
||||
R"delimiter(
|
||||
</method>
|
||||
<method name="getObjPath">
|
||||
<arg type="o" direction="out"/>
|
||||
</method>
|
||||
<method name="getSignature">
|
||||
<arg type="g" direction="out"/>
|
||||
</method>
|
||||
<method name="getStructInStruct">
|
||||
<arg type="(s(a{ii}))" direction="out"/>
|
||||
</method>
|
||||
<method name="getTuple">
|
||||
<arg type="u" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="getUnixFd">
|
||||
<arg type="h" direction="out"/>
|
||||
</method>
|
||||
<method name="multiply">)delimiter"
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
R"delimiter(
|
||||
<arg type="x" name="a" direction="in"/>
|
||||
<arg type="d" name="b" direction="in"/>
|
||||
<arg type="d" name="result" direction="out"/>)delimiter"
|
||||
#else
|
||||
R"delimiter(
|
||||
<arg type="x" direction="in"/>
|
||||
<arg type="d" direction="in"/>
|
||||
<arg type="d" direction="out"/>)delimiter"
|
||||
#endif
|
||||
R"delimiter(
|
||||
</method>
|
||||
<method name="multiplyWithNoReply">
|
||||
<arg type="x" direction="in"/>
|
||||
<arg type="d" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="noArgNoReturn">
|
||||
</method>
|
||||
<method name="processVariant">
|
||||
<arg type="v" direction="in"/>
|
||||
<arg type="v" direction="out"/>
|
||||
</method>
|
||||
<method name="sumStructItems">
|
||||
<arg type="(yq)" direction="in"/>
|
||||
<arg type="(ix)" direction="in"/>
|
||||
<arg type="i" direction="out"/>
|
||||
</method>
|
||||
<method name="sumVectorItems">
|
||||
<arg type="aq" direction="in"/>
|
||||
<arg type="at" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="throwError">
|
||||
</method>
|
||||
<method name="throwErrorWithNoReply">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<signal name="signalWithMap">
|
||||
<arg type="a{is}"/>
|
||||
</signal>
|
||||
<signal name="signalWithVariant">
|
||||
<arg type="v"/>
|
||||
</signal>
|
||||
<signal name="simpleSignal">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</signal>
|
||||
<property name="action" type="u" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
|
||||
</property>
|
||||
<property name="blocking" type="b" access="readwrite">
|
||||
</property>
|
||||
<property name="state" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>
|
||||
)delimiter";
|
||||
}
|
||||
|
||||
}}
|
151
backup/tests/integrationtests/TestAdaptor.h
Normal file
151
backup/tests/integrationtests/TestAdaptor.h
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestAdaptor.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_
|
||||
#define SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_
|
||||
|
||||
#include "integrationtests-adaptor.h"
|
||||
#include "Defs.h"
|
||||
#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 >
|
||||
{
|
||||
public:
|
||||
TestAdaptor(sdbus::IConnection& connection, const std::string& path);
|
||||
~TestAdaptor();
|
||||
|
||||
protected:
|
||||
void noArgNoReturn() override;
|
||||
int32_t getInt() override;
|
||||
std::tuple<uint32_t, std::string> getTuple() override;
|
||||
double multiply(const int64_t& a, const double& b) override;
|
||||
void multiplyWithNoReply(const int64_t& a, const double& b) override;
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) override;
|
||||
sdbus::Variant processVariant(const sdbus::Variant& variant) override;
|
||||
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 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::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;
|
||||
void emitTwoSimpleSignals() override;
|
||||
|
||||
uint32_t action() override;
|
||||
void action(const uint32_t& value) override;
|
||||
bool blocking() override;
|
||||
void blocking(const bool& value) override;
|
||||
std::string state() override;
|
||||
|
||||
public:
|
||||
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
|
||||
std::string getExpectedXmlApiDescription() const;
|
||||
|
||||
private:
|
||||
const std::string m_state{DEFAULT_STATE_VALUE};
|
||||
uint32_t m_action{DEFAULT_ACTION_VALUE};
|
||||
bool m_blocking{DEFAULT_BLOCKING_VALUE};
|
||||
|
||||
public: // for tests
|
||||
// For dont-expect-reply method call verifications
|
||||
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 sumVectorItems(const std::vector<uint16_t>&, const std::vector<uint64_t>&) 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::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 {}; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INTEGRATIONTESTS_TESTADAPTOR_H_ */
|
40
backup/tests/integrationtests/TestFixture.cpp
Normal file
40
backup/tests/integrationtests/TestFixture.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestFixture.cpp
|
||||
*
|
||||
* Created on: May 23, 2020
|
||||
* 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"
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_adaptorConnection = sdbus::createSystemBusConnection();
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_proxyConnection = sdbus::createSystemBusConnection();
|
||||
|
||||
std::thread TestFixture<SdEventLoop>::s_adaptorEventLoopThread{};
|
||||
std::thread TestFixture<SdEventLoop>::s_proxyEventLoopThread{};
|
||||
sd_event *TestFixture<SdEventLoop>::s_adaptorSdEvent{};
|
||||
sd_event *TestFixture<SdEventLoop>::s_proxySdEvent{};
|
||||
int TestFixture<SdEventLoop>::s_eventExitFd{-1};
|
||||
|
||||
}}
|
205
backup/tests/integrationtests/TestFixture.h
Normal file
205
backup/tests/integrationtests/TestFixture.h
Normal file
@ -0,0 +1,205 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestFixture.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_
|
||||
#define SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_
|
||||
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "Defs.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
class BaseTestFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
s_adaptorConnection->requestName(BUS_NAME);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
s_adaptorConnection->releaseName(BUS_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);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_proxy.reset();
|
||||
m_adaptor.reset();
|
||||
}
|
||||
|
||||
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;
|
||||
std::unique_ptr<TestAdaptor> m_adaptor;
|
||||
std::unique_ptr<TestProxy> m_proxy;
|
||||
};
|
||||
|
||||
struct SdBusCppLoop{};
|
||||
struct SdEventLoop{};
|
||||
|
||||
template <typename _EventLoop>
|
||||
class TestFixture : public BaseTestFixture{};
|
||||
|
||||
// Fixture working upon internal sdbus-c++ event loop
|
||||
template <>
|
||||
class TestFixture<SdBusCppLoop> : public BaseTestFixture
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
BaseTestFixture::SetUpTestCase();
|
||||
s_proxyConnection->enterEventLoopAsync();
|
||||
s_adaptorConnection->enterEventLoopAsync();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
BaseTestFixture::TearDownTestCase();
|
||||
s_adaptorConnection->leaveEventLoop();
|
||||
s_proxyConnection->leaveEventLoop();
|
||||
}
|
||||
};
|
||||
|
||||
// Fixture working upon attached external sd-event loop
|
||||
template <>
|
||||
class TestFixture<SdEventLoop> : public BaseTestFixture
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
sd_event_new(&s_adaptorSdEvent);
|
||||
sd_event_new(&s_proxySdEvent);
|
||||
|
||||
s_adaptorConnection->attachSdEventLoop(s_adaptorSdEvent);
|
||||
s_proxyConnection->attachSdEventLoop(s_proxySdEvent);
|
||||
|
||||
s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
// No callback means that the event loop will exit when this event source triggers
|
||||
sd_event_add_io(s_adaptorSdEvent, nullptr, s_eventExitFd, EPOLLIN, nullptr, NULL);
|
||||
sd_event_add_io(s_proxySdEvent, nullptr, s_eventExitFd, EPOLLIN, nullptr, NULL);
|
||||
|
||||
s_adaptorEventLoopThread = std::thread([]()
|
||||
{
|
||||
sd_event_loop(s_adaptorSdEvent);
|
||||
});
|
||||
s_proxyEventLoopThread = std::thread([]()
|
||||
{
|
||||
sd_event_loop(s_proxySdEvent);
|
||||
});
|
||||
|
||||
BaseTestFixture::SetUpTestCase();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
uint64_t value = 1;
|
||||
write(s_eventExitFd, &value, sizeof(value));
|
||||
|
||||
s_adaptorEventLoopThread.join();
|
||||
s_proxyEventLoopThread.join();
|
||||
|
||||
sd_event_unref(s_adaptorSdEvent);
|
||||
sd_event_unref(s_proxySdEvent);
|
||||
close(s_eventExitFd);
|
||||
|
||||
BaseTestFixture::TearDownTestCase();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::thread s_adaptorEventLoopThread;
|
||||
static std::thread s_proxyEventLoopThread;
|
||||
static sd_event *s_adaptorSdEvent;
|
||||
static sd_event *s_proxySdEvent;
|
||||
static int s_eventExitFd;
|
||||
};
|
||||
|
||||
typedef ::testing::Types<SdBusCppLoop, SdEventLoop> EventLoopTags;
|
||||
|
||||
TYPED_TEST_SUITE(TestFixture, EventLoopTags);
|
||||
|
||||
template <typename _EventLoop>
|
||||
using SdbusTestObject = TestFixture<_EventLoop>;
|
||||
TYPED_TEST_SUITE(SdbusTestObject, EventLoopTags);
|
||||
|
||||
template <typename _EventLoop>
|
||||
using AsyncSdbusTestObject = TestFixture<_EventLoop>;
|
||||
TYPED_TEST_SUITE(AsyncSdbusTestObject, EventLoopTags);
|
||||
|
||||
template <typename _EventLoop>
|
||||
using AConnection = TestFixture<_EventLoop>;
|
||||
TYPED_TEST_SUITE(AConnection, EventLoopTags);
|
||||
|
||||
}}
|
||||
|
||||
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */
|
168
backup/tests/integrationtests/TestProxy.cpp
Normal file
168
backup/tests/integrationtests/TestProxy.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestProxy.cpp
|
||||
*
|
||||
* Created on: May 23, 2020
|
||||
* 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 "TestProxy.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
TestProxy::TestProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath))
|
||||
{
|
||||
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
|
||||
|
||||
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))
|
||||
{
|
||||
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
|
||||
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
TestProxy::~TestProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
void TestProxy::onSimpleSignal()
|
||||
{
|
||||
m_signalMsg = getProxy().getCurrentlyProcessedMessage();
|
||||
m_signalMemberName = m_signalMsg->getMemberName();
|
||||
|
||||
m_gotSimpleSignal = true;
|
||||
}
|
||||
|
||||
void TestProxy::onSignalWithMap(const std::map<int32_t, std::string>& aMap)
|
||||
{
|
||||
m_mapFromSignal = aMap;
|
||||
m_gotSignalWithMap = true;
|
||||
}
|
||||
|
||||
void TestProxy::onSignalWithVariant(const sdbus::Variant& aVariant)
|
||||
{
|
||||
m_variantFromSignal = aVariant.get<double>();
|
||||
m_gotSignalWithVariant = true;
|
||||
}
|
||||
|
||||
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
|
||||
{
|
||||
m_signatureFromSignal[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
|
||||
m_gotSignalWithSignature = true;
|
||||
}
|
||||
|
||||
void TestProxy::onDoOperationReply(uint32_t returnValue, const sdbus::Error* error)
|
||||
{
|
||||
if (m_DoOperationClientSideAsyncReplyHandler)
|
||||
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
|
||||
}
|
||||
|
||||
void TestProxy::onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties )
|
||||
{
|
||||
if (m_onPropertiesChangedHandler)
|
||||
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
uint32_t result;
|
||||
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(timeout).withArguments(param).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperation")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.withArguments(param)
|
||||
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
|
||||
{
|
||||
this->onDoOperationReply(returnValue, error);
|
||||
});
|
||||
}
|
||||
|
||||
void TestProxy::doErroneousOperationClientSideAsync()
|
||||
{
|
||||
getProxy().callMethodAsync("throwError")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.uponReplyInvoke([this](const sdbus::Error* error)
|
||||
{
|
||||
this->onDoOperationReply(0, error);
|
||||
});
|
||||
}
|
||||
|
||||
void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
getProxy().callMethodAsync("doOperation")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.withTimeout(timeout)
|
||||
.withArguments(param)
|
||||
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
|
||||
{
|
||||
this->onDoOperationReply(returnValue, error);
|
||||
});
|
||||
}
|
||||
|
||||
int32_t TestProxy::callNonexistentMethod()
|
||||
{
|
||||
int32_t result;
|
||||
getProxy().callMethod("callNonexistentMethod").onInterface(sdbus::test::INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t TestProxy::callMethodOnNonexistentInterface()
|
||||
{
|
||||
int32_t result;
|
||||
getProxy().callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void TestProxy::setStateProperty(const std::string& value)
|
||||
{
|
||||
getProxy().setProperty("state").onInterface(sdbus::test::INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
}}
|
146
backup/tests/integrationtests/TestProxy.h
Normal file
146
backup/tests/integrationtests/TestProxy.h
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestProxy.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_
|
||||
#define SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_
|
||||
|
||||
#include "integrationtests-proxy.h"
|
||||
#include "Defs.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
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 >
|
||||
{
|
||||
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();
|
||||
|
||||
protected:
|
||||
void onSimpleSignal() override;
|
||||
void onSignalWithMap(const std::map<int32_t, std::string>& aMap) override;
|
||||
void onSignalWithVariant(const sdbus::Variant& aVariant) override;
|
||||
|
||||
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
|
||||
void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error);
|
||||
|
||||
// Signals of standard D-Bus interfaces
|
||||
void onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties ) 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);
|
||||
sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param);
|
||||
void doErroneousOperationClientSideAsync();
|
||||
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||
int32_t callNonexistentMethod();
|
||||
int32_t callMethodOnNonexistentInterface();
|
||||
void setStateProperty(const std::string& value);
|
||||
|
||||
//private:
|
||||
public: // for tests
|
||||
int m_SimpleSignals = 0;
|
||||
std::atomic<bool> m_gotSimpleSignal{false};
|
||||
std::atomic<bool> m_gotSignalWithMap{false};
|
||||
std::map<int32_t, std::string> m_mapFromSignal;
|
||||
std::atomic<bool> m_gotSignalWithVariant{false};
|
||||
double m_variantFromSignal;
|
||||
std::atomic<bool> m_gotSignalWithSignature{false};
|
||||
std::map<std::string, std::string> m_signatureFromSignal;
|
||||
|
||||
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 {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */
|
@ -0,0 +1,20 @@
|
||||
<!-- This configuration file specifies the required security policies
|
||||
for the Kistler DBUS example to run core daemon to work. -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
|
||||
<!-- ../system.conf have denied everything, so we just punch some holes -->
|
||||
|
||||
<policy context="default">
|
||||
<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>
|
||||
|
114
backup/tests/integrationtests/integrationtests-adaptor.h
Normal file
114
backup/tests/integrationtests/integrationtests-adaptor.h
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__integrationtests_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp__integrationtests_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
|
||||
class integrationtests_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests";
|
||||
|
||||
protected:
|
||||
integrationtests_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
object_->registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
|
||||
object_->registerMethod("getInt").onInterface(INTERFACE_NAME).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(); })/*.withNoReply()*/;
|
||||
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);
|
||||
}
|
||||
|
||||
void emitSignalWithMap(const std::map<int32_t, std::string>& aMap)
|
||||
{
|
||||
object_->emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
|
||||
}
|
||||
|
||||
void emitSignalWithVariant(const sdbus::Variant& aVariant)
|
||||
{
|
||||
object_->emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void noArgNoReturn() = 0;
|
||||
virtual int32_t getInt() = 0;
|
||||
virtual std::tuple<uint32_t, std::string> getTuple() = 0;
|
||||
virtual double multiply(const int64_t& a, const double& b) = 0;
|
||||
virtual void multiplyWithNoReply(const int64_t& a, const double& b) = 0;
|
||||
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) = 0;
|
||||
virtual sdbus::Variant processVariant(const sdbus::Variant& variant) = 0;
|
||||
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 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::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;
|
||||
virtual void emitTwoSimpleSignals() = 0;
|
||||
|
||||
private:
|
||||
virtual uint32_t action() = 0;
|
||||
virtual void action(const uint32_t& value) = 0;
|
||||
virtual bool blocking() = 0;
|
||||
virtual void blocking(const bool& value) = 0;
|
||||
virtual std::string state() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
220
backup/tests/integrationtests/integrationtests-proxy.h
Normal file
220
backup/tests/integrationtests/integrationtests-proxy.h
Normal file
@ -0,0 +1,220 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__integrationtests_proxy_h__proxy__H__
|
||||
#define __sdbuscpp__integrationtests_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
|
||||
class integrationtests_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests";
|
||||
|
||||
protected:
|
||||
integrationtests_proxy(sdbus::IProxy& 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); });
|
||||
}
|
||||
|
||||
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;
|
||||
virtual void onSignalWithMap(const std::map<int32_t, std::string>& aMap) = 0;
|
||||
virtual void onSignalWithVariant(const sdbus::Variant& aVariant) = 0;
|
||||
|
||||
public:
|
||||
void noArgNoReturn()
|
||||
{
|
||||
proxy_->callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
int32_t getInt()
|
||||
{
|
||||
int32_t 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
double multiply(const int64_t& a, const double& b)
|
||||
{
|
||||
double 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();
|
||||
}
|
||||
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Variant processVariant(const sdbus::Variant& variant)
|
||||
{
|
||||
sdbus::Variant 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);
|
||||
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);
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1)
|
||||
{
|
||||
uint32_t 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperationAsync(const uint32_t& arg0)
|
||||
{
|
||||
uint32_t 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::ObjectPath getObjPath()
|
||||
{
|
||||
sdbus::ObjectPath 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);
|
||||
return 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>> 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>> result;
|
||||
proxy_->callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void throwError()
|
||||
{
|
||||
proxy_->callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void throwErrorWithNoReply()
|
||||
{
|
||||
proxy_->callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
}
|
||||
|
||||
void doPrivilegedStuff()
|
||||
{
|
||||
proxy_->callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void emitTwoSimpleSignals()
|
||||
{
|
||||
proxy_->callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME)/*.dontExpectReply()*/;
|
||||
}
|
||||
|
||||
void unregisterSimpleSignalHandler()
|
||||
{
|
||||
proxy_->muteSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void reRegisterSimpleSignalHandler()
|
||||
{
|
||||
proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
|
||||
proxy_->finishRegistration();
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t action()
|
||||
{
|
||||
return proxy_->getProperty("action").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void action(const uint32_t& value)
|
||||
{
|
||||
proxy_->setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool blocking()
|
||||
{
|
||||
return proxy_->getProperty("blocking").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void blocking(const bool& value)
|
||||
{
|
||||
proxy_->setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
std::string state()
|
||||
{
|
||||
return proxy_->getProperty("state").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
105
backup/tests/integrationtests/org.sdbuscpp.integrationtests.xml
Normal file
105
backup/tests/integrationtests/org.sdbuscpp.integrationtests.xml
Normal file
@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/integrationtest">
|
||||
<interface name="org.sdbuscpp.integrationtests">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false" />
|
||||
<method name="noArgNoReturn">
|
||||
</method>
|
||||
<method name="getInt">
|
||||
<arg type="i" name="anInt" direction="out" />
|
||||
</method>
|
||||
<method name="getTuple">
|
||||
<arg type="u" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
</method>
|
||||
<method name="multiply">
|
||||
<arg type="x" name="a" direction="in" />
|
||||
<arg type="d" name="b" direction="in" />
|
||||
<arg type="d" name="result" direction="out" />
|
||||
</method>
|
||||
<method name="multiplyWithNoReply">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true" />
|
||||
<arg type="x" name="a" direction="in" />
|
||||
<arg type="d" name="b" direction="in" />
|
||||
</method>
|
||||
<method name="getInts16FromStruct">
|
||||
<arg type="(yndsan)" direction="in" />
|
||||
<arg type="an" direction="out" />
|
||||
</method>
|
||||
<method name="processVariant">
|
||||
<arg type="v" name="variant" direction="in" />
|
||||
<arg type="v" name="result" direction="out" />
|
||||
</method>
|
||||
<method name="getMapOfVariants">
|
||||
<arg type="ai" name="x" direction="in" />
|
||||
<arg type="(vv)" name="y" direction="in" />
|
||||
<arg type="a{iv}" name="aMapOfVariants" direction="out" />
|
||||
</method>
|
||||
<method name="getStructInStruct">
|
||||
<arg type="(s(a{ii}))" name="aMapOfVariants" direction="out" />
|
||||
</method>
|
||||
<method name="sumStructItems">
|
||||
<arg type="(yq)" direction="in" />
|
||||
<arg type="(ix)" direction="in" />
|
||||
<arg type="i" direction="out" />
|
||||
</method>
|
||||
<method name="sumVectorItems">
|
||||
<arg type="aq" direction="in" />
|
||||
<arg type="at" direction="in" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<method name="doOperation">
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<method name="doOperationAsync">
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<method name="getSignature">
|
||||
<arg type="g" direction="out" />
|
||||
</method>
|
||||
<method name="getObjPath">
|
||||
<arg type="o" direction="out" />
|
||||
</method>
|
||||
<method name="getUnixFd">
|
||||
<arg type="h" direction="out" />
|
||||
</method>
|
||||
<method name="getComplex">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
|
||||
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out" />
|
||||
</method>
|
||||
<method name="throwError">
|
||||
</method>
|
||||
<method name="throwErrorWithNoReply">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true" />
|
||||
</method>
|
||||
<method name="doPrivilegedStuff">
|
||||
<annotation name="org.freedesktop.systemd1.Privileged" value="true" />
|
||||
</method>
|
||||
<method name="emitTwoSimpleSignals">
|
||||
</method>
|
||||
|
||||
<signal name="simpleSignal">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
|
||||
</signal>
|
||||
<signal name="signalWithMap">
|
||||
<arg type="a{is}" name="aMap" />
|
||||
</signal>
|
||||
<signal name="signalWithVariant">
|
||||
<arg type="v" name="aVariant" />
|
||||
</signal>
|
||||
<property name="action" type="u" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
|
||||
</property>
|
||||
<property name="blocking" type="b" access="readwrite">
|
||||
</property>
|
||||
<property name="state" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file sdbus-c++-integration-tests.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 "gmock/gmock.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleMock(&argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
190
backup/tests/perftests/client.cpp
Normal file
190
backup/tests/perftests/client.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
/**
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file client.cpp
|
||||
*
|
||||
* Created on: Jan 25, 2019
|
||||
* 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 "perftests-proxy.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
uint64_t totalDuration = 0;
|
||||
|
||||
class PerftestProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::perftests_proxy>
|
||||
{
|
||||
public:
|
||||
PerftestProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
~PerftestProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onDataSignal([[maybe_unused]] const std::string& data) override
|
||||
{
|
||||
static unsigned int counter = 0;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> startTime;
|
||||
|
||||
assert(data.size() == m_msgSize);
|
||||
|
||||
++counter;
|
||||
|
||||
if (counter == 1)
|
||||
startTime = std::chrono::steady_clock::now();
|
||||
else if (counter == m_msgCount)
|
||||
{
|
||||
auto stopTime = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
|
||||
totalDuration += duration;
|
||||
std::cout << "Received " << m_msgCount << " signals in: " << duration << " ms" << std::endl;
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int m_msgSize{};
|
||||
unsigned int m_msgCount{};
|
||||
};
|
||||
|
||||
std::string createRandomString(size_t length)
|
||||
{
|
||||
auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[ rand() % max_index ];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
int main(int /*argc*/, char */*argv*/[])
|
||||
{
|
||||
const char* destinationName = "org.sdbuscpp.perftests";
|
||||
const char* objectPath = "/org/sdbuscpp/perftests";
|
||||
PerftestProxy client(destinationName, objectPath);
|
||||
|
||||
const unsigned int repetitions{20};
|
||||
unsigned int msgCount = 1000;
|
||||
unsigned int msgSize{};
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << std::endl << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
assert(result.size() == str1.size() + str2.size());
|
||||
assert(result.size() == msgSize);
|
||||
}
|
||||
auto stopTime = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
|
||||
totalDuration += duration;
|
||||
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
assert(result.size() == str1.size() + str2.size());
|
||||
assert(result.size() == msgSize);
|
||||
}
|
||||
auto stopTime = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
|
||||
totalDuration += duration;
|
||||
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
return 0;
|
||||
}
|
16
backup/tests/perftests/files/org.sdbuscpp.perftests.conf
Normal file
16
backup/tests/perftests/files/org.sdbuscpp.perftests.conf
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- This configuration file specifies the required security policies
|
||||
for the Kistler DBUS example to run core daemon to work. -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
|
||||
<!-- ../system.conf have denied everything, so we just punch some holes -->
|
||||
|
||||
<policy context="default">
|
||||
<allow own="org.sdbuscpp.perftests"/>
|
||||
<allow send_destination="org.sdbuscpp.perftests"/>
|
||||
<allow send_interface="org.sdbuscpp.perftests"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
18
backup/tests/perftests/org.sdbuscpp.perftests.xml
Normal file
18
backup/tests/perftests/org.sdbuscpp.perftests.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/perftest">
|
||||
<interface name="org.sdbuscpp.perftests">
|
||||
<method name="sendDataSignals">
|
||||
<arg type="u" name="numberOfSignals" direction="in" />
|
||||
<arg type="u" name="signalMsgSize" direction="in" />
|
||||
</method>
|
||||
<method name="concatenateTwoStrings">
|
||||
<arg type="s" name="string1" direction="in" />
|
||||
<arg type="s" name="string2" direction="in" />
|
||||
<arg type="s" name="result" direction="out" />
|
||||
</method>
|
||||
<signal name="dataSignal">
|
||||
<arg type="s" name="data" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
53
backup/tests/perftests/perftests-adaptor.h
Normal file
53
backup/tests/perftests/perftests-adaptor.h
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__perftests_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp__perftests_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
|
||||
class perftests_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.perftests";
|
||||
|
||||
protected:
|
||||
perftests_adaptor(sdbus::IObject& 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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) = 0;
|
||||
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
56
backup/tests/perftests/perftests-proxy.h
Normal file
56
backup/tests/perftests/perftests-proxy.h
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__perftests_proxy_h__proxy__H__
|
||||
#define __sdbuscpp__perftests_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
|
||||
class perftests_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.perftests";
|
||||
|
||||
protected:
|
||||
perftests_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
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;
|
||||
|
||||
public:
|
||||
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
101
backup/tests/perftests/server.cpp
Normal file
101
backup/tests/perftests/server.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file server.cpp
|
||||
*
|
||||
* Created on: Jan 25, 2019
|
||||
* 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 "perftests-adaptor.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
std::string createRandomString(size_t length);
|
||||
|
||||
class PerftestAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::perftests_adaptor>
|
||||
{
|
||||
public:
|
||||
PerftestAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
~PerftestAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override
|
||||
{
|
||||
auto data = createRandomString(signalMsgSize);
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
for (uint32_t i = 0; i < numberOfSignals; ++i)
|
||||
{
|
||||
// Emit signal
|
||||
emitDataSignal(data);
|
||||
}
|
||||
auto stop_time = std::chrono::steady_clock::now();
|
||||
std::cout << "Server sent " << numberOfSignals << " signals in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count() << " ms" << std::endl;
|
||||
}
|
||||
|
||||
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override
|
||||
{
|
||||
return string1 + string2;
|
||||
}
|
||||
};
|
||||
|
||||
std::string createRandomString(size_t length)
|
||||
{
|
||||
auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[ rand() % max_index ];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
int main(int /*argc*/, char */*argv*/[])
|
||||
{
|
||||
const char* serviceName = "org.sdbuscpp.perftests";
|
||||
auto connection = sdbus::createSystemBusConnection(serviceName);
|
||||
|
||||
const char* objectPath = "/org/sdbuscpp/perftests";
|
||||
PerftestAdaptor server(*connection, objectPath);
|
||||
|
||||
connection->enterEventLoop();
|
||||
}
|
46
backup/tests/stresstests/celsius-thermometer-adaptor.h
Normal file
46
backup/tests/stresstests/celsius-thermometer-adaptor.h
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__celsius_thermometer_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp__celsius_thermometer_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace celsius {
|
||||
|
||||
class thermometer_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.celsius.thermometer";
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
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_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif
|
50
backup/tests/stresstests/celsius-thermometer-proxy.h
Normal file
50
backup/tests/stresstests/celsius-thermometer-proxy.h
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__celsius_thermometer_proxy_h__proxy__H__
|
||||
#define __sdbuscpp__celsius_thermometer_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace celsius {
|
||||
|
||||
class thermometer_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.celsius.thermometer";
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif
|
52
backup/tests/stresstests/concatenator-adaptor.h
Normal file
52
backup/tests/stresstests/concatenator-adaptor.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__concatenator_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp__concatenator_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
|
||||
class concatenator_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.concatenator";
|
||||
|
||||
protected:
|
||||
concatenator_adaptor(sdbus::IObject& 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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
52
backup/tests/stresstests/concatenator-proxy.h
Normal file
52
backup/tests/stresstests/concatenator-proxy.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__concatenator_proxy_h__proxy__H__
|
||||
#define __sdbuscpp__concatenator_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
|
||||
class concatenator_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.concatenator";
|
||||
|
||||
protected:
|
||||
concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
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;
|
||||
|
||||
virtual void onConcatenateReply(const std::string& result, const sdbus::Error* error) = 0;
|
||||
|
||||
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); });
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
82
backup/tests/stresstests/fahrenheit-thermometer-adaptor.h
Normal file
82
backup/tests/stresstests/fahrenheit-thermometer-adaptor.h
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__fahrenheit_thermometer_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp__fahrenheit_thermometer_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace fahrenheit {
|
||||
|
||||
class thermometer_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.fahrenheit.thermometer";
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
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_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace fahrenheit {
|
||||
namespace thermometer {
|
||||
|
||||
class factory_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.fahrenheit.thermometer.factory";
|
||||
|
||||
protected:
|
||||
factory_adaptor(sdbus::IObject& 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();
|
||||
}
|
||||
|
||||
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:
|
||||
virtual void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) = 0;
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& result, sdbus::ObjectPath delegate) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
|
||||
#endif
|
93
backup/tests/stresstests/fahrenheit-thermometer-proxy.h
Normal file
93
backup/tests/stresstests/fahrenheit-thermometer-proxy.h
Normal file
@ -0,0 +1,93 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__fahrenheit_thermometer_proxy_h__proxy__H__
|
||||
#define __sdbuscpp__fahrenheit_thermometer_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace fahrenheit {
|
||||
|
||||
class thermometer_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.fahrenheit.thermometer";
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace sdbuscpp {
|
||||
namespace stresstests {
|
||||
namespace fahrenheit {
|
||||
namespace thermometer {
|
||||
|
||||
class factory_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.stresstests.fahrenheit.thermometer.factory";
|
||||
|
||||
protected:
|
||||
factory_proxy(sdbus::IProxy& 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
void destroyDelegateObject(const sdbus::ObjectPath& delegate)
|
||||
{
|
||||
proxy_->callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
|
||||
#endif
|
22
backup/tests/stresstests/files/org.sdbuscpp.stresstests.conf
Normal file
22
backup/tests/stresstests/files/org.sdbuscpp.stresstests.conf
Normal file
@ -0,0 +1,22 @@
|
||||
<!-- This configuration file specifies the required security policies
|
||||
for the Kistler DBUS example to run core daemon to work. -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
|
||||
<!-- ../system.conf have denied everything, so we just punch some holes -->
|
||||
|
||||
<policy context="default">
|
||||
<allow own="org.sdbuscpp.stresstests.service1"/>
|
||||
<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"/>
|
||||
<allow send_interface="org.sdbuscpp.stresstests.service2"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/stresstests/celsius/thermometer">
|
||||
<interface name="org.sdbuscpp.stresstests.celsius.thermometer">
|
||||
<method name="getCurrentTemperature">
|
||||
<arg type="u" name="result" direction="out" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/stresstests/concatenator">
|
||||
<interface name="org.sdbuscpp.stresstests.concatenator">
|
||||
<method name="concatenate">
|
||||
<arg type="a{sv}" name="params" direction="in" />
|
||||
<arg type="s" name="result" direction="out" />
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="clientserver" />
|
||||
</method>
|
||||
<signal name="concatenatedSignal">
|
||||
<arg type="s" name="concatenatedString" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/stresstests/fahrenheit/thermometer">
|
||||
<interface name="org.sdbuscpp.stresstests.fahrenheit.thermometer">
|
||||
<method name="getCurrentTemperature">
|
||||
<arg type="u" name="result" direction="out" />
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.sdbuscpp.stresstests.fahrenheit.thermometer.factory">
|
||||
<method name="createDelegateObject">
|
||||
<arg type="o" name="delegate" direction="out" />
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
|
||||
</method>
|
||||
<method name="destroyDelegateObject">
|
||||
<arg type="o" name="delegate" direction="in" />
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
514
backup/tests/stresstests/sdbus-c++-stress-tests.cpp
Normal file
514
backup/tests/stresstests/sdbus-c++-stress-tests.cpp
Normal file
@ -0,0 +1,514 @@
|
||||
/**
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file sdbus-c++-stress-tests.cpp
|
||||
*
|
||||
* Created on: Jan 25, 2019
|
||||
* 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 "celsius-thermometer-adaptor.h"
|
||||
#include "celsius-thermometer-proxy.h"
|
||||
#include "fahrenheit-thermometer-adaptor.h"
|
||||
#include "fahrenheit-thermometer-proxy.h"
|
||||
#include "concatenator-adaptor.h"
|
||||
#include "concatenator-proxy.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::string_literals;
|
||||
|
||||
#define SERVICE_1_BUS_NAME "org.sdbuscpp.stresstests.service1"s
|
||||
#define SERVICE_2_BUS_NAME "org.sdbuscpp.stresstests.service2"s
|
||||
#define CELSIUS_THERMOMETER_OBJECT_PATH "/org/sdbuscpp/stresstests/celsius/thermometer"s
|
||||
#define FAHRENHEIT_THERMOMETER_OBJECT_PATH "/org/sdbuscpp/stresstests/fahrenheit/thermometer"s
|
||||
#define CONCATENATOR_OBJECT_PATH "/org/sdbuscpp/stresstests/concatenator"s
|
||||
|
||||
class CelsiusThermometerAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_adaptor>
|
||||
{
|
||||
public:
|
||||
CelsiusThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
~CelsiusThermometerAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual uint32_t getCurrentTemperature() override
|
||||
{
|
||||
return m_currentTemperature++;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_currentTemperature{};
|
||||
};
|
||||
|
||||
class CelsiusThermometerProxy : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_proxy>
|
||||
{
|
||||
public:
|
||||
CelsiusThermometerProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
~CelsiusThermometerProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
};
|
||||
|
||||
class FahrenheitThermometerAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::stresstests::fahrenheit::thermometer_adaptor
|
||||
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_adaptor >
|
||||
{
|
||||
public:
|
||||
FahrenheitThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath, bool isDelegate)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
, celsiusProxy_(connection, SERVICE_2_BUS_NAME, CELSIUS_THERMOMETER_OBJECT_PATH)
|
||||
{
|
||||
if (!isDelegate)
|
||||
{
|
||||
unsigned int workers = std::thread::hardware_concurrency();
|
||||
if (workers < 4)
|
||||
workers = 4;
|
||||
|
||||
for (unsigned int i = 0; i < workers; ++i)
|
||||
workers_.emplace_back([this]()
|
||||
{
|
||||
//std::cout << "Created FTA worker thread 0x" << std::hex << std::this_thread::get_id() << std::dec << std::endl;
|
||||
|
||||
while(!exit_)
|
||||
{
|
||||
// Pop a work item from the queue
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_.wait(lock, [this]{return !requests_.empty() || exit_;});
|
||||
if (exit_)
|
||||
break;
|
||||
auto request = std::move(requests_.front());
|
||||
requests_.pop();
|
||||
lock.unlock();
|
||||
|
||||
// Either create or destroy a delegate object
|
||||
if (request.delegateObjectPath.empty())
|
||||
{
|
||||
// Create new delegate object
|
||||
auto& connection = getObject().getConnection();
|
||||
sdbus::ObjectPath newObjectPath = FAHRENHEIT_THERMOMETER_OBJECT_PATH + "/" + std::to_string(request.objectNr);
|
||||
|
||||
// Here we are testing dynamic creation of a D-Bus object in an async way
|
||||
auto adaptor = std::make_unique<FahrenheitThermometerAdaptor>(connection, newObjectPath, true);
|
||||
|
||||
std::unique_lock<std::mutex> lock{childrenMutex_};
|
||||
children_.emplace(newObjectPath, std::move(adaptor));
|
||||
lock.unlock();
|
||||
|
||||
request.result.returnResults(newObjectPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destroy existing delegate object
|
||||
// Here we are testing dynamic removal of a D-Bus object in an async way
|
||||
std::lock_guard<std::mutex> lock{childrenMutex_};
|
||||
children_.erase(request.delegateObjectPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
~FahrenheitThermometerAdaptor()
|
||||
{
|
||||
exit_ = true;
|
||||
cond_.notify_all();
|
||||
for (auto& worker : workers_)
|
||||
worker.join();
|
||||
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual uint32_t getCurrentTemperature() override
|
||||
{
|
||||
// In this D-Bus call, make yet another D-Bus call to another service over the same connection
|
||||
return static_cast<uint32_t>(celsiusProxy_.getCurrentTemperature() * 1.8 + 32.);
|
||||
}
|
||||
|
||||
virtual void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) override
|
||||
{
|
||||
static size_t objectCounter{};
|
||||
objectCounter++;
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
requests_.push(WorkItem{objectCounter, std::string{}, std::move(result)});
|
||||
lock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& /*result*/, sdbus::ObjectPath delegate) override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
requests_.push(WorkItem{0, std::move(delegate), {}});
|
||||
lock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
CelsiusThermometerProxy celsiusProxy_;
|
||||
std::map<std::string, std::unique_ptr<FahrenheitThermometerAdaptor>> children_;
|
||||
std::mutex childrenMutex_;
|
||||
|
||||
struct WorkItem
|
||||
{
|
||||
size_t objectNr;
|
||||
sdbus::ObjectPath delegateObjectPath;
|
||||
sdbus::Result<sdbus::ObjectPath> result;
|
||||
};
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_;
|
||||
std::queue<WorkItem> requests_;
|
||||
std::vector<std::thread> workers_;
|
||||
std::atomic<bool> exit_{};
|
||||
};
|
||||
|
||||
class FahrenheitThermometerProxy : public sdbus::ProxyInterfaces< org::sdbuscpp::stresstests::fahrenheit::thermometer_proxy
|
||||
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_proxy >
|
||||
{
|
||||
public:
|
||||
FahrenheitThermometerProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
~FahrenheitThermometerProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
};
|
||||
|
||||
class ConcatenatorAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::concatenator_adaptor>
|
||||
{
|
||||
public:
|
||||
ConcatenatorAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
unsigned int workers = std::thread::hardware_concurrency();
|
||||
if (workers < 4)
|
||||
workers = 4;
|
||||
|
||||
for (unsigned int i = 0; i < workers; ++i)
|
||||
workers_.emplace_back([this]()
|
||||
{
|
||||
//std::cout << "Created CA worker thread 0x" << std::hex << std::this_thread::get_id() << std::dec << std::endl;
|
||||
|
||||
while(!exit_)
|
||||
{
|
||||
// Pop a work item from the queue
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_.wait(lock, [this]{return !requests_.empty() || exit_;});
|
||||
if (exit_)
|
||||
break;
|
||||
auto request = std::move(requests_.front());
|
||||
requests_.pop();
|
||||
lock.unlock();
|
||||
|
||||
// Do concatenation work, return results and fire signal
|
||||
auto aString = request.input.at("key1").get<std::string>();
|
||||
auto aNumber = request.input.at("key2").get<uint32_t>();
|
||||
auto resultString = aString + " " + std::to_string(aNumber);
|
||||
|
||||
request.result.returnResults(resultString);
|
||||
|
||||
emitConcatenatedSignal(resultString);
|
||||
}
|
||||
});
|
||||
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
~ConcatenatorAdaptor()
|
||||
{
|
||||
exit_ = true;
|
||||
cond_.notify_all();
|
||||
for (auto& worker : workers_)
|
||||
worker.join();
|
||||
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
requests_.push(WorkItem{std::move(params), std::move(result)});
|
||||
lock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
struct WorkItem
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> input;
|
||||
sdbus::Result<std::string> result;
|
||||
};
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_;
|
||||
std::queue<WorkItem> requests_;
|
||||
std::vector<std::thread> workers_;
|
||||
std::atomic<bool> exit_{};
|
||||
};
|
||||
|
||||
class ConcatenatorProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::concatenator_proxy>
|
||||
{
|
||||
public:
|
||||
ConcatenatorProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
~ConcatenatorProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void onConcatenateReply(const std::string& result, [[maybe_unused]] const sdbus::Error* error) override
|
||||
{
|
||||
assert(error == nullptr);
|
||||
|
||||
std::stringstream str(result);
|
||||
std::string aString;
|
||||
str >> aString;
|
||||
assert(aString == "sdbus-c++-stress-tests");
|
||||
|
||||
uint32_t aNumber;
|
||||
str >> aNumber;
|
||||
assert(aNumber > 0);
|
||||
|
||||
++repliesReceived_;
|
||||
}
|
||||
|
||||
virtual void onConcatenatedSignal(const std::string& concatenatedString) override
|
||||
{
|
||||
std::stringstream str(concatenatedString);
|
||||
std::string aString;
|
||||
str >> aString;
|
||||
assert(aString == "sdbus-c++-stress-tests");
|
||||
|
||||
uint32_t aNumber;
|
||||
str >> aNumber;
|
||||
assert(aNumber > 0);
|
||||
|
||||
++signalsReceived_;
|
||||
}
|
||||
|
||||
public:
|
||||
std::atomic<uint32_t> repliesReceived_{};
|
||||
std::atomic<uint32_t> signalsReceived_{};
|
||||
};
|
||||
|
||||
//-----------------------------------------
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
long loops;
|
||||
long loopDuration;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
loops = 1;
|
||||
loopDuration = 30000;
|
||||
}
|
||||
else if (argc == 3)
|
||||
{
|
||||
loops = std::atol(argv[1]);
|
||||
loopDuration = std::atol(argv[2]);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Wrong program options");
|
||||
|
||||
std::cout << "Going on with " << loops << " loops and " << loopDuration << "ms loop duration" << std::endl;
|
||||
|
||||
std::atomic<uint32_t> concatenationCallsMade{0};
|
||||
std::atomic<uint32_t> concatenationRepliesReceived{0};
|
||||
std::atomic<uint32_t> concatenationSignalsReceived{0};
|
||||
std::atomic<uint32_t> thermometerCallsMade{0};
|
||||
|
||||
std::atomic<bool> exitLogger{};
|
||||
std::thread loggerThread([&]()
|
||||
{
|
||||
while (!exitLogger)
|
||||
{
|
||||
std::this_thread::sleep_for(1s);
|
||||
|
||||
std::cout << "Made " << concatenationCallsMade << " concatenation calls, received " << concatenationRepliesReceived << " replies and " << concatenationSignalsReceived << " signals so far." << std::endl;
|
||||
std::cout << "Made " << thermometerCallsMade << " thermometer calls so far." << std::endl << std::endl;
|
||||
}
|
||||
});
|
||||
|
||||
for (long loop = 0; loop < loops; ++loop)
|
||||
{
|
||||
std::cout << "Entering loop " << loop+1 << std::endl;
|
||||
|
||||
auto service2Connection = sdbus::createSystemBusConnection(SERVICE_2_BUS_NAME);
|
||||
std::atomic<bool> service2ThreadReady{};
|
||||
std::thread service2Thread([&con = *service2Connection, &service2ThreadReady]()
|
||||
{
|
||||
CelsiusThermometerAdaptor thermometer(con, CELSIUS_THERMOMETER_OBJECT_PATH);
|
||||
service2ThreadReady = true;
|
||||
con.enterEventLoop();
|
||||
});
|
||||
|
||||
auto service1Connection = sdbus::createSystemBusConnection(SERVICE_1_BUS_NAME);
|
||||
std::atomic<bool> service1ThreadReady{};
|
||||
std::thread service1Thread([&con = *service1Connection, &service1ThreadReady]()
|
||||
{
|
||||
ConcatenatorAdaptor concatenator(con, CONCATENATOR_OBJECT_PATH);
|
||||
FahrenheitThermometerAdaptor thermometer(con, FAHRENHEIT_THERMOMETER_OBJECT_PATH, false);
|
||||
service1ThreadReady = true;
|
||||
con.enterEventLoop();
|
||||
});
|
||||
|
||||
// Wait for both services to export their D-Bus objects
|
||||
while (!service2ThreadReady || !service1ThreadReady)
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
auto clientConnection = sdbus::createSystemBusConnection();
|
||||
std::mutex clientThreadExitMutex;
|
||||
std::condition_variable clientThreadExitCond;
|
||||
bool clientThreadExit{};
|
||||
std::thread clientThread([&, &con = *clientConnection]()
|
||||
{
|
||||
std::atomic<bool> stopClients{false};
|
||||
|
||||
std::thread concatenatorThread([&]()
|
||||
{
|
||||
ConcatenatorProxy concatenator(con, SERVICE_1_BUS_NAME, CONCATENATOR_OBJECT_PATH);
|
||||
|
||||
uint32_t localCounter{};
|
||||
|
||||
// Issue async concatenate calls densely one after another
|
||||
while (!stopClients)
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> param;
|
||||
param["key1"] = "sdbus-c++-stress-tests";
|
||||
param["key2"] = ++localCounter;
|
||||
|
||||
concatenator.concatenate(param);
|
||||
|
||||
if ((localCounter % 10) == 0)
|
||||
{
|
||||
// Make sure the system is catching up with our async requests,
|
||||
// otherwise sleep a bit to slow down flooding the server.
|
||||
assert(localCounter >= concatenator.repliesReceived_);
|
||||
while ((localCounter - concatenator.repliesReceived_) > 40 && !stopClients)
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
// Update statistics
|
||||
concatenationCallsMade = localCounter;
|
||||
concatenationRepliesReceived = (uint32_t)concatenator.repliesReceived_;
|
||||
concatenationSignalsReceived = (uint32_t)concatenator.signalsReceived_;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::thread thermometerThread([&]()
|
||||
{
|
||||
// Here we continuously remotely call getCurrentTemperature(). We have one proxy object,
|
||||
// first we use it's factory interface to create another proxy object, call getCurrentTemperature()
|
||||
// on that one, and then destroy that proxy object. All that continously in a loop.
|
||||
// This tests dynamic creation and destruction of remote D-Bus objects and local object proxies.
|
||||
|
||||
FahrenheitThermometerProxy thermometer(con, SERVICE_1_BUS_NAME, FAHRENHEIT_THERMOMETER_OBJECT_PATH);
|
||||
uint32_t localCounter{};
|
||||
[[maybe_unused]] uint32_t previousTemperature{};
|
||||
|
||||
while (!stopClients)
|
||||
{
|
||||
localCounter++;
|
||||
|
||||
auto newObjectPath = thermometer.createDelegateObject();
|
||||
FahrenheitThermometerProxy proxy{con, SERVICE_1_BUS_NAME, newObjectPath};
|
||||
|
||||
auto temperature = proxy.getCurrentTemperature();
|
||||
assert(temperature >= previousTemperature); // The temperature shall rise continually
|
||||
previousTemperature = temperature;
|
||||
//std::this_thread::sleep_for(1ms);
|
||||
|
||||
if ((localCounter % 10) == 0)
|
||||
thermometerCallsMade = localCounter;
|
||||
|
||||
thermometer.destroyDelegateObject(newObjectPath);
|
||||
}
|
||||
});
|
||||
|
||||
// We could run the loop in a sync way, but we want it to run also when proxies are destroyed for better
|
||||
// coverage of multi-threaded scenarios, so we run it async and use condition variable for exit notification
|
||||
//con.enterEventLoop();
|
||||
con.enterEventLoopAsync();
|
||||
|
||||
std::unique_lock<std::mutex> lock(clientThreadExitMutex);
|
||||
clientThreadExitCond.wait(lock, [&]{return clientThreadExit;});
|
||||
|
||||
stopClients = true;
|
||||
thermometerThread.join();
|
||||
concatenatorThread.join();
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(loopDuration));
|
||||
|
||||
//clientConnection->leaveEventLoop();
|
||||
std::unique_lock<std::mutex> lock(clientThreadExitMutex);
|
||||
clientThreadExit = true;
|
||||
lock.unlock();
|
||||
clientThreadExitCond.notify_one();
|
||||
clientThread.join();
|
||||
|
||||
service1Connection->leaveEventLoop();
|
||||
service1Thread.join();
|
||||
|
||||
service2Connection->leaveEventLoop();
|
||||
service2Thread.join();
|
||||
}
|
||||
|
||||
exitLogger = true;
|
||||
loggerThread.join();
|
||||
|
||||
return 0;
|
||||
}
|
218
backup/tests/unittests/Connection_test.cpp
Normal file
218
backup/tests/unittests/Connection_test.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection_test.cpp
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
*
|
||||
* Created on: Feb 4, 2019
|
||||
* 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 "Connection.h"
|
||||
#include "unittests/mocks/SdBusMock.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::DoAll;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::Return;
|
||||
using ::testing::NiceMock;
|
||||
using ::sdbus::internal::Connection;
|
||||
|
||||
class ConnectionCreationTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
ConnectionCreationTest() = default;
|
||||
|
||||
std::unique_ptr<NiceMock<SdBusMock>> sdBusIntfMock_ = std::make_unique<NiceMock<SdBusMock>>();
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(ASystemBusConnection, ClosesAndUnrefsBusWhenDestructed)
|
||||
{
|
||||
ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
|
||||
EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1);
|
||||
Connection(std::move(sdBusIntfMock_), Connection::system_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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename _BusTypeTag>
|
||||
class AConnectionNameRequest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void setUpBusOpenExpectation();
|
||||
std::unique_ptr<Connection> makeConnection();
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
setUpBusOpenExpectation();
|
||||
ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(1));
|
||||
ON_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).WillByDefault(Return(fakeBusPtr_));
|
||||
con_ = makeConnection();
|
||||
}
|
||||
|
||||
NiceMock<SdBusMock>* sdBusIntfMock_ = new NiceMock<SdBusMock>(); // con_ below will assume ownership
|
||||
sd_bus* fakeBusPtr_ = reinterpret_cast<sd_bus*>(1);
|
||||
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)));
|
||||
}
|
||||
template<> void AConnectionNameRequest<Connection::session_bus_t>::setUpBusOpenExpectation()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
typedef ::testing::Types< Connection::default_bus_t
|
||||
, 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);
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnectionNameRequest, DoesNotThrowOnSuccess)
|
||||
{
|
||||
EXPECT_CALL(*this->sdBusIntfMock_, sd_bus_request_name(_, _, _)).WillOnce(Return(1));
|
||||
this->con_->requestName("org.sdbuscpp.somename");
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnectionNameRequest, ThrowsOnFail)
|
||||
{
|
||||
EXPECT_CALL(*this->sdBusIntfMock_, sd_bus_request_name(_, _, _)).WillOnce(Return(-1));
|
||||
|
||||
ASSERT_THROW(this->con_->requestName("org.sdbuscpp.somename"), sdbus::Error);
|
||||
}
|
266
backup/tests/unittests/Message_test.cpp
Normal file
266
backup/tests/unittests/Message_test.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message_test.cpp
|
||||
*
|
||||
* Created on: Dec 3, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include "MessageUtils.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstdint>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Gt;
|
||||
using ::testing::DoubleEq;
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string deserializeString(sdbus::PlainMessage& msg)
|
||||
{
|
||||
std::string str;
|
||||
msg >> str;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(AMessage, CanBeDefaultConstructed)
|
||||
{
|
||||
ASSERT_NO_THROW(sdbus::PlainMessage());
|
||||
}
|
||||
|
||||
TEST(AMessage, IsInvalidAfterDefaultConstructed)
|
||||
{
|
||||
sdbus::PlainMessage msg;
|
||||
|
||||
ASSERT_FALSE(msg.isValid());
|
||||
}
|
||||
|
||||
TEST(AMessage, IsValidWhenConstructedAsRealMessage)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
ASSERT_TRUE(msg.isValid());
|
||||
}
|
||||
|
||||
TEST(AMessage, CreatesShallowCopyWhenCopyConstructed)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
msg << "I am a string"s;
|
||||
msg.seal();
|
||||
|
||||
sdbus::PlainMessage msgCopy = msg;
|
||||
|
||||
std::string str;
|
||||
msgCopy >> str;
|
||||
|
||||
ASSERT_THAT(str, Eq("I am a string"));
|
||||
ASSERT_THROW(msgCopy >> str, sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(AMessage, CreatesDeepCopyWhenEplicitlyCopied)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
msg << "I am a string"s;
|
||||
msg.seal();
|
||||
|
||||
auto msgCopy = sdbus::createPlainMessage();
|
||||
msg.copyTo(msgCopy, true);
|
||||
msgCopy.seal(); // Seal to be able to read from it subsequently
|
||||
msg.rewind(true); // Rewind to the beginning after copying
|
||||
|
||||
ASSERT_THAT(deserializeString(msg), Eq("I am a string"));
|
||||
ASSERT_THAT(deserializeString(msgCopy), Eq("I am a string"));
|
||||
}
|
||||
|
||||
TEST(AMessage, IsEmptyWhenContainsNoValue)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
ASSERT_TRUE(msg.isEmpty());
|
||||
}
|
||||
|
||||
TEST(AMessage, IsNotEmptyWhenContainsAValue)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
msg << "I am a string"s;
|
||||
|
||||
ASSERT_FALSE(msg.isEmpty());
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryASimpleInteger)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
int dataWritten = 5;
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
int dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryAUnixFd)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
sdbus::UnixFd dataWritten{0};
|
||||
msg << dataWritten;
|
||||
|
||||
msg.seal();
|
||||
|
||||
sdbus::UnixFd dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead.get(), Gt(dataWritten.get()));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryAVariant)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
auto dataWritten = sdbus::Variant((double)3.14);
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
sdbus::Variant dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead.get<double>(), Eq(dataWritten.get<double>()));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryACollectionOfEmbeddedVariants)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
auto value = std::vector<sdbus::Variant>{"hello"s, (double)3.14};
|
||||
auto dataWritten = sdbus::Variant{value};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
sdbus::Variant dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead.get<decltype(value)>()[0].get<std::string>(), Eq(value[0].get<std::string>()));
|
||||
ASSERT_THAT(dataRead.get<decltype(value)>()[1].get<double>(), Eq(value[1].get<double>()));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryAnArray)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
std::vector<int64_t> dataWritten{3545342, 43643532, 324325};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::vector<int64_t> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryADictionary)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
std::map<int, std::string> dataWritten{{1, "one"}, {2, "two"}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::map<int, std::string> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryAComplexType)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
using ComplexType = std::map<
|
||||
uint64_t,
|
||||
sdbus::Struct<
|
||||
std::map<
|
||||
uint8_t,
|
||||
std::vector<
|
||||
sdbus::Struct<
|
||||
sdbus::ObjectPath,
|
||||
bool,
|
||||
int16_t,
|
||||
/*sdbus::Variant,*/
|
||||
std::map<int, std::string>
|
||||
>
|
||||
>
|
||||
>,
|
||||
sdbus::Signature,
|
||||
double
|
||||
>
|
||||
>;
|
||||
|
||||
ComplexType dataWritten = { {1, {{{5, {{"/some/object", true, 45, {{6, "hello"}, {7, "world"}}}}}}, "av", 3.14}}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
ComplexType dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
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}");
|
||||
}
|
125
backup/tests/unittests/PollData_test.cpp
Normal file
125
backup/tests/unittests/PollData_test.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file PollData_test.cpp
|
||||
*
|
||||
* Created on: Jan 19, 2023
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <chrono>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Ge;
|
||||
using ::testing::Le;
|
||||
using ::testing::AllOf;
|
||||
using namespace std::string_literals;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(PollData, ReturnsZeroRelativeTimeoutForZeroAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::zero();
|
||||
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::zero()));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroPollTimeoutForZeroAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::zero();
|
||||
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(0));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsInfiniteRelativeTimeoutForInfiniteAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::max();
|
||||
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::max()));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsNegativePollTimeoutForInfiniteAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::max();
|
||||
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(-1));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroRelativeTimeoutForPastAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto past = std::chrono::steady_clock::now() - 10s;
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(0us));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroPollTimeoutForPastAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto past = std::chrono::steady_clock::now() - 10s;
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(0));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsCorrectRelativeTimeoutForFutureAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto future = std::chrono::steady_clock::now() + 1s;
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, AllOf(Ge(900ms), Le(1100ms)));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsCorrectPollTimeoutForFutureAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto future = std::chrono::steady_clock::now() + 1s;
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, AllOf(Ge(900), Le(1100)));
|
||||
}
|
173
backup/tests/unittests/TypeTraits_test.cpp
Normal file
173
backup/tests/unittests/TypeTraits_test.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TypeTraits_test.cpp
|
||||
*
|
||||
* Created on: Nov 27, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
namespace
|
||||
{
|
||||
// ---
|
||||
// FIXTURE DEFINITION FOR TYPED TESTS
|
||||
// ----
|
||||
|
||||
template <typename _T>
|
||||
class Type2DBusTypeSignatureConversion
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
const std::string dbusTypeSignature_{getDBusTypeSignature()};
|
||||
private:
|
||||
static std::string getDBusTypeSignature();
|
||||
};
|
||||
|
||||
#define TYPE(...) \
|
||||
template <> \
|
||||
std::string Type2DBusTypeSignatureConversion<__VA_ARGS__>::getDBusTypeSignature() \
|
||||
/**/
|
||||
#define HAS_DBUS_TYPE_SIGNATURE(_SIG) \
|
||||
{ \
|
||||
return (_SIG); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
TYPE(bool)HAS_DBUS_TYPE_SIGNATURE("b")
|
||||
TYPE(uint8_t)HAS_DBUS_TYPE_SIGNATURE("y")
|
||||
TYPE(int16_t)HAS_DBUS_TYPE_SIGNATURE("n")
|
||||
TYPE(uint16_t)HAS_DBUS_TYPE_SIGNATURE("q")
|
||||
TYPE(int32_t)HAS_DBUS_TYPE_SIGNATURE("i")
|
||||
TYPE(uint32_t)HAS_DBUS_TYPE_SIGNATURE("u")
|
||||
TYPE(int64_t)HAS_DBUS_TYPE_SIGNATURE("x")
|
||||
TYPE(uint64_t)HAS_DBUS_TYPE_SIGNATURE("t")
|
||||
TYPE(double)HAS_DBUS_TYPE_SIGNATURE("d")
|
||||
TYPE(const char*)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(std::string)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(sdbus::ObjectPath)HAS_DBUS_TYPE_SIGNATURE("o")
|
||||
TYPE(sdbus::Signature)HAS_DBUS_TYPE_SIGNATURE("g")
|
||||
TYPE(sdbus::Variant)HAS_DBUS_TYPE_SIGNATURE("v")
|
||||
TYPE(sdbus::UnixFd)HAS_DBUS_TYPE_SIGNATURE("h")
|
||||
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::map<int32_t, int64_t>)HAS_DBUS_TYPE_SIGNATURE("a{ix}")
|
||||
using ComplexType = std::map<
|
||||
uint64_t,
|
||||
sdbus::Struct<
|
||||
std::map<
|
||||
uint8_t,
|
||||
std::vector<
|
||||
sdbus::Struct<
|
||||
sdbus::ObjectPath,
|
||||
bool,
|
||||
sdbus::Variant,
|
||||
std::map<int, std::string>
|
||||
>
|
||||
>
|
||||
>,
|
||||
sdbus::Signature,
|
||||
sdbus::UnixFd,
|
||||
const char*
|
||||
>
|
||||
>;
|
||||
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(obva{is})}ghs)}")
|
||||
|
||||
typedef ::testing::Types< bool
|
||||
, uint8_t
|
||||
, int16_t
|
||||
, uint16_t
|
||||
, int32_t
|
||||
, uint32_t
|
||||
, int64_t
|
||||
, uint64_t
|
||||
, double
|
||||
, const char*
|
||||
, std::string
|
||||
, sdbus::ObjectPath
|
||||
, sdbus::Signature
|
||||
, sdbus::Variant
|
||||
, sdbus::UnixFd
|
||||
, sdbus::Struct<bool>
|
||||
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
|
||||
, std::vector<int16_t>
|
||||
, std::map<int32_t, int64_t>
|
||||
, ComplexType
|
||||
> DBusSupportedTypes;
|
||||
|
||||
TYPED_TEST_SUITE(Type2DBusTypeSignatureConversion, DBusSupportedTypes);
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(Type2DBusTypeSignatureConversion, ConvertsTypeToProperDBusSignature)
|
||||
{
|
||||
ASSERT_THAT(sdbus::signature_of<TypeParam>::str(), Eq(this->dbusTypeSignature_));
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfTrivialSignatureFunction)
|
||||
{
|
||||
void f();
|
||||
using Fnc = decltype(f);
|
||||
|
||||
static_assert(!sdbus::is_async_method_v<Fnc>, "Free function incorrectly detected as async method");
|
||||
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<>>::value, "Incorrectly detected free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<>>::value, "Incorrectly detected tuple of free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, void>::value, "Incorrectly detected tuple of free function return types");
|
||||
static_assert(sdbus::function_argument_count_v<Fnc> == 0, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_void<sdbus::function_result_t<Fnc>>::value, "Incorrectly detected free function return type");
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfNontrivialSignatureFunction)
|
||||
{
|
||||
std::tuple<char, int> f(double&, const char*, int);
|
||||
using Fnc = decltype(f);
|
||||
|
||||
static_assert(!sdbus::is_async_method_v<Fnc>, "Free function incorrectly detected as async method");
|
||||
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>::value, "Incorrectly detected free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>::value, "Incorrectly detected tuple of free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected tuple of free function return types");
|
||||
static_assert(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfAsyncFunction)
|
||||
{
|
||||
void f(sdbus::Result<char, int>, double&, const char*, int);
|
||||
using Fnc = decltype(f);
|
||||
|
||||
static_assert(sdbus::is_async_method_v<Fnc>, "Free async function incorrectly detected as sync method");
|
||||
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>::value, "Incorrectly detected free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>::value, "Incorrectly detected tuple of free function parameters");
|
||||
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected tuple of free function return types");
|
||||
static_assert(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
|
||||
}
|
382
backup/tests/unittests/Types_test.cpp
Normal file
382
backup/tests/unittests/Types_test.cpp
Normal file
@ -0,0 +1,382 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types_test.cpp
|
||||
*
|
||||
* Created on: Dec 3, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include "MessageUtils.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstdint>
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Gt;
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr const uint64_t ANY_UINT64 = 84578348354;
|
||||
constexpr const double ANY_DOUBLE = 3.14;
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(AVariant, CanBeDefaultConstructed)
|
||||
{
|
||||
ASSERT_NO_THROW(sdbus::Variant());
|
||||
}
|
||||
|
||||
TEST(AVariant, ContainsNoValueAfterDefaultConstructed)
|
||||
{
|
||||
sdbus::Variant v;
|
||||
|
||||
ASSERT_TRUE(v.isEmpty());
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeConstructedFromASimpleValue)
|
||||
{
|
||||
int value = 5;
|
||||
|
||||
ASSERT_NO_THROW(sdbus::Variant{value});
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeConstructedFromAComplexValue)
|
||||
{
|
||||
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, 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});
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeCopied)
|
||||
{
|
||||
auto value = "hello"s;
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
auto variantCopy1{variant};
|
||||
auto variantCopy2 = variantCopy1;
|
||||
|
||||
ASSERT_THAT(variantCopy1.get<std::string>(), Eq(value));
|
||||
ASSERT_THAT(variantCopy2.get<std::string>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AVariant, IsNotEmptyWhenContainsAValue)
|
||||
{
|
||||
sdbus::Variant v("hello");
|
||||
|
||||
ASSERT_FALSE(v.isEmpty());
|
||||
}
|
||||
|
||||
TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
|
||||
{
|
||||
int value = 5;
|
||||
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_THAT(variant.get<int>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
|
||||
{
|
||||
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, 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);
|
||||
|
||||
ASSERT_THAT(variant.get<decltype(value)>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
|
||||
{
|
||||
std::string value{"I am a string"};
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_THAT(variant.get<std::string>(), Eq(value));
|
||||
ASSERT_THAT(variant.get<std::string>(), Eq(value));
|
||||
ASSERT_THAT(variant.get<std::string>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AVariant, ReturnsTrueWhenAskedIfItContainsTheTypeItReallyContains)
|
||||
{
|
||||
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, 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);
|
||||
|
||||
ASSERT_TRUE(variant.containsValueOfType<ComplexType>());
|
||||
}
|
||||
|
||||
TEST(ASimpleVariant, ReturnsFalseWhenAskedIfItContainsTypeItDoesntReallyContain)
|
||||
{
|
||||
int value = 5;
|
||||
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_FALSE(variant.containsValueOfType<double>());
|
||||
}
|
||||
|
||||
TEST(AVariant, CanContainOtherEmbeddedVariants)
|
||||
{
|
||||
using TypeWithVariants = std::vector<sdbus::Struct<sdbus::Variant, double>>;
|
||||
TypeWithVariants value;
|
||||
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);
|
||||
|
||||
ASSERT_TRUE(variant.containsValueOfType<TypeWithVariants>());
|
||||
}
|
||||
|
||||
TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
|
||||
{
|
||||
sdbus::Variant variant("a string");
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
ASSERT_NO_THROW(variant.serializeTo(msg));
|
||||
}
|
||||
|
||||
TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
|
||||
{
|
||||
sdbus::Variant variant;
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
ASSERT_THROW(variant.serializeTo(msg), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
|
||||
{
|
||||
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, 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();
|
||||
variant.serializeTo(msg);
|
||||
msg.seal();
|
||||
sdbus::Variant variant2;
|
||||
variant2.deserializeFrom(msg);
|
||||
|
||||
ASSERT_THAT(variant2.get<decltype(value)>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
|
||||
{
|
||||
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, 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;
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
variant.serializeTo(msg);
|
||||
variantCopy1.serializeTo(msg);
|
||||
variantCopy2.serializeTo(msg);
|
||||
msg.seal();
|
||||
sdbus::Variant receivedVariant1, receivedVariant2, receivedVariant3;
|
||||
receivedVariant1.deserializeFrom(msg);
|
||||
receivedVariant2.deserializeFrom(msg);
|
||||
receivedVariant3.deserializeFrom(msg);
|
||||
|
||||
ASSERT_THAT(receivedVariant1.get<decltype(value)>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant2.get<decltype(value)>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant3.get<decltype(value)>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AStruct, CreatesStructFromTuple)
|
||||
{
|
||||
std::tuple<int32_t, std::string> value{1234, "abcd"};
|
||||
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(AnObjectPath, CanBeConstructedFromCString)
|
||||
{
|
||||
const char* aPath = "/some/path";
|
||||
|
||||
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
|
||||
}
|
||||
|
||||
TEST(AnObjectPath, CanBeConstructedFromStdString)
|
||||
{
|
||||
std::string aPath{"/some/path"};
|
||||
|
||||
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";
|
||||
|
||||
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
|
||||
}
|
||||
|
||||
TEST(ASignature, CanBeConstructedFromStdString)
|
||||
{
|
||||
std::string aSignature{"us"};
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_THAT(sdbus::UnixFd{fd}.get(), Gt(fd));
|
||||
EXPECT_THAT(::close(fd), Eq(0));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, AdoptsAndOwnsFdAsIsUponAdoptionConstruction)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
|
||||
EXPECT_THAT(sdbus::UnixFd(fd, sdbus::adopt_fd).get(), Eq(fd));
|
||||
EXPECT_THAT(::close(fd), Eq(-1));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, DuplicatesFdUponCopyConstruction)
|
||||
{
|
||||
sdbus::UnixFd unixFd(::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK));
|
||||
|
||||
sdbus::UnixFd unixFdCopy{unixFd};
|
||||
|
||||
EXPECT_THAT(unixFdCopy.get(), Gt(unixFd.get()));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, TakesOverFdUponMoveConstruction)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
|
||||
sdbus::UnixFd unixFdNew{std::move(unixFd)};
|
||||
|
||||
EXPECT_FALSE(unixFd.isValid());
|
||||
EXPECT_THAT(unixFdNew.get(), Eq(fd));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, ClosesFdProperlyUponDestruction)
|
||||
{
|
||||
int fd, fdCopy;
|
||||
{
|
||||
fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
auto unixFdNew = std::move(unixFd);
|
||||
auto unixFdCopy = unixFdNew;
|
||||
fdCopy = unixFdCopy.get();
|
||||
}
|
||||
|
||||
EXPECT_THAT(::close(fd), Eq(-1));
|
||||
EXPECT_THAT(::close(fdCopy), Eq(-1));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, DoesNotCloseReleasedFd)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
int fdReleased;
|
||||
{
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
fdReleased = unixFd.release();
|
||||
EXPECT_FALSE(unixFd.isValid());
|
||||
}
|
||||
|
||||
EXPECT_THAT(fd, Eq(fdReleased));
|
||||
EXPECT_THAT(::close(fd), Eq(0));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, ClosesFdOnReset)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
|
||||
unixFd.reset();
|
||||
|
||||
EXPECT_FALSE(unixFd.isValid());
|
||||
EXPECT_THAT(::close(fd), Eq(-1));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, DuplicatesNewFdAndClosesOriginalFdOnReset)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
auto newFd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
|
||||
unixFd.reset(newFd);
|
||||
|
||||
EXPECT_THAT(unixFd.get(), Gt(newFd));
|
||||
EXPECT_THAT(::close(fd), Eq(-1));
|
||||
EXPECT_THAT(::close(newFd), Eq(0));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, TakesOverNewFdAndClosesOriginalFdOnAdoptingReset)
|
||||
{
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
auto newFd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
|
||||
unixFd.reset(newFd, sdbus::adopt_fd);
|
||||
|
||||
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>(""));
|
||||
}
|
99
backup/tests/unittests/mocks/SdBusMock.h
Normal file
99
backup/tests/unittests/mocks/SdBusMock.h
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file SdBusMock.h
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
*
|
||||
* Created on: Mar 12, 2019
|
||||
* 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_SDBUS_MOCK_H
|
||||
#define SDBUS_CXX_SDBUS_MOCK_H
|
||||
|
||||
#include "ISdBus.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
class SdBusMock : public sdbus::internal::ISdBus
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD1(sd_bus_message_ref, sd_bus_message*(sd_bus_message *m));
|
||||
MOCK_METHOD1(sd_bus_message_unref, sd_bus_message*(sd_bus_message *m));
|
||||
|
||||
MOCK_METHOD3(sd_bus_send, int(sd_bus *bus, sd_bus_message *m, uint64_t *cookie));
|
||||
MOCK_METHOD5(sd_bus_call, int(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply));
|
||||
MOCK_METHOD6(sd_bus_call_async, int(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec));
|
||||
|
||||
MOCK_METHOD3(sd_bus_message_new, int(sd_bus *bus, sd_bus_message **m, uint8_t type));
|
||||
MOCK_METHOD6(sd_bus_message_new_method_call, int(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member));
|
||||
MOCK_METHOD5(sd_bus_message_new_signal, int(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member));
|
||||
MOCK_METHOD2(sd_bus_message_new_method_return, int(sd_bus_message *call, sd_bus_message **m));
|
||||
MOCK_METHOD3(sd_bus_message_new_method_error, int(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e));
|
||||
|
||||
MOCK_METHOD2(sd_bus_set_method_call_timeout, int(sd_bus *bus, uint64_t usec));
|
||||
MOCK_METHOD2(sd_bus_get_method_call_timeout, int(sd_bus *bus, uint64_t *ret));
|
||||
|
||||
MOCK_METHOD4(sd_bus_emit_properties_changed_strv, int(sd_bus *bus, const char *path, const char *interface, char **names));
|
||||
MOCK_METHOD2(sd_bus_emit_object_added, int(sd_bus *bus, const char *path));
|
||||
MOCK_METHOD2(sd_bus_emit_object_removed, int(sd_bus *bus, const char *path));
|
||||
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_METHOD2(sd_bus_open_system_remote, int(sd_bus **ret, const char *host));
|
||||
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_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_METHOD2(sd_bus_get_n_queued_read, int(sd_bus *bus, uint64_t *ret));
|
||||
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 **));
|
||||
|
||||
MOCK_METHOD1(sd_bus_get_event, sd_event *(sd_bus *bus));
|
||||
};
|
||||
|
||||
#endif //SDBUS_CXX_SDBUS_MOCK_H
|
34
backup/tests/unittests/sdbus-c++-unit-tests.cpp
Normal file
34
backup/tests/unittests/sdbus-c++-unit-tests.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file sdbus-c++-unit-tests.cpp
|
||||
*
|
||||
* Created on: Nov 27, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleMock(&argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -46,7 +46,7 @@ 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} -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR> ${LIBSYSTEMD_EXTRA_CONFIG_OPTS}
|
||||
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}
|
||||
BUILD_COMMAND ${BUILD_VERSION_H}
|
||||
COMMAND ${NINJA} -C <BINARY_DIR> libsystemd.a
|
||||
BUILD_ALWAYS 0
|
||||
|
@ -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 =
|
||||
STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ @PROJECT_BINARY_DIR@
|
||||
|
||||
# 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
|
||||
|
@ -19,8 +19,9 @@ Using sdbus-c++ library
|
||||
14. [Asynchronous client-side methods](#asynchronous-client-side-methods)
|
||||
15. [Using D-Bus properties](#using-d-bus-properties)
|
||||
16. [Standard D-Bus interfaces](#standard-d-bus-interfaces)
|
||||
17. [Support for match rules](#support-for-match-rules)
|
||||
18. [Conclusion](#conclusion)
|
||||
17. [Using D-Bus Types](#using-d-bus-types)
|
||||
18. [Support for match rules](#support-for-match-rules)
|
||||
19. [Conclusion](#conclusion)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
@ -378,7 +379,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
```
|
||||
|
||||
In simple cases, we don't need to create D-Bus connection explicitly for our proxies. Unless a connection is provided to a proxy object explicitly via factory parameter, the proxy will create a connection of his own, and it will be a system bus connection. This is the case in the example above. (This approach is not scalable and resource-saving if we have plenty of proxies; see section [Working with D-Bus connections](#working-with-d-bus-connections-in-sdbus-c) for elaboration.) So, in the example, we create a proxy for object `/org/sdbuscpp/concatenator` publicly available at bus `org.sdbuscpp.concatenator`. We register signal handlers, if any, and finish the registration, making the proxy ready for use.
|
||||
In simple cases, we don't need to create D-Bus connection explicitly for our proxies. Unless a connection is provided to a proxy object explicitly via factory parameter, the proxy will create a connection of his own (unless it is a light-weight, short-lived proxy created with `dont_run_event_loop_thread_t`), and it will be a system bus connection. This is the case in the example above. (This approach is not scalable and resource-saving if we have plenty of proxies; see section [Working with D-Bus connections](#working-with-d-bus-connections-in-sdbus-c) for elaboration.) So, in the example, we create a proxy for object `/org/sdbuscpp/concatenator` publicly available at bus `org.sdbuscpp.concatenator`. We register signal handlers, if any, and finish the registration, making the proxy ready for use.
|
||||
|
||||
The callback for a D-Bus signal handler on this level is any callable of signature `void(sdbus::Signal& signal)`. The one and only parameter `signal` is the incoming signal message. We need to deserialize arguments from it, and then we can do our business logic with it.
|
||||
|
||||
@ -410,19 +411,23 @@ On the **server** side, we generally need to create D-Bus objects and publish th
|
||||
* or in a non-blocking async way, through `enterEventLoopAsync()`,
|
||||
* or, when we have our own implementation of an event loop (e.g. we are using sd-event event loop), we can ask the connection for its underlying fd, I/O events and timeouts through `getEventLoopPollData()` and use that data in our event loop mechanism.
|
||||
|
||||
The object takes the D-Bus connection as a reference in its constructor. This is the only way to wire connection and object together. We must make sure the connection exists as long as objects using it exist.
|
||||
|
||||
Of course, at any time before or after running the event loop on the connection, we can create and "hook", as well as remove, objects and proxies upon that connection.
|
||||
|
||||
#### Using D-Bus connections on the client side
|
||||
|
||||
On the **client** side we have more options when creating D-Bus proxies. That corresponds to three overloads of the `createProxy()` factory:
|
||||
On the **client** side we likewise need a connection -- just that unlike on the server side, we don't need to request a unique bus name on it. We have more options here when creating a proxy:
|
||||
|
||||
* In case we (the application) already maintain a D-Bus connection, e.g. because we a D-Bus service anyway, the simple and typical approach is to create proxy upon that connection. The proxy will share the connection with others. So we pass connection reference to proxy factory. With this approach we must of course ensure that the connection exists as long as the proxy exists.
|
||||
* Pass an already existing connection as a reference. This is the typical approach when the application already maintains a D-Bus connection (maybe it provide D-Bus API on it, and/or it already has some proxies hooked on it). The proxy will share the connection with others. With this approach we must of course ensure that the connection exists as long as the proxy exists.
|
||||
|
||||
* Or -- and this is typical when we have a simple D-Bus client application -- we have another option: we let proxy maintain its own connection (and an associated thread):
|
||||
* Or -- and this is typical when we have a simple D-Bus client application -- we have another option: we let the proxy maintain its own connection (and potentially an associated event loop thread, see below):
|
||||
|
||||
* We either create the connection ourselves and `std::move` it to the proxy object factory. The proxy becomes an owner of this connection, and will run the event loop on that connection. This had the advantage that we may choose the type of connection (system, session, remote).
|
||||
|
||||
* Or we don't bother about any connection at all when creating a proxy (the factory overload with no connection parameter). Under the hood, the proxy creates its own *system bus* connection, creates a separate thread and runs an event loop in it. This is **the simplest approach** for non-complex D-Bus clients. For more complex ones, with big number of proxies, this hurts scalability but may improve concurrency (see discussion higher above), so we should make a conscious choice.
|
||||
* Or we don't bother about any connection at all when creating a proxy (the factory overload with no connection parameter). Under the hood, the proxy creates its own *system bus* connection, creates a separate thread and runs an event loop in it. Quite **simple**, but as you can see, this hurts scalability in case of many proxies, as each would spawn and maintain its own event loop thread (see discussion higher above). But we don't necessarily need an event loop thread, in case our proxy doesn't need to listen to signals or async method call replies. Read on.
|
||||
|
||||
It's also possible in this case to instruct the proxy to **not spawn an event loop thread** for its connection. There are many situations that we want to quickly create a proxy, carry out one or a few (synchronous) D-Bus calls, and let go of proxy. We call them light-weight proxies. For that purpose, spawning a new event loop thread comes with time and resource penalty, for nothing. To create such **a light-weight proxy**, use the factory/constructor overload with `dont_run_event_loop_thread_t`. All in above two bullet sub-points holds; the proxy just won't spawn a thread with an event loop in it. Note that such a proxy can be used only for synchronous D-Bus calls; it may not receive signals or async call replies.
|
||||
|
||||
#### Stopping I/O event loops graciously
|
||||
|
||||
@ -604,7 +609,7 @@ sdbus-c++ ships with the native stub generator tool called `sdbus-c++-xml2cpp`.
|
||||
The generator tool takes D-Bus XML IDL description of D-Bus interfaces on its input, and can be instructed to generate one or both of these: an adaptor header file for use on the server side, and a proxy header file for use on the client side. Like this:
|
||||
|
||||
```bash
|
||||
sdbus-c++-xml2cpp database-bindings.xml --adaptor=database-server-glue.h --proxy=database-client-glue.h
|
||||
sdbus-c++-xml2cpp concatenator-bindings.xml --adaptor=concatenator-server-glue.h --proxy=concatenator-client-glue.h
|
||||
```
|
||||
|
||||
The adaptor header file contains classes that can be used to implement interfaces described in the IDL (these classes represent object interfaces). The proxy header file contains classes that can be used to make calls to remote objects (these classes represent remote object interfaces).
|
||||
@ -630,12 +635,14 @@ As an example, let's look at an XML description of our Concatenator's interfaces
|
||||
</node>
|
||||
```
|
||||
|
||||
After running this through the stubs generator, we get the stub code that is described in the following two subsections.
|
||||
After running this through the code generator, we get the generated code that is described in the following two subsections.
|
||||
|
||||
### concatenator-server-glue.h
|
||||
|
||||
For each interface in the XML IDL file the generator creates one class that represents it. The class is de facto an interface which shall be implemented by the class inheriting it. The class' constructor takes care of registering all methods, signals and properties. For each D-Bus method there is a pure virtual member function. These pure virtual functions must be implemented in the child class. For each signal, there is a public function member that emits this signal.
|
||||
|
||||
Generated adaptor classes support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
@ -658,25 +665,30 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
|
||||
object_.registerSignal("concatenated").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
|
||||
object_->registerSignal("concatenated").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 emitConcatenated(const std::string& concatenatedString)
|
||||
{
|
||||
object_.emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
object_->emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@ -686,7 +698,9 @@ private:
|
||||
|
||||
### concatenator-client-glue.h
|
||||
|
||||
Analogously to the adaptor classes described above, there is one class generated for one interface in the XML IDL file. The class is de facto a proxy to the concrete single interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child class. For each method, there is a public function member that calls the method remotely.
|
||||
Analogously to the adaptor classes described above, there is one proxy class generated for one interface in the XML IDL file. The class is de facto a proxy to the concrete single interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child class. For each method, there is a public function member that calls the method remotely.
|
||||
|
||||
Generated proxy classes support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
@ -710,11 +724,16 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_.uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
|
||||
proxy_->uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(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 onConcatenated(const std::string& concatenatedString) = 0;
|
||||
@ -723,12 +742,12 @@ public:
|
||||
std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
proxy_.callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
proxy_->callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@ -1216,9 +1235,9 @@ class PropertyProvider_adaptor
|
||||
|
||||
public:
|
||||
PropertyProvider_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
|
||||
object_->registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
|
||||
}
|
||||
|
||||
~PropertyProvider_adaptor() = default;
|
||||
@ -1245,13 +1264,13 @@ public:
|
||||
// getting the property value
|
||||
uint32_t status()
|
||||
{
|
||||
return object_.getProperty("status").onInterface(INTERFACE_NAME);
|
||||
return object_->getProperty("status").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
// setting the property value
|
||||
void status(const uint32_t& value)
|
||||
{
|
||||
object_.setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
object_->setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
/*...*/
|
||||
@ -1280,6 +1299,47 @@ Note that signals of afore-mentioned standard D-Bus interfaces are not emitted b
|
||||
|
||||
Working examples of using standard D-Bus interfaces can be found in [sdbus-c++ integration tests](/tests/integrationtests/DBusStandardInterfacesTests.cpp) or the [examples](/examples) directory.
|
||||
|
||||
Using D-Bus Types
|
||||
-----------------
|
||||
|
||||
For many D-Bus interactions dealing with D-Bus types is necessary. For that, sdbus-c++ provides many predefined D-Bus types. The table below shows which C++ type corresponds to which D-Bus type.
|
||||
|
||||
|
||||
| Category | Code | Code ASCII | Conventional Name | C++ Type |
|
||||
|---------------------|-------------|------------|--------------------|---------------------------------|
|
||||
| reserved | 0 | NUL | INVALID | - |
|
||||
| fixed, basic | 121 | y | BYTE | `uint8_t` |
|
||||
| fixed, basic | 98 | b | BOOLEAN | `bool` |
|
||||
| fixed, basic | 110 | n | INT16 | `int16_t` |
|
||||
| fixed, basic | 113 | q | UINT16 | `uint16_t` |
|
||||
| fixed, basic | 105 | i | INT32 | `int32_t` |
|
||||
| fixed, basic | 117 | u | UINT32 | `uint32_t` |
|
||||
| fixed, basic | 120 | x | INT64 | `int64_t` |
|
||||
| fixed, basic | 116 | t | UINT64 | `uint64_t` |
|
||||
| fixed, basic | 100 | d | DOUBLE | `double` |
|
||||
| string-like, basic | 115 | s | STRING | `const char*`, `std::string` |
|
||||
| string-like, basic | 111 | o | OBJECT_PATH | `sdbus::ObjectPath` |
|
||||
| string-like, basic | 103 | g | SIGNATURE | `sdbus::Signature` |
|
||||
| container | 97 | a | ARRAY | `std::vector<T>` (if used as an array followed by a single complete type T), or `std::map<T1, T2>` (if used as an array of dict entries) |
|
||||
| container | 114,40,41 | r() | STRUCT | `sdbus::Struct<T1, T2, ...>` variadic class template |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant` |
|
||||
| container | 101,123,125 | e{} | DICT_ENTRY | - |
|
||||
| fixed, basic | 104 | h | UNIX_FD | `sdbus::UnixFd` |
|
||||
| reserved | 109 | m | (reserved) | - |
|
||||
| reserved | 42 | * | (reserved) | - |
|
||||
| reserved | 63 | ? | (reserved) | - |
|
||||
| reserved | 64,38,94 | @&^ | (reserved) | - |
|
||||
|
||||
A few examples:
|
||||
|
||||
* The D-Bus signature of an output argument of method `GetManagedObjects()` on standard interface `org.freedesktop.DBus.ObjectManager` is `a{oa{sa{sv}}}`. For this the corresponding C++ method return type is: `std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>>`.
|
||||
* Or an input argument of method `InterfacesRemoved` on that interface has signature `as`. Ths corresponds to the C++ parameter of type `std::vector<std::string>`.
|
||||
* Or a D-Bus signature `a(bdh)` corresponds to the array of D-Bus structures: `std::vector<sdbus::Struct<bool, double, sdbus::UnixFd>>`.
|
||||
|
||||
To see how C++ types are mapped to D-Bus types (including container types) in sdbus-c++, have a look at individual [specializations of `sdbus::signature_of` class template](https://github.com/Kistler-Group/sdbus-cpp/blob/master/include/sdbus-c%2B%2B/TypeTraits.h#L87) in TypeTraits.h header file. For more examples of type mappings, look into [TypeTraits unit tests](https://github.com/Kistler-Group/sdbus-cpp/blob/master/tests/unittests/TypeTraits_test.cpp#L62).
|
||||
|
||||
For more information on basic D-Bus types, D-Bus container types, and D-Bus type system in general, make sure to consult the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#type-system).
|
||||
|
||||
Support for match rules
|
||||
-----------------------
|
||||
|
||||
|
@ -141,6 +141,11 @@ 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;
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
struct sd_event;
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/********************************************//**
|
||||
@ -49,62 +51,7 @@ 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;
|
||||
};
|
||||
struct PollData;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
|
||||
@ -127,7 +74,7 @@ namespace sdbus {
|
||||
virtual void releaseName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Retrieve the unique name of a connection. E.g. ":1.xx"
|
||||
* @brief Retrieves the unique name of a connection. E.g. ":1.xx"
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@ -178,44 +125,62 @@ namespace sdbus {
|
||||
[[deprecated("Use one of other addObjectManager overloads")]] virtual void addObjectManager(const std::string& objectPath) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Returns fd, I/O events and timeout data you can pass to poll
|
||||
* @brief Returns fd's, I/O events and timeout data to be used in an external event loop
|
||||
*
|
||||
* To integrate sdbus with your app's own custom event handling system
|
||||
* (without the requirement of an extra thread), you can use this
|
||||
* method to query which file descriptors, poll events and timeouts you
|
||||
* should add to your app's poll call in your main event loop. If these
|
||||
* file descriptors signal, then you should call processPendingRequest
|
||||
* to process the event. This means that all of sdbus's callbacks will
|
||||
* arrive on your app's main event thread (opposed to on a thread created
|
||||
* by sdbus-c++). If you are unsure what this all means then use
|
||||
* enterEventLoop() or enterEventLoopAsync() instead.
|
||||
* This function is useful to hook up a bus connection object with an
|
||||
* external (like GMainLoop, boost::asio, etc.) or manual event loop
|
||||
* involving poll() or a similar I/O polling call.
|
||||
*
|
||||
* To integrate sdbus-c++ into a gtk app, pass the file descriptor returned
|
||||
* by this method to g_main_context_add_poll.
|
||||
* Before **each** invocation of the I/O polling call, this function
|
||||
* should be invoked. Returned PollData::fd file descriptor should
|
||||
* be polled for the events indicated by PollData::events, and the I/O
|
||||
* call should block for that up to the returned PollData::timeout.
|
||||
*
|
||||
* Additionally, returned PollData::eventFd should be polled for POLLIN
|
||||
* events.
|
||||
*
|
||||
* After each I/O polling call the bus connection needs to process
|
||||
* incoming or outgoing data, by invoking processPendingEvent().
|
||||
*
|
||||
* Note that the returned timeout should be considered only a maximum
|
||||
* sleeping time. It is permissible (and even expected) that shorter
|
||||
* timeouts are used by the calling program, in case other event sources
|
||||
* are polled in the same event loop. Note that the returned time-value
|
||||
* is absolute, based of CLOCK_MONOTONIC and specified in microseconds.
|
||||
* Use PollData::getPollTimeout() to have the timeout value converted
|
||||
* in a form that can be passed to poll(2).
|
||||
*
|
||||
* The bus connection conveniently integrates sd-event event loop.
|
||||
* To attach the bus connection to an sd-event event loop, use
|
||||
* attachSdEventLoop() function.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PollData getEventLoopPollData() const = 0;
|
||||
[[nodiscard]] virtual PollData getEventLoopPollData() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Process a pending request
|
||||
* @brief Processes a pending event
|
||||
*
|
||||
* @returns true if an event was processed, false if poll should be called
|
||||
* @returns True if an event was processed, false if no operations were pending
|
||||
*
|
||||
* Processes a single dbus event. All of sdbus-c++'s callbacks will be called
|
||||
* from within this method. This method should ONLY be used in conjuction
|
||||
* with getEventLoopPollData().
|
||||
* This method returns true if an I/O message was processed. This you can try
|
||||
* to call this method again before going to poll on I/O events. The method
|
||||
* returns false if no operations were pending, and the caller should then
|
||||
* poll for I/O events before calling this method again.
|
||||
* enterEventLoop() and enterEventLoopAsync() will call this method for you,
|
||||
* so there is no need to call it when using these. If you are unsure what
|
||||
* this all means then don't use this method.
|
||||
* This function drives the D-Bus connection. It processes pending I/O events.
|
||||
* Queued outgoing messages (or parts thereof) are sent out. Queued incoming
|
||||
* messages are dispatched to registered callbacks. Timeouts are recalculated.
|
||||
*
|
||||
* It returns false when no operations were pending and true if a message was
|
||||
* processed. When false is returned the caller should synchronously poll for
|
||||
* I/O events before calling into processPendingEvent() again.
|
||||
* Don't forget to call getEventLoopPollData() each time before the next poll.
|
||||
*
|
||||
* You don't need to directly call this method or getEventLoopPollData() method
|
||||
* when using convenient, internal bus connection event loops through
|
||||
* enterEventLoop() or enterEventLoopAsync() calls, or when the bus is
|
||||
* connected to an sd-event event loop through attachSdEventLoop().
|
||||
* It is invoked automatically when necessary.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual bool processPendingRequest() = 0;
|
||||
virtual bool processPendingEvent() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets general method call timeout
|
||||
@ -293,7 +258,6 @@ namespace sdbus {
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon incoming D-Bus message matching the rule
|
||||
* @param[in] Floating slot tag
|
||||
*
|
||||
* 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
|
||||
@ -306,6 +270,32 @@ namespace sdbus {
|
||||
*/
|
||||
virtual void addMatch(const std::string& match, message_handler callback, floating_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Attaches the bus connection to an sd-event event loop
|
||||
*
|
||||
* @param[in] event sd-event event loop object
|
||||
* @param[in] priority Specified priority
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*
|
||||
* See `man sd_bus_attach_event'.
|
||||
*/
|
||||
virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Detaches the bus connection from an sd-event event loop
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void detachSdEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Gets current sd-event event loop for the bus connection
|
||||
*
|
||||
* @return Pointer to event loop object if attached, nullptr otherwise
|
||||
*/
|
||||
virtual sd_event *getSdEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::enterEventLoop()
|
||||
*
|
||||
@ -314,25 +304,74 @@ namespace sdbus {
|
||||
[[deprecated("This function has been replaced by enterEventLoop()")]] void enterProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::enterProcessingLoopAsync()
|
||||
* @copydoc IConnection::enterEventLoopAsync()
|
||||
*
|
||||
* @deprecated This function has been replaced by enterEventLoopAsync()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by enterEventLoopAsync()")]] void enterProcessingLoopAsync();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::leaveProcessingLoop()
|
||||
* @copydoc IConnection::leaveEventLoop()
|
||||
*
|
||||
* @deprecated This function has been replaced by leaveEventLoop()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by leaveEventLoop()")]] void leaveProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::getProcessLoopPollData()
|
||||
* @copydoc IConnection::getEventLoopPollData()
|
||||
*
|
||||
* @deprecated This function has been replaced by getEventLoopPollData()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by getEventLoopPollData()")]] PollData getProcessLoopPollData() const;
|
||||
|
||||
/*!
|
||||
* @struct PollData
|
||||
*
|
||||
* Carries poll data needed for integration with external event loop implementations.
|
||||
*
|
||||
* See getEventLoopPollData() for more info.
|
||||
*/
|
||||
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 microseconds, based of CLOCK_MONOTONIC.
|
||||
*
|
||||
* Call getPollTimeout() to get timeout recalculated to relative timeout that can be passed to poll(2).
|
||||
*/
|
||||
std::chrono::microseconds timeout;
|
||||
|
||||
/*!
|
||||
* An additional event fd to be monitored by the event loop for POLLIN events.
|
||||
*/
|
||||
int eventFd;
|
||||
|
||||
/*!
|
||||
* Returns the timeout as relative value from now.
|
||||
*
|
||||
* Returned value is std::chrono::microseconds::max() if the timeout is indefinite.
|
||||
*
|
||||
* @return Relative timeout as a time duration
|
||||
*/
|
||||
[[nodiscard]] std::chrono::microseconds getRelativeTimeout() const;
|
||||
|
||||
/*!
|
||||
* Returns relative timeout in the form 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 milliseconds otherwise.
|
||||
*/
|
||||
[[nodiscard]] int getPollTimeout() const;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
|
@ -81,20 +81,29 @@ namespace sdbus {
|
||||
virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the proxied D-Bus object
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return A method reply message
|
||||
*
|
||||
* Normally, the call is blocking, i.e. it waits for the remote method to finish with either
|
||||
* a return value or an error.
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* If the method call argument is set to not expect reply, the call will not wait for the remote
|
||||
* method to finish, i.e. the call will be non-blocking, and the function will return an empty,
|
||||
* invalid MethodReply object (representing void).
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply, or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. Slim proxies created with `dont_run_event_loop_thread` tag are
|
||||
* designed for exactly that purpose.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@ -115,10 +124,10 @@ namespace sdbus {
|
||||
* @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.
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@ -412,6 +421,11 @@ namespace sdbus {
|
||||
return PropertySetter(*this, propertyName);
|
||||
}
|
||||
|
||||
// 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{};
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
@ -458,6 +472,30 @@ 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).
|
||||
*
|
||||
* 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
|
||||
*
|
||||
@ -466,7 +504,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 a procesing loop upon that connection
|
||||
* his own connection, and will automatically start an event 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.
|
||||
*
|
||||
@ -478,6 +516,28 @@ 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>
|
||||
|
@ -48,7 +48,6 @@ namespace sdbus {
|
||||
class MethodReply;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
class IConnection;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,12 +186,11 @@ namespace sdbus {
|
||||
bool doesntExpectReply() const;
|
||||
|
||||
protected:
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept;
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
private:
|
||||
MethodReply sendWithReply(uint64_t timeout = 0) const;
|
||||
MethodReply sendWithNoReply() const;
|
||||
const internal::IConnection* connection_{};
|
||||
};
|
||||
|
||||
class MethodReply : public Message
|
||||
|
@ -109,6 +109,21 @@ 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
|
||||
*
|
||||
@ -141,6 +156,22 @@ 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
|
||||
*
|
||||
@ -175,6 +206,11 @@ 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;
|
||||
};
|
||||
|
||||
|
@ -43,27 +43,32 @@ 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
|
||||
@ -73,22 +78,27 @@ 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
|
||||
@ -98,10 +108,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
|
||||
@ -111,6 +121,11 @@ 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
|
||||
@ -120,23 +135,23 @@ namespace sdbus {
|
||||
public:
|
||||
sdbus::Variant Get(const std::string& interfaceName, const std::string& propertyName)
|
||||
{
|
||||
return proxy_.getProperty(propertyName).onInterface(interfaceName);
|
||||
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);
|
||||
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> GetAll(const std::string& interfaceName)
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> props;
|
||||
proxy_.callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
|
||||
proxy_->callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
|
||||
return props;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for object manager
|
||||
@ -146,10 +161,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 )
|
||||
@ -157,8 +172,7 @@ 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 )
|
||||
@ -167,6 +181,11 @@ 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
|
||||
@ -178,12 +197,12 @@ 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
|
||||
@ -197,25 +216,30 @@ 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_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -234,15 +258,20 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object)
|
||||
: object_(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_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -259,10 +288,16 @@ namespace sdbus {
|
||||
class ManagedObject_adaptor
|
||||
{
|
||||
protected:
|
||||
explicit ManagedObject_adaptor(sdbus::IObject& object) : object_(object)
|
||||
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:
|
||||
@ -273,7 +308,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesAddedSignal()
|
||||
{
|
||||
object_.emitInterfacesAddedSignal();
|
||||
object_->emitInterfacesAddedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -283,7 +318,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
object_.emitInterfacesAddedSignal(interfaces);
|
||||
object_->emitInterfacesAddedSignal(interfaces);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -293,7 +328,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesRemovedSignal()
|
||||
{
|
||||
object_.emitInterfacesRemovedSignal();
|
||||
object_->emitInterfacesRemovedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -303,11 +338,11 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
object_.emitInterfacesRemovedSignal(interfaces);
|
||||
object_->emitInterfacesRemovedSignal(interfaces);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -32,49 +32,51 @@
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include "ScopeGuard.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory)
|
||||
: iface_(std::move(interface))
|
||||
: sdbus_(std::move(interface))
|
||||
, bus_(openBus(busFactory))
|
||||
{
|
||||
assert(iface_ != nullptr);
|
||||
assert(sdbus_ != 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(std::move(interface), [this](sd_bus** bus){ return sdbus_->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); })
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return sdbus_->sd_bus_open_system(bus); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, session_bus_t)
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return iface_->sd_bus_open_user(bus); })
|
||||
: Connection(std::move(interface), [this](sd_bus** bus){ return sdbus_->sd_bus_open_user(bus); })
|
||||
{
|
||||
}
|
||||
|
||||
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(std::move(interface), [&](sd_bus** bus) { return sdbus_->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(std::move(interface), [this, &host](sd_bus** bus){ return sdbus_->sd_bus_open_system_remote(bus, host.c_str()); })
|
||||
{
|
||||
}
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
|
||||
: iface_(std::move(interface))
|
||||
: sdbus_(std::move(interface))
|
||||
, bus_(openPseudoBus())
|
||||
{
|
||||
assert(iface_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
@ -86,38 +88,34 @@ 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);
|
||||
auto r = sdbus_->sd_bus_request_name(bus_.get(), name.c_str(), 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
|
||||
}
|
||||
|
||||
void Connection::releaseName(const std::string& name)
|
||||
{
|
||||
auto r = iface_->sd_bus_release_name(bus_.get(), name.c_str());
|
||||
auto r = sdbus_->sd_bus_release_name(bus_.get(), name.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
|
||||
}
|
||||
|
||||
std::string Connection::getUniqueName() const
|
||||
{
|
||||
const char* unique = nullptr;
|
||||
auto r = iface_->sd_bus_get_unique_name(bus_.get(), &unique);
|
||||
auto r = sdbus_->sd_bus_get_unique_name(bus_.get(), &unique);
|
||||
SDBUS_THROW_ERROR_IF(r < 0 || unique == nullptr, "Failed to get unique bus name", -r);
|
||||
return unique;
|
||||
}
|
||||
|
||||
void Connection::enterEventLoop()
|
||||
{
|
||||
loopThreadId_ = std::this_thread::get_id();
|
||||
SCOPE_EXIT{ loopThreadId_ = std::thread::id{}; };
|
||||
|
||||
std::lock_guard guard(loopMutex_);
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto processed = processPendingRequest();
|
||||
if (processed)
|
||||
continue; // Process next one
|
||||
// Process one pending event
|
||||
(void)processPendingEvent();
|
||||
|
||||
auto success = waitForNextRequest();
|
||||
// And go to poll(), which wakes us up right away
|
||||
// if there's another pending event, or sleeps otherwise.
|
||||
auto success = waitForNextEvent();
|
||||
if (!success)
|
||||
break; // Exit I/O event loop
|
||||
}
|
||||
@ -138,20 +136,24 @@ void Connection::leaveEventLoop()
|
||||
Connection::PollData Connection::getEventLoopPollData() const
|
||||
{
|
||||
ISdBus::PollData pollData{};
|
||||
auto r = iface_->sd_bus_get_poll_data(bus_.get(), &pollData);
|
||||
auto r = sdbus_->sd_bus_get_poll_data(bus_.get(), &pollData);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
|
||||
|
||||
return {pollData.fd, pollData.events, pollData.timeout_usec};
|
||||
assert(eventFd_.fd >= 0);
|
||||
|
||||
auto timeout = pollData.timeout_usec == UINT64_MAX ? std::chrono::microseconds::max() : std::chrono::microseconds(pollData.timeout_usec);
|
||||
|
||||
return {pollData.fd, pollData.events, timeout, eventFd_.fd};
|
||||
}
|
||||
|
||||
const ISdBus& Connection::getSdBusInterface() const
|
||||
{
|
||||
return *iface_.get();
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
ISdBus& Connection::getSdBusInterface()
|
||||
{
|
||||
return *iface_.get();
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
void Connection::addObjectManager(const std::string& objectPath)
|
||||
@ -161,7 +163,7 @@ void Connection::addObjectManager(const std::string& objectPath)
|
||||
|
||||
void Connection::addObjectManager(const std::string& objectPath, floating_slot_t)
|
||||
{
|
||||
auto r = iface_->sd_bus_add_object_manager(bus_.get(), nullptr, objectPath.c_str());
|
||||
auto r = sdbus_->sd_bus_add_object_manager(bus_.get(), nullptr, objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
|
||||
}
|
||||
@ -170,16 +172,16 @@ Slot Connection::addObjectManager(const std::string& objectPath, request_slot_t)
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = iface_->sd_bus_add_object_manager(bus_.get(), &slot, objectPath.c_str());
|
||||
auto r = sdbus_->sd_bus_add_object_manager(bus_.get(), &slot, objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
|
||||
|
||||
return {slot, [this](void *slot){ iface_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
void Connection::setMethodCallTimeout(uint64_t timeout)
|
||||
{
|
||||
auto r = iface_->sd_bus_set_method_call_timeout(bus_.get(), timeout);
|
||||
auto r = sdbus_->sd_bus_set_method_call_timeout(bus_.get(), timeout);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set method call timeout", -r);
|
||||
}
|
||||
@ -188,7 +190,7 @@ uint64_t Connection::getMethodCallTimeout() const
|
||||
{
|
||||
uint64_t timeout;
|
||||
|
||||
auto r = iface_->sd_bus_get_method_call_timeout(bus_.get(), &timeout);
|
||||
auto r = sdbus_->sd_bus_get_method_call_timeout(bus_.get(), &timeout);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get method call timeout", -r);
|
||||
|
||||
@ -207,13 +209,13 @@ Slot Connection::addMatch(const std::string& match, message_handler callback)
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto r = iface_->sd_bus_add_match(bus_.get(), &matchInfo->slot, match.c_str(), std::move(messageHandler), matchInfo.get());
|
||||
auto r = sdbus_->sd_bus_add_match(bus_.get(), &matchInfo->slot, match.c_str(), std::move(messageHandler), 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);
|
||||
sdbus_->sd_bus_slot_unref(matchInfo->slot);
|
||||
std::default_delete<MatchInfo>{}(matchInfo);
|
||||
}};
|
||||
}
|
||||
@ -223,6 +225,149 @@ void Connection::addMatch(const std::string& match, message_handler callback, fl
|
||||
floatingMatchRules_.push_back(addMatch(match, std::move(callback)));
|
||||
}
|
||||
|
||||
void Connection::attachSdEventLoop(sd_event *event, int priority)
|
||||
{
|
||||
// Get default event if no event is provided by the caller
|
||||
if (event != nullptr)
|
||||
event = sd_event_ref(event);
|
||||
else
|
||||
(void)sd_event_default(&event);
|
||||
SDBUS_THROW_ERROR_IF(!event, "Invalid sd_event handle", EINVAL);
|
||||
Slot sdEvent{event, [](void* event){ sd_event_unref((sd_event*)event); }};
|
||||
// TODO: auto sdEvent = createSdEventSlot(...);
|
||||
|
||||
sd_event_source *timeEventSource{};
|
||||
auto r = sd_event_add_time(event, &timeEventSource, CLOCK_MONOTONIC, 0, 0, onSdTimerEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add timer event", -r);
|
||||
Slot sdTimeEventSource{timeEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
r = sd_event_source_set_priority(timeEventSource, priority); // TODO maybe use custom EventSourceSlot with custom type? Then we can use slot.get() here
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event priority", -r);
|
||||
|
||||
r = sd_event_source_set_description(timeEventSource, "bus-time");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event description", -r);
|
||||
// TODO: auto sdTimeEventSource = createSdTimeEventSourceSlot(...);
|
||||
|
||||
auto pollData = getEventLoopPollData();
|
||||
|
||||
sd_event_source *ioEventSource{};
|
||||
r = sd_event_add_io(event, &ioEventSource, pollData.fd, 0, onSdIoEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add io event", -r);
|
||||
Slot sdIoEventSource{ioEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
r = sd_event_source_set_prepare(ioEventSource, onSdEventPrepare);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for IO event", -r);
|
||||
|
||||
r = sd_event_source_set_priority(ioEventSource, priority);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
|
||||
r = sd_event_source_set_description(ioEventSource, "bus-input");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
// TODO: auto sdIoEventSource = createSdIoEventSourceSlot(...);
|
||||
|
||||
sd_event_source *internalEventSource{};
|
||||
r = sd_event_add_io(event, &internalEventSource, pollData.eventFd, 0, onSdInternalEvent, this);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add internal event", -r);
|
||||
Slot sdInternalEventSource{internalEventSource, [](void* source){ sd_event_source_disable_unref((sd_event_source*)source); }};
|
||||
|
||||
// sd-event loop calls prepare callbacks for all event sources, not just for the one that fired now.
|
||||
// So since onSdEventPrepare is already registered on ioEventSource, we don't need to duplicate it here.
|
||||
//r = sd_event_source_set_prepare(internalEventSource, onSdEventPrepare);
|
||||
//SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for internal event", -r);
|
||||
|
||||
r = sd_event_source_set_priority(internalEventSource, priority);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for internal event", -r);
|
||||
|
||||
r = sd_event_source_set_description(internalEventSource, "internal-event");
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r);
|
||||
// TODO: auto sdInternalEventSource = createSdInternalEventSourceSlot(...);
|
||||
|
||||
sdEvent_ = std::make_unique<SdEvent>(SdEvent{ std::move(sdEvent)
|
||||
, std::move(sdTimeEventSource)
|
||||
, std::move(sdIoEventSource)
|
||||
, std::move(sdInternalEventSource) });
|
||||
}
|
||||
|
||||
void Connection::detachSdEventLoop()
|
||||
{
|
||||
sdEvent_.reset();
|
||||
}
|
||||
|
||||
sd_event *Connection::getSdEventLoop()
|
||||
{
|
||||
return sdEvent_ ? static_cast<sd_event*>(sdEvent_->sdEvent.get()) : nullptr;
|
||||
}
|
||||
|
||||
int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
(void)connection->processPendingEvent();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
(void)connection->processPendingEvent();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdInternalEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
// It's not really necessary to processPendingEvent() here. We just clear the event fd.
|
||||
// The sd-event loop will before the next poll call prepare callbacks for all event sources,
|
||||
// including I/O bus fd. This will get up-to-date poll timeout, which will be zero if there
|
||||
// are pending D-Bus messages in the read queue, which will immediately wake up next poll
|
||||
// and go to onSdIoEvent() handler, which calls processPendingEvent(). Viola.
|
||||
// For external event loops that only have access to public sdbus-c++ API, processPendingEvent()
|
||||
// is the only option to clear event fd (it comes at a little extra cost but on the other hand
|
||||
// the solution is simpler for clients -- we don't provide an extra method for just clearing
|
||||
// the event fd. There is one method for both fd's -- and that's processPendingEvent().
|
||||
|
||||
// Kept here so that potential readers know what to do in their custom external event loops.
|
||||
//(void)connection->processPendingEvent();
|
||||
|
||||
connection->eventFd_.clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata)
|
||||
{
|
||||
auto connection = static_cast<Connection*>(userdata);
|
||||
assert(connection != nullptr);
|
||||
|
||||
auto sdbusPollData = connection->getEventLoopPollData();
|
||||
|
||||
// Set poll events to watch out for on I/O fd
|
||||
auto* sdIoEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdIoEventSource.get());
|
||||
auto r = sd_event_source_set_io_events(sdIoEventSource, sdbusPollData.events);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for IO event source", -r);
|
||||
|
||||
// Set poll events to watch out for on internal event fd
|
||||
auto* sdInternalEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdInternalEventSource.get());
|
||||
r = sd_event_source_set_io_events(sdInternalEventSource, POLLIN);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for internal event source", -r);
|
||||
|
||||
// Set current timeout to the time event source (it may be zero if there are messages in the sd-bus queues to be processed)
|
||||
auto* sdTimeEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdTimeEventSource.get());
|
||||
r = sd_event_source_set_time(sdTimeEventSource, static_cast<uint64_t>(sdbusPollData.timeout.count()));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set timeout for time event source", -r);
|
||||
r = sd_event_source_set_enabled(sdTimeEventSource, SD_EVENT_ON);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enable time event source", -r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
@ -230,7 +375,7 @@ Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = iface_->sd_bus_add_object_vtable( bus_.get()
|
||||
auto r = sdbus_->sd_bus_add_object_vtable(bus_.get()
|
||||
, &slot
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
@ -239,18 +384,18 @@ Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register object vtable", -r);
|
||||
|
||||
return {slot, [this](void *slot){ iface_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
PlainMessage Connection::createPlainMessage() const
|
||||
{
|
||||
sd_bus_message* sdbusMsg{};
|
||||
|
||||
auto r = iface_->sd_bus_message_new(bus_.get(), &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID);
|
||||
auto r = sdbus_->sd_bus_message_new(bus_.get(), &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a plain message", -r);
|
||||
|
||||
return Message::Factory::create<PlainMessage>(sdbusMsg, iface_.get(), adopt_message);
|
||||
return Message::Factory::create<PlainMessage>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
MethodCall Connection::createMethodCall( const std::string& destination
|
||||
@ -260,7 +405,7 @@ MethodCall Connection::createMethodCall( const std::string& destination
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = iface_->sd_bus_message_new_method_call( bus_.get()
|
||||
auto r = sdbus_->sd_bus_message_new_method_call(bus_.get()
|
||||
, &sdbusMsg
|
||||
, destination.c_str()
|
||||
, objectPath.c_str()
|
||||
@ -269,7 +414,7 @@ MethodCall Connection::createMethodCall( const std::string& destination
|
||||
|
||||
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, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
Signal Connection::createSignal( const std::string& objectPath
|
||||
@ -278,7 +423,7 @@ Signal Connection::createSignal( const std::string& objectPath
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = iface_->sd_bus_message_new_signal( bus_.get()
|
||||
auto r = sdbus_->sd_bus_message_new_signal(bus_.get()
|
||||
, &sdbusMsg
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
@ -286,7 +431,51 @@ Signal Connection::createSignal( const std::string& objectPath
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
|
||||
|
||||
return Message::Factory::create<Signal>(sdbusMsg, iface_.get(), adopt_message);
|
||||
return Message::Factory::create<Signal>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
MethodReply Connection::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
// If the call expects reply, this call will block the bus connection from
|
||||
// serving other messages until the reply arrives or the call times out.
|
||||
auto reply = message.send(timeout);
|
||||
|
||||
// Some messages may have arrived while waiting for the call reply. They were set aside while waiting.
|
||||
// In case an event loop is inside a poll in another thread, or an external event loop polls in the
|
||||
// same thread but as an unrelated event source, then we need to wake up the poll explicitly so the
|
||||
// event loop 1. processes all messages in the read queue, 2. updates poll timeout before next poll.
|
||||
if (arePendingMessagesInReadQueue())
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
message.send(callback, userData, timeout, floating_slot);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
}
|
||||
|
||||
Slot Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
auto slot = message.send(callback, userData, timeout);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
@ -295,7 +484,7 @@ void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(propNames);
|
||||
|
||||
auto r = iface_->sd_bus_emit_properties_changed_strv( bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_properties_changed_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, propNames.empty() ? nullptr : &names[0] );
|
||||
@ -305,7 +494,7 @@ void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
|
||||
void Connection::emitInterfacesAddedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = iface_->sd_bus_emit_object_added(bus_.get(), objectPath.c_str());
|
||||
auto r = sdbus_->sd_bus_emit_object_added(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal for all registered interfaces", -r);
|
||||
}
|
||||
@ -315,7 +504,7 @@ void Connection::emitInterfacesAddedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = iface_->sd_bus_emit_interfaces_added_strv( bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_added_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
@ -324,7 +513,7 @@ void Connection::emitInterfacesAddedSignal( const std::string& objectPath
|
||||
|
||||
void Connection::emitInterfacesRemovedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = iface_->sd_bus_emit_object_removed(bus_.get(), objectPath.c_str());
|
||||
auto r = sdbus_->sd_bus_emit_object_removed(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal for all registered interfaces", -r);
|
||||
}
|
||||
@ -334,7 +523,7 @@ void Connection::emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = iface_->sd_bus_emit_interfaces_removed_strv( bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv(bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
@ -354,40 +543,11 @@ Slot Connection::registerSignalHandler( const std::string& sender
|
||||
// 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 r = iface_->sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
|
||||
auto r = sdbus_->sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
|
||||
|
||||
return {slot, [this](void *slot){ iface_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
MethodReply Connection::tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
auto loopThreadId = loopThreadId_.load(std::memory_order_relaxed);
|
||||
|
||||
// Is the loop not yet on? => Go make synchronous call
|
||||
while (loopThreadId == std::thread::id{})
|
||||
{
|
||||
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||
if (!loopMutex_.try_lock())
|
||||
{
|
||||
loopThreadId = loopThreadId_.load(std::memory_order_relaxed);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Synchronous D-Bus call
|
||||
std::lock_guard guard(loopMutex_, std::adopt_lock);
|
||||
return message.send(timeout);
|
||||
}
|
||||
|
||||
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||
if (loopThreadId == std::this_thread::get_id())
|
||||
{
|
||||
assert(!loopMutex_.try_lock());
|
||||
return message.send(timeout);
|
||||
}
|
||||
|
||||
return {};
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
|
||||
@ -396,7 +556,7 @@ Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
|
||||
int r = busFactory(&bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
|
||||
|
||||
BusPtr busPtr{bus, [this](sd_bus* bus){ return iface_->sd_bus_flush_close_unref(bus); }};
|
||||
BusPtr busPtr{bus, [this](sd_bus* bus){ return sdbus_->sd_bus_flush_close_unref(bus); }};
|
||||
finishHandshake(busPtr.get());
|
||||
return busPtr;
|
||||
}
|
||||
@ -405,17 +565,17 @@ Connection::BusPtr Connection::openPseudoBus()
|
||||
{
|
||||
sd_bus* bus{};
|
||||
|
||||
int r = iface_->sd_bus_new(&bus);
|
||||
int r = sdbus_->sd_bus_new(&bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open pseudo bus", -r);
|
||||
|
||||
(void)iface_->sd_bus_start(bus);
|
||||
(void)sdbus_->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); }};
|
||||
return {bus, [this](sd_bus* bus){ return sdbus_->sd_bus_close_unref(bus); }};
|
||||
}
|
||||
|
||||
void Connection::finishHandshake(sd_bus* bus)
|
||||
@ -426,43 +586,19 @@ void Connection::finishHandshake(sd_bus* bus)
|
||||
|
||||
assert(bus != nullptr);
|
||||
|
||||
auto r = iface_->sd_bus_flush(bus);
|
||||
auto r = sdbus_->sd_bus_flush(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);
|
||||
|
||||
uint64_t value = 1;
|
||||
auto r = write(fd, &value, sizeof(value));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify event loop", -errno);
|
||||
loopExitFd_.notify();
|
||||
}
|
||||
|
||||
void Connection::notifyEventLoopToExit() const
|
||||
void Connection::notifyEventLoopToWakeUpFromPoll()
|
||||
{
|
||||
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
|
||||
{
|
||||
uint64_t value{};
|
||||
auto r = read(fd, &value, sizeof(value));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
|
||||
eventFd_.notify();
|
||||
}
|
||||
|
||||
void Connection::joinWithEventLoop()
|
||||
@ -471,32 +607,36 @@ void Connection::joinWithEventLoop()
|
||||
asyncLoopThread_.join();
|
||||
}
|
||||
|
||||
bool Connection::processPendingRequest()
|
||||
bool Connection::processPendingEvent()
|
||||
{
|
||||
auto bus = bus_.get();
|
||||
assert(bus != nullptr);
|
||||
|
||||
int r = iface_->sd_bus_process(bus, nullptr);
|
||||
int r = sdbus_->sd_bus_process(bus, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
|
||||
|
||||
// In correct use of sdbus-c++ API, r can be 0 only when processPendingEvent()
|
||||
// is called from an external event loop as a reaction to event fd being signalled.
|
||||
// If there are no more D-Bus messages to process, we know we have to clear event fd.
|
||||
if (r == 0)
|
||||
eventFd_.clear();
|
||||
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
bool Connection::waitForNextRequest()
|
||||
bool Connection::waitForNextEvent()
|
||||
{
|
||||
assert(bus_ != nullptr);
|
||||
assert(loopExitFd_.fd >= 0);
|
||||
assert(eventFd_.fd >= 0);
|
||||
|
||||
auto sdbusPollData = getEventLoopPollData();
|
||||
struct pollfd fds[] = {
|
||||
{sdbusPollData.fd, sdbusPollData.events, 0},
|
||||
{eventFd_.fd, POLLIN, 0},
|
||||
{loopExitFd_.fd, POLLIN, 0}
|
||||
};
|
||||
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
|
||||
struct pollfd fds[] = { {sdbusPollData.fd, sdbusPollData.events, 0}
|
||||
, {eventFd_.fd, POLLIN, 0}
|
||||
, {loopExitFd_.fd, POLLIN, 0} };
|
||||
constexpr auto fdsCount = sizeof(fds)/sizeof(fds[0]);
|
||||
|
||||
auto timeout = sdbusPollData.getPollTimeout();
|
||||
activeTimeout_.store(sdbusPollData.timeout_usec, std::memory_order_relaxed);
|
||||
auto r = poll(fds, fdsCount, timeout);
|
||||
|
||||
if (r < 0 && errno == EINTR)
|
||||
@ -504,21 +644,35 @@ bool Connection::waitForNextRequest()
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
|
||||
|
||||
// new timeout notification
|
||||
// Wake up notification, in order that we re-enter poll with freshly read PollData (namely, new poll timeout thereof)
|
||||
if (fds[1].revents & POLLIN)
|
||||
{
|
||||
clearEventLoopNotification(fds[1].fd);
|
||||
auto cleared = eventFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the event descriptor", -errno);
|
||||
// Go poll() again, but with up-to-date timeout (which will wake poll() up right away if there are messages to process)
|
||||
return waitForNextEvent();
|
||||
}
|
||||
// loop exit notification
|
||||
// Loop exit notification
|
||||
if (fds[2].revents & POLLIN)
|
||||
{
|
||||
clearEventLoopNotification(fds[2].fd);
|
||||
auto cleared = loopExitFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the loop exit descriptor", -errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::arePendingMessagesInReadQueue() const
|
||||
{
|
||||
uint64_t readQueueSize{};
|
||||
|
||||
auto r = sdbus_->sd_bus_get_n_queued_read(bus_.get(), &readQueueSize);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get number of pending messages in read queue", -r);
|
||||
|
||||
return readQueueSize > 0;
|
||||
}
|
||||
|
||||
std::string Connection::composeSignalMatchFilter( const std::string &sender
|
||||
, const std::string &objectPath
|
||||
, const std::string &interfaceName
|
||||
@ -556,33 +710,48 @@ Connection::EventFd::~EventFd()
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void Connection::EventFd::notify()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
auto r = eventfd_write(fd, 1);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify event descriptor", -errno);
|
||||
}
|
||||
|
||||
bool Connection::EventFd::clear()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
|
||||
uint64_t value{};
|
||||
auto r = eventfd_read(fd, &value);
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::optional<std::chrono::microseconds> IConnection::PollData::getRelativeTimeout() const
|
||||
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;
|
||||
constexpr auto max = std::chrono::microseconds::max();
|
||||
using internal::now;
|
||||
|
||||
// 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);
|
||||
if (timeout == zero)
|
||||
return zero;
|
||||
else if (timeout == max)
|
||||
return max;
|
||||
else
|
||||
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
|
||||
}
|
||||
|
||||
int IConnection::PollData::getPollTimeout() const
|
||||
{
|
||||
auto timeout = getRelativeTimeout();
|
||||
return timeout ? static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(timeout.value()).count()) : -1;
|
||||
const auto relativeTimeout = getRelativeTimeout();
|
||||
|
||||
if (relativeTimeout == decltype(relativeTimeout)::max())
|
||||
return -1;
|
||||
else
|
||||
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user