diff options
author | Johannes Schanda <schanda@itestra.de> | 2013-05-27 11:47:36 +0200 |
---|---|---|
committer | Johannes Schanda <schanda@itestra.de> | 2013-05-27 11:47:36 +0200 |
commit | d5c7906b728d6a03c468d9c4211417f97702494a (patch) | |
tree | c5a52ce78f80d009ea89ddee8c5bfdcce57ee532 | |
parent | d505e2e38717f3a22be24cc66b5b6559d4efe69f (diff) | |
parent | f330e0d83eb92b07709a305f515a152d714ded0f (diff) | |
download | genivi-common-api-dbus-runtime-d5c7906b728d6a03c468d9c4211417f97702494a.tar.gz |
Merge branch 'master' into genivi_releasegenivi_release_42.0.6
Conflicts:
TODO
58 files changed, 2970 insertions, 897 deletions
@@ -37,3 +37,4 @@ /DBusAddressTranslatorTest /.pydevproject /DBusServiceRegistryTest +/DBusConnectionTest diff --git a/Makefile.am b/Makefile.am index 0a42ea5..f5e43e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,55 +4,65 @@ EXTRA_DIST = LICENSE LICENSE_dbus_patch LICENSE_MurmurHash MOSTLYCLEANFILES = AM_CPPFLAGS = \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/src/test \ - ${COMMONAPI_CFLAGS} \ - ${DBUS_CFLAGS} - + -include $(top_builddir)/build-aux/config.h \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/test \ + ${COMMONAPI_CFLAGS} \ + ${DBUS_CFLAGS} -LDADD = \ - ${COMMONAPI_LIBS} \ - ${DBUS_LIBS} +AM_LDFLAGS = \ + ${COMMONAPI_LIBS} \ + ${DBUS_LIBS} + +noinst_LTLIBRARIES = lib_LTLIBRARIES = -lib_LIBRARIES = + +# Library interface (not package version!) +LIBCOMMONAPI_DBUS_CURRENT=2 +LIBCOMMONAPI_DBUS_REVISION=0 +LIBCOMMONAPI_DBUS_AGE=0 # ------------------------------------------------------------------------------ -lib_LTLIBRARIES += libmurmurhash-internal.la +noinst_LTLIBRARIES += libmurmurhash-internal.la libmurmurhash_internal_la_SOURCES = \ - src/murmurhash/MurmurHash3.h \ - src/murmurhash/MurmurHash3.cpp + src/murmurhash/MurmurHash3.h \ + src/murmurhash/MurmurHash3.cpp # ------------------------------------------------------------------------------ lib_LTLIBRARIES += libCommonAPI-DBus.la libCommonAPI_DBus_la_SOURCES = \ - src/CommonAPI/DBus/DBusAddressTranslator.cpp \ - src/CommonAPI/DBus/DBusConnection.cpp \ - src/CommonAPI/DBus/DBusDaemonProxy.cpp \ - src/CommonAPI/DBus/DBusError.cpp \ - src/CommonAPI/DBus/DBusFunctionalHash.cpp \ - src/CommonAPI/DBus/DBusInputStream.cpp \ - src/CommonAPI/DBus/DBusMessage.cpp \ - src/CommonAPI/DBus/DBusObjectManager.cpp \ - src/CommonAPI/DBus/DBusOutputStream.cpp \ - src/CommonAPI/DBus/DBusProxyBase.cpp \ - src/CommonAPI/DBus/DBusProxy.cpp \ - src/CommonAPI/DBus/DBusFactory.cpp \ - src/CommonAPI/DBus/DBusRuntime.cpp \ - src/CommonAPI/DBus/DBusServiceRegistry.cpp \ - src/CommonAPI/DBus/DBusServiceStatusEvent.cpp \ - src/CommonAPI/DBus/DBusStubAdapter.cpp + src/CommonAPI/DBus/DBusAddressTranslator.cpp \ + src/CommonAPI/DBus/DBusConnection.cpp \ + src/CommonAPI/DBus/DBusDaemonProxy.cpp \ + src/CommonAPI/DBus/DBusError.cpp \ + src/CommonAPI/DBus/DBusFunctionalHash.cpp \ + src/CommonAPI/DBus/DBusInputStream.cpp \ + src/CommonAPI/DBus/DBusMainLoopContext.cpp \ + src/CommonAPI/DBus/DBusMessage.cpp \ + src/CommonAPI/DBus/DBusObjectManager.cpp \ + src/CommonAPI/DBus/DBusOutputStream.cpp \ + src/CommonAPI/DBus/DBusProxyBase.cpp \ + src/CommonAPI/DBus/DBusProxy.cpp \ + src/CommonAPI/DBus/DBusFactory.cpp \ + src/CommonAPI/DBus/DBusRuntime.cpp \ + src/CommonAPI/DBus/DBusServiceRegistry.cpp \ + src/CommonAPI/DBus/DBusServiceStatusEvent.cpp \ + src/CommonAPI/DBus/DBusStubAdapter.cpp libCommonAPI_DBus_la_LIBADD = \ - libmurmurhash-internal.la \ - ${COMMONAPI_LIBS} + libmurmurhash-internal.la \ + ${COMMONAPI_LIBS} +libCommonAPI_DBus_la_LDFLAGS = \ + ${AM_LDFLAGS} \ + -version-info ${LIBCOMMONAPI_DBUS_CURRENT}:${LIBCOMMONAPI_DBUS_REVISION}:${LIBCOMMONAPI_DBUS_AGE} CommonAPI_DBus_includedir=$(includedir)/CommonAPI-${VERSION}/CommonAPI/DBus CommonAPI_DBus_include_HEADERS = \ - src/CommonAPI/DBus/DBusAddressTranslator.h \ - src/CommonAPI/DBus/DBusAttribute.h \ + src/CommonAPI/DBus/DBusAddressTranslator.h \ + src/CommonAPI/DBus/DBusAttribute.h \ src/CommonAPI/DBus/DBusConnection.h \ src/CommonAPI/DBus/DBusDaemonProxy.h \ src/CommonAPI/DBus/DBusError.h \ @@ -60,6 +70,7 @@ CommonAPI_DBus_include_HEADERS = \ src/CommonAPI/DBus/DBusFunctionalHash.h \ src/CommonAPI/DBus/DBusHelper.h \ src/CommonAPI/DBus/DBusInputStream.h \ + src/CommonAPI/DBus/DBusMainLoopContext.h \ src/CommonAPI/DBus/DBusMessage.h \ src/CommonAPI/DBus/DBusMultiEvent.h \ src/CommonAPI/DBus/DBusObjectManager.h \ @@ -68,15 +79,15 @@ CommonAPI_DBus_include_HEADERS = \ src/CommonAPI/DBus/DBusProxy.h \ src/CommonAPI/DBus/DBusProxyAsyncCallbackHandler.h \ src/CommonAPI/DBus/DBusProxyConnection.h \ - src/CommonAPI/DBus/DBusFactory.h \ - src/CommonAPI/DBus/DBusProxyHelper.h \ - src/CommonAPI/DBus/DBusRuntime.h \ - src/CommonAPI/DBus/DBusSerializableArguments.h \ - src/CommonAPI/DBus/DBusServiceRegistry.h \ - src/CommonAPI/DBus/DBusServiceStatusEvent.h \ - src/CommonAPI/DBus/DBusStubAdapter.h \ - src/CommonAPI/DBus/DBusStubAdapterHelper.h \ - src/CommonAPI/DBus/DBusUtils.h + src/CommonAPI/DBus/DBusFactory.h \ + src/CommonAPI/DBus/DBusProxyHelper.h \ + src/CommonAPI/DBus/DBusRuntime.h \ + src/CommonAPI/DBus/DBusSerializableArguments.h \ + src/CommonAPI/DBus/DBusServiceRegistry.h \ + src/CommonAPI/DBus/DBusServiceStatusEvent.h \ + src/CommonAPI/DBus/DBusStubAdapter.h \ + src/CommonAPI/DBus/DBusStubAdapterHelper.h \ + src/CommonAPI/DBus/DBusUtils.h pkgconfigdir = ${libdir}/pkgconfig pkgconfig_DATA = CommonAPI-DBus.pc @@ -85,46 +96,60 @@ pkgconfig_DATA = CommonAPI-DBus.pc if ENABLE_TESTS TestInterfaceSources = \ - src/test/commonapi/tests/DerivedTypeCollection.cpp \ - src/test/commonapi/tests/TestInterfaceDBusProxy.cpp \ - src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp \ - src/test/commonapi/tests/TestInterfaceStubDefault.cpp \ - src/test/fakeLegacyService/fake/legacy/service/LegacyInterfaceDBusProxy.cpp + src/test/commonapi/tests/DerivedTypeCollection.cpp \ + src/test/commonapi/tests/TestInterfaceDBusProxy.cpp \ + src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp \ + src/test/commonapi/tests/TestInterfaceStubDefault.cpp \ + src/test/fakeLegacyService/fake/legacy/service/LegacyInterfaceDBusProxy.cpp check_PROGRAMS = \ - DBusServiceRegistryTest \ - DBusProxyTest \ - DBusAddressTranslatorTest \ - DBusInputStreamTest \ - DBusOutputStreamTest \ - DBusRuntimeTest \ - DBusFactoryTest \ - DBusVariantTest \ - DBusTypeStreamTest \ - DBusVariantOutputStreamTest \ - DBusDaemonProxyTest \ - DBusCommunicationTest \ - DBusMultipleConnectionTest \ - DBusBenchmarkingTest - - -TESTS = ${check_PROGRAMS} + DBusMainLoopIntegrationTest \ + DBusConnectionTest \ + DBusServiceRegistryTest \ + DBusProxyTest \ + DBusAddressTranslatorTest \ + DBusInputStreamTest \ + DBusOutputStreamTest \ + DBusRuntimeTest \ + DBusFactoryTest \ + DBusVariantTest \ + DBusTypeStreamTest \ + DBusVariantOutputStreamTest \ + DBusDaemonProxyTest \ + DBusCommunicationTest \ + DBusMultipleConnectionTest \ + DBusBenchmarkingTest + + +TESTS = ${check_PROGRAMS} LDADD_FOR_GTEST = libCommonAPI-DBus.la ${GTEST_LIBS} ${LDADD} +DBusMainLoopIntegrationTest_SOURCES = \ + src/test/DBusMainLoopIntegrationTest.cpp \ + ${TestInterfaceSources} +DBusMainLoopIntegrationTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} ${GLIB_CFLAGS} +DBusMainLoopIntegrationTest_CXXFLAGS = ${GTEST_CXXFLAGS} ${GLIB_CFLAGS} +DBusMainLoopIntegrationTest_LDADD = ${LDADD_FOR_GTEST} ${GLIB_LIBS} + DBusServiceRegistryTest_SOURCES = \ - src/test/DBusServiceRegistryTest.cpp \ - ${TestInterfaceSources} + src/test/DBusServiceRegistryTest.cpp \ + ${TestInterfaceSources} DBusServiceRegistryTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusServiceRegistryTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusServiceRegistryTest_LDADD = ${LDADD_FOR_GTEST} DBusAddressTranslatorTest_SOURCES = \ - src/test/DBusAddressTranslatorTest.cpp \ - ${TestInterfaceSources} + src/test/DBusAddressTranslatorTest.cpp \ + ${TestInterfaceSources} DBusAddressTranslatorTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusAddressTranslatorTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusAddressTranslatorTest_LDADD = ${LDADD_FOR_GTEST} +DBusConnectionTest_SOURCES = src/test/DBusConnectionTest.cpp +DBusConnectionTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} +DBusConnectionTest_CXXFLAGS = ${GTEST_CXXFLAGS} +DBusConnectionTest_LDADD = ${LDADD_FOR_GTEST} + DBusTypeStreamTest_SOURCES = src/test/DBusTypeStreamTest.cpp DBusTypeStreamTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusTypeStreamTest_CXXFLAGS = ${GTEST_CXXFLAGS} @@ -141,8 +166,8 @@ DBusBenchmarkingTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusBenchmarkingTest_LDADD = ${LDADD_FOR_GTEST} DBusCommunicationTest_SOURCES = \ - src/test/DBusCommunicationTest.cpp \ - ${TestInterfaceSources} + src/test/DBusCommunicationTest.cpp \ + ${TestInterfaceSources} DBusCommunicationTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusCommunicationTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusCommunicationTest_LDADD = ${LDADD_FOR_GTEST} @@ -153,22 +178,22 @@ DBusDaemonProxyTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusDaemonProxyTest_LDADD = ${LDADD_FOR_GTEST} DBusInputStreamTest_SOURCES = \ - src/test/DBusInputStreamTest.cpp \ - ${TestInterfaceSources} + src/test/DBusInputStreamTest.cpp \ + ${TestInterfaceSources} DBusInputStreamTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusInputStreamTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusInputStreamTest_LDADD = ${LDADD_FOR_GTEST} DBusOutputStreamTest_SOURCES = \ - src/test/DBusOutputStreamTest.cpp \ - ${TestInterfaceSources} + src/test/DBusOutputStreamTest.cpp \ + ${TestInterfaceSources} DBusOutputStreamTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusOutputStreamTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusOutputStreamTest_LDADD = ${LDADD_FOR_GTEST} DBusFactoryTest_SOURCES = \ - src/test/DBusFactoryTest.cpp \ - ${TestInterfaceSources} + src/test/DBusFactoryTest.cpp \ + ${TestInterfaceSources} DBusFactoryTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusFactoryTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusFactoryTest_LDADD = ${LDADD_FOR_GTEST} @@ -178,20 +203,16 @@ DBusRuntimeTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusRuntimeTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusRuntimeTest_LDADD = ${LDADD_FOR_GTEST} -#DBusStubAdapterTest_SOURCES = src/test/DBusStubAdapterTest.cpp -#DBusStubAdapterTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -#DBusStubAdapterTest_CXXFLAGS = ${GTEST_CXXFLAGS} -#DBusStubAdapterTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusMultipleConnectionTest_SOURCES = src/test/DBusMultipleConnectionTest.cpp \ - ${TestInterfaceSources} +DBusMultipleConnectionTest_SOURCES = \ + src/test/DBusMultipleConnectionTest.cpp \ + ${TestInterfaceSources} DBusMultipleConnectionTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusMultipleConnectionTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusMultipleConnectionTest_LDADD = ${LDADD_FOR_GTEST} DBusProxyTest_SOURCES = \ - src/test/DBusProxyTest.cpp \ - ${TestInterfaceSources} + src/test/DBusProxyTest.cpp \ + ${TestInterfaceSources} DBusProxyTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} DBusProxyTest_CXXFLAGS = ${GTEST_CXXFLAGS} DBusProxyTest_LDADD = ${LDADD_FOR_GTEST} @@ -212,9 +233,9 @@ MOSTLYCLEANFILES += ${DX_CLEANFILES} # ------------------------------------------------------------------------------ MAINTAINERCLEANFILES = \ - Makefile.in \ - aclocal.m4 \ - configure + Makefile.in \ + aclocal.m4 \ + configure clean-local: -rm -rf src-gen @@ -223,4 +244,4 @@ maintainer-clean-local: -rm -rf build-aux -rm -f config.h.in* -rm -f m4/libtool*.m4 - -rm -f m4/lt*.m4
\ No newline at end of file + -rm -f m4/lt*.m4 @@ -49,12 +49,6 @@ CommonAPI-D-Bus-Tools - The eclipse based tools for CommonAPI D-Bus. This is the To build this package the CommonAPI library and a version of libdbus patched with the marshaling patch must be available through PkgConfig. - -== Build Instructions - - -To build this package CommonAPI and a version of libdbus patched with the marshaling patch must be available. - Instructions for making a patched version of libdbus available in /usr/local: ---- # wget http://dbus.freedesktop.org/releases/dbus/dbus-1.4.16.tar.gz @@ -89,6 +83,54 @@ Use autotools to build this package withthe above requirements available through ---- If the environment variable GTEST_CONFIG is set to the path of the gtest-config script in a Gtest tree test will also be built. +=== Defining D-Bus Service Parameters +Normally, a CommonAPI address, format +---- +<Domain>:<ServiceID>:<InstanceID> +---- + +is mapped to a D-Bus address the following way: +---- +# D-Bus Interface Name = ServiceID +# D-Bus Connection Name = InstanceID +# D-Bus Object Path = InstanceID with a preceding '/' and all '.' replaced with '/' +---- +For Domain, only the value "local" is allowed in this context, and it has no influence on the associated D-Bus service address values. + +In case a proxy or a service should not use the default mapping, it is possible to define config files that use the CommonAPI Address +as a key in order to map any combination of D-Bus address values to it. The config files can be defined locally per binary, globally +per binary or globally for all binaries. If more than one config file is defined and a CommonAPI address is defined more than once +across several config files, the locally defined values override the global ones. If a CommonAPI address is defined more than once +within a single file, the first definition found will be the only definition used. + +Config files have to be named this way: +---- +# Binary local: "<FqnOfBinary>_dbus.conf", e.g. "/usr/bin/myBinary_dbus.conf" if the binary is "/usr/bin/myBinary" +# Binary global: "/etc/CommonApiDBus/<NameOfBinary>_dbus.conf", e.g. "/etc/CommonApiDBus/myBinary_dbus.conf" +# Global: "/etc/CommonApiDBus/dbusAddresses.conf" +---- + +Each config file may have an arbitrary number of entries of the following format, with each entry being separated from the others by a newline: +---- +[<CommonAPI Address>] +dbus_connection=<valid D-Bus Connection Name> +dbus_object=<valid D-Bus Object Path> +dbus_interface=<valid D-Bus Interface Name> +dbus_predefined=<true/false> +---- +All "dbus_*"-values are optional. For each such omitted value the default value as described above will be used. For "dbus_predefined", +the default value is "false". + +"dbus_predefined" should be used if the associated service of a proxy is a legacy service that does not provide the +"org.freedesktop.DBus.ObjectManager" interface. +---- +# If "dbus_predefined" is set to "false" (which is default), a proxy will try to verify the existence of the specific interface + at the specific connection name and object path, using the "org.freedesktop.DBus.ObjectManager" interface, before it is marked as available. +# If "dbus_predefined" is set to "true", a proxy is marked as available as soon as the connection name of the associated + service is visible. No further checks will be executed. +---- + + == Working on the code & contribution .First get the code from the git: diff --git a/configure.ac b/configure.ac index 90ae370..3ab0d8f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,17 +1,19 @@ -AC_PREREQ(2.61) +AC_PREREQ([2.61]) AC_INIT([GENIVI Common API DBus C++ Library], [2.0], [], [CommonAPI-DBus]) +AC_USE_SYSTEM_EXTENSIONS + AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([build-aux/config.h]) AC_CONFIG_FILES([ - Makefile - CommonAPI-DBus.pc - CommonAPI-DBus-uninstalled.pc]) + Makefile + CommonAPI-DBus.pc + CommonAPI-DBus-uninstalled.pc]) AC_CANONICAL_SYSTEM @@ -31,6 +33,13 @@ LT_INIT PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(COMMONAPI, [CommonAPI >= 0.7]) PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.4.6]) +PKG_CHECK_MODULES(GLIB, [glib-2.0], + [], + [ + echo "WARNING: No glib found, tests will not be compiled!" + TESTS_CAN_BE_EXECUTED=false + ] +) GTEST_MIN_VERSION="1.6.0" GTEST_URL="http://code.google.com/p/googletest" @@ -58,8 +67,7 @@ AS_IF([test -f "${GTEST_CONFIG}"], [] ) -AM_CONDITIONAL(ENABLE_TESTS, [test -f "${GTEST_CONFIG}"]) - +AM_CONDITIONAL(ENABLE_TESTS, [test -f "${GTEST_CONFIG}" && ${TESTS_CAN_BE_EXECUTED}]) # Doxygen support DX_HTML_FEATURE(ON) @@ -71,17 +79,17 @@ DX_XML_FEATURE(OFF) DX_PDF_FEATURE(OFF) DX_PS_FEATURE(OFF) DX_INIT_DOXYGEN(${PACKAGE_NAME}, doxygen.cfg, doc) - + AC_MSG_RESULT([ $PACKAGE_NAME v$VERSION enable docs: ${ENABLE_DOCS} - COMMONAPI_CFLAGS: ${COMMONAPI_CFLAGS} - COMMONAPI_LIBS: ${COMMONAPI_LIBS} + COMMONAPI_CFLAGS: ${COMMONAPI_CFLAGS} + COMMONAPI_LIBS: ${COMMONAPI_LIBS} - DBUS_CFLAGS: ${DBUS_CFLAGS} - DBUS_LIBS: ${DBUS_LIBS} + DBUS_CFLAGS: ${DBUS_CFLAGS} + DBUS_LIBS: ${DBUS_LIBS} GTEST_CONFIG: ${GTEST_CONFIG} GTEST_CPPFLAGS: ${GTEST_CPPFLAGS} @@ -95,4 +103,4 @@ AC_MSG_RESULT([ LDFLAGS: ${LDFLAGS} ]) -AC_OUTPUT
\ No newline at end of file +AC_OUTPUT diff --git a/src/CommonAPI/DBus/DBusAttribute.h b/src/CommonAPI/DBus/DBusAttribute.h index 04d1e72..4844b87 100644 --- a/src/CommonAPI/DBus/DBusAttribute.h +++ b/src/CommonAPI/DBus/DBusAttribute.h @@ -31,11 +31,9 @@ class DBusReadonlyAttribute: public _AttributeType { assert(getMethodName); } - CallStatus getValue(ValueType& value) const { - CallStatus callStatus; + void getValue(CallStatus& callStatus, ValueType& value) const { DBusProxyHelper<DBusSerializableArguments<>, DBusSerializableArguments<ValueType> >::callMethodWithReply(dbusProxy_, getMethodName_, "", callStatus, value); - return callStatus; } std::future<CallStatus> getValueAsync(AttributeAsyncCallback attributeAsyncCallback) { diff --git a/src/CommonAPI/DBus/DBusConnection.cpp b/src/CommonAPI/DBus/DBusConnection.cpp index 4b4c406..df77e95 100644 --- a/src/CommonAPI/DBus/DBusConnection.cpp +++ b/src/CommonAPI/DBus/DBusConnection.cpp @@ -29,17 +29,43 @@ DBusObjectPathVTable DBusConnection::libdbusObjectPathVTable_ = { &DBusConnection::onLibdbusObjectPathMessageThunk }; -void DBusConnection::dispatch() { - while (!stopDispatching_ && readWriteDispatch(10)) { +void DBusConnection::dispatch(std::shared_ptr<DBusConnection> selfReference) { + while (!stopDispatching_ && readWriteDispatch(10) && !selfReference.unique()) { + if(pauseDispatching_) { + dispatchSuspendLock_.lock(); + dispatchSuspendLock_.unlock(); + } } } +bool DBusConnection::readWriteDispatch(int timeoutMilliseconds) { + if(isConnected()) { + const dbus_bool_t libdbusSuccess = dbus_connection_read_write_dispatch(libdbusConnection_, + timeoutMilliseconds); + return libdbusSuccess; + } + return false; +} + +void DBusConnection::suspendDispatching() const { + dispatchSuspendLock_.lock(); + pauseDispatching_ = true; +} + +void DBusConnection::resumeDispatching() const { + pauseDispatching_ = false; + dispatchSuspendLock_.unlock(); +} + DBusConnection::DBusConnection(BusType busType) : busType_(busType), libdbusConnection_(NULL), dbusConnectionStatusEvent_(this), - isLibdbusSignalFilterAdded_(false), - stopDispatching_(false) { + stopDispatching_(false), + pauseDispatching_(false), + dispatchThread_(NULL), + dbusObjectMessageHandler_(), + watchContext_(NULL) { dbus_threads_init_default(); } @@ -47,27 +73,176 @@ DBusConnection::DBusConnection(::DBusConnection* libDbusConnection) : busType_(WRAPPED), libdbusConnection_(libDbusConnection), dbusConnectionStatusEvent_(this), - isLibdbusSignalFilterAdded_(false), - stopDispatching_(false) { + stopDispatching_(false), + pauseDispatching_(false), + dispatchThread_(NULL), + dbusObjectMessageHandler_(), + watchContext_(NULL) { dbus_threads_init_default(); } +void DBusConnection::setObjectPathMessageHandler(DBusObjectPathMessageHandler handler) { + dbusObjectMessageHandler_ = handler; +} + +bool DBusConnection::isObjectPathMessageHandlerSet() { + return dbusObjectMessageHandler_.operator bool(); +} + DBusConnection::~DBusConnection() { - if (isConnected()) { - disconnect(); + if(auto lockedContext = mainLoopContext_.lock()) { + dbus_connection_set_watch_functions(libdbusConnection_, NULL, NULL, NULL, NULL, NULL); + dbus_connection_set_timeout_functions(libdbusConnection_, NULL, NULL, NULL, NULL, NULL); + + lockedContext->deregisterDispatchSource(dispatchSource_); + delete watchContext_; + delete dispatchSource_; + } + + disconnect(); +} + + +bool DBusConnection::attachMainLoopContext(std::weak_ptr<MainLoopContext> mainLoopContext) { + mainLoopContext_ = mainLoopContext; + + if (auto lockedContext = mainLoopContext_.lock()) { + dispatchSource_ = new DBusDispatchSource(this); + watchContext_ = new WatchContext(mainLoopContext_, dispatchSource_); + lockedContext->registerDispatchSource(dispatchSource_); + + dbus_connection_set_wakeup_main_function( + libdbusConnection_, + &DBusConnection::onWakeupMainContext, + &mainLoopContext_, + NULL); + + bool success = dbus_connection_set_watch_functions( + libdbusConnection_, + &DBusConnection::onAddWatch, + &DBusConnection::onRemoveWatch, + &DBusConnection::onToggleWatch, + watchContext_, + NULL); + + if (!success) { + return false; + } + + success = dbus_connection_set_timeout_functions( + libdbusConnection_, + &DBusConnection::onAddTimeout, + &DBusConnection::onRemoveTimeout, + &DBusConnection::onToggleTimeout, + &mainLoopContext_, + NULL); + + if (!success) { + dbus_connection_set_watch_functions(libdbusConnection_, NULL, NULL, NULL, NULL, NULL); + return false; + } + + return true; } + return false; } -bool DBusConnection::connect() { +void DBusConnection::onWakeupMainContext(void* data) { + std::weak_ptr<MainLoopContext>* mainloop = static_cast<std::weak_ptr<MainLoopContext>*>(data); + assert(mainloop); + + if(auto lockedContext = mainloop->lock()) { + lockedContext->wakeup(); + } +} + + +dbus_bool_t DBusConnection::onAddWatch(::DBusWatch* libdbusWatch, void* data) { + WatchContext* watchContext = static_cast<WatchContext*>(data); + assert(watchContext); + + DBusWatch* dbusWatch = new DBusWatch(libdbusWatch, watchContext->mainLoopContext_); + dbusWatch->addDependentDispatchSource(watchContext->dispatchSource_); + dbus_watch_set_data(libdbusWatch, dbusWatch, NULL); + + if (dbusWatch->isReadyToBeWatched()) { + dbusWatch->startWatching(); + } + + return TRUE; +} + +void DBusConnection::onRemoveWatch(::DBusWatch* libdbusWatch, void* data) { + assert(static_cast<WatchContext*>(data)); + + DBusWatch* dbusWatch = static_cast<DBusWatch*>(dbus_watch_get_data(libdbusWatch)); + if(dbusWatch->isReadyToBeWatched()) { + dbusWatch->stopWatching(); + } + dbus_watch_set_data(libdbusWatch, NULL, NULL); + delete dbusWatch; +} + +void DBusConnection::onToggleWatch(::DBusWatch* libdbusWatch, void* data) { + assert(static_cast<WatchContext*>(data)); + + DBusWatch* dbusWatch = static_cast<DBusWatch*>(dbus_watch_get_data(libdbusWatch)); + + if (dbusWatch->isReadyToBeWatched()) { + dbusWatch->startWatching(); + } else { + dbusWatch->stopWatching(); + } +} + + +dbus_bool_t DBusConnection::onAddTimeout(::DBusTimeout* libdbusTimeout, void* data) { + std::weak_ptr<MainLoopContext>* mainloop = static_cast<std::weak_ptr<MainLoopContext>*>(data); + assert(mainloop); + + DBusTimeout* dbusTimeout = new DBusTimeout(libdbusTimeout, *mainloop); + dbus_timeout_set_data(libdbusTimeout, dbusTimeout, NULL); + + if (dbusTimeout->isReadyToBeMonitored()) { + dbusTimeout->startMonitoring(); + } + + return TRUE; +} + +void DBusConnection::onRemoveTimeout(::DBusTimeout* libdbusTimeout, void* data) { + assert(static_cast<std::weak_ptr<MainLoopContext>*>(data)); + + DBusTimeout* dbusTimeout = static_cast<DBusTimeout*>(dbus_timeout_get_data(libdbusTimeout)); + dbusTimeout->stopMonitoring(); + dbus_timeout_set_data(libdbusTimeout, NULL, NULL); + delete dbusTimeout; +} + +void DBusConnection::onToggleTimeout(::DBusTimeout* dbustimeout, void* data) { + assert(static_cast<std::weak_ptr<MainLoopContext>*>(data)); + + DBusTimeout* timeout = static_cast<DBusTimeout*>(dbus_timeout_get_data(dbustimeout)); + + if (timeout->isReadyToBeMonitored()) { + timeout->startMonitoring(); + } else { + timeout->stopMonitoring(); + } +} + + +bool DBusConnection::connect(bool startDispatchThread) { DBusError dbusError; - return connect(dbusError); + return connect(dbusError, startDispatchThread); } -bool DBusConnection::connect(DBusError& dbusError) { +bool DBusConnection::connect(DBusError& dbusError, bool startDispatchThread) { assert(!dbusError); - if (isConnected()) + if (isConnected()) { return true; + } const ::DBusBusType libdbusType = static_cast<DBusBusType>(busType_); @@ -83,8 +258,10 @@ bool DBusConnection::connect(DBusError& dbusError) { initLibdbusSignalFilterAfterConnect(); - stopDispatching_ = false; - dispatchThread_ = std::thread(std::bind(&DBusConnection::dispatch, this)); + if(startDispatchThread) { + dispatchThread_ = new std::thread(&DBusConnection::dispatch, this, this->shared_from_this()); + } + stopDispatching_ = !startDispatchThread; dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::AVAILABLE); @@ -94,6 +271,8 @@ bool DBusConnection::connect(DBusError& dbusError) { void DBusConnection::disconnect() { std::lock_guard<std::mutex> dbusConnectionLock(libdbusConnectionGuard_); if (isConnected()) { + dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::NOT_AVAILABLE); + if (!dbusSignalMatchRulesMap_.empty()) { dbus_connection_remove_filter(libdbusConnection_, &onLibdbusSignalFilterThunk, this); } @@ -102,18 +281,20 @@ void DBusConnection::disconnect() { dbus_connection_close(libdbusConnection_); - //It is possible for the disconnect to be called from within a callback, i.e. from within the dispatch - //thread. Self-join is prevented this way. - if (dispatchThread_.joinable() && std::this_thread::get_id() != dispatchThread_.get_id()) { - dispatchThread_.join(); - } else { - dispatchThread_.detach(); + if(dispatchThread_) { + //It is possible for the disconnect to be called from within a callback, i.e. from within the dispatch + //thread. Self-join is prevented this way. + if (dispatchThread_->joinable() && std::this_thread::get_id() != dispatchThread_->get_id()) { + dispatchThread_->join(); + } else { + dispatchThread_->detach(); + } + delete dispatchThread_; + dispatchThread_ = NULL; } dbus_connection_unref(libdbusConnection_); libdbusConnection_ = NULL; - - dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::NOT_AVAILABLE); } } @@ -128,9 +309,13 @@ DBusProxyConnection::ConnectionStatusEvent& DBusConnection::getConnectionStatusE const std::shared_ptr<DBusServiceRegistry> DBusConnection::getDBusServiceRegistry() { std::shared_ptr<DBusServiceRegistry> serviceRegistry = dbusServiceRegistry_.lock(); if (!serviceRegistry || dbusServiceRegistry_.expired()) { - serviceRegistry = std::make_shared<DBusServiceRegistry>(this->shared_from_this()); - serviceRegistry->init(); - dbusServiceRegistry_ = serviceRegistry; + serviceRegistryGuard_.lock(); + if (!serviceRegistry || dbusServiceRegistry_.expired()) { + serviceRegistry = std::make_shared<DBusServiceRegistry>(shared_from_this()); + serviceRegistry->init(); + dbusServiceRegistry_ = serviceRegistry; + } + serviceRegistryGuard_.unlock(); } return serviceRegistry; @@ -138,7 +323,11 @@ const std::shared_ptr<DBusServiceRegistry> DBusConnection::getDBusServiceRegistr const std::shared_ptr<DBusObjectManager> DBusConnection::getDBusObjectManager() { if (!dbusObjectManager_) { - dbusObjectManager_ = std::make_shared<DBusObjectManager>(this->shared_from_this()); + objectManagerGuard_.lock(); + if (!dbusObjectManager_) { + dbusObjectManager_ = std::make_shared<DBusObjectManager>(shared_from_this()); + } + objectManagerGuard_.unlock(); } return dbusObjectManager_; @@ -146,10 +335,16 @@ const std::shared_ptr<DBusObjectManager> DBusConnection::getDBusObjectManager() bool DBusConnection::requestServiceNameAndBlock(const std::string& serviceName) const { DBusError dbusError; + + suspendDispatching(); + const int libdbusStatus = dbus_bus_request_name(libdbusConnection_, serviceName.c_str(), DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbusError.libdbusError_); + + resumeDispatching(); + const bool isServiceNameAcquired = (libdbusStatus == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); return isServiceNameAcquired; @@ -157,9 +352,11 @@ bool DBusConnection::requestServiceNameAndBlock(const std::string& serviceName) bool DBusConnection::releaseServiceName(const std::string& serviceName) const { DBusError dbusError; + suspendDispatching(); const int libdbusStatus = dbus_bus_release_name(libdbusConnection_, serviceName.c_str(), &dbusError.libdbusError_); + resumeDispatching(); const bool isServiceNameReleased = (libdbusStatus == DBUS_RELEASE_NAME_REPLY_RELEASED); return isServiceNameReleased; @@ -242,31 +439,39 @@ std::future<CallStatus> DBusConnection::sendDBusMessageWithReplyAsync( DBusMessage DBusConnection::sendDBusMessageWithReplyAndBlock(const DBusMessage& dbusMessage, DBusError& dbusError, int timeoutMilliseconds) const { + auto selfReference = this->shared_from_this(); + assert(dbusMessage); assert(!dbusError); assert(isConnected()); + suspendDispatching(); + ::DBusMessage* libdbusMessageReply = dbus_connection_send_with_reply_and_block(libdbusConnection_, dbusMessage.libdbusMessage_, timeoutMilliseconds, &dbusError.libdbusError_); - if (dbusError) + + resumeDispatching(); + + if (dbusError) { return DBusMessage(); + } const bool increaseLibdbusMessageReferenceCount = false; return DBusMessage(libdbusMessageReply, increaseLibdbusMessageReferenceCount); } -bool DBusConnection::readWriteDispatch(int timeoutMilliseconds) { - if(isConnected()) { - const dbus_bool_t libdbusSuccess = dbus_connection_read_write_dispatch(libdbusConnection_, - timeoutMilliseconds); - return libdbusSuccess; - } - return false; +bool DBusConnection::singleDispatch() { + return (dbus_connection_dispatch(libdbusConnection_) == DBUS_DISPATCH_DATA_REMAINS); +} + +bool DBusConnection::isDispatchReady() { + return (dbus_connection_get_dispatch_status(libdbusConnection_) == DBUS_DISPATCH_DATA_REMAINS); } + DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandler(const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, @@ -291,25 +496,23 @@ DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandl void DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken) { std::lock_guard<std::mutex> dbusSignalLock(signalGuard_); auto equalRangeIteratorPair = dbusSignalHandlerTable_.equal_range(dbusSignalHandlerToken); + if (equalRangeIteratorPair.first != equalRangeIteratorPair.second) { + // advance to the next element + equalRangeIteratorPair.first++; - // the range can't be empty! - assert(equalRangeIteratorPair.first != equalRangeIteratorPair.second); - - // advance to the next element - equalRangeIteratorPair.first++; + // check if the first element was the only element + const bool isLastSignalMemberHandler = equalRangeIteratorPair.first == equalRangeIteratorPair.second; - // check if the first element was the only element - const bool isLastSignalMemberHandler = equalRangeIteratorPair.first == equalRangeIteratorPair.second; + if (isLastSignalMemberHandler) { + const std::string& objectPath = std::get<0>(dbusSignalHandlerToken); + const std::string& interfaceName = std::get<1>(dbusSignalHandlerToken); + const std::string& interfaceMemberName = std::get<2>(dbusSignalHandlerToken); - if (isLastSignalMemberHandler) { - const std::string& objectPath = std::get<0>(dbusSignalHandlerToken); - const std::string& interfaceName = std::get<1>(dbusSignalHandlerToken); - const std::string& interfaceMemberName = std::get<2>(dbusSignalHandlerToken); + removeLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName); + } - removeLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName); + dbusSignalHandlerTable_.erase(dbusSignalHandlerToken); } - - dbusSignalHandlerTable_.erase(dbusSignalHandlerToken); } void DBusConnection::registerObjectPath(const std::string& objectPath) { @@ -397,6 +600,7 @@ void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath, // if not connected the filter and the rules will be added as soon as the connection is established if (isConnected()) { + suspendDispatching(); // add the libdbus message signal filter if (isFirstMatchRule) { const dbus_bool_t libdbusSuccess = dbus_connection_add_filter(libdbusConnection_, @@ -410,6 +614,8 @@ void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath, DBusError dbusError; dbus_bus_add_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_); assert(!dbusError); + + resumeDispatching(); } } @@ -430,8 +636,12 @@ void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath, } const std::string& matchRuleString = matchRuleIterator->second.second; + + suspendDispatching(); + DBusError dbusError; dbus_bus_remove_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_); + assert(!dbusError); dbusSignalMatchRulesMap_.erase(matchRuleIterator); @@ -440,14 +650,17 @@ void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath, if (isLastMatchRule) { dbus_connection_remove_filter(libdbusConnection_, &onLibdbusSignalFilterThunk, this); } + + resumeDispatching(); } void DBusConnection::initLibdbusObjectPathHandlerAfterConnect() { assert(isConnected()); // nothing to do if there aren't any registered object path handlers - if (libdbusRegisteredObjectPaths_.empty()) + if (libdbusRegisteredObjectPaths_.empty()) { return; + } DBusError dbusError; dbus_bool_t libdbusSuccess; @@ -476,6 +689,8 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { if (dbusSignalMatchRulesMap_.empty()) return; + suspendDispatching(); + // first we add the libdbus message signal filter const dbus_bool_t libdbusSuccess = dbus_connection_add_filter(libdbusConnection_, &onLibdbusSignalFilterThunk, @@ -492,9 +707,10 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { dbus_bus_add_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_); assert(!dbusError); } + resumeDispatching(); } -::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage) const { +::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage) { assert(libdbusMessage); // handle only method call messages @@ -502,7 +718,7 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - bool isDBusMessageHandled = dbusObjectManager_->handleMessage(DBusMessage(libdbusMessage)); + bool isDBusMessageHandled = dbusObjectMessageHandler_(DBusMessage(libdbusMessage)); return isDBusMessageHandled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -511,8 +727,9 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { auto selfReference = this->shared_from_this(); // handle only signal messages - if (dbus_message_get_type(libdbusMessage) != DBUS_MESSAGE_TYPE_SIGNAL) + if (dbus_message_get_type(libdbusMessage) != DBUS_MESSAGE_TYPE_SIGNAL) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } const char* objectPath = dbus_message_get_path(libdbusMessage); const char* interfaceName = dbus_message_get_interface(libdbusMessage); @@ -536,9 +753,7 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { const SubscriptionStatus dbusSignalHandlerSubscriptionStatus = dbusSignalHandler->onSignalDBusMessage(dbusMessage); if (dbusSignalHandlerSubscriptionStatus == SubscriptionStatus::CANCEL) { - auto dbusSignalHandlerSubscription = equalRangeIteratorPair.first; - equalRangeIteratorPair.first++; - dbusSignalHandlerTable_.erase(dbusSignalHandlerSubscription); + equalRangeIteratorPair.first = dbusSignalHandlerTable_.erase(equalRangeIteratorPair.first); } else { equalRangeIteratorPair.first++; } @@ -571,7 +786,7 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { assert(libdbusMessage); assert(userData); - const DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData); + DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData); assert(dbusConnection->libdbusConnection_ == libdbusConnection); diff --git a/src/CommonAPI/DBus/DBusConnection.h b/src/CommonAPI/DBus/DBusConnection.h index 8e95296..81c8cfa 100644 --- a/src/CommonAPI/DBus/DBusConnection.h +++ b/src/CommonAPI/DBus/DBusConnection.h @@ -11,10 +11,10 @@ #include "DBusDaemonProxy.h" #include "DBusServiceRegistry.h" #include "DBusObjectManager.h" +#include "DBusMainLoopContext.h" #include <dbus/dbus.h> - namespace CommonAPI { namespace DBus { @@ -32,134 +32,169 @@ class DBusConnectionStatusEvent: public DBusProxyConnection::ConnectionStatusEve DBusConnection* dbusConnection_; }; +struct WatchContext { + WatchContext(std::weak_ptr<MainLoopContext> mainLoopContext, DispatchSource* dispatchSource) : + mainLoopContext_(mainLoopContext), dispatchSource_(dispatchSource) { + } + + std::weak_ptr<MainLoopContext> mainLoopContext_; + DispatchSource* dispatchSource_; +}; class DBusConnection: public DBusProxyConnection, public std::enable_shared_from_this<DBusConnection> { public: - enum BusType { - SESSION = DBUS_BUS_SESSION, - SYSTEM = DBUS_BUS_SYSTEM, - STARTER = DBUS_BUS_STARTER, - WRAPPED - }; + enum BusType { + SESSION = DBUS_BUS_SESSION, + SYSTEM = DBUS_BUS_SYSTEM, + STARTER = DBUS_BUS_STARTER, + WRAPPED + }; - DBusConnection(BusType busType); + DBusConnection(BusType busType); - inline static std::shared_ptr<DBusConnection> getBus(const BusType& busType); - inline static std::shared_ptr<DBusConnection> wrapLibDBus(::DBusConnection* libDbusConnection); - inline static std::shared_ptr<DBusConnection> getSessionBus(); - inline static std::shared_ptr<DBusConnection> getSystemBus(); - inline static std::shared_ptr<DBusConnection> getStarterBus(); + inline static std::shared_ptr<DBusConnection> getBus(const BusType& busType); + inline static std::shared_ptr<DBusConnection> wrapLibDBus(::DBusConnection* libDbusConnection); + inline static std::shared_ptr<DBusConnection> getSessionBus(); + inline static std::shared_ptr<DBusConnection> getSystemBus(); + inline static std::shared_ptr<DBusConnection> getStarterBus(); - DBusConnection(const DBusConnection&) = delete; - DBusConnection(::DBusConnection* libDbusConnection); + DBusConnection(const DBusConnection&) = delete; + DBusConnection(::DBusConnection* libDbusConnection); - DBusConnection& operator=(const DBusConnection&) = delete; - virtual ~DBusConnection(); + DBusConnection& operator=(const DBusConnection&) = delete; + virtual ~DBusConnection(); - BusType getBusType() const; + BusType getBusType() const; - bool connect(); - bool connect(DBusError& dbusError); - void disconnect(); + bool connect(bool startDispatchThread = true); + bool connect(DBusError& dbusError, bool startDispatchThread = true); + void disconnect(); - virtual bool isConnected() const; + virtual bool isConnected() const; - virtual ConnectionStatusEvent& getConnectionStatusEvent(); + virtual ConnectionStatusEvent& getConnectionStatusEvent(); - virtual bool requestServiceNameAndBlock(const std::string& serviceName) const; - virtual bool releaseServiceName(const std::string& serviceName) const; + virtual bool requestServiceNameAndBlock(const std::string& serviceName) const; + virtual bool releaseServiceName(const std::string& serviceName) const; - bool sendDBusMessage(const DBusMessage& dbusMessage, uint32_t* allocatedSerial = NULL) const; + bool sendDBusMessage(const DBusMessage& dbusMessage, uint32_t* allocatedSerial = NULL) const; - static const int kDefaultSendTimeoutMs = 100 * 1000; + static const int kDefaultSendTimeoutMs = 5000; - std::future<CallStatus> sendDBusMessageWithReplyAsync( - const DBusMessage& dbusMessage, - std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler, - int timeoutMilliseconds = kDefaultSendTimeoutMs) const; + std::future<CallStatus> sendDBusMessageWithReplyAsync( + const DBusMessage& dbusMessage, + std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler, + int timeoutMilliseconds = kDefaultSendTimeoutMs) const; - DBusMessage sendDBusMessageWithReplyAndBlock(const DBusMessage& dbusMessage, - DBusError& dbusError, - int timeoutMilliseconds = kDefaultSendTimeoutMs) const; + DBusMessage sendDBusMessageWithReplyAndBlock(const DBusMessage& dbusMessage, + DBusError& dbusError, + int timeoutMilliseconds = kDefaultSendTimeoutMs) const; - DBusSignalHandlerToken addSignalMemberHandler(const std::string& objectPath, - const std::string& interfaceName, - const std::string& interfaceMemberName, - const std::string& interfaceMemberSignature, - DBusSignalHandler* dbusSignalHandler); + DBusSignalHandlerToken addSignalMemberHandler(const std::string& objectPath, + const std::string& interfaceName, + const std::string& interfaceMemberName, + const std::string& interfaceMemberSignature, + DBusSignalHandler* dbusSignalHandler); - void registerObjectPath(const std::string& objectPath); - void unregisterObjectPath(const std::string& objectPath); + void registerObjectPath(const std::string& objectPath); + void unregisterObjectPath(const std::string& objectPath); - void removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken); + void removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken); - bool readWriteDispatch(int timeoutMilliseconds = -1); + bool readWriteDispatch(int timeoutMilliseconds = -1); virtual const std::shared_ptr<DBusServiceRegistry> getDBusServiceRegistry(); virtual const std::shared_ptr<DBusObjectManager> getDBusObjectManager(); + void setObjectPathMessageHandler(DBusObjectPathMessageHandler); + bool isObjectPathMessageHandlerSet(); + + virtual bool attachMainLoopContext(std::weak_ptr<MainLoopContext>); + + bool isDispatchReady(); + bool singleDispatch(); + private: - void dispatch(); + void dispatch(std::shared_ptr<DBusConnection> selfReference); + void suspendDispatching() const; + void resumeDispatching() const; - std::thread dispatchThread_; + std::thread* dispatchThread_; bool stopDispatching_; - void addLibdbusSignalMatchRule(const std::string& objectPath, - const std::string& interfaceName, - const std::string& interfaceMemberName); + std::weak_ptr<MainLoopContext> mainLoopContext_; + DispatchSource* dispatchSource_; + WatchContext* watchContext_; - void removeLibdbusSignalMatchRule(const std::string& objectPath, - const std::string& interfaceName, - const std::string& interfaceMemberName); + mutable bool pauseDispatching_; + mutable std::mutex dispatchSuspendLock_; - void initLibdbusObjectPathHandlerAfterConnect(); + void addLibdbusSignalMatchRule(const std::string& objectPath, + const std::string& interfaceName, + const std::string& interfaceMemberName); - void initLibdbusSignalFilterAfterConnect(); + void removeLibdbusSignalMatchRule(const std::string& objectPath, + const std::string& interfaceName, + const std::string& interfaceMemberName); - ::DBusHandlerResult onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage) const; + void initLibdbusSignalFilterAfterConnect(); + ::DBusHandlerResult onLibdbusSignalFilter(::DBusMessage* libdbusMessage); - ::DBusHandlerResult onLibdbusSignalFilter(::DBusMessage* libdbusMessage); + void initLibdbusObjectPathHandlerAfterConnect(); + ::DBusHandlerResult onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage); - static void onLibdbusPendingCallNotifyThunk(::DBusPendingCall* libdbusPendingCall, void* userData); - static void onLibdbusDataCleanup(void* userData); + static void onLibdbusPendingCallNotifyThunk(::DBusPendingCall* libdbusPendingCall, void* userData); + static void onLibdbusDataCleanup(void* userData); - static ::DBusHandlerResult onLibdbusObjectPathMessageThunk(::DBusConnection* libdbusConnection, - ::DBusMessage* libdbusMessage, - void* userData); + static ::DBusHandlerResult onLibdbusObjectPathMessageThunk(::DBusConnection* libdbusConnection, + ::DBusMessage* libdbusMessage, + void* userData); - static ::DBusHandlerResult onLibdbusSignalFilterThunk(::DBusConnection* libdbusConnection, - ::DBusMessage* libdbusMessage, - void* userData); + static ::DBusHandlerResult onLibdbusSignalFilterThunk(::DBusConnection* libdbusConnection, + ::DBusMessage* libdbusMessage, + void* userData); - BusType busType_; + static dbus_bool_t onAddWatch(::DBusWatch* libdbusWatch, void* data); + static void onRemoveWatch(::DBusWatch* libdbusWatch, void* data); + static void onToggleWatch(::DBusWatch* libdbusWatch, void* data); - ::DBusConnection* libdbusConnection_; - std::mutex libdbusConnectionGuard_; - std::mutex signalGuard_; + static dbus_bool_t onAddTimeout(::DBusTimeout* dbus_timeout, void* data); + static void onRemoveTimeout(::DBusTimeout* dbus_timeout, void* data); + static void onToggleTimeout(::DBusTimeout* dbus_timeout, void* data); - std::weak_ptr<DBusServiceRegistry> dbusServiceRegistry_; - std::shared_ptr<DBusObjectManager> dbusObjectManager_; + static void onWakeupMainContext(void* data); + + ::DBusConnection* libdbusConnection_; + std::mutex libdbusConnectionGuard_; + std::mutex signalGuard_; + std::mutex objectManagerGuard_; + std::mutex serviceRegistryGuard_; + + BusType busType_; - DBusConnectionStatusEvent dbusConnectionStatusEvent_; + std::weak_ptr<DBusServiceRegistry> dbusServiceRegistry_; + std::shared_ptr<DBusObjectManager> dbusObjectManager_; - typedef std::tuple<std::string, std::string, std::string> DBusSignalMatchRuleTuple; - typedef std::pair<uint32_t, std::string> DBusSignalMatchRuleMapping; - typedef std::unordered_map<DBusSignalMatchRuleTuple, DBusSignalMatchRuleMapping> DBusSignalMatchRulesMap; - DBusSignalMatchRulesMap dbusSignalMatchRulesMap_; + DBusConnectionStatusEvent dbusConnectionStatusEvent_; - bool isLibdbusSignalFilterAdded_; + typedef std::tuple<std::string, std::string, std::string> DBusSignalMatchRuleTuple; + typedef std::pair<uint32_t, std::string> DBusSignalMatchRuleMapping; + typedef std::unordered_map<DBusSignalMatchRuleTuple, DBusSignalMatchRuleMapping> DBusSignalMatchRulesMap; + DBusSignalMatchRulesMap dbusSignalMatchRulesMap_; DBusSignalHandlerTable dbusSignalHandlerTable_; - // referenceCount, objectPath + // objectPath, referenceCount typedef std::unordered_map<std::string, uint32_t> LibdbusRegisteredObjectPathHandlersTable; LibdbusRegisteredObjectPathHandlersTable libdbusRegisteredObjectPaths_; static DBusObjectPathVTable libdbusObjectPathVTable_; + + DBusObjectPathMessageHandler dbusObjectMessageHandler_; }; std::shared_ptr<DBusConnection> DBusConnection::getBus(const BusType& busType) { - return std::make_shared<DBusConnection>(busType); + return std::make_shared<DBusConnection>(busType); } std::shared_ptr<DBusConnection> DBusConnection::wrapLibDBus(::DBusConnection* libDbusConnection) { @@ -167,18 +202,17 @@ std::shared_ptr<DBusConnection> DBusConnection::wrapLibDBus(::DBusConnection* li } std::shared_ptr<DBusConnection> DBusConnection::getSessionBus() { - return getBus(BusType::SESSION); + return getBus(BusType::SESSION); } std::shared_ptr<DBusConnection> DBusConnection::getSystemBus() { - return getBus(BusType::SYSTEM); + return getBus(BusType::SYSTEM); } std::shared_ptr<DBusConnection> DBusConnection::getStarterBus() { - return getBus(BusType::STARTER); + return getBus(BusType::STARTER); } - } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusDaemonProxy.cpp b/src/CommonAPI/DBus/DBusDaemonProxy.cpp index f18d2ac..fe81995 100644 --- a/src/CommonAPI/DBus/DBusDaemonProxy.cpp +++ b/src/CommonAPI/DBus/DBusDaemonProxy.cpp @@ -15,10 +15,9 @@ StaticInterfaceVersionAttribute::StaticInterfaceVersionAttribute(const uint32_t& version_(majorValue, minorValue) { } -CallStatus StaticInterfaceVersionAttribute::getValue(Version& version) const { +void StaticInterfaceVersionAttribute::getValue(CallStatus& callStatus, Version& version) const { version = version_; - - return CallStatus::SUCCESS; + callStatus = CallStatus::SUCCESS; } std::future<CallStatus> StaticInterfaceVersionAttribute::getValueAsync(AttributeAsyncCallback attributeAsyncCallback) { @@ -32,12 +31,40 @@ std::future<CallStatus> StaticInterfaceVersionAttribute::getValueAsync(Attribute StaticInterfaceVersionAttribute DBusDaemonProxy::interfaceVersionAttribute_(1, 0); +const std::string DBusDaemonProxy::dbusBusName_ = "org.freedesktop.DBus"; +const std::string DBusDaemonProxy::dbusObjectPath_ = "/org/freedesktop/DBus"; +const std::string DBusDaemonProxy::dbusInterfaceName_ = getInterfaceId(); +const std::string DBusDaemonProxy::commonApiParticipantId_ = "org.freedesktop.DBus-/org/freedesktop/DBus"; + DBusDaemonProxy::DBusDaemonProxy(const std::shared_ptr<DBusProxyConnection>& dbusConnection): - DBusProxyBase(getInterfaceId(), "org.freedesktop.DBus", "/org/freedesktop/DBus", dbusConnection), + DBusProxyBase(dbusConnection), nameOwnerChangedEvent_(*this, "NameOwnerChanged", "sss") { } +std::string DBusDaemonProxy::getAddress() const { + return getDomain() + ":" + getServiceId() + ":" + getInstanceId(); +} +const std::string& DBusDaemonProxy::getDomain() const { + return commonApiDomain_; +} +const std::string& DBusDaemonProxy::getServiceId() const { + return dbusInterfaceName_; +} +const std::string& DBusDaemonProxy::getInstanceId() const { + return commonApiParticipantId_; +} + +const std::string& DBusDaemonProxy::getDBusBusName() const { + return dbusBusName_; +} +const std::string& DBusDaemonProxy::getDBusObjectPath() const { + return dbusObjectPath_; +} +const std::string& DBusDaemonProxy::getInterfaceName() const { + return dbusInterfaceName_; +} + bool DBusDaemonProxy::isAvailable() const { return getDBusConnection()->isConnected(); } @@ -138,12 +165,9 @@ std::future<CallStatus> DBusDaemonProxy::getManagedObjectsAsync(const std::strin "GetManagedObjects", ""); - const int timeoutMilliseconds = 100; - return getDBusConnection()->sendDBusMessageWithReplyAsync( dbusMethodCallMessage, - DBusProxyAsyncCallbackHandler<DBusObjectToInterfaceDict>::create(callback), - timeoutMilliseconds); + DBusProxyAsyncCallbackHandler<DBusObjectToInterfaceDict>::create(callback)); } diff --git a/src/CommonAPI/DBus/DBusDaemonProxy.h b/src/CommonAPI/DBus/DBusDaemonProxy.h index aeb2feb..0053c1b 100644 --- a/src/CommonAPI/DBus/DBusDaemonProxy.h +++ b/src/CommonAPI/DBus/DBusDaemonProxy.h @@ -22,7 +22,7 @@ class StaticInterfaceVersionAttribute: public InterfaceVersionAttribute { public: StaticInterfaceVersionAttribute(const uint32_t& majorValue, const uint32_t& minorValue); - CallStatus getValue(Version& version) const; + void getValue(CallStatus& callStatus, Version& version) const; std::future<CallStatus> getValueAsync(AttributeAsyncCallback attributeAsyncCallback); private: @@ -61,9 +61,23 @@ class DBusDaemonProxy: public DBusProxyBase { std::future<CallStatus> getManagedObjectsAsync(const std::string& forDBusServiceName, GetManagedObjectsAsyncCallback) const; + virtual std::string getAddress() const; + virtual const std::string& getDomain() const; + virtual const std::string& getServiceId() const; + virtual const std::string& getInstanceId() const; + + virtual const std::string& getDBusBusName() const; + virtual const std::string& getDBusObjectPath() const; + virtual const std::string& getInterfaceName() const; + private: DBusEvent<NameOwnerChangedEvent> nameOwnerChangedEvent_; static StaticInterfaceVersionAttribute interfaceVersionAttribute_; + + static const std::string dbusBusName_; + static const std::string dbusObjectPath_; + static const std::string commonApiParticipantId_; + static const std::string dbusInterfaceName_; }; const char* DBusDaemonProxy::getInterfaceId() { diff --git a/src/CommonAPI/DBus/DBusFactory.cpp b/src/CommonAPI/DBus/DBusFactory.cpp index de74ef1..c75a393 100644 --- a/src/CommonAPI/DBus/DBusFactory.cpp +++ b/src/CommonAPI/DBus/DBusFactory.cpp @@ -4,6 +4,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + #include "DBusProxy.h" #include "DBusConnection.h" #include "DBusFactory.h" @@ -20,6 +21,7 @@ namespace CommonAPI { namespace DBus { + std::unordered_map<std::string, DBusProxyFactoryFunction>* registeredProxyFactoryFunctions_; std::unordered_map<std::string, DBusAdapterFactoryFunction>* registeredAdapterFactoryFunctions_; @@ -39,12 +41,16 @@ void DBusFactory::registerAdapterFactoryMethod(std::string interfaceName, DBusAd } - -DBusFactory::DBusFactory(std::shared_ptr<Runtime> runtime, const MiddlewareInfo* middlewareInfo) : +DBusFactory::DBusFactory(std::shared_ptr<Runtime> runtime, const MiddlewareInfo* middlewareInfo, std::shared_ptr<MainLoopContext> mainLoopContext) : CommonAPI::Factory(runtime, middlewareInfo), dbusConnection_(CommonAPI::DBus::DBusConnection::getSessionBus()), - acquiredConnectionName_("") { - dbusConnection_->connect(); + acquiredConnectionName_(""), + mainLoopContext_(mainLoopContext) { + bool startDispatchThread = !mainLoopContext_; + dbusConnection_->connect(startDispatchThread); + if(mainLoopContext_) { + dbusConnection_->attachMainLoopContext(mainLoopContext); + } } @@ -120,27 +126,28 @@ bool DBusFactory::registerAdapter(std::shared_ptr<StubBase> stubBase, DBusAddressTranslator::getInstance().searchForDBusAddress(commonApiAddress, interfaceName, connectionName, objectPath); if(acquiredConnectionName_ == "") { - dbusConnection_->requestServiceNameAndBlock(connectionName); + bool isServiceNameAcquired = dbusConnection_->requestServiceNameAndBlock(connectionName); + if(!isServiceNameAcquired) { + return false; + } acquiredConnectionName_ = connectionName; } else if (acquiredConnectionName_ != connectionName) { - return NULL; + return false; } if(!registeredAdapterFactoryFunctions_) { registeredAdapterFactoryFunctions_ = new std::unordered_map<std::string, DBusAdapterFactoryFunction> {}; } - for (auto it = registeredAdapterFactoryFunctions_->begin(); it != registeredAdapterFactoryFunctions_->end(); ++it) { - if(it->first == interfaceId) { - std::shared_ptr<DBusStubAdapter> dbusStubAdapter = (it->second)(commonApiAddress, interfaceName, connectionName, objectPath, dbusConnection_, stubBase); - if(!dbusStubAdapter) { - return false; - } - std::string address = domain + ":" + serviceName + ":" + participantId; - if(registeredServices_.insert( {std::move(address), dbusStubAdapter} ).second) { - dbusStubAdapter->init(); - return true; - } + auto foundFunction = registeredAdapterFactoryFunctions_->find(interfaceId); + if(foundFunction != registeredAdapterFactoryFunctions_->end()) { + std::shared_ptr<DBusStubAdapter> dbusStubAdapter = (foundFunction->second)(commonApiAddress, interfaceName, connectionName, objectPath, dbusConnection_, stubBase); + if(!dbusStubAdapter) { + return false; + } + if(registeredServices_.insert( {std::move(commonApiAddress), dbusStubAdapter} ).second) { + dbusStubAdapter->init(); + return true; } } diff --git a/src/CommonAPI/DBus/DBusFactory.h b/src/CommonAPI/DBus/DBusFactory.h index a3edfdc..2b1a813 100644 --- a/src/CommonAPI/DBus/DBusFactory.h +++ b/src/CommonAPI/DBus/DBusFactory.h @@ -18,11 +18,14 @@ namespace CommonAPI { namespace DBus { +class DBusMainLoopContext; + typedef std::shared_ptr<DBusProxy> (*DBusProxyFactoryFunction) (const std::string& commonApiAddress, const std::string& interfaceName, const std::string& busName, const std::string& objectPath, const std::shared_ptr<DBusProxyConnection>& dbusProxyConnection); + typedef std::shared_ptr<DBusStubAdapter> (*DBusAdapterFactoryFunction) (const std::string& commonApiAddress, const std::string& interfaceName, const std::string& busName, @@ -32,7 +35,7 @@ typedef std::shared_ptr<DBusStubAdapter> (*DBusAdapterFactoryFunction) (const st class DBusFactory: public Factory { public: - DBusFactory(std::shared_ptr<Runtime> runtime, const MiddlewareInfo* middlewareInfo); + DBusFactory(std::shared_ptr<Runtime> runtime, const MiddlewareInfo* middlewareInfo, std::shared_ptr<MainLoopContext> mainLoopContext = std::shared_ptr<MainLoopContext>(NULL)); virtual ~DBusFactory(); static void registerProxyFactoryMethod(std::string interfaceName, DBusProxyFactoryFunction proxyFactoryFunction); @@ -53,6 +56,7 @@ class DBusFactory: public Factory { std::shared_ptr<CommonAPI::DBus::DBusConnection> dbusConnection_; std::string acquiredConnectionName_; std::unordered_map<std::string, std::shared_ptr<DBusStubAdapter>> registeredServices_; + std::shared_ptr<MainLoopContext> mainLoopContext_; }; } // namespace DBus diff --git a/src/CommonAPI/DBus/DBusInputStream.h b/src/CommonAPI/DBus/DBusInputStream.h index 3409d4c..6a8b32b 100644 --- a/src/CommonAPI/DBus/DBusInputStream.h +++ b/src/CommonAPI/DBus/DBusInputStream.h @@ -193,11 +193,6 @@ class DBusInputStream: public InputStream { return *this; } - /** - * Returns the position of the reading pointer, relative to the beginning of the data stream. - */ - position_t getCurrentPosition() const; - private: inline void beginReadGenericVector() { uint32_t vectorByteSize; diff --git a/src/CommonAPI/DBus/DBusMainLoopContext.cpp b/src/CommonAPI/DBus/DBusMainLoopContext.cpp new file mode 100644 index 0000000..9b9c57c --- /dev/null +++ b/src/CommonAPI/DBus/DBusMainLoopContext.cpp @@ -0,0 +1,143 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "DBusMainLoopContext.h" +#include "DBusConnection.h" + +#include <poll.h> +#include <chrono> + + +namespace CommonAPI { +namespace DBus { + + +DBusDispatchSource::DBusDispatchSource(DBusConnection* dbusConnection): + dbusConnection_(dbusConnection) { +} + +DBusDispatchSource::~DBusDispatchSource() { +} + +bool DBusDispatchSource::prepare(int64_t& timeout) { + return dbusConnection_->isDispatchReady(); +} + +bool DBusDispatchSource::check() { + return dbusConnection_->isDispatchReady(); +} + +bool DBusDispatchSource::dispatch() { + return dbusConnection_->singleDispatch(); +} + + +DBusWatch::DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext): + libdbusWatch_(libdbusWatch), + mainLoopContext_(mainLoopContext), + channelFlags_(0) { + assert(libdbusWatch_); +} + +bool DBusWatch::isReadyToBeWatched() { + return dbus_watch_get_enabled(libdbusWatch_); +} + +void DBusWatch::startWatching() { + channelFlags_ = dbus_watch_get_flags(libdbusWatch_); + short int pollFlags = POLLERR | POLLHUP; + if(channelFlags_ & DBUS_WATCH_READABLE) { + pollFlags |= POLLIN; + } + if(channelFlags_ & DBUS_WATCH_WRITABLE) { + pollFlags |= POLLOUT; + } + + pollFileDescriptor_.fd = dbus_watch_get_unix_fd(libdbusWatch_); + pollFileDescriptor_.events = pollFlags; + pollFileDescriptor_.revents = 0; + + auto lockedContext = mainLoopContext_.lock(); + assert(lockedContext); + lockedContext->registerWatch(this); +} + +void DBusWatch::stopWatching() { + auto lockedContext = mainLoopContext_.lock(); + assert(lockedContext); + lockedContext->deregisterWatch(this); +} + +const pollfd& DBusWatch::getAssociatedFileDescriptor() { + return pollFileDescriptor_; +} + +//XXX Default hierfür die revent-flags? +void DBusWatch::dispatch(unsigned int eventFlags) { + dbus_watch_handle(libdbusWatch_, eventFlags); +} + +const std::vector<DispatchSource*>& DBusWatch::getDependentDispatchSources() { + return dependentDispatchSources_; +} + +void DBusWatch::addDependentDispatchSource(DispatchSource* dispatchSource) { + dependentDispatchSources_.push_back(dispatchSource); +} + + +DBusTimeout::DBusTimeout(::DBusTimeout* libdbusTimeout, std::weak_ptr<MainLoopContext>& mainLoopContext) : + libdbusTimeout_(libdbusTimeout), + mainLoopContext_(mainLoopContext), + dueTimeInMs_(TIMEOUT_INFINITE) { +} + +bool DBusTimeout::isReadyToBeMonitored() { + return dbus_timeout_get_enabled(libdbusTimeout_); +} + +void DBusTimeout::startMonitoring() { + auto lockedContext = mainLoopContext_.lock(); + assert(lockedContext); + recalculateDueTime(); + lockedContext->registerTimeoutSource(this); +} + +void DBusTimeout::stopMonitoring() { + dueTimeInMs_ = TIMEOUT_INFINITE; + auto lockedContext = mainLoopContext_.lock(); + assert(lockedContext); + lockedContext->deregisterTimeoutSource(this); +} + +bool DBusTimeout::dispatch() { + recalculateDueTime(); + dbus_timeout_handle(libdbusTimeout_); + return true; +} + +int64_t DBusTimeout::getTimeoutInterval() const { + return dbus_timeout_get_interval(libdbusTimeout_); +} + +int64_t DBusTimeout::getReadyTime() const { + return dueTimeInMs_; +} + +void DBusTimeout::recalculateDueTime() { + if(dbus_timeout_get_enabled(libdbusTimeout_)) { + unsigned int intervalInMs = dbus_timeout_get_interval(libdbusTimeout_); + dueTimeInMs_ = getCurrentTimeInMs() + intervalInMs; + } else { + dueTimeInMs_ = TIMEOUT_INFINITE; + } +} + + +} // namespace DBus +} // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusMainLoopContext.h b/src/CommonAPI/DBus/DBusMainLoopContext.h new file mode 100644 index 0000000..8558527 --- /dev/null +++ b/src/CommonAPI/DBus/DBusMainLoopContext.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DBUS_MAINLOOPCONTEXT_H_ +#define DBUS_MAINLOOPCONTEXT_H_ + +#include <list> +#include <memory> +#include <poll.h> + +#include <dbus/dbus.h> + +#include <CommonAPI/MainLoopContext.h> + + +namespace CommonAPI { +namespace DBus { + +class DBusConnection; + + + +class DBusDispatchSource: public DispatchSource { + public: + DBusDispatchSource(DBusConnection* dbusConnection); + ~DBusDispatchSource(); + + bool prepare(int64_t& timeout); + bool check(); + bool dispatch(); + + private: + DBusConnection* dbusConnection_; +}; + +class DBusWatch: public Watch { + public: + DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext); + + bool isReadyToBeWatched(); + void startWatching(); + void stopWatching(); + + void dispatch(unsigned int eventFlags); + + const pollfd& getAssociatedFileDescriptor(); + + const std::vector<DispatchSource*>& getDependentDispatchSources(); + void addDependentDispatchSource(DispatchSource* dispatchSource); + + private: + bool isReady(); + + ::DBusWatch* libdbusWatch_; + pollfd pollFileDescriptor_; + std::vector<DispatchSource*> dependentDispatchSources_; + + std::weak_ptr<MainLoopContext> mainLoopContext_; + + //XXX Necessary? Are they not covered by the fd-events? + unsigned int channelFlags_; +}; + + +class DBusTimeout: public Timeout { + public: + DBusTimeout(::DBusTimeout* libdbusTimeout, std::weak_ptr<MainLoopContext>& mainLoopContext); + + bool isReadyToBeMonitored(); + void startMonitoring(); + void stopMonitoring(); + + bool dispatch(); + + int64_t getTimeoutInterval() const; + int64_t getReadyTime() const; + + private: + void recalculateDueTime(); + + int64_t dueTimeInMs_; + ::DBusTimeout* libdbusTimeout_; + std::weak_ptr<MainLoopContext> mainLoopContext_; +}; + + +} // namespace DBus +} // namespace CommonAPI + +#endif diff --git a/src/CommonAPI/DBus/DBusMessage.cpp b/src/CommonAPI/DBus/DBusMessage.cpp index 5990894..fc99b90 100644 --- a/src/CommonAPI/DBus/DBusMessage.cpp +++ b/src/CommonAPI/DBus/DBusMessage.cpp @@ -199,6 +199,24 @@ const char* DBusMessage::getErrorName() const { return dbus_message_get_error_name(libdbusMessage_); } +bool DBusMessage::hasObjectPath(const char* objectPath) const { + const char* dbusMessageObjectPath = getObjectPath(); + + assert(objectPath); + assert(dbusMessageObjectPath); + + return !strcmp(dbusMessageObjectPath, objectPath); +} + +bool DBusMessage::hasInterfaceName(const char* interfaceName) const { + const char* dbusMessageInterfaceName = getInterfaceName(); + + assert(interfaceName); + assert(dbusMessageInterfaceName); + + return !strcmp(dbusMessageInterfaceName, interfaceName); +} + bool DBusMessage::hasMemberName(const char* memberName) const { const char* dbusMessageMemberName = getMemberName(); diff --git a/src/CommonAPI/DBus/DBusMessage.h b/src/CommonAPI/DBus/DBusMessage.h index 98cd9b7..558654e 100644 --- a/src/CommonAPI/DBus/DBusMessage.h +++ b/src/CommonAPI/DBus/DBusMessage.h @@ -69,6 +69,10 @@ class DBusMessage { const char* getSignatureString() const; const char* getErrorName() const; + inline bool hasObjectPath(const std::string& objectPath) const; + + bool hasObjectPath(const char* objectPath) const; + bool hasInterfaceName(const char* interfaceName) const; bool hasMemberName(const char* memberName) const; bool hasSignature(const char* signature) const; @@ -98,6 +102,10 @@ class DBusMessage { friend class DBusConnection; }; +bool DBusMessage::hasObjectPath(const std::string& objectPath) const { + return hasObjectPath(objectPath.c_str()); +} + bool DBusMessage::isInvalidType() const { return (getType() == Type::Invalid); } diff --git a/src/CommonAPI/DBus/DBusObjectManager.cpp b/src/CommonAPI/DBus/DBusObjectManager.cpp index 57c0727..09ff9ba 100644 --- a/src/CommonAPI/DBus/DBusObjectManager.cpp +++ b/src/CommonAPI/DBus/DBusObjectManager.cpp @@ -5,50 +5,74 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DBusObjectManager.h" +#include "DBusDaemonProxy.h" +#include "DBusStubAdapter.h" #include "DBusOutputStream.h" +#include "DBusUtils.h" + +#include <dbus/dbus-protocol.h> #include <cassert> +#include <sstream> + +#include <unordered_set> namespace CommonAPI { namespace DBus { -DBusObjectManager::DBusObjectManager(const std::shared_ptr<DBusConnection>& dbusConnection): +DBusObjectManager::DBusObjectManager(const std::shared_ptr<DBusProxyConnection>& dbusConnection): dbusConnection_(dbusConnection) { - registerInterfaceHandler("/", - "org.freedesktop.DBus.ObjectManager", - std::bind(&DBusObjectManager::onGetDBusObjectManagerData, this, std::placeholders::_1)); + if (!dbusConnection->isObjectPathMessageHandlerSet()) { + dbusConnection->setObjectPathMessageHandler( + std::bind(&DBusObjectManager::handleMessage, this, std::placeholders::_1)); + } + dbusConnection->registerObjectPath("/"); +} + +DBusObjectManager::~DBusObjectManager() { + std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock(); + if (dbusConnection) { + dbusConnection->unregisterObjectPath("/"); + dbusConnection->setObjectPathMessageHandler(DBusProxyConnection::DBusObjectPathMessageHandler()); + } } -DBusInterfaceHandlerToken DBusObjectManager::registerInterfaceHandler(const std::string& objectPath, - const std::string& interfaceName, - const DBusMessageInterfaceHandler& dbusMessageInterfaceHandler) { +DBusInterfaceHandlerToken DBusObjectManager::registerDBusStubAdapter(const std::string& objectPath, + const std::string& interfaceName, + DBusStubAdapter* dbusStubAdapter) { DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName); + + objectPathLock_.lock(); bool noSuchHandlerRegistered = dbusRegisteredObjectsTable_.find(handlerPath) == dbusRegisteredObjectsTable_.end(); assert(noSuchHandlerRegistered); - dbusRegisteredObjectsTable_.insert({handlerPath, dbusMessageInterfaceHandler}); - std::shared_ptr<DBusConnection> lockedConnection = dbusConnection_.lock(); - if(lockedConnection) { - lockedConnection->registerObjectPath(objectPath); + dbusRegisteredObjectsTable_.insert({handlerPath, dbusStubAdapter}); + objectPathLock_.unlock(); + + std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock(); + if (dbusConnection) { + dbusConnection->registerObjectPath(objectPath); } return handlerPath; } -void DBusObjectManager::unregisterInterfaceHandler(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken) { +void DBusObjectManager::unregisterDBusStubAdapter(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken) { + objectPathLock_.lock(); const std::string& objectPath = dbusInterfaceHandlerToken.first; - std::shared_ptr<DBusConnection> lockedConnection = dbusConnection_.lock(); - if(lockedConnection) { + std::shared_ptr<DBusProxyConnection> lockedConnection = dbusConnection_.lock(); + if (lockedConnection) { lockedConnection->unregisterObjectPath(objectPath); } dbusRegisteredObjectsTable_.erase(dbusInterfaceHandlerToken); + objectPathLock_.unlock(); } -bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) const { +bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) { const char* objectPath = dbusMessage.getObjectPath(); const char* interfaceName = dbusMessage.getInterfaceName(); @@ -56,57 +80,147 @@ bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) const { assert(interfaceName); DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName); + + objectPathLock_.lock(); auto handlerIterator = dbusRegisteredObjectsTable_.find(handlerPath); const bool foundDBusInterfaceHandler = handlerIterator != dbusRegisteredObjectsTable_.end(); bool dbusMessageHandled = false; if (foundDBusInterfaceHandler) { - const DBusMessageInterfaceHandler& interfaceHandlerDBusMessageHandler = handlerIterator->second; - dbusMessageHandled = interfaceHandlerDBusMessageHandler(dbusMessage); + DBusStubAdapter* dbusStubAdapter = handlerIterator->second; + dbusMessageHandled = dbusStubAdapter->onInterfaceDBusMessage(dbusMessage); + } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.Introspectable")) { + dbusMessageHandled = onIntrospectableInterfaceDBusMessage(dbusMessage); + } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")) { + dbusMessageHandled = onObjectManagerInterfaceDBusMessage(dbusMessage); } + objectPathLock_.unlock(); return dbusMessageHandled; } -bool DBusObjectManager::onGetDBusObjectManagerData(const DBusMessage& callMessage) { - DBusDaemonProxy::DBusObjectToInterfaceDict dictToSend; +bool DBusObjectManager::onObjectManagerInterfaceDBusMessage(const DBusMessage& dbusMessage) { + std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock(); - const char* interfaceName = callMessage.getInterfaceName(); - const char* signature = callMessage.getSignatureString(); + if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("GetManagedObjects")) { + return false; + } - assert(!strcmp(interfaceName, "org.freedesktop.DBus.ObjectManager")); - assert(!strcmp(signature, "")); - assert(callMessage.getType() == DBusMessage::Type::MethodCall); + DBusDaemonProxy::DBusObjectToInterfaceDict ObjectPathsInterfacesAndPropertiesDict; + objectPathLock_.lock(); auto registeredObjectsIterator = dbusRegisteredObjectsTable_.begin(); while(registeredObjectsIterator != dbusRegisteredObjectsTable_.end()) { DBusInterfaceHandlerPath handlerPath = registeredObjectsIterator->first; - auto foundDictEntry = dictToSend.find(handlerPath.first); + auto foundDictEntry = ObjectPathsInterfacesAndPropertiesDict.find(handlerPath.first); - if(foundDictEntry == dictToSend.end()) { - dictToSend.insert( { handlerPath.first, { { handlerPath.second, {} } } } ); + if (foundDictEntry == ObjectPathsInterfacesAndPropertiesDict.end()) { + ObjectPathsInterfacesAndPropertiesDict.insert( { handlerPath.first, { { handlerPath.second, {} } } } ); } else { foundDictEntry->second.insert( {handlerPath.second, {} } ); } ++registeredObjectsIterator; } + objectPathLock_.unlock(); const char* getManagedObjectsDBusSignature = "a{oa{sa{sv}}}"; - DBusMessage replyMessage = callMessage.createMethodReturn(getManagedObjectsDBusSignature); + DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(getManagedObjectsDBusSignature); + DBusOutputStream outStream(dbusMessageReply); - DBusOutputStream outStream(replyMessage); - outStream << dictToSend; + outStream << ObjectPathsInterfacesAndPropertiesDict; outStream.flush(); - std::shared_ptr<DBusConnection> lockedConnection = dbusConnection_.lock(); - if(lockedConnection) { - return lockedConnection->sendDBusMessage(replyMessage); + return dbusConnection->sendDBusMessage(dbusMessageReply); +} + +bool DBusObjectManager::onIntrospectableInterfaceDBusMessage(const DBusMessage& dbusMessage) { + std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock(); + + if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("Introspect")) { + return false; + } + + bool foundRegisteredObjects = false; + std::stringstream xmlData(std::ios_base::out); + + xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" + DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" + "<node name=\"" << dbusMessage.getObjectPath() << "\">\n" + "<interface name=\"org.freedesktop.DBus.Introspectable\">\n" + "<method name=\"Introspect\">\n" + "<arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n" + "</method>\n" + "</interface>\n"; + + std::unordered_set<std::string> nodeSet; + for (auto& registeredObjectsIterator : dbusRegisteredObjectsTable_) { + const DBusInterfaceHandlerPath& handlerPath = registeredObjectsIterator.first; + const std::string& dbusObjectPath = handlerPath.first; + const std::string& dbusInterfaceName = handlerPath.second; + DBusStubAdapter* dbusStubAdapter = registeredObjectsIterator.second; + + if (dbusMessage.hasObjectPath(dbusObjectPath)) { + foundRegisteredObjects = true; + + xmlData << "<interface name=\"" << dbusInterfaceName << "\">\n" + << dbusStubAdapter->getMethodsDBusIntrospectionXmlData() << "\n" + "</interface>\n"; + } else { + std::vector<std::string> elems = CommonAPI::DBus::split(dbusObjectPath, '/'); + if (dbusMessage.hasObjectPath("/") && elems.size() > 1) { + if (nodeSet.find(elems[1]) == nodeSet.end()) { + if (nodeSet.size() == 0) { + xmlData.str(""); + xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" + DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" + "<node>\n"; + } + xmlData << " <node name=\"" << elems[1] << "\"/>\n"; + nodeSet.insert(elems[1]); + foundRegisteredObjects = true; + } + } else { + for (int i = 1; i < elems.size() - 1; i++) { + std::string build; + for (int j = 1; j <= i; j++) { + build = build + "/" + elems[j]; + if (dbusMessage.hasObjectPath(dbusObjectPath)) { + if (nodeSet.find(elems[j + 1]) == nodeSet.end()) { + if (nodeSet.size() == 0) { + xmlData.str(""); + xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" + DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" + "<node>\n"; + } + xmlData << " <node name=\"" << elems[j + 1] << "\"/>\n"; + nodeSet.insert(elems[j + 1]); + foundRegisteredObjects = true; + } + break; + } + } + } + } + } + } + + if (foundRegisteredObjects) { + DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("s"); + DBusOutputStream dbusOutputStream(dbusMessageReply); + + xmlData << "</node>" + ""; + + dbusOutputStream << xmlData.str(); + dbusOutputStream.flush(); + + return dbusConnection->sendDBusMessage(dbusMessageReply); } + return false; } - } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusObjectManager.h b/src/CommonAPI/DBus/DBusObjectManager.h index bfd2a71..cb60948 100644 --- a/src/CommonAPI/DBus/DBusObjectManager.h +++ b/src/CommonAPI/DBus/DBusObjectManager.h @@ -7,48 +7,46 @@ #ifndef COMMONAPI_DBUS_DBUS_OBJECT_MANAGER_H_ #define COMMONAPI_DBUS_DBUS_OBJECT_MANAGER_H_ +#include "DBusProxyConnection.h" #include "DBusMessage.h" -#include "DBusConnection.h" namespace CommonAPI { namespace DBus { // objectPath, interfaceName -typedef std::function<bool(const DBusMessage&)> DBusMessageInterfaceHandler; typedef std::pair<std::string, std::string> DBusInterfaceHandlerPath; typedef DBusInterfaceHandlerPath DBusInterfaceHandlerToken; -class DBusConnection; +class DBusStubAdapter; class DBusObjectManager { public: - DBusObjectManager(const std::shared_ptr<DBusConnection>&); + DBusObjectManager(const std::shared_ptr<DBusProxyConnection>&); + ~DBusObjectManager(); void init(); - const DBusInterfaceHandlerToken registerInterfaceHandlerForDBusObject(const std::string& objectPath, - const std::string& interfaceName, - const DBusMessageInterfaceHandler& dbusMessageInterfaceHandler); + DBusInterfaceHandlerToken registerDBusStubAdapter(const std::string& objectPath, + const std::string& interfaceName, + DBusStubAdapter* dbusStubAdapter); - DBusInterfaceHandlerToken registerInterfaceHandler(const std::string& objectPath, - const std::string& interfaceName, - const DBusMessageInterfaceHandler& dbusMessageInterfaceHandler); + void unregisterDBusStubAdapter(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken); - void unregisterInterfaceHandler(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken); - - bool handleMessage(const DBusMessage&) const; + bool handleMessage(const DBusMessage&); private: void addLibdbusObjectPathHandler(const std::string& objectPath); void removeLibdbusObjectPathHandler(const std::string& objectPath); - bool onGetDBusObjectManagerData(const DBusMessage& callMessage); + bool onObjectManagerInterfaceDBusMessage(const DBusMessage& callMessage); + bool onIntrospectableInterfaceDBusMessage(const DBusMessage& callMessage); - typedef std::unordered_map<DBusInterfaceHandlerPath, DBusMessageInterfaceHandler> DBusRegisteredObjectsTable; + typedef std::unordered_map<DBusInterfaceHandlerPath, DBusStubAdapter*> DBusRegisteredObjectsTable; DBusRegisteredObjectsTable dbusRegisteredObjectsTable_; - std::weak_ptr<DBusConnection> dbusConnection_; + std::weak_ptr<DBusProxyConnection> dbusConnection_; + std::recursive_mutex objectPathLock_; }; } // namespace DBus diff --git a/src/CommonAPI/DBus/DBusOutputStream.cpp b/src/CommonAPI/DBus/DBusOutputStream.cpp index f600ced..0466b0e 100644 --- a/src/CommonAPI/DBus/DBusOutputStream.cpp +++ b/src/CommonAPI/DBus/DBusOutputStream.cpp @@ -229,7 +229,8 @@ void DBusOutputStream::flush() { memcpy(destinationDataPtr, payload_.c_str(), toWrite); } -void DBusOutputStream::setError() {} +void DBusOutputStream::setError() { +} /** * Reserves the given number of bytes for writing, thereby negating the need to dynamically allocate memory while writing. @@ -242,12 +243,6 @@ void DBusOutputStream::reserveMemory(size_t numOfBytes) { payload_.reserve(numOfBytes); } -/** - * @return current data position where later writing is possible - */ -size_t getCurrentPosition(); - - DBusOutputStream& DBusOutputStream::writeString(const char* cString, const uint32_t& length) { assert(cString != NULL); assert(cString[length] == '\0'); diff --git a/src/CommonAPI/DBus/DBusOutputStream.h b/src/CommonAPI/DBus/DBusOutputStream.h index 3a6a83b..c55f109 100644 --- a/src/CommonAPI/DBus/DBusOutputStream.h +++ b/src/CommonAPI/DBus/DBusOutputStream.h @@ -264,11 +264,6 @@ class DBusOutputStream: public OutputStream { */ void reserveMemory(size_t numOfBytes); - /** - * @return current data position where later writing is possible - */ - size_t getCurrentPosition(); - template<typename _BasicType> DBusOutputStream& writeBasicTypeValue(const _BasicType& basicValue) { if (sizeof(_BasicType) > 1) diff --git a/src/CommonAPI/DBus/DBusProxy.cpp b/src/CommonAPI/DBus/DBusProxy.cpp index 314c63f..9946859 100644 --- a/src/CommonAPI/DBus/DBusProxy.cpp +++ b/src/CommonAPI/DBus/DBusProxy.cpp @@ -33,12 +33,12 @@ DBusProxy::DBusProxy(const std::string& commonApiAddress, const std::string& dbusBusName, const std::string& dbusObjectPath, const std::shared_ptr<DBusProxyConnection>& dbusConnection): - DBusProxyBase(split(commonApiAddress, ':')[1], - split(commonApiAddress, ':')[2], - dbusInterfaceName, - dbusBusName, - dbusObjectPath, - dbusConnection), + DBusProxyBase(dbusConnection), + commonApiServiceId_(split(commonApiAddress, ':')[1]), + commonApiParticipantId_(split(commonApiAddress, ':')[2]), + dbusBusName_(dbusBusName), + dbusObjectPath_(dbusObjectPath), + dbusInterfaceName_(dbusInterfaceName), dbusProxyStatusEvent_(this), availabilityStatus_(AvailabilityStatus::UNKNOWN), interfaceVersionAttribute_(*this, "getInterfaceVersion"), @@ -64,7 +64,7 @@ bool DBusProxy::isAvailable() const { bool DBusProxy::isAvailableBlocking() const { if (availabilityStatus_ == AvailabilityStatus::UNKNOWN) { - std::chrono::milliseconds singleWaitDuration(100); + std::chrono::milliseconds singleWaitDuration(2); // Wait for the service registry while (availabilityStatus_ == AvailabilityStatus::UNKNOWN) { @@ -85,9 +85,36 @@ InterfaceVersionAttribute& DBusProxy::getInterfaceVersionAttribute() { void DBusProxy::onDBusServiceInstanceStatus(const AvailabilityStatus& availabilityStatus) { availabilityStatus_ = availabilityStatus; - dbusProxyStatusEvent_.notifyListeners(availabilityStatus); } +const std::string& DBusProxy::getDBusBusName() const { + return dbusBusName_; +} + +const std::string& DBusProxy::getDBusObjectPath() const { + return dbusObjectPath_; +} + +const std::string& DBusProxy::getInterfaceName() const { + return dbusInterfaceName_; +} + +const std::string& DBusProxy::getDomain() const { + return commonApiDomain_; +} + +const std::string& DBusProxy::getServiceId() const { + return commonApiServiceId_; +} + +const std::string& DBusProxy::getInstanceId() const { + return commonApiParticipantId_; +} + +std::string DBusProxy::getAddress() const { + return commonApiDomain_ + ":" + commonApiServiceId_ + ":" + commonApiParticipantId_; +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusProxy.h b/src/CommonAPI/DBus/DBusProxy.h index 6021a01..e838f6b 100644 --- a/src/CommonAPI/DBus/DBusProxy.h +++ b/src/CommonAPI/DBus/DBusProxy.h @@ -48,6 +48,15 @@ class DBusProxy: public DBusProxyBase { virtual bool isAvailableBlocking() const; + virtual std::string getAddress() const; + virtual const std::string& getDomain() const; + virtual const std::string& getServiceId() const; + virtual const std::string& getInstanceId() const; + + virtual const std::string& getDBusBusName() const; + virtual const std::string& getDBusObjectPath() const; + virtual const std::string& getInterfaceName() const; + private: DBusProxy(const DBusProxy&) = delete; @@ -61,6 +70,13 @@ class DBusProxy: public DBusProxyBase { DBusReadonlyAttribute<InterfaceVersionAttribute> interfaceVersionAttribute_; std::shared_ptr<DBusServiceRegistry> dbusServiceRegistry_; + + const std::string commonApiServiceId_; + const std::string commonApiParticipantId_; + + const std::string dbusBusName_; + const std::string dbusObjectPath_; + const std::string dbusInterfaceName_; }; diff --git a/src/CommonAPI/DBus/DBusProxyBase.cpp b/src/CommonAPI/DBus/DBusProxyBase.cpp index 8cb2400..633fab4 100644 --- a/src/CommonAPI/DBus/DBusProxyBase.cpp +++ b/src/CommonAPI/DBus/DBusProxyBase.cpp @@ -12,54 +12,16 @@ namespace DBus { const std::string DBusProxyBase::commonApiDomain_ = "local"; -DBusProxyBase::DBusProxyBase(const std::string& commonApiServiceId, - const std::string& commonApiParticipantId, - const std::string& dbusInterfaceName, - const std::string& dbusBusName, - const std::string& dbusObjectPath, - const std::shared_ptr<DBusProxyConnection>& dbusConnection) : - commonApiServiceId_(commonApiServiceId), - commonApiParticipantId_(commonApiParticipantId), - dbusBusName_(dbusBusName), - dbusObjectPath_(dbusObjectPath), - dbusInterfaceName_(dbusInterfaceName), +DBusProxyBase::DBusProxyBase(const std::shared_ptr<DBusProxyConnection>& dbusConnection) : dbusConnection_(dbusConnection) { } -DBusProxyBase::DBusProxyBase(const std::string& dbusInterfaceName, - const std::string& dbusBusName, - const std::string& dbusObjectPath, - const std::shared_ptr<DBusProxyConnection>& dbusConnection) : - commonApiServiceId_(dbusInterfaceName), - commonApiParticipantId_(dbusBusName + "-" + dbusObjectPath), - dbusBusName_(dbusBusName), - dbusObjectPath_(dbusObjectPath), - dbusInterfaceName_(dbusInterfaceName), - dbusConnection_(dbusConnection) { -} - -std::string DBusProxyBase::getAddress() const { - return commonApiDomain_ + ":" + commonApiServiceId_ + ":" + commonApiParticipantId_; -} - -const std::string& DBusProxyBase::getDomain() const { - return commonApiDomain_; -} - -const std::string& DBusProxyBase::getServiceId() const { - return commonApiServiceId_; -} - -const std::string& DBusProxyBase::getInstanceId() const { - return commonApiParticipantId_; -} - DBusMessage DBusProxyBase::createMethodCall(const char* methodName, const char* methodSignature) const { return DBusMessage::createMethodCall( - dbusBusName_.c_str(), - dbusObjectPath_.c_str(), - dbusInterfaceName_.c_str(), + getDBusBusName().c_str(), + getDBusObjectPath().c_str(), + getInterfaceName().c_str(), methodName, methodSignature); } diff --git a/src/CommonAPI/DBus/DBusProxyBase.h b/src/CommonAPI/DBus/DBusProxyBase.h index 10b5bae..686c878 100644 --- a/src/CommonAPI/DBus/DBusProxyBase.h +++ b/src/CommonAPI/DBus/DBusProxyBase.h @@ -21,26 +21,16 @@ namespace DBus { class DBusProxyBase: public virtual CommonAPI::Proxy { public: - DBusProxyBase(const std::string& commonApiServiceId, - const std::string& commonApiParticipantId, - const std::string& dbusInterfaceName, - const std::string& dbusBusName, - const std::string& dbusObjectPath, - const std::shared_ptr<DBusProxyConnection>& dbusProxyConnection); - - DBusProxyBase(const std::string& dbusInterfaceName, - const std::string& dbusBusName, - const std::string& dbusObjectPath, - const std::shared_ptr<DBusProxyConnection>& dbusProxyConnection); - - virtual std::string getAddress() const; - virtual const std::string& getDomain() const; - virtual const std::string& getServiceId() const; - virtual const std::string& getInstanceId() const; - - inline const std::string& getDBusBusName() const; - inline const std::string& getDBusObjectPath() const; - inline const std::string& getInterfaceName() const; + DBusProxyBase(const std::shared_ptr<DBusProxyConnection>& dbusProxyConnection); + + virtual std::string getAddress() const = 0; + virtual const std::string& getDomain() const = 0; + virtual const std::string& getServiceId() const = 0; + virtual const std::string& getInstanceId() const = 0; + + virtual const std::string& getDBusBusName() const = 0; + virtual const std::string& getDBusObjectPath() const = 0; + virtual const std::string& getInterfaceName() const = 0; inline const std::shared_ptr<DBusProxyConnection>& getDBusConnection() const; DBusMessage createMethodCall(const char* methodName, @@ -53,33 +43,15 @@ class DBusProxyBase: public virtual CommonAPI::Proxy { inline void removeSignalMemberHandler(const DBusProxyConnection::DBusSignalHandlerToken& dbusSignalHandlerToken); + protected: + static const std::string commonApiDomain_; + private: DBusProxyBase(const DBusProxyBase&) = delete; - const std::string commonApiServiceId_; - const std::string commonApiParticipantId_; - - const std::string dbusBusName_; - const std::string dbusObjectPath_; - const std::string dbusInterfaceName_; - std::shared_ptr<DBusProxyConnection> dbusConnection_; - - static const std::string commonApiDomain_; }; -const std::string& DBusProxyBase::getDBusBusName() const { - return dbusBusName_; -} - -const std::string& DBusProxyBase::getDBusObjectPath() const { - return dbusObjectPath_; -} - -const std::string& DBusProxyBase::getInterfaceName() const { - return dbusInterfaceName_; -} - const std::shared_ptr<DBusProxyConnection>& DBusProxyBase::getDBusConnection() const { return dbusConnection_; } @@ -89,11 +61,11 @@ DBusProxyConnection::DBusSignalHandlerToken DBusProxyBase::addSignalMemberHandle const std::string& signalSignature, DBusProxyConnection::DBusSignalHandler* dbusSignalHandler) { return dbusConnection_->addSignalMemberHandler( - dbusObjectPath_, - getInterfaceName(), - signalName, - signalSignature, - dbusSignalHandler); + getDBusObjectPath(), + getInterfaceName(), + signalName, + signalSignature, + dbusSignalHandler); } void DBusProxyBase::removeSignalMemberHandler(const DBusProxyConnection::DBusSignalHandlerToken& dbusSignalHandlerToken) { diff --git a/src/CommonAPI/DBus/DBusProxyConnection.h b/src/CommonAPI/DBus/DBusProxyConnection.h index e5dc24a..19140f2 100644 --- a/src/CommonAPI/DBus/DBusProxyConnection.h +++ b/src/CommonAPI/DBus/DBusProxyConnection.h @@ -59,37 +59,46 @@ class DBusProxyConnection { typedef Event<AvailabilityStatus> ConnectionStatusEvent; - virtual ~DBusProxyConnection() { } + virtual ~DBusProxyConnection() { + } - virtual bool isConnected() const = 0; + virtual bool isConnected() const = 0; - virtual ConnectionStatusEvent& getConnectionStatusEvent() = 0; + virtual ConnectionStatusEvent& getConnectionStatusEvent() = 0; - virtual bool sendDBusMessage(const DBusMessage& dbusMessage, uint32_t* allocatedSerial = NULL) const = 0; + virtual bool sendDBusMessage(const DBusMessage& dbusMessage, uint32_t* allocatedSerial = NULL) const = 0; - static const int kDefaultSendTimeoutMs = 100 * 1000; + static const int kDefaultSendTimeoutMs = 100 * 1000; - virtual std::future<CallStatus> sendDBusMessageWithReplyAsync( - const DBusMessage& dbusMessage, - std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler, - int timeoutMilliseconds = kDefaultSendTimeoutMs) const = 0; + virtual std::future<CallStatus> sendDBusMessageWithReplyAsync( + const DBusMessage& dbusMessage, + std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler, + int timeoutMilliseconds = kDefaultSendTimeoutMs) const = 0; - virtual DBusMessage sendDBusMessageWithReplyAndBlock( - const DBusMessage& dbusMessage, - DBusError& dbusError, - int timeoutMilliseconds = kDefaultSendTimeoutMs) const = 0; + virtual DBusMessage sendDBusMessageWithReplyAndBlock( + const DBusMessage& dbusMessage, + DBusError& dbusError, + int timeoutMilliseconds = kDefaultSendTimeoutMs) const = 0; - virtual DBusSignalHandlerToken addSignalMemberHandler( - const std::string& objectPath, - const std::string& interfaceName, - const std::string& interfaceMemberName, - const std::string& interfaceMemberSignature, - DBusSignalHandler* dbusSignalHandler) = 0; + virtual DBusSignalHandlerToken addSignalMemberHandler( + const std::string& objectPath, + const std::string& interfaceName, + const std::string& interfaceMemberName, + const std::string& interfaceMemberSignature, + DBusSignalHandler* dbusSignalHandler) = 0; - virtual void removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken) = 0; + virtual void removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken) = 0; virtual const std::shared_ptr<DBusServiceRegistry> getDBusServiceRegistry() = 0; virtual const std::shared_ptr<DBusObjectManager> getDBusObjectManager() = 0; + + virtual void registerObjectPath(const std::string& objectPath) = 0; + virtual void unregisterObjectPath(const std::string& objectPath) = 0; + + typedef std::function<bool(const DBusMessage&)> DBusObjectPathMessageHandler; + + virtual void setObjectPathMessageHandler(DBusObjectPathMessageHandler) = 0; + virtual bool isObjectPathMessageHandlerSet() = 0; }; diff --git a/src/CommonAPI/DBus/DBusRuntime.cpp b/src/CommonAPI/DBus/DBusRuntime.cpp index da1b272..a6d92db 100644 --- a/src/CommonAPI/DBus/DBusRuntime.cpp +++ b/src/CommonAPI/DBus/DBusRuntime.cpp @@ -23,8 +23,8 @@ std::shared_ptr<Runtime> DBusRuntime::getInstance() { return singleton_; } -std::shared_ptr<Factory> DBusRuntime::createFactory() { - auto factory = std::make_shared<DBusFactory>(this->shared_from_this(), &middlewareInfo_); +std::shared_ptr<Factory> DBusRuntime::createFactory(std::shared_ptr<MainLoopContext> mainLoopContext) { + auto factory = std::make_shared<DBusFactory>(this->shared_from_this(), &middlewareInfo_, mainLoopContext); return factory; } diff --git a/src/CommonAPI/DBus/DBusRuntime.h b/src/CommonAPI/DBus/DBusRuntime.h index b91f304..3784f91 100644 --- a/src/CommonAPI/DBus/DBusRuntime.h +++ b/src/CommonAPI/DBus/DBusRuntime.h @@ -18,7 +18,7 @@ class DBusRuntime: public Runtime, public std::enable_shared_from_this<DBusRunti public: static std::shared_ptr<Runtime> getInstance(); - std::shared_ptr<Factory> createFactory(); + std::shared_ptr<Factory> createFactory(std::shared_ptr<MainLoopContext> = std::shared_ptr<MainLoopContext>(NULL)); static const MiddlewareInfo middlewareInfo_; }; diff --git a/src/CommonAPI/DBus/DBusServiceRegistry.cpp b/src/CommonAPI/DBus/DBusServiceRegistry.cpp index a0ad227..9924cb6 100644 --- a/src/CommonAPI/DBus/DBusServiceRegistry.cpp +++ b/src/CommonAPI/DBus/DBusServiceRegistry.cpp @@ -20,7 +20,6 @@ DBusServiceRegistry::DBusServiceRegistry(std::shared_ptr<DBusProxyConnection> db DBusServiceRegistry::~DBusServiceRegistry() { if(initialized_) { - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); dbusDaemonProxy_->getNameOwnerChangedEvent().unsubscribe(dbusDaemonProxyNameOwnerChangedEventSubscription_); dbusDaemonProxy_->getProxyStatusEvent().unsubscribe(dbusDaemonProxyStatusEventSubscription_); } @@ -42,26 +41,25 @@ void DBusServiceRegistry::init() { } bool DBusServiceRegistry::waitDBusServicesAvailable(std::unique_lock<std::mutex>& lock, std::chrono::milliseconds& timeout) { - bool dbusServicesStatusIsKnown = (dbusNameListStatus_ != AvailabilityStatus::UNKNOWN); + bool dbusServicesStatusIsKnown = (dbusNameListStatus_ == AvailabilityStatus::AVAILABLE); - while (!dbusServicesStatusIsKnown && timeout.count() > 0) { + if(!dbusServicesStatusIsKnown) { typedef std::chrono::high_resolution_clock clock; clock::time_point startTimePoint = clock::now(); - dbusServicesStatusIsKnown = dbusServiceChanged_.wait_for( - lock, - timeout, - [&]{ return dbusNameListStatus_ != AvailabilityStatus::UNKNOWN; }); + while (!dbusServicesStatusIsKnown && timeout.count() > 0) { + dbusServicesStatusIsKnown = dbusServiceChanged_.wait_for( + lock, + timeout / 10, + [&]{ return dbusNameListStatus_ == AvailabilityStatus::AVAILABLE; }); - std::chrono::milliseconds elapsedWaitTime = - std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - startTimePoint); + std::chrono::milliseconds elapsedWaitTime = + std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - startTimePoint); - if (elapsedWaitTime > timeout) { - timeout = std::chrono::milliseconds::zero(); - break; + if (elapsedWaitTime > timeout) { + break; + } } - - timeout -= elapsedWaitTime; } return (dbusNameListStatus_ == AvailabilityStatus::AVAILABLE); @@ -72,7 +70,7 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac return false; } - std::chrono::milliseconds timeout(2000); + std::chrono::milliseconds timeout(1000); std::unique_lock<std::mutex> dbusServicesLock(dbusServicesMutex_); if (!waitDBusServicesAvailable(dbusServicesLock, timeout)) { @@ -128,7 +126,7 @@ std::vector<std::string> DBusServiceRegistry::getAvailableServiceInstances(const return availableServiceInstances; } - std::chrono::milliseconds timeout(2000); + std::chrono::milliseconds timeout(1000); std::unique_lock<std::mutex> dbusServicesLock(dbusServicesMutex_); if (!waitDBusServicesAvailable(dbusServicesLock, timeout)) { @@ -234,10 +232,11 @@ DBusServiceRegistry::Subscription DBusServiceRegistry::subscribeAvailabilityList DBusServiceList::iterator dbusServiceIterator = dbusServices_.find(dbusServiceName); - // add service for the first time + // Service not known, so just add it to the list of unkown or definitely not available services if (dbusServiceIterator == dbusServices_.end()) { DBusServiceState dbusConnectionNameState = DBusServiceState::UNKNOWN; + // Service is definitely not available if the complete list of available services is known and it is not in there if (dbusNameListStatus_ == AvailabilityStatus::AVAILABLE) { dbusConnectionNameState = DBusServiceState::RESOLVED; } diff --git a/src/CommonAPI/DBus/DBusStubAdapter.cpp b/src/CommonAPI/DBus/DBusStubAdapter.cpp index e230062..050ed40 100644 --- a/src/CommonAPI/DBus/DBusStubAdapter.cpp +++ b/src/CommonAPI/DBus/DBusStubAdapter.cpp @@ -7,8 +7,6 @@ #include "DBusStubAdapter.h" #include "DBusUtils.h" -#include <dbus/dbus-protocol.h> - #include <cassert> #include <functional> #include <sstream> @@ -47,23 +45,17 @@ DBusStubAdapter::~DBusStubAdapter() { void DBusStubAdapter::deinit() { assert(dbusConnection_); - if(isInitialized_) { - dbusConnection_->getDBusObjectManager()->unregisterInterfaceHandler(dbusIntrospectionInterfaceHandlerToken_); - dbusConnection_->getDBusObjectManager()->unregisterInterfaceHandler(dbusInterfaceHandlerToken_); + if (isInitialized_) { + dbusConnection_->getDBusObjectManager()->unregisterDBusStubAdapter(dbusInterfaceHandlerToken_); isInitialized_ = false; } } void DBusStubAdapter::init() { - dbusIntrospectionInterfaceHandlerToken_ = dbusConnection_->getDBusObjectManager()->registerInterfaceHandler( - dbusObjectPath_, - "org.freedesktop.DBus.Introspectable", - std::bind(&DBusStubAdapter::onIntrospectionInterfaceDBusMessage, this, std::placeholders::_1)); - - dbusInterfaceHandlerToken_ = dbusConnection_->getDBusObjectManager()->registerInterfaceHandler( + dbusInterfaceHandlerToken_ = dbusConnection_->getDBusObjectManager()->registerDBusStubAdapter( dbusObjectPath_, dbusInterfaceName_, - std::bind(&DBusStubAdapter::onInterfaceDBusMessage, this, std::placeholders::_1)); + this); isInitialized_ = true; } @@ -84,34 +76,5 @@ const std::string& DBusStubAdapter::getInstanceId() const { return commonApiParticipantId_; } -bool DBusStubAdapter::onIntrospectionInterfaceDBusMessage(const DBusMessage& dbusMessage) { - bool dbusMessageHandled = false; - - if (dbusMessage.isMethodCallType() && dbusMessage.hasMemberName("Introspect")) { - std::stringstream xmlData(std::ios_base::out); - xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" - DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" - "<node name=\"" << dbusObjectPath_ << "\">\n" - "<interface name=\"org.freedesktop.DBus.Introspectable\">\n" - "<method name=\"Introspect\">\n" - "<arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n" - "</method>\n" - "</interface>\n" - "<interface name=\"" << dbusInterfaceName_ << "\">\n" - << getMethodsDBusIntrospectionXmlData() << "\n" - "</interface>\n" - "</node>"; - - DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("s"); - DBusOutputStream dbusOutputStream(dbusMessageReply); - dbusOutputStream << xmlData.str(); - dbusOutputStream.flush(); - - dbusMessageHandled = dbusConnection_->sendDBusMessage(dbusMessageReply); - } - - return dbusMessageHandled; -} - } // namespace dbus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusStubAdapter.h b/src/CommonAPI/DBus/DBusStubAdapter.h index fafea2e..0382e61 100644 --- a/src/CommonAPI/DBus/DBusStubAdapter.h +++ b/src/CommonAPI/DBus/DBusStubAdapter.h @@ -7,10 +7,11 @@ #ifndef COMMONAPI_DBUS_DBUS_STUB_ADAPTER_H_ #define COMMONAPI_DBUS_DBUS_STUB_ADAPTER_H_ -#include "DBusConnection.h" +#include "DBusProxyConnection.h" +#include "DBusObjectManager.h" +#include "DBusMessage.h" #include <CommonAPI/Stub.h> -#include <CommonAPI/DBus/DBusMessage.h> #include <string> #include <memory> @@ -41,13 +42,10 @@ class DBusStubAdapter: virtual public CommonAPI::StubAdapter { inline const std::shared_ptr<DBusProxyConnection>& getDBusConnection() const; - protected: virtual const char* getMethodsDBusIntrospectionXmlData() const = 0; virtual bool onInterfaceDBusMessage(const DBusMessage& dbusMessage) = 0; private: - bool onIntrospectionInterfaceDBusMessage(const DBusMessage& dbusMessage); - const std::string commonApiDomain_; const std::string commonApiServiceId_; const std::string commonApiParticipantId_; @@ -59,7 +57,6 @@ class DBusStubAdapter: virtual public CommonAPI::StubAdapter { bool isInitialized_; - DBusInterfaceHandlerToken dbusIntrospectionInterfaceHandlerToken_; DBusInterfaceHandlerToken dbusInterfaceHandlerToken_; static const std::string domain_; diff --git a/src/CommonAPI/DBus/DBusStubAdapterHelper.h b/src/CommonAPI/DBus/DBusStubAdapterHelper.h index 4417c74..ee627a3 100644 --- a/src/CommonAPI/DBus/DBusStubAdapterHelper.h +++ b/src/CommonAPI/DBus/DBusStubAdapterHelper.h @@ -11,6 +11,7 @@ #include "DBusInputStream.h" #include "DBusOutputStream.h" #include "DBusHelper.h" +#include "DBusSerializableArguments.h" #include <memory> #include <initializer_list> diff --git a/src/test/DBusAddressTranslatorTest.cpp b/src/test/DBusAddressTranslatorTest.cpp index c9dcca7..3382934 100644 --- a/src/test/DBusAddressTranslatorTest.cpp +++ b/src/test/DBusAddressTranslatorTest.cpp @@ -120,6 +120,7 @@ protected: } virtual void TearDown() { + usleep(30000); } }; @@ -158,28 +159,32 @@ TEST_F(AddressTranslatorTest, ParsesCommonAPIAddresses) { TEST_F(AddressTranslatorTest, ServicesUsingPredefinedAddressesCanCommunicate) { - std::shared_ptr<CommonAPI::Runtime> runtime; - std::shared_ptr<CommonAPI::Factory> proxyFactory; - std::shared_ptr<CommonAPI::Factory> stubFactory; - - runtime = CommonAPI::Runtime::load(); + std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::load(); ASSERT_TRUE((bool)runtime); CommonAPI::DBus::DBusRuntime* dbusRuntime = dynamic_cast<CommonAPI::DBus::DBusRuntime*>(&(*runtime)); ASSERT_TRUE(dbusRuntime != NULL); - proxyFactory = runtime->createFactory(); + std::shared_ptr<CommonAPI::Factory> proxyFactory = runtime->createFactory(); ASSERT_TRUE((bool)proxyFactory); - stubFactory = runtime->createFactory(); + std::shared_ptr<CommonAPI::Factory> stubFactory = runtime->createFactory(); ASSERT_TRUE((bool)stubFactory); auto defaultTestProxy = proxyFactory->buildProxy<commonapi::tests::TestInterfaceProxy>(commonApiAddresses[0]); ASSERT_TRUE((bool)defaultTestProxy); auto stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); - bool success = stubFactory->registerService(stub, commonApiAddresses[0]); - ASSERT_TRUE(success); - sleep(1); + bool serviceNameAcquired = stubFactory->registerService(stub, commonApiAddresses[0]); + for(unsigned int i = 0; !serviceNameAcquired && i < 100; i++) { + serviceNameAcquired = stubFactory->registerService(stub, commonApiAddresses[0]); + usleep(10000); + } + ASSERT_TRUE(serviceNameAcquired); + + for(unsigned int i = 0; !defaultTestProxy->isAvailable() && i < 100; ++i) { + usleep(10000); + } + ASSERT_TRUE(defaultTestProxy->isAvailable()); uint32_t v1 = 5; std::string v2 = "Hai :)"; @@ -223,7 +228,7 @@ void fakeLegacyServiceThread() { TEST_F(AddressTranslatorTest, FakeLegacyServiceCanBeAddressed) { std::thread fakeServiceThread = std::thread(fakeLegacyServiceThread); - sleep(1); + usleep(500000); std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::load(); ASSERT_TRUE((bool)runtime); @@ -259,7 +264,7 @@ TEST_F(AddressTranslatorTest, FakeLegacyServiceCanBeAddressed) { //end the fake legacy service via dbus int resultCode = system("python ./src/test/fakeLegacyService/sendToFakeLegacyService.py finish"); - EXPECT_EQ(0, resultCode); + ASSERT_EQ(0, resultCode); fakeServiceThread.join(); } diff --git a/src/test/DBusCommunicationTest.cpp b/src/test/DBusCommunicationTest.cpp index 5eeb765..a2b62e0 100644 --- a/src/test/DBusCommunicationTest.cpp +++ b/src/test/DBusCommunicationTest.cpp @@ -73,6 +73,7 @@ class DBusCommunicationTest: public ::testing::Test { } virtual void TearDown() { + usleep(30000); } std::shared_ptr<CommonAPI::Runtime> runtime_; @@ -83,7 +84,7 @@ class DBusCommunicationTest: public ::testing::Test { static const std::string nonstandardAddress_; }; -const std::string DBusCommunicationTest::serviceAddress_ = "local:commonapi.tests.TestInterface:commonapi.tests.TestInterface"; +const std::string DBusCommunicationTest::serviceAddress_ = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService"; const std::string DBusCommunicationTest::nonstandardAddress_ = "local:non.standard.ServiceName:non.standard.participand.ID"; @@ -93,10 +94,18 @@ TEST_F(DBusCommunicationTest, RemoteMethodCallSucceeds) { ASSERT_TRUE((bool)defaultTestProxy); auto stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); - bool success = stubFactory_->registerService(stub, serviceAddress_); - ASSERT_TRUE(success); - sleep(1); + bool serviceRegistered = stubFactory_->registerService(stub, serviceAddress_); + for(unsigned int i = 0; !serviceRegistered && i < 100; ++i) { + serviceRegistered = stubFactory_->registerService(stub, serviceAddress_); + usleep(10000); + } + ASSERT_TRUE(serviceRegistered); + + for(unsigned int i = 0; !defaultTestProxy->isAvailable() && i < 100; ++i) { + usleep(10000); + } + ASSERT_TRUE(defaultTestProxy->isAvailable()); uint32_t v1 = 5; std::string v2 = "Ciao ;)"; @@ -114,10 +123,18 @@ TEST_F(DBusCommunicationTest, RemoteMethodCallWithNonstandardAddressSucceeds) { ASSERT_TRUE((bool)defaultTestProxy); auto stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); - bool success = stubFactory_->registerService(stub, nonstandardAddress_); - ASSERT_TRUE(success); - sleep(1); + bool serviceRegistered = stubFactory_->registerService(stub, nonstandardAddress_); + for(unsigned int i = 0; !serviceRegistered && i < 100; ++i) { + serviceRegistered = stubFactory_->registerService(stub, nonstandardAddress_); + usleep(10000); + } + ASSERT_TRUE(serviceRegistered); + + for(unsigned int i = 0; !defaultTestProxy->isAvailable() && i < 100; ++i) { + usleep(10000); + } + ASSERT_TRUE(defaultTestProxy->isAvailable()); uint32_t v1 = 5; std::string v2 = "Hai :)"; @@ -129,6 +146,94 @@ TEST_F(DBusCommunicationTest, RemoteMethodCallWithNonstandardAddressSucceeds) { } +//XXX This test case requires CommonAPI::DBus::DBusConnection::suspendDispatching and ...::resumeDispatching to be public! + +//static const std::string commonApiAddress = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService"; +//static const std::string interfaceName = "CommonAPI.DBus.tests.DBusProxyTestInterface"; +//static const std::string busName = "CommonAPI.DBus.tests.DBusProxyTestService"; +//static const std::string objectPath = "/CommonAPI/DBus/tests/DBusProxyTestService"; + +//TEST_F(DBusCommunicationTest, AsyncCallsAreQueuedCorrectly) { +// auto proxyDBusConnection = CommonAPI::DBus::DBusConnection::getSessionBus(); +// ASSERT_TRUE(proxyDBusConnection->connect()); +// +// auto stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); +// +// bool serviceRegistered = stubFactory_->registerService(stub, serviceAddress_); +// for(unsigned int i = 0; !serviceRegistered && i < 100; ++i) { +// serviceRegistered = stubFactory_->registerService(stub, serviceAddress_); +// usleep(10000); +// } +// ASSERT_TRUE(serviceRegistered); +// +// auto defaultTestProxy = std::make_shared<commonapi::tests::TestInterfaceDBusProxy>( +// commonApiAddress, +// interfaceName, +// busName, +// objectPath, +// proxyDBusConnection); +// +// for(unsigned int i = 0; !defaultTestProxy->isAvailable() && i < 100; ++i) { +// usleep(10000); +// } +// ASSERT_TRUE(defaultTestProxy->isAvailable()); +// +// auto val1 = commonapi::tests::DerivedTypeCollection::TestEnumExtended2::E_OK; +// commonapi::tests::DerivedTypeCollection::TestMap val2; +// CommonAPI::CallStatus status; +// unsigned int numCalled = 0; +// const unsigned int maxNumCalled = 1000; +// for(unsigned int i = 0; i < maxNumCalled/2; ++i) { +// defaultTestProxy->testVoidDerivedTypeMethodAsync(val1, val2, +// [&] (CommonAPI::CallStatus stat) { +// if(stat == CommonAPI::CallStatus::SUCCESS) { +// numCalled++; +// } +// } +// ); +// } +// +// proxyDBusConnection->suspendDispatching(); +// +// for(unsigned int i = maxNumCalled/2; i < maxNumCalled; ++i) { +// defaultTestProxy->testVoidDerivedTypeMethodAsync(val1, val2, +// [&] (CommonAPI::CallStatus stat) { +// if(stat == CommonAPI::CallStatus::SUCCESS) { +// numCalled++; +// } +// } +// ); +// } +// sleep(2); +// +// proxyDBusConnection->resumeDispatching(); +// +// sleep(2); +// +// ASSERT_EQ(maxNumCalled, numCalled); +// +// numCalled = 0; +// +// defaultTestProxy->getTestPredefinedTypeBroadcastEvent().subscribe( +// [&] (uint32_t, std::string) { +// numCalled++; +// } +// ); +// +// proxyDBusConnection->suspendDispatching(); +// +// for(unsigned int i = 0; i < maxNumCalled; ++i) { +// stub->fireTestPredefinedTypeBroadcastEvent(0, "Nonething"); +// } +// +// sleep(2); +// proxyDBusConnection->resumeDispatching(); +// sleep(2); +// +// ASSERT_EQ(maxNumCalled, numCalled); +//} + + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/test/DBusConnectionTest.cpp b/src/test/DBusConnectionTest.cpp index 0b85009..19a02a8 100644 --- a/src/test/DBusConnectionTest.cpp +++ b/src/test/DBusConnectionTest.cpp @@ -4,195 +4,275 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <common-api-dbus/dbus-connection.h> -#include <common-api-dbus/dbus-output-message-stream.h> +#include <CommonAPI/DBus/DBusConnection.h> +#include <CommonAPI/DBus/DBusProxyAsyncCallbackHandler.h> #include <gtest/gtest.h> +#include <dbus/dbus.h> #include <cstring> -#define ASSERT_DBUSMESSAGE_EQ(_dbusMessage1, _dbusMessage2) \ - ASSERT_FALSE(_dbusMessage1.getSignatureString() == NULL); \ - ASSERT_FALSE(_dbusMessage2.getSignatureString() == NULL); \ - ASSERT_STREQ(_dbusMessage1.getSignatureString(), _dbusMessage2.getSignatureString()); \ - ASSERT_EQ(_dbusMessage1.getBodyLength(), _dbusMessage2.getBodyLength()); \ - ASSERT_FALSE(_dbusMessage1.getBodyData() == NULL); \ - ASSERT_FALSE(_dbusMessage2.getBodyData() == NULL); \ - ASSERT_EQ(memcmp(_dbusMessage1.getBodyData(), _dbusMessage2.getBodyData(), _dbusMessage1.getBodyLength()), 0) - - -namespace { - class DBusConnectionTest: public ::testing::Test { - public: - void onConnectionStatusEvent(const common::api::AvailabilityStatus& newConnectionStatus) { - connectionStatusEventCount_++; - connectionStatus_ = newConnectionStatus; - } - - bool onInterfaceHandlerDBusMessageReply(const common::api::dbus::DBusMessage& dbusMessage, - const std::shared_ptr<common::api::dbus::DBusConnection>& dbusConnection) { - interfaceHandlerDBusMessageCount_++; - interfaceHandlerDBusMessage_ = dbusMessage; - interfaceHandlerDBusMessageReply_ = dbusMessage.createMethodReturn("si"); - - common::api::dbus::DBusOutputMessageStream dbusOutputMessageStream(interfaceHandlerDBusMessageReply_); - dbusOutputMessageStream << "This is a default message reply!" << interfaceHandlerDBusMessageCount_; - dbusOutputMessageStream.flush(); - - dbusConnection->sendDBusMessage(interfaceHandlerDBusMessageReply_); - - return true; - } - - void onDBusMessageHandler(const common::api::dbus::DBusMessage& dbusMessage) { - dbusMessageHandlerCount_++; - dbusMessageHandlerDBusMessage_ = dbusMessage; - } - protected: virtual void SetUp() { - dbusConnection_ = common::api::dbus::DBusConnection::getSessionBus(); - connectionStatusEventCount_ = 0; - interfaceHandlerDBusMessageCount_ = 0; - dbusMessageHandlerCount_ = 0; } virtual void TearDown() { - if (dbusConnection_ && dbusConnection_->isConnected()) - dbusConnection_->disconnect(); - - // reset DBusMessage - interfaceHandlerDBusMessage_ = common::api::dbus::DBusMessage(); - interfaceHandlerDBusMessageReply_ = common::api::dbus::DBusMessage(); - - dbusMessageHandlerDBusMessage_ = common::api::dbus::DBusMessage(); } - - - std::shared_ptr<common::api::dbus::DBusConnection> dbusConnection_; - - uint32_t connectionStatusEventCount_; - common::api::AvailabilityStatus connectionStatus_; - - uint32_t interfaceHandlerDBusMessageCount_; - common::api::dbus::DBusMessage interfaceHandlerDBusMessage_; - common::api::dbus::DBusMessage interfaceHandlerDBusMessageReply_; - - uint32_t dbusMessageHandlerCount_; - common::api::dbus::DBusMessage dbusMessageHandlerDBusMessage_; }; -TEST_F(DBusConnectionTest, IsInitiallyDisconnected) { - ASSERT_FALSE(dbusConnection_->isConnected()); +//TEST_F(DBusConnectionTest, IsInitiallyDisconnected) { +// ASSERT_FALSE(dbusConnection_->isConnected()); +//} +// +//TEST_F(DBusConnectionTest, ConnectAndDisconnectWork) { +// ASSERT_TRUE(dbusConnection_->connect()); +// ASSERT_TRUE(dbusConnection_->isConnected()); +// +// dbusConnection_->disconnect(); +// ASSERT_FALSE(dbusConnection_->isConnected()); +//} +// +//TEST_F(DBusConnectionTest, ConnectionStatusEventWorks) { +// ASSERT_EQ(connectionStatusEventCount_, 0); +// +// auto connectionStatusSubscription = dbusConnection_->getConnectionStatusEvent().subscribe(std::bind( +// &DBusConnectionTest::onConnectionStatusEvent, +// this, +// std::placeholders::_1)); +// +// ASSERT_FALSE(dbusConnection_->isConnected()); +// ASSERT_EQ(connectionStatusEventCount_, 0); +// +// uint32_t expectedEventCount = 0; +// while (expectedEventCount < 10) { +// ASSERT_TRUE(dbusConnection_->connect()); +// ASSERT_TRUE(dbusConnection_->isConnected()); +// ASSERT_EQ(connectionStatusEventCount_, ++expectedEventCount); +// ASSERT_EQ(connectionStatus_, common::api::AvailabilityStatus::AVAILABLE); +// +// dbusConnection_->disconnect(); +// ASSERT_FALSE(dbusConnection_->isConnected()); +// ASSERT_EQ(connectionStatusEventCount_, ++expectedEventCount); +// ASSERT_EQ(connectionStatus_, common::api::AvailabilityStatus::NOT_AVAILABLE); +// } +// +// dbusConnection_->getConnectionStatusEvent().unsubscribe(connectionStatusSubscription); +// ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); +// +// ASSERT_TRUE(dbusConnection_->connect()); +// ASSERT_TRUE(dbusConnection_->isConnected()); +// ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); +// +// dbusConnection_->disconnect(); +// ASSERT_FALSE(dbusConnection_->isConnected()); +// ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); +//} +// +//TEST_F(DBusConnectionTest, SendingAsyncDBusMessagesWorks) { +// const char* busName = "common.api.dbus.test.TestInterfaceHandler"; +// const char* objectPath = "/common/api/dbus/test/TestObject"; +// const char* interfaceName = "common.api.dbus.test.TestInterface"; +// const char* methodName = "TestMethod"; +// +// auto interfaceHandlerDBusConnection = common::api::dbus::DBusConnection::getSessionBus(); +// +// ASSERT_TRUE(interfaceHandlerDBusConnection->connect()); +// ASSERT_TRUE(interfaceHandlerDBusConnection->requestServiceNameAndBlock(busName)); +// +// auto interfaceHandlerToken = interfaceHandlerDBusConnection->registerInterfaceHandler( +// objectPath, +// interfaceName, +// std::bind(&DBusConnectionTest::onInterfaceHandlerDBusMessageReply, +// this, +// std::placeholders::_1, +// interfaceHandlerDBusConnection)); +// +// +// ASSERT_TRUE(dbusConnection_->connect()); +// +// for (uint32_t expectedDBusMessageCount = 1; expectedDBusMessageCount <= 10; expectedDBusMessageCount++) { +// auto dbusMessageCall = common::api::dbus::DBusMessage::createMethodCall( +// busName, +// objectPath, +// interfaceName, +// methodName, +// "si"); +// ASSERT_TRUE(dbusMessageCall); +// +// common::api::dbus::DBusOutputMessageStream dbusOutputMessageStream(dbusMessageCall); +// dbusOutputMessageStream << "This is a test async call" +// << expectedDBusMessageCount; +// dbusOutputMessageStream.flush(); +// +// dbusConnection_->sendDBusMessageWithReplyAsync( +// dbusMessageCall, +// std::bind(&DBusConnectionTest::onDBusMessageHandler, this, std::placeholders::_1)); +// +// for (int i = 0; i < 10 && interfaceHandlerDBusMessageCount_ < expectedDBusMessageCount; i++) +// interfaceHandlerDBusConnection->readWriteDispatch(100); +// +// ASSERT_EQ(interfaceHandlerDBusMessageCount_, expectedDBusMessageCount); +// ASSERT_DBUSMESSAGE_EQ(dbusMessageCall, interfaceHandlerDBusMessage_); +// +// for (int i = 0; i < 10 && dbusMessageHandlerCount_ < expectedDBusMessageCount; i++) +// dbusConnection_->readWriteDispatch(100); +// +// ASSERT_EQ(dbusMessageHandlerCount_, expectedDBusMessageCount); +// ASSERT_DBUSMESSAGE_EQ(dbusMessageHandlerDBusMessage_, interfaceHandlerDBusMessageReply_); +// } +// +// dbusConnection_->disconnect(); +// +// +// interfaceHandlerDBusConnection->unregisterInterfaceHandler(interfaceHandlerToken); +// +// ASSERT_TRUE(interfaceHandlerDBusConnection->releaseServiceName(busName)); +// interfaceHandlerDBusConnection->disconnect(); +//} + + +void dispatch(::DBusConnection* libdbusConnection) { + dbus_bool_t success = TRUE; + while(success) { + success = dbus_connection_read_write_dispatch(libdbusConnection, 1); + } } -TEST_F(DBusConnectionTest, ConnectAndDisconnectWork) { - ASSERT_TRUE(dbusConnection_->connect()); - ASSERT_TRUE(dbusConnection_->isConnected()); +std::promise<bool> promise; +std::future<bool> future = promise.get_future(); - dbusConnection_->disconnect(); - ASSERT_FALSE(dbusConnection_->isConnected()); +void notifyThunk(DBusPendingCall*, void* data) { + ::DBusConnection* libdbusConnection = reinterpret_cast<DBusConnection*>(data); + dbus_connection_close(libdbusConnection); + dbus_connection_unref(libdbusConnection); + promise.set_value(true); } -TEST_F(DBusConnectionTest, ConnectionStatusEventWorks) { - ASSERT_EQ(connectionStatusEventCount_, 0); +TEST_F(DBusConnectionTest, LibdbusConnectionsMayCommitSuicide) { + const ::DBusBusType libdbusType = ::DBusBusType::DBUS_BUS_SESSION; + ::DBusError libdbusError; + dbus_error_init(&libdbusError); + ::DBusConnection* libdbusConnection = dbus_bus_get_private(libdbusType, &libdbusError); - auto connectionStatusSubscription = dbusConnection_->getConnectionStatusEvent().subscribe(std::bind( - &DBusConnectionTest::onConnectionStatusEvent, - this, - std::placeholders::_1)); + assert(libdbusConnection); + dbus_connection_set_exit_on_disconnect(libdbusConnection, false); - ASSERT_FALSE(dbusConnection_->isConnected()); - ASSERT_EQ(connectionStatusEventCount_, 0); + auto dispatchThread = std::thread(&dispatch, libdbusConnection); - uint32_t expectedEventCount = 0; - while (expectedEventCount < 10) { - ASSERT_TRUE(dbusConnection_->connect()); - ASSERT_TRUE(dbusConnection_->isConnected()); - ASSERT_EQ(connectionStatusEventCount_, ++expectedEventCount); - ASSERT_EQ(connectionStatus_, common::api::AvailabilityStatus::AVAILABLE); + ::DBusMessage* libdbusMessageCall = dbus_message_new_method_call( + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListNames"); - dbusConnection_->disconnect(); - ASSERT_FALSE(dbusConnection_->isConnected()); - ASSERT_EQ(connectionStatusEventCount_, ++expectedEventCount); - ASSERT_EQ(connectionStatus_, common::api::AvailabilityStatus::NOT_AVAILABLE); - } + dbus_message_set_signature(libdbusMessageCall, ""); - dbusConnection_->getConnectionStatusEvent().unsubscribe(connectionStatusSubscription); - ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); + DBusPendingCall* libdbusPendingCall; + dbus_bool_t libdbusSuccess; - ASSERT_TRUE(dbusConnection_->connect()); - ASSERT_TRUE(dbusConnection_->isConnected()); - ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); + dbus_connection_send_with_reply( + libdbusConnection, + libdbusMessageCall, + &libdbusPendingCall, + 500); - dbusConnection_->disconnect(); - ASSERT_FALSE(dbusConnection_->isConnected()); - ASSERT_EQ(connectionStatusEventCount_, expectedEventCount); -} + dbus_pending_call_set_notify( + libdbusPendingCall, + notifyThunk, + libdbusConnection, + NULL); -TEST_F(DBusConnectionTest, SendingAsyncDBusMessagesWorks) { - const char* busName = "common.api.dbus.test.TestInterfaceHandler"; - const char* objectPath = "/common/api/dbus/test/TestObject"; - const char* interfaceName = "common.api.dbus.test.TestInterface"; - const char* methodName = "TestMethod"; - - auto interfaceHandlerDBusConnection = common::api::dbus::DBusConnection::getSessionBus(); + ASSERT_EQ(true, future.get()); + dispatchThread.join(); +} - ASSERT_TRUE(interfaceHandlerDBusConnection->connect()); - ASSERT_TRUE(interfaceHandlerDBusConnection->requestServiceNameAndBlock(busName)); - auto interfaceHandlerToken = interfaceHandlerDBusConnection->registerInterfaceHandler( - objectPath, - interfaceName, - std::bind(&DBusConnectionTest::onInterfaceHandlerDBusMessageReply, - this, - std::placeholders::_1, - interfaceHandlerDBusConnection)); +std::promise<bool> promise2; +std::future<bool> future2 = promise2.get_future(); +std::promise<bool> promise3; +std::future<bool> future3 = promise3.get_future(); +void noPartnerCallback(DBusPendingCall*, void* data) { + ::DBusConnection* libdbusConnection = reinterpret_cast<DBusConnection*>(data); + dbus_connection_close(libdbusConnection); + dbus_connection_unref(libdbusConnection); + promise2.set_value(true); +} - ASSERT_TRUE(dbusConnection_->connect()); +void noPartnerCleanup(void* data) { + std::cout << "Cleanup" << std::endl; + promise3.set_value(true); +} - for (uint32_t expectedDBusMessageCount = 1; expectedDBusMessageCount <= 10; expectedDBusMessageCount++) { - auto dbusMessageCall = common::api::dbus::DBusMessage::createMethodCall( - busName, - objectPath, - interfaceName, - methodName, - "si"); - ASSERT_TRUE(dbusMessageCall); +TEST_F(DBusConnectionTest, TimeoutForNonexistingServices) { + const ::DBusBusType libdbusType = ::DBusBusType::DBUS_BUS_SESSION; + ::DBusError libdbusError; + dbus_error_init(&libdbusError); + ::DBusConnection* libdbusConnection = dbus_bus_get_private(libdbusType, &libdbusError); - common::api::dbus::DBusOutputMessageStream dbusOutputMessageStream(dbusMessageCall); - dbusOutputMessageStream << "This is a test async call" - << expectedDBusMessageCount; - dbusOutputMessageStream.flush(); + assert(libdbusConnection); + dbus_connection_set_exit_on_disconnect(libdbusConnection, false); - dbusConnection_->sendDBusMessageWithReplyAsync( - dbusMessageCall, - std::bind(&DBusConnectionTest::onDBusMessageHandler, this, std::placeholders::_1)); + auto dispatchThread = std::thread(&dispatch, libdbusConnection); - for (int i = 0; i < 10 && interfaceHandlerDBusMessageCount_ < expectedDBusMessageCount; i++) - interfaceHandlerDBusConnection->readWriteDispatch(100); + ::DBusMessage* libdbusMessageCall = dbus_message_new_method_call( + "some.connection.somewhere", + "/some/non/existing/object", + "some.interface.somewhere.but.same.place", + "NoReasonableMethod"); - ASSERT_EQ(interfaceHandlerDBusMessageCount_, expectedDBusMessageCount); - ASSERT_DBUSMESSAGE_EQ(dbusMessageCall, interfaceHandlerDBusMessage_); + dbus_message_set_signature(libdbusMessageCall, ""); - for (int i = 0; i < 10 && dbusMessageHandlerCount_ < expectedDBusMessageCount; i++) - dbusConnection_->readWriteDispatch(100); + bool hasHappened = false; - ASSERT_EQ(dbusMessageHandlerCount_, expectedDBusMessageCount); - ASSERT_DBUSMESSAGE_EQ(dbusMessageHandlerDBusMessage_, interfaceHandlerDBusMessageReply_); - } + DBusPendingCall* libdbusPendingCall; + dbus_bool_t libdbusSuccess; - dbusConnection_->disconnect(); + dbus_connection_send_with_reply( + libdbusConnection, + libdbusMessageCall, + &libdbusPendingCall, + 5000); + dbus_pending_call_set_notify( + libdbusPendingCall, + noPartnerCallback, + libdbusConnection, + noPartnerCleanup); - interfaceHandlerDBusConnection->unregisterInterfaceHandler(interfaceHandlerToken); + ASSERT_EQ(true, future2.get()); + dispatchThread.join(); +} - ASSERT_TRUE(interfaceHandlerDBusConnection->releaseServiceName(busName)); - interfaceHandlerDBusConnection->disconnect(); +//TEST_F(DBusConnectionTest, ConnectionsMayCommitAsynchronousSuicide) { +// CommonAPI::DBus::DBusConnection* dbusConnection_ = new CommonAPI::DBus::DBusConnection(CommonAPI::DBus::DBusConnection::BusType::SESSION); +// dbusConnection_->connect(); +// +// auto dbusMessageCall = CommonAPI::DBus::DBusMessage::createMethodCall( +// "org.freedesktop.DBus", +// "/org/freedesktop/DBus", +// "org.freedesktop.DBus", +// "ListNames", +// ""); +// +// bool hasHappened = false; +// +// auto future = dbusConnection_->sendDBusMessageWithReplyAsync(dbusMessageCall, CommonAPI::DBus::DBusProxyAsyncCallbackHandler<std::vector<std::string>>::create( +// [&] (const CommonAPI::CallStatus&, std::vector<std::string>) { +// hasHappened = true; +// delete dbusConnection_; +// } +// )); +// +// ASSERT_EQ(CommonAPI::CallStatus::SUCCESS, future.get()); +//} + + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } -} // namespace diff --git a/src/test/DBusDaemonProxyTest.cpp b/src/test/DBusDaemonProxyTest.cpp index c25098e..16338f5 100644 --- a/src/test/DBusDaemonProxyTest.cpp +++ b/src/test/DBusDaemonProxyTest.cpp @@ -25,8 +25,6 @@ class DBusDaemonProxyTest: public ::testing::Test { } virtual void TearDown() { - if (dbusConnection_ && dbusConnection_->isConnected()) { - } } std::shared_ptr<CommonAPI::DBus::DBusConnection> dbusConnection_; @@ -56,7 +54,7 @@ TEST_F(DBusDaemonProxyTest, ListNamesAsync) { promise.set_value(std::tuple<CommonAPI::CallStatus, std::vector<std::string>>(callStatus, std::move(busNames))); }); - auto status = future.wait_for(std::chrono::milliseconds(200)); + auto status = future.wait_for(std::chrono::milliseconds(500)); bool waitResult = CommonAPI::DBus::checkReady(status); ASSERT_EQ(waitResult, true); @@ -98,12 +96,6 @@ TEST_F(DBusDaemonProxyTest, NameHasOwnerAsync) { promise.set_value(std::tuple<CommonAPI::CallStatus, bool>(callStatus, std::move(nameHasOwner))); }); - //while (readWriteDispatchCount_ < 5) { - // ASSERT_TRUE(doReadWriteDispatch()); - //if (callStatusFuture.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready) - // break; - //} - //ASSERT_NE(readWriteDispatchCount_, 5); auto status = future.wait_for(std::chrono::milliseconds(100)); const bool waitResult = CommonAPI::DBus::checkReady(status); ASSERT_EQ(waitResult, true); @@ -122,7 +114,7 @@ TEST_F(DBusDaemonProxyTest, NameOwnerChangedEvent) { std::promise<bool> promise; auto future = promise.get_future(); - dbusDaemonProxy_->getNameOwnerChangedEvent().subscribe( + auto subscription = dbusDaemonProxy_->getNameOwnerChangedEvent().subscribe( [&](const std::string& name, const std::string& oldOwner, const std::string& newOwner) { static bool promiseIsSet = false; if(!promiseIsSet) { @@ -134,14 +126,9 @@ TEST_F(DBusDaemonProxyTest, NameOwnerChangedEvent) { // Trigger NameOwnerChanged using a new DBusConnection ASSERT_TRUE(CommonAPI::DBus::DBusConnection::getSessionBus()->connect()); - //while (readWriteDispatchCount_ < 5) { - // ASSERT_TRUE(doReadWriteDispatch()); - //if (future.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready) - // break; - //} - - //ASSERT_NE(readWriteDispatchCount_, 5); ASSERT_TRUE(future.get()); + + dbusDaemonProxy_->getNameOwnerChangedEvent().unsubscribe(subscription); } } // namespace diff --git a/src/test/DBusFactoryTest.cpp b/src/test/DBusFactoryTest.cpp index d99cb6b..52330a9 100644 --- a/src/test/DBusFactoryTest.cpp +++ b/src/test/DBusFactoryTest.cpp @@ -45,6 +45,7 @@ class DBusProxyFactoryTest: public ::testing::Test { } virtual void TearDown() { + usleep(30000); } std::shared_ptr<CommonAPI::Runtime> runtime_; diff --git a/src/test/DBusMainLoopIntegrationTest.cpp b/src/test/DBusMainLoopIntegrationTest.cpp new file mode 100644 index 0000000..1a16171 --- /dev/null +++ b/src/test/DBusMainLoopIntegrationTest.cpp @@ -0,0 +1,613 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <gtest/gtest.h> + +#include <cassert> +#include <cstdint> +#include <iostream> +#include <functional> +#include <memory> +#include <stdint.h> +#include <string> +#include <utility> +#include <tuple> +#include <type_traits> +#include <glib.h> + +#include <CommonAPI/types.h> +#include <CommonAPI/AttributeExtension.h> +#include <CommonAPI/Runtime.h> + +#include <CommonAPI/DBus/DBusConnection.h> +#include <CommonAPI/DBus/DBusProxy.h> +#include <CommonAPI/DBus/DBusRuntime.h> + +#include "DBusTestUtils.h" +#include "DemoMainLoop.h" + +#include "commonapi/tests/PredefinedTypeCollection.h" +#include "commonapi/tests/DerivedTypeCollection.h" +#include "commonapi/tests/TestInterfaceProxy.h" +#include "commonapi/tests/TestInterfaceStubDefault.h" +#include "commonapi/tests/TestInterfaceDBusStubAdapter.h" + +#include "commonapi/tests/TestInterfaceDBusProxy.h" + + +const std::string testAddress1 = "local:my.first.test:commonapi.address.one"; +const std::string testAddress2 = "local:my.second.test:commonapi.address.two"; +const std::string testAddress3 = "local:my.third.test:commonapi.address.three"; +const std::string testAddress4 = "local:my.fourth.test:commonapi.address.four"; +const std::string testAddress5 = "local:my.fifth.test:commonapi.address.five"; +const std::string testAddress6 = "local:my.sixth.test:commonapi.address.six"; +const std::string testAddress7 = "local:my.seventh.test:commonapi.address.seven"; +const std::string testAddress8 = "local:my.eigth.test:commonapi.address.eight"; + +//#################################################################################################################### + +class DBusBasicMainLoopTest: public ::testing::Test { +protected: + virtual void SetUp() { + } + + virtual void TearDown() { + } +}; + + +TEST_F(DBusBasicMainLoopTest, MainloopContextCanBeCreated) { + std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::load(); + ASSERT_TRUE((bool) runtime); + + std::shared_ptr<CommonAPI::MainLoopContext> context = runtime->getNewMainLoopContext(); + ASSERT_TRUE((bool) context); +} + + +TEST_F(DBusBasicMainLoopTest, SeveralMainloopContextsCanBeCreated) { + std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::load(); + ASSERT_TRUE((bool)runtime); + + std::shared_ptr<CommonAPI::MainLoopContext> context1 = runtime->getNewMainLoopContext(); + ASSERT_TRUE((bool) context1); + std::shared_ptr<CommonAPI::MainLoopContext> context2 = runtime->getNewMainLoopContext(); + ASSERT_TRUE((bool) context2); + std::shared_ptr<CommonAPI::MainLoopContext> context3 = runtime->getNewMainLoopContext(); + ASSERT_TRUE((bool) context3); + + ASSERT_NE(context1, context2); + ASSERT_NE(context1, context3); + ASSERT_NE(context2, context3); +} + +struct TestSource: public CommonAPI::DispatchSource { + TestSource(const std::string value, std::string& result): value_(value), result_(result) {} + + bool prepare(int64_t& timeout) { + return true; + } + bool check() { + return true; + } + bool dispatch() { + result_.append(value_); + return false; + } + + private: + std::string value_; + std::string& result_; +}; + +TEST_F(DBusBasicMainLoopTest, PrioritiesAreHandledCorrectlyInDemoMainloop) { + std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::load(); + ASSERT_TRUE((bool) runtime); + + std::shared_ptr<CommonAPI::MainLoopContext> context = runtime->getNewMainLoopContext(); + ASSERT_TRUE((bool) context); + + auto mainLoop = new CommonAPI::MainLoop(context); + + std::string result = ""; + + TestSource* testSource1Default = new TestSource("A", result); + TestSource* testSource2Default = new TestSource("B", result); + TestSource* testSource1High = new TestSource("C", result); + TestSource* testSource1Low = new TestSource("D", result); + TestSource* testSource1VeryHigh = new TestSource("E", result); + context->registerDispatchSource(testSource1Default); + context->registerDispatchSource(testSource2Default, CommonAPI::DispatchPriority::DEFAULT); + context->registerDispatchSource(testSource1High, CommonAPI::DispatchPriority::HIGH); + context->registerDispatchSource(testSource1Low, CommonAPI::DispatchPriority::LOW); + context->registerDispatchSource(testSource1VeryHigh, CommonAPI::DispatchPriority::VERY_HIGH); + + mainLoop->doSingleIteration(CommonAPI::TIMEOUT_INFINITE); + + std::string reference("ECABD"); + ASSERT_EQ(reference, result); +} + + +//#################################################################################################################### + +class DBusMainLoopTest: public ::testing::Test { +protected: + virtual void SetUp() { + runtime_ = CommonAPI::Runtime::load(); + ASSERT_TRUE((bool) runtime_); + + context_ = runtime_->getNewMainLoopContext(); + ASSERT_TRUE((bool) context_); + mainLoop_ = new CommonAPI::MainLoop(context_); + + mainloopFactory_ = runtime_->createFactory(context_); + ASSERT_TRUE((bool) mainloopFactory_); + standardFactory_ = runtime_->createFactory(); + ASSERT_TRUE((bool) standardFactory_); + } + + virtual void TearDown() { + delete mainLoop_; + } + + std::shared_ptr<CommonAPI::Runtime> runtime_; + std::shared_ptr<CommonAPI::MainLoopContext> context_; + std::shared_ptr<CommonAPI::Factory> mainloopFactory_; + std::shared_ptr<CommonAPI::Factory> standardFactory_; + CommonAPI::MainLoop* mainLoop_; +}; + + +TEST_F(DBusMainLoopTest, ServiceInDemoMainloopCanBeAddressed) { + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(mainloopFactory_->registerService(stub, testAddress1)); + + auto proxy = standardFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress1); + ASSERT_TRUE((bool) proxy); + + while (!proxy->isAvailable()) { + mainLoop_->doSingleIteration(50000); + } + + uint32_t uint32Value = 42; + std::string stringValue = "Hai :)"; + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + mainLoop_->stop(); + } + ); + + mainLoop_->run(); + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + mainloopFactory_->unregisterService(testAddress1); +} + + +TEST_F(DBusMainLoopTest, ProxyInDemoMainloopCanCallMethods) { + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(standardFactory_->registerService(stub, testAddress2)); + + usleep(500000); + + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress2); + ASSERT_TRUE((bool) proxy); + + while (!proxy->isAvailable()) { + mainLoop_->doSingleIteration(); + usleep(50000); + } + + uint32_t uint32Value = 42; + std::string stringValue = "Hai :)"; + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + mainLoop_->stop(); + } + ); + + mainLoop_->run(); + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + standardFactory_->unregisterService(testAddress2); +} + +TEST_F(DBusMainLoopTest, ProxyAndServiceInSameDemoMainloopCanCommunicate) { + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(mainloopFactory_->registerService(stub, testAddress4)); + + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress4); + ASSERT_TRUE((bool) proxy); + + while (!proxy->isAvailable()) { + mainLoop_->doSingleIteration(); + usleep(50000); + } + + uint32_t uint32Value = 42; + std::string stringValue = "Hai :)"; + bool running = true; + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + mainLoop_->stop(); + } + ); + + mainLoop_->run(); + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + mainloopFactory_->unregisterService(testAddress4); +} + + +class BigDataTestStub: public commonapi::tests::TestInterfaceStubDefault { + void testDerivedTypeMethod( + commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testEnumExtended2InValue, + commonapi::tests::DerivedTypeCollection::TestMap testMapInValue, + commonapi::tests::DerivedTypeCollection::TestEnumExtended2& testEnumExtended2OutValue, + commonapi::tests::DerivedTypeCollection::TestMap& testMapOutValue) { + testEnumExtended2OutValue = testEnumExtended2InValue; + testMapOutValue = testMapInValue; + } +}; + + +TEST_F(DBusMainLoopTest, ProxyAndServiceInSameDemoMainloopCanHandleBigData) { + std::shared_ptr<BigDataTestStub> stub = std::make_shared< + BigDataTestStub>(); + ASSERT_TRUE(mainloopFactory_->registerService(stub, testAddress8)); + + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress8); + ASSERT_TRUE((bool) proxy); + + while (!proxy->isAvailable()) { + mainLoop_->doSingleIteration(); + usleep(50000); + } + + uint32_t uint32Value = 42; + std::string stringValue = "Hai :)"; + bool running = true; + + commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testEnumExtended2InValue = + commonapi::tests::DerivedTypeCollection::TestEnumExtended2::E_OK; + commonapi::tests::DerivedTypeCollection::TestMap testMapInValue; + + // Estimated amount of data (differring padding at beginning/end of Map/Array etc. not taken into account): + // 4 + 4 + 100 * (4 + (4 + 4 + 100 * (11 + 1 + 4)) + 4 ) = 161608 + for(uint32_t i = 0; i < 500; ++i) { + commonapi::tests::DerivedTypeCollection::TestArrayTestStruct testArrayTestStruct; + for(uint32_t j = 0; j < 100; ++j) { + commonapi::tests::DerivedTypeCollection::TestStruct testStruct("Hai all (:", j); + testArrayTestStruct.push_back(testStruct); + } + testMapInValue.insert( {i, testArrayTestStruct} ); + } + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testDerivedTypeMethodAsync( + testEnumExtended2InValue, + testMapInValue, + [&] (const CommonAPI::CallStatus& status, + commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testEnumExtended2OutValue, + commonapi::tests::DerivedTypeCollection::TestMap testMapOutValue) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + EXPECT_EQ(testEnumExtended2InValue, testEnumExtended2OutValue); + EXPECT_EQ(testMapInValue.size(), testMapOutValue.size()); + mainLoop_->stop(); + } + ); + + mainLoop_->run(); + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + mainloopFactory_->unregisterService(testAddress8); +} + +TEST_F(DBusMainLoopTest, DemoMainloopClientsHandleNonavailableServices) { + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress3); + ASSERT_TRUE((bool) proxy); + + uint32_t uint32Value = 42; + std::string stringValue = "Hai :)"; + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + //Will never be called, @see DBusProxyAsyncCallbackHandler + EXPECT_EQ(toString(CommonAPI::CallStatus::NOT_AVAILABLE), toString(status)); + } + ); + + ASSERT_EQ(toString(CommonAPI::CallStatus::NOT_AVAILABLE), toString(futureStatus.get())); +} + +//################################################################################################## + +class GDispatchWrapper: public GSource { + public: + GDispatchWrapper(CommonAPI::DispatchSource* dispatchSource): dispatchSource_(dispatchSource) {} + CommonAPI::DispatchSource* dispatchSource_; +}; + +gboolean dispatchPrepare(GSource* source, gint* timeout) { + int64_t eventTimeout; + return static_cast<GDispatchWrapper*>(source)->dispatchSource_->prepare(eventTimeout); +} + +gboolean dispatchCheck(GSource* source) { + return static_cast<GDispatchWrapper*>(source)->dispatchSource_->check(); +} + +gboolean dispatchExecute(GSource* source, GSourceFunc callback, gpointer userData) { + static_cast<GDispatchWrapper*>(source)->dispatchSource_->dispatch(); + return true; +} + +gboolean gWatchDispatcher(GIOChannel *source, GIOCondition condition, gpointer userData) { + CommonAPI::Watch* watch = static_cast<CommonAPI::Watch*>(userData); + watch->dispatch(condition); + return true; +} + +gboolean gTimeoutDispatcher(void* userData) { + return static_cast<CommonAPI::DispatchSource*>(userData)->dispatch(); +} + + +static GSourceFuncs standardGLibSourceCallbackFuncs = { + dispatchPrepare, + dispatchCheck, + dispatchExecute, + NULL +}; + + +class DBusInGLibMainLoopTest: public ::testing::Test { + protected: + virtual void SetUp() { + running_ = true; + + std::shared_ptr<CommonAPI::Runtime> runtime_ = CommonAPI::Runtime::load(); + ASSERT_TRUE((bool) runtime_); + + context_ = runtime_->getNewMainLoopContext(); + ASSERT_TRUE((bool) context_); + + doSubscriptions(); + + mainloopFactory_ = runtime_->createFactory(context_); + ASSERT_TRUE((bool) mainloopFactory_); + standardFactory_ = runtime_->createFactory(); + ASSERT_TRUE((bool) standardFactory_); + } + + virtual void TearDown() { + } + + void doSubscriptions() { + context_->subscribeForTimeouts( + std::bind(&DBusInGLibMainLoopTest::timeoutAddedCallback, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&DBusInGLibMainLoopTest::timeoutRemovedCallback, this, std::placeholders::_1) + ); + + context_->subscribeForWatches( + std::bind(&DBusInGLibMainLoopTest::watchAddedCallback, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&DBusInGLibMainLoopTest::watchRemovedCallback, this, std::placeholders::_1) + ); + + context_->subscribeForWakeupEvents( + std::bind(&DBusInGLibMainLoopTest::wakeupMain, this) + ); + } + + + public: + std::shared_ptr<CommonAPI::MainLoopContext> context_; + std::shared_ptr<CommonAPI::Factory> mainloopFactory_; + std::shared_ptr<CommonAPI::Factory> standardFactory_; + bool running_; + static constexpr bool mayBlock_ = true; + + std::map<CommonAPI::DispatchSource*, GSource*> gSourceMappings; + + GIOChannel* dbusChannel_; + + void watchAddedCallback(CommonAPI::Watch* watch, const CommonAPI::DispatchPriority dispatchPriority) { + const pollfd& fileDesc = watch->getAssociatedFileDescriptor(); + dbusChannel_ = g_io_channel_unix_new(fileDesc.fd); + + GSource* gWatch = g_io_create_watch(dbusChannel_, static_cast<GIOCondition>(fileDesc.events)); + g_source_set_callback(gWatch, reinterpret_cast<GSourceFunc>(&gWatchDispatcher), watch, NULL); + + const auto& dependentSources = watch->getDependentDispatchSources(); + for (auto dependentSourceIterator = dependentSources.begin(); + dependentSourceIterator != dependentSources.end(); + dependentSourceIterator++) { + GSource* gDispatchSource = g_source_new(&standardGLibSourceCallbackFuncs, sizeof(GDispatchWrapper)); + static_cast<GDispatchWrapper*>(gDispatchSource)->dispatchSource_ = *dependentSourceIterator; + + g_source_add_child_source(gWatch, gDispatchSource); + + gSourceMappings.insert( {*dependentSourceIterator, gDispatchSource} ); + } + g_source_attach(gWatch, NULL); + } + + void watchRemovedCallback(CommonAPI::Watch* watch) { + g_source_remove_by_user_data(watch); + + if(dbusChannel_) { + g_io_channel_unref(dbusChannel_); + dbusChannel_ = NULL; + } + + const auto& dependentSources = watch->getDependentDispatchSources(); + for (auto dependentSourceIterator = dependentSources.begin(); + dependentSourceIterator != dependentSources.end(); + dependentSourceIterator++) { + GSource* gDispatchSource = g_source_new(&standardGLibSourceCallbackFuncs, sizeof(GDispatchWrapper)); + GSource* gSource = gSourceMappings.find(*dependentSourceIterator)->second; + g_source_destroy(gSource); + g_source_unref(gSource); + } + } + + void timeoutAddedCallback(CommonAPI::Timeout* commonApiTimeoutSource, const CommonAPI::DispatchPriority dispatchPriority) { + GSource* gTimeoutSource = g_timeout_source_new(commonApiTimeoutSource->getTimeoutInterval()); + g_source_set_callback(gTimeoutSource, &gTimeoutDispatcher, commonApiTimeoutSource, NULL); + g_source_attach(gTimeoutSource, NULL); + } + + void timeoutRemovedCallback(CommonAPI::Timeout* timeout) { + g_source_remove_by_user_data(timeout); + } + + void wakeupMain() { + g_main_context_wakeup(NULL); + } +}; + + +TEST_F(DBusInGLibMainLoopTest, ProxyInGLibMainloopCanCallMethods) { + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress5); + ASSERT_TRUE((bool) proxy); + + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(standardFactory_->registerService(stub, testAddress5)); + + while(!proxy->isAvailable()) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + uint32_t uint32Value = 24; + std::string stringValue = "Hai :)"; + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + running_ = false; + } + ); + + while(running_) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + standardFactory_->unregisterService(testAddress5); +} + + +TEST_F(DBusInGLibMainLoopTest, ServiceInGLibMainloopCanBeAddressed) { + auto proxy = standardFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress6); + ASSERT_TRUE((bool) proxy); + + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(mainloopFactory_->registerService(stub, testAddress6)); + + uint32_t uint32Value = 42; + std::string stringValue = "Ciao (:"; + + while(!proxy->isAvailable()) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + running_ = false; + //Wakeup needed as the service will be in a poll-block when the client + //call returns, and no other timeout is present to get him out of there. + g_main_context_wakeup(NULL); + } + ); + + while(running_) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + mainloopFactory_->unregisterService(testAddress6); +} + + +TEST_F(DBusInGLibMainLoopTest, ProxyAndServiceInSameGlibMainloopCanCommunicate) { + auto proxy = mainloopFactory_->buildProxy<commonapi::tests::TestInterfaceProxy>(testAddress7); + ASSERT_TRUE((bool) proxy); + + std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stub = std::make_shared< + commonapi::tests::TestInterfaceStubDefault>(); + ASSERT_TRUE(mainloopFactory_->registerService(stub, testAddress7)); + + uint32_t uint32Value = 42; + std::string stringValue = "Ciao (:"; + + while(!proxy->isAvailable()) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + std::future<CommonAPI::CallStatus> futureStatus = proxy->testVoidPredefinedTypeMethodAsync( + uint32Value, + stringValue, + [&] (const CommonAPI::CallStatus& status) { + EXPECT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(status)); + running_ = false; + //Wakeup needed as the service will be in a poll-block when the client + //call returns, and no other timeout is present to get him out of there. + g_main_context_wakeup(NULL); + } + ); + + while(running_) { + g_main_context_iteration(NULL, mayBlock_); + usleep(50000); + } + + ASSERT_EQ(toString(CommonAPI::CallStatus::SUCCESS), toString(futureStatus.get())); + + mainloopFactory_->unregisterService(testAddress7); +} + + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test/DBusMultipleConnectionTest.cpp b/src/test/DBusMultipleConnectionTest.cpp index a0cc497..382470a 100644 --- a/src/test/DBusMultipleConnectionTest.cpp +++ b/src/test/DBusMultipleConnectionTest.cpp @@ -35,16 +35,25 @@ class DBusMultipleConnectionTest: public ::testing::Test { ASSERT_TRUE((bool)stubFactory); stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); - bool success = stubFactory->registerService(stub, serviceAddress); - ASSERT_TRUE(success); + bool serviceNameAcquired = stubFactory->registerService(stub, serviceAddress); + + for(unsigned int i = 0; !serviceNameAcquired && i < 100; i++) { + usleep(10000); + serviceNameAcquired = stubFactory->registerService(stub, serviceAddress); + } + ASSERT_TRUE(serviceNameAcquired); proxy = proxyFactory->buildProxy<commonapi::tests::TestInterfaceProxy>(serviceAddress); ASSERT_TRUE((bool)proxy); + + for(unsigned int i = 0; !proxy->isAvailable() && i < 100; ++i) { + usleep(10000); + } } virtual void TearDown() { stubFactory->unregisterService(serviceAddress); - sleep(1); + usleep(30000); } std::shared_ptr<CommonAPI::Factory> proxyFactory; @@ -71,7 +80,7 @@ TEST_F(DBusMultipleConnectionTest, Broadcast) { std::promise<bool> promise; auto future = promise.get_future(); - proxy->getTestPredefinedTypeBroadcastEvent().subscribe([&]( + auto subscription = proxy->getTestPredefinedTypeBroadcastEvent().subscribe([&]( const uint32_t intVal, const std::string& strVal) { v3 = intVal; promise.set_value(true); @@ -81,6 +90,8 @@ TEST_F(DBusMultipleConnectionTest, Broadcast) { ASSERT_TRUE(future.get()); ASSERT_EQ(v1, v3); + + proxy->getTestPredefinedTypeBroadcastEvent().unsubscribe(subscription); } TEST_F(DBusMultipleConnectionTest, SetAttribute) { @@ -100,7 +111,7 @@ TEST_F(DBusMultipleConnectionTest, SetAttributeBroadcast) { std::promise<bool> promise; auto future = promise.get_future(); - proxy->getTestPredefinedTypeAttributeAttribute().getChangedEvent().subscribe([&]( + auto subscription = proxy->getTestPredefinedTypeAttributeAttribute().getChangedEvent().subscribe([&]( const uint32_t intVal) { v3 = intVal; promise.set_value(true); @@ -113,12 +124,15 @@ TEST_F(DBusMultipleConnectionTest, SetAttributeBroadcast) { ASSERT_TRUE(future.get()); ASSERT_EQ(v1, v3); + + proxy->getTestPredefinedTypeAttributeAttribute().getChangedEvent().unsubscribe(subscription); } TEST_F(DBusMultipleConnectionTest, GetAttribute) { uint32_t v1; - CommonAPI::CallStatus stat = proxy->getTestPredefinedTypeAttributeAttribute().getValue(v1); + CommonAPI::CallStatus stat; + proxy->getTestPredefinedTypeAttributeAttribute().getValue(stat, v1); ASSERT_EQ(CommonAPI::CallStatus::SUCCESS, stat); } diff --git a/src/test/DBusProxyTest.cpp b/src/test/DBusProxyTest.cpp index 7efdda9..a45f6f2 100644 --- a/src/test/DBusProxyTest.cpp +++ b/src/test/DBusProxyTest.cpp @@ -13,12 +13,13 @@ #include <CommonAPI/DBus/DBusProxy.h> #include <CommonAPI/DBus/DBusConnection.h> #include <CommonAPI/DBus/DBusStubAdapter.h> -#include <CommonAPI/DBus/DBusUtils.h> #include <commonapi/tests/TestInterfaceDBusProxy.h> #include <commonapi/tests/TestInterfaceDBusStubAdapter.h> #include <commonapi/tests/TestInterfaceStubDefault.h> +#include "DBusTestUtils.h" + #include <gtest/gtest.h> #include <algorithm> @@ -52,14 +53,13 @@ protected: } virtual void TearDown() { + usleep(30000); } void registerTestStub() { stubDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus(); ASSERT_TRUE(stubDBusConnection_->connect()); - ASSERT_TRUE(stubDBusConnection_->requestServiceNameAndBlock(busName)); - auto stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>( commonApiAddress, @@ -69,6 +69,15 @@ protected: stubDBusConnection_, stubDefault); stubAdapter_->init(); + + bool serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName); + + for(unsigned int i = 0; !serviceNameAcquired && i < 100; i++) { + usleep(10000); + serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName); + } + ASSERT_TRUE(serviceNameAcquired); + usleep(500000); } void deregisterTestStub() { @@ -84,22 +93,21 @@ protected: void proxyRegisterForAvailabilityStatus() { proxyAvailabilityStatus_ = CommonAPI::AvailabilityStatus::UNKNOWN; - proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) { + proxyStatusSubscription_ = proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) { proxyAvailabilityStatus_ = availabilityStatus; }); + usleep(100000); } - bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const { - std::chrono::milliseconds loopWaitDuration(100); - - if (proxyAvailabilityStatus_ == availabilityStatus) - return true; + void proxyDeregisterForAvailabilityStatus() { + proxy_->getProxyStatusEvent().unsubscribe(proxyStatusSubscription_); + } + bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const { for (int i = 0; i < 10; i++) { - std::this_thread::sleep_for(loopWaitDuration); - if (proxyAvailabilityStatus_ == availabilityStatus) return true; + usleep(100000); } return false; @@ -109,6 +117,8 @@ protected: std::shared_ptr<commonapi::tests::TestInterfaceDBusProxy> proxy_; CommonAPI::AvailabilityStatus proxyAvailabilityStatus_; + CommonAPI::ProxyStatusEvent::Subscription proxyStatusSubscription_; + std::shared_ptr<CommonAPI::DBus::DBusConnection> stubDBusConnection_; std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter_; }; @@ -133,7 +143,11 @@ TEST_F(ProxyTest, IsNotAvailable) { EXPECT_FALSE(isAvailable); } -TEST_F(ProxyTest, ServiceRegistry) { +TEST_F(ProxyTest, IsConnected) { + ASSERT_TRUE(proxy_->getDBusConnection()->isConnected()); +} + +TEST_F(ProxyTest, AssociatedConnectionHasServiceRegistry) { std::shared_ptr<CommonAPI::DBus::DBusProxyConnection> connection = proxy_->getDBusConnection(); auto registry = connection->getDBusServiceRegistry(); ASSERT_FALSE(!registry); @@ -153,6 +167,7 @@ TEST_F(ProxyTest, DBusProxyStatusEventBeforeServiceIsRegistered) { EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE)); deregisterTestStub(); + proxyDeregisterForAvailabilityStatus(); } TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) { @@ -171,6 +186,7 @@ TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) { EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE)); deregisterTestStub(); + proxyDeregisterForAvailabilityStatus(); } TEST_F(ProxyTest, ServiceStatus) { @@ -178,6 +194,7 @@ TEST_F(ProxyTest, ServiceStatus) { std::vector<std::string> availableDBusServices; + //Service actually IS available! for (int i = 0; i < 5; i++) { availableDBusServices = proxyDBusConnection_->getDBusServiceRegistry()->getAvailableServiceInstances( commonApiServiceName, @@ -187,7 +204,7 @@ TEST_F(ProxyTest, ServiceStatus) { break; } } - sleep(1); + auto found = std::find(availableDBusServices.begin(), availableDBusServices.end(), commonApiAddress); EXPECT_TRUE(availableDBusServices.begin() != availableDBusServices.end()); @@ -214,14 +231,12 @@ TEST_F(ProxyTest, isServiceInstanceAlive) { TEST_F(ProxyTest, IsAvailableBlocking) { registerTestStub(); - // blocking in terms of "if it's still uknown" - bool isAvailable = proxy_->isAvailableBlocking(); - for (int i = 0; !isAvailable && i < 10; i++) { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - isAvailable = proxy_->isAvailableBlocking(); + // blocking in terms of "if it's still unknown" + for (int i = 0; !proxy_->isAvailableBlocking() && i < 3; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - EXPECT_TRUE(isAvailable); + EXPECT_TRUE(proxy_->isAvailableBlocking()); deregisterTestStub(); } @@ -231,30 +246,27 @@ TEST_F(ProxyTest, HasNecessaryAttributesAndEvents) { CommonAPI::ProxyStatusEvent& statusEvent = (proxy_->getProxyStatusEvent()); } -TEST_F(ProxyTest, IsConnected) { - ASSERT_TRUE(proxy_->getDBusConnection()->isConnected()); -} - TEST_F(ProxyTest, TestInterfaceVersionAttribute) { CommonAPI::InterfaceVersionAttribute& versionAttribute = proxy_->getInterfaceVersionAttribute(); CommonAPI::Version version; - CommonAPI::CallStatus status = versionAttribute.getValue(version); + CommonAPI::CallStatus status; + ASSERT_NO_THROW(versionAttribute.getValue(status, version)); ASSERT_EQ(CommonAPI::CallStatus::NOT_AVAILABLE, status); } TEST_F(ProxyTest, AsyncCallbacksAreCalledIfServiceNotAvailable) { commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testInputStruct; commonapi::tests::DerivedTypeCollection::TestMap testInputMap; - bool wasCalled = false; + std::promise<bool> wasCalledPromise; + std::future<bool> wasCalledFuture = wasCalledPromise.get_future(); proxy_->testDerivedTypeMethodAsync(testInputStruct, testInputMap, [&] (const CommonAPI::CallStatus& callStatus, const commonapi::tests::DerivedTypeCollection::TestEnumExtended2&, const commonapi::tests::DerivedTypeCollection::TestMap&) { ASSERT_EQ(callStatus, CommonAPI::CallStatus::NOT_AVAILABLE); - wasCalled = true; + wasCalledPromise.set_value(true); } ); - sleep(1); - ASSERT_TRUE(wasCalled); + ASSERT_TRUE(wasCalledFuture.get()); } int main(int argc, char** argv) { diff --git a/src/test/DBusServiceRegistryTest.cpp b/src/test/DBusServiceRegistryTest.cpp index c6036eb..2955eb6 100644 --- a/src/test/DBusServiceRegistryTest.cpp +++ b/src/test/DBusServiceRegistryTest.cpp @@ -82,6 +82,7 @@ TEST_F(DBusServiceRegistryTest, CanBeConstructed) { std::shared_ptr<CommonAPI::DBus::DBusConnection> dbusConnection = CommonAPI::DBus::DBusConnection::getSessionBus(); CommonAPI::DBus::DBusServiceRegistry* registry = new CommonAPI::DBus::DBusServiceRegistry(dbusConnection); ASSERT_TRUE(registry != NULL); + delete registry; } @@ -138,7 +139,7 @@ TEST_F(DBusServiceRegistryTest, PredefinedInstances) { auto stubDBusConnection = CommonAPI::DBus::DBusConnection::getSessionBus(); ASSERT_TRUE(stubDBusConnection->connect()); - stubDBusConnection->requestServiceNameAndBlock(dbusServiceName); + ASSERT_TRUE(stubDBusConnection->requestServiceNameAndBlock(dbusServiceName)); auto proxyDBusConnection = CommonAPI::DBus::DBusConnection::getSessionBus(); auto dbusServiceRegistry = proxyDBusConnection->getDBusServiceRegistry(); @@ -188,8 +189,8 @@ TEST_F(DBusServiceRegistryTest, PredefinedInstances) { bool isInstanceAlive = dbusServiceRegistry->isServiceInstanceAlive(dbusInterfaceName, dbusServiceName, dbusObjectPath); - for (int i = 0; !isInstanceAlive && i < 5; i++) { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + for (int i = 0; !isInstanceAlive && i < 100; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); isInstanceAlive = dbusServiceRegistry->isServiceInstanceAlive(dbusInterfaceName, dbusServiceName, dbusObjectPath); } @@ -223,7 +224,13 @@ class DBusServiceRegistryTestWithPredefinedRemote: public ::testing::Test { auto stub = std::make_shared<commonapi::tests::TestInterfaceStubDefault>(); - dbusStubConnection_->requestServiceNameAndBlock("test.instance.name"); + bool serviceNameAcquired = dbusStubConnection_->requestServiceNameAndBlock("test.instance.name"); + for(unsigned int i = 0; !serviceNameAcquired && i < 100; ++i) { + usleep(10000); + serviceNameAcquired = dbusStubConnection_->requestServiceNameAndBlock("test.instance.name"); + } + ASSERT_TRUE(serviceNameAcquired); + stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>( "local:test.service.name:test.instance.name", "test.service.name", @@ -232,10 +239,12 @@ class DBusServiceRegistryTestWithPredefinedRemote: public ::testing::Test { dbusStubConnection_, stub); stubAdapter_->init(); + usleep(200000); } virtual void TearDown() { stubAdapter_->deinit(); + usleep(30000); } std::shared_ptr<CommonAPI::DBus::DBusConnection> dbusConnection_; @@ -247,13 +256,11 @@ class DBusServiceRegistryTestWithPredefinedRemote: public ::testing::Test { TEST_F(DBusServiceRegistryTestWithPredefinedRemote, RecognizesCommonAPIDBusServiceInstanceAsAlive) { - sleep(1); ASSERT_TRUE(dbusServiceRegistry_->isServiceInstanceAlive("test.service.name", "test.instance.name", "/test/instance/name")); } TEST_F(DBusServiceRegistryTestWithPredefinedRemote, FindsCommonAPIDBusServiceInstance) { - sleep(1); auto availableServices = dbusServiceRegistry_->getAvailableServiceInstances("test.service.name", "local"); ASSERT_EQ(1, availableServices.size()); bool serviceFound; diff --git a/src/test/DBusStubAdapterTest.cpp b/src/test/DBusStubAdapterTest.cpp index 984132b..45cabe1 100644 --- a/src/test/DBusStubAdapterTest.cpp +++ b/src/test/DBusStubAdapterTest.cpp @@ -220,6 +220,7 @@ int main(void) { } assert(dispatchedMessageCount > 0); + testStubAdapter->deinit(); return 0; } diff --git a/src/test/DBusTestUtils.h b/src/test/DBusTestUtils.h index 8b0cbf9..a1140e4 100644 --- a/src/test/DBusTestUtils.h +++ b/src/test/DBusTestUtils.h @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <dbus/dbus.h> +#include <CommonAPI/DBus/DBusServiceRegistry.h> inline char eliminateZeroes(char val) { @@ -32,3 +33,43 @@ inline void printLibdbusMessage(DBusMessage* libdbusMessage) { printLibdbusMessage(libdbusMessage, 0, dbus_message_get_body_length(libdbusMessage)); } +inline std::string toString(CommonAPI::DBus::DBusServiceRegistry::DBusServiceState state) { + switch(state) { + case CommonAPI::DBus::DBusServiceRegistry::DBusServiceState::AVAILABLE: + return "AVAILABLE"; + case CommonAPI::DBus::DBusServiceRegistry::DBusServiceState::NOT_AVAILABLE: + return "NOT_AVAILABLE"; + case CommonAPI::DBus::DBusServiceRegistry::DBusServiceState::RESOLVED: + return "RESOLVED"; + case CommonAPI::DBus::DBusServiceRegistry::DBusServiceState::RESOLVING: + return "RESOLVING"; + case CommonAPI::DBus::DBusServiceRegistry::DBusServiceState::UNKNOWN: + return "UNKNOWN"; + } +} + +inline std::string toString(CommonAPI::AvailabilityStatus state) { + switch(state) { + case CommonAPI::AvailabilityStatus::AVAILABLE: + return "AVAILABLE"; + case CommonAPI::AvailabilityStatus::NOT_AVAILABLE: + return "NOT_AVAILABLE"; + case CommonAPI::AvailabilityStatus::UNKNOWN: + return "UNKNOWN"; + } +} + +inline std::string toString(CommonAPI::CallStatus state) { + switch(state) { + case CommonAPI::CallStatus::CONNECTION_FAILED: + return "CONNECTION_FAILED"; + case CommonAPI::CallStatus::NOT_AVAILABLE: + return "NOT_AVAILABLE"; + case CommonAPI::CallStatus::OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case CommonAPI::CallStatus::REMOTE_ERROR: + return "REMOTE_ERROR"; + case CommonAPI::CallStatus::SUCCESS: + return "SUCCESS"; + } +} diff --git a/src/test/DemoMainLoop.h b/src/test/DemoMainLoop.h new file mode 100644 index 0000000..4cbf47a --- /dev/null +++ b/src/test/DemoMainLoop.h @@ -0,0 +1,334 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DEMO_MAIN_LOOP_H_ +#define DEMO_MAIN_LOOP_H_ + + +#include <CommonAPI/MainLoopContext.h> + +#include <vector> +#include <set> +#include <map> +#include <poll.h> +#include <unistd.h> +#include <sys/eventfd.h> +#include <cassert> + + +namespace CommonAPI { + +class MainLoop { + public: + MainLoop() = delete; + MainLoop(const MainLoop&) = delete; + MainLoop& operator=(const MainLoop&) = delete; + MainLoop(MainLoop&&) = delete; + MainLoop& operator=(MainLoop&&) = delete; + + explicit MainLoop(std::shared_ptr<MainLoopContext> context) : + context_(context), currentMinimalTimeoutInterval_(TIMEOUT_INFINITE), running_(false), breakLoop_(false) { + wakeFd_.fd = eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK); + wakeFd_.events = POLLIN | POLLOUT | POLLERR; + + assert(wakeFd_.fd != -1); + registerFileDescriptor(wakeFd_); + + dispatchSourceListenerSubscription_ = context_->subscribeForDispatchSources( + std::bind(&CommonAPI::MainLoop::registerDispatchSource, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&CommonAPI::MainLoop::deregisterDispatchSource, this, std::placeholders::_1)); + watchListenerSubscription_ = context_->subscribeForWatches( + std::bind(&CommonAPI::MainLoop::registerWatch, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&CommonAPI::MainLoop::deregisterWatch, this, std::placeholders::_1)); + timeoutSourceListenerSubscription_ = context_->subscribeForTimeouts( + std::bind(&CommonAPI::MainLoop::registerTimeout, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&CommonAPI::MainLoop::deregisterTimeout, this, std::placeholders::_1)); + wakeupListenerSubscription_ = context_->subscribeForWakeupEvents( + std::bind(&CommonAPI::MainLoop::wakeup, this)); + } + + ~MainLoop() { + deregisterFileDescriptor(wakeFd_); + + context_->unsubscribeForDispatchSources(dispatchSourceListenerSubscription_); + context_->unsubscribeForWatches(watchListenerSubscription_); + context_->unsubscribeForTimeouts(timeoutSourceListenerSubscription_); + context_->unsubscribeForWakeupEvents(wakeupListenerSubscription_); + + close(wakeFd_.fd); + } + + /** + * The given timeout will be overridden if a timeout-event is present that defines an earlier ready time. + */ + void run(const int64_t& timeoutInterval = TIMEOUT_INFINITE) { + running_ = true; + while(running_) { + doSingleIteration(timeoutInterval); + } + } + + void stop() { + running_ = false; + wakeup(); + } + + /** + * \brief Executes a single cycle of the mainloop. + * + * Subsequently calls prepare(), poll(), check() and, if necessary, dispatch(). + * The given timeout (milliseconds) represents the maximum time + * this iteration will remain in the poll state. All other steps + * are handled in a non-blocking way. Note however that a source + * might claim to have infinite amounts of data to dispatch. + * This demo-implementation of a Mainloop will dispatch a source + * until it no longer claims to have data to dispatch. + * Dispatch will not be called if no sources, watches and timeouts + * claim to be ready during the check()-phase. + * + * @param timeout The maximum poll-timeout for this iteration. + */ + void doSingleIteration(const int64_t& timeout = TIMEOUT_INFINITE) { + prepare(timeout); + poll(); + if(check()) { + dispatch(); + } + } + + /* + * The given timeout is a maximum timeout in ms, measured from the current time in the future + * (a value of 0 means "no timeout"). It will be overridden if a timeout-event is present + * that defines an earlier ready time. + */ + void prepare(const int64_t& timeout = TIMEOUT_INFINITE) { + currentMinimalTimeoutInterval_ = timeout; + + for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); + dispatchSourceIterator != registeredDispatchSources_.end(); + dispatchSourceIterator++) { + + int64_t dispatchTimeout = TIMEOUT_INFINITE; + if(dispatchSourceIterator->second->prepare(dispatchTimeout)) { + sourcesToDispatch_.insert(*dispatchSourceIterator); + } else if (dispatchTimeout < currentMinimalTimeoutInterval_) { + currentMinimalTimeoutInterval_ = dispatchTimeout; + } + } + + int64_t currentContextTime = getCurrentTimeInMs(); + + for (auto timeoutPriorityRange = registeredTimeouts_.begin(); + timeoutPriorityRange != registeredTimeouts_.end(); + timeoutPriorityRange++) { + + int64_t intervalToReady = timeoutPriorityRange->second->getReadyTime() - currentContextTime; + + if (intervalToReady <= 0) { + timeoutsToDispatch_.insert(*timeoutPriorityRange); + currentMinimalTimeoutInterval_ = TIMEOUT_NONE; + } else if (intervalToReady < currentMinimalTimeoutInterval_) { + currentMinimalTimeoutInterval_ = intervalToReady; + } + } + } + + void poll() { + for (auto fileDescriptor = managedFileDescriptors_.begin() + 1; fileDescriptor != managedFileDescriptors_.end(); ++fileDescriptor) { + (*fileDescriptor).revents = 0; + } + + auto numReadyFileDescriptors = ::poll(&(managedFileDescriptors_[0]), managedFileDescriptors_.size(), currentMinimalTimeoutInterval_); + + // If no FileDescriptors are ready, poll returned because of a timeout that has expired. + // The only case in which this is not the reason is when the timeout handed in "prepare" + // expired before any other timeouts. + if(!numReadyFileDescriptors) { + int64_t currentContextTime = getCurrentTimeInMs(); + + for (auto timeoutPriorityRange = registeredTimeouts_.begin(); + timeoutPriorityRange != registeredTimeouts_.end(); + timeoutPriorityRange++) { + + int64_t intervalToReady = timeoutPriorityRange->second->getReadyTime() - currentContextTime; + + if (intervalToReady <= 0) { + timeoutsToDispatch_.insert(*timeoutPriorityRange); + } + } + } + + if (wakeFd_.revents) { + acknowledgeWakeup(); + } + } + + bool check() { + //The first file descriptor always is the loop's wakeup-descriptor. All others need to be linked to a watch. + for (auto fileDescriptor = managedFileDescriptors_.begin() + 1; fileDescriptor != managedFileDescriptors_.end(); ++fileDescriptor) { + for(auto registeredWatchIterator = registeredWatches_.begin(); + registeredWatchIterator != registeredWatches_.end(); + registeredWatchIterator++) { + const auto& correspondingWatchPriority = registeredWatchIterator->first; + const auto& correspondingWatchPair = registeredWatchIterator->second; + + if (std::get<0>(correspondingWatchPair) == fileDescriptor->fd && fileDescriptor->revents) { + watchesToDispatch_.insert( { correspondingWatchPriority, {std::get<1>(correspondingWatchPair), fileDescriptor->revents} } ); + } + } + } + + for(auto dispatchSourceIterator = registeredDispatchSources_.begin(); dispatchSourceIterator != registeredDispatchSources_.end(); ++dispatchSourceIterator) { + if((std::get<1>(*dispatchSourceIterator))->check()) { + sourcesToDispatch_.insert( {std::get<0>(*dispatchSourceIterator), std::get<1>(*dispatchSourceIterator)}); + } + } + + return !timeoutsToDispatch_.empty() || !watchesToDispatch_.empty() || !sourcesToDispatch_.empty(); + } + + void dispatch() { + for (auto timeoutIterator = timeoutsToDispatch_.begin(); + timeoutIterator != timeoutsToDispatch_.end(); + timeoutIterator++) { + std::get<1>(*timeoutIterator)->dispatch(); + } + + for (auto watchIterator = watchesToDispatch_.begin(); + watchIterator != watchesToDispatch_.end(); + watchIterator++) { + Watch* watch = std::get<0>(watchIterator->second); + const unsigned int flags = std::get<1>(watchIterator->second); + const auto& dependentSources = watch->getDependentDispatchSources(); + watch->dispatch(flags); + + for (auto dependentSourceIterator = dependentSources.begin(); + dependentSourceIterator != dependentSources.end(); + dependentSourceIterator++) { + if((*dependentSourceIterator)->check()) { + sourcesToDispatch_.insert( {watchIterator->first, *dependentSourceIterator} ); + } + } + } + + breakLoop_ = false; + for (auto dispatchSourceIterator = sourcesToDispatch_.begin(); + dispatchSourceIterator != sourcesToDispatch_.end() && !breakLoop_; + dispatchSourceIterator++) { + + while(std::get<1>(*dispatchSourceIterator)->dispatch()); + } + + timeoutsToDispatch_.clear(); + sourcesToDispatch_.clear(); + watchesToDispatch_.clear(); + } + + void wakeup() { + uint32_t wake = 1; + ::write(wakeFd_.fd, &wake, sizeof(uint32_t)); + } + + private: + void registerFileDescriptor(const pollfd& fileDescriptor) { + managedFileDescriptors_.push_back(fileDescriptor); + } + + void deregisterFileDescriptor(const pollfd& fileDescriptor) { + for (auto it = managedFileDescriptors_.begin(); it != managedFileDescriptors_.end(); it++) { + if ((*it).fd == fileDescriptor.fd) { + managedFileDescriptors_.erase(it); + break; + } + } + } + + void registerDispatchSource(DispatchSource* dispatchSource, const DispatchPriority dispatchPriority) { + registeredDispatchSources_.insert( {dispatchPriority, dispatchSource} ); + } + + void deregisterDispatchSource(DispatchSource* dispatchSource) { + for(auto dispatchSourceIterator = registeredDispatchSources_.begin(); + dispatchSourceIterator != registeredDispatchSources_.end(); + dispatchSourceIterator++) { + + if(dispatchSourceIterator->second == dispatchSource) { + registeredDispatchSources_.erase(dispatchSourceIterator); + break; + } + } + breakLoop_ = true; + } + + void registerWatch(Watch* watch, const DispatchPriority dispatchPriority) { + registerFileDescriptor(watch->getAssociatedFileDescriptor()); + registeredWatches_.insert( { dispatchPriority, {watch->getAssociatedFileDescriptor().fd, watch} } ); + } + + void deregisterWatch(Watch* watch) { + deregisterFileDescriptor(watch->getAssociatedFileDescriptor()); + + for(auto watchIterator = registeredWatches_.begin(); + watchIterator != registeredWatches_.end(); + watchIterator++) { + + if(watchIterator->second.first == watch->getAssociatedFileDescriptor().fd) { + registeredWatches_.erase(watchIterator); + break; + } + } + } + + void registerTimeout(Timeout* timeout, const DispatchPriority dispatchPriority) { + registeredTimeouts_.insert( {dispatchPriority, timeout} ); + } + + void deregisterTimeout(Timeout* timeout) { + for(auto timeoutIterator = registeredTimeouts_.begin(); + timeoutIterator != registeredTimeouts_.end(); + timeoutIterator++) { + + if(timeoutIterator->second == timeout) { + registeredTimeouts_.erase(timeoutIterator); + break; + } + } + } + + void acknowledgeWakeup() { + uint32_t buffer; + while (::read(wakeFd_.fd, &buffer, sizeof(uint32_t)) == sizeof(buffer)); + } + + std::shared_ptr<MainLoopContext> context_; + + std::vector<pollfd> managedFileDescriptors_; + + std::multimap<DispatchPriority, DispatchSource*> registeredDispatchSources_; + std::multimap<DispatchPriority, std::pair<int, Watch*>> registeredWatches_; + std::multimap<DispatchPriority, Timeout*> registeredTimeouts_; + + std::set<std::pair<DispatchPriority, DispatchSource*>> sourcesToDispatch_; + std::set<std::pair<DispatchPriority, std::pair<Watch*, unsigned short>>> watchesToDispatch_; + std::set<std::pair<DispatchPriority, Timeout*>> timeoutsToDispatch_; + + DispatchSourceListenerSubscription dispatchSourceListenerSubscription_; + WatchListenerSubscription watchListenerSubscription_; + TimeoutSourceListenerSubscription timeoutSourceListenerSubscription_; + WakeupListenerSubscription wakeupListenerSubscription_; + + int64_t currentMinimalTimeoutInterval_; + bool breakLoop_; + bool running_; + + pollfd wakeFd_; +}; + + +} // namespace CommonAPI + +#endif /* DEMO_MAIN_LOOP_H_ */ diff --git a/src/test/commonapi/tests/DerivedTypeCollection.cpp b/src/test/commonapi/tests/DerivedTypeCollection.cpp index 1ad1cce..14b083e 100644 --- a/src/test/commonapi/tests/DerivedTypeCollection.cpp +++ b/src/test/commonapi/tests/DerivedTypeCollection.cpp @@ -7,10 +7,9 @@ namespace commonapi { namespace tests { namespace DerivedTypeCollection { -TestStructExtended::TestStructExtended(const PredefinedTypeCollection::TestString& testStringValue, const uint16_t& uintValueValue, const TestEnumExtended2& testEnumExtended2Value, const PredefinedTypeCollection::WeirdStrangeAlienEnum& alienEnumValue): +TestStructExtended::TestStructExtended(const PredefinedTypeCollection::TestString& testStringValue, const uint16_t& uintValueValue, const TestEnumExtended2& testEnumExtended2Value): TestStruct(testStringValue, uintValueValue), - testEnumExtended2(testEnumExtended2Value), - alienEnum(alienEnumValue) + testEnumExtended2(testEnumExtended2Value) { } @@ -20,21 +19,18 @@ bool operator==(const TestStructExtended& lhs, const TestStructExtended& rhs) { return static_cast<TestStructExtended::TestStruct>(lhs) == static_cast<TestStructExtended::TestStruct>(rhs) && - lhs.testEnumExtended2 == rhs.testEnumExtended2 && - lhs.alienEnum == rhs.alienEnum + lhs.testEnumExtended2 == rhs.testEnumExtended2 ; } void TestStructExtended::readFromInputStream(CommonAPI::InputStream& inputStream) { TestStruct::readFromInputStream(inputStream); inputStream >> testEnumExtended2; - inputStream >> alienEnum; } void TestStructExtended::writeToOutputStream(CommonAPI::OutputStream& outputStream) const { TestStruct::writeToOutputStream(outputStream); outputStream << testEnumExtended2; - outputStream << alienEnum; } TestStruct::TestStruct(const PredefinedTypeCollection::TestString& testStringValue, const uint16_t& uintValueValue): testString(testStringValue), diff --git a/src/test/commonapi/tests/DerivedTypeCollection.h b/src/test/commonapi/tests/DerivedTypeCollection.h index b1cd43f..26409d6 100644 --- a/src/test/commonapi/tests/DerivedTypeCollection.h +++ b/src/test/commonapi/tests/DerivedTypeCollection.h @@ -8,7 +8,7 @@ #include <CommonAPI/OutputStream.h> #include <CommonAPI/SerializableStruct.h> #include <CommonAPI/types.h> -#include "PredefinedTypeCollection.h" +#include <commonapi/tests/PredefinedTypeCollection.h> #include <cstdint> #include <string> #include <unordered_map> @@ -18,6 +18,26 @@ namespace commonapi { namespace tests { namespace DerivedTypeCollection { + struct TestStruct: CommonAPI::SerializableStruct { + PredefinedTypeCollection::TestString testString; + uint16_t uintValue; + + TestStruct() = default; + TestStruct(const PredefinedTypeCollection::TestString& testString, const uint16_t& uintValue); + + virtual void readFromInputStream(CommonAPI::InputStream& inputStream); + virtual void writeToOutputStream(CommonAPI::OutputStream& outputStream) const; + + static inline void writeToTypeOutputStream(CommonAPI::TypeOutputStream& typeOutputStream) { + typeOutputStream.writeStringType(); + typeOutputStream.writeUInt16Type(); + } + }; + + typedef std::vector<TestStruct> TestArrayTestStruct; + + typedef std::unordered_map<uint32_t, TestArrayTestStruct> TestMap; + enum class TestEnum: int32_t { E_UNKNOWN = 0, E_OK = 1, @@ -27,6 +47,7 @@ namespace DerivedTypeCollection { // XXX Definition of a comparator still is necessary for GCC 4.4.1, topic is fixed since 4.5.1 struct TestEnumComparator; + enum class TestEnumExtended: int32_t { E_UNKNOWN = TestEnum::E_UNKNOWN, E_OK = TestEnum::E_OK, @@ -38,23 +59,7 @@ namespace DerivedTypeCollection { // XXX Definition of a comparator still is necessary for GCC 4.4.1, topic is fixed since 4.5.1 struct TestEnumExtendedComparator; - typedef std::unordered_map<TestEnum, std::string> TestEnumMap; - struct TestStruct: CommonAPI::SerializableStruct { - PredefinedTypeCollection::TestString testString; - uint16_t uintValue; - - TestStruct() = default; - TestStruct(const PredefinedTypeCollection::TestString& testString, const uint16_t& uintValue); - virtual void readFromInputStream(CommonAPI::InputStream& inputStream); - virtual void writeToOutputStream(CommonAPI::OutputStream& outputStream) const; - - static inline void writeToTypeOutputStream(CommonAPI::TypeOutputStream& typeOutputStream) { - typeOutputStream.writeStringType(); - typeOutputStream.writeUInt16Type(); - } - }; - typedef std::vector<TestStruct> TestArrayTestStruct; enum class TestEnumExtended2: int32_t { E_UNKNOWN = TestEnum::E_UNKNOWN, E_OK = TestEnum::E_OK, @@ -68,12 +73,12 @@ namespace DerivedTypeCollection { // XXX Definition of a comparator still is necessary for GCC 4.4.1, topic is fixed since 4.5.1 struct TestEnumExtended2Comparator; + struct TestStructExtended: TestStruct { TestEnumExtended2 testEnumExtended2; - PredefinedTypeCollection::WeirdStrangeAlienEnum alienEnum; TestStructExtended() = default; - TestStructExtended(const PredefinedTypeCollection::TestString& testString, const uint16_t& uintValue, const TestEnumExtended2& testEnumExtended2, const PredefinedTypeCollection::WeirdStrangeAlienEnum& alienEnum); + TestStructExtended(const PredefinedTypeCollection::TestString& testString, const uint16_t& uintValue, const TestEnumExtended2& testEnumExtended2); virtual void readFromInputStream(CommonAPI::InputStream& inputStream); virtual void writeToOutputStream(CommonAPI::OutputStream& outputStream) const; @@ -81,10 +86,11 @@ namespace DerivedTypeCollection { static inline void writeToTypeOutputStream(CommonAPI::TypeOutputStream& typeOutputStream) { TestStruct::writeToTypeOutputStream(typeOutputStream); typeOutputStream.writeInt32Type(); - typeOutputStream.writeInt32Type(); } }; - typedef std::unordered_map<uint32_t, TestArrayTestStruct> TestMap; + + typedef std::unordered_map<TestEnum, std::string> TestEnumMap; + enum class TestEnumMissingValue: int32_t { E1 = 10, E2, @@ -93,7 +99,9 @@ namespace DerivedTypeCollection { // XXX Definition of a comparator still is necessary for GCC 4.4.1, topic is fixed since 4.5.1 struct TestEnumMissingValueComparator; + typedef std::vector<uint64_t> TestArrayUInt64; + bool operator==(const TestStructExtended& lhs, const TestStructExtended& rhs); inline bool operator!=(const TestStructExtended& lhs, const TestStructExtended& rhs) { diff --git a/src/test/commonapi/tests/PredefinedTypeCollection.h b/src/test/commonapi/tests/PredefinedTypeCollection.h index ee9c1ec..f1d3cc2 100644 --- a/src/test/commonapi/tests/PredefinedTypeCollection.h +++ b/src/test/commonapi/tests/PredefinedTypeCollection.h @@ -5,8 +5,6 @@ #define COMMONAPI_TESTS_PREDEFINED_TYPE_COLLECTION_H_ #include <CommonAPI/ByteBuffer.h> -#include <CommonAPI/InputStream.h> -#include <CommonAPI/OutputStream.h> #include <CommonAPI/types.h> #include <cstdint> #include <string> @@ -16,40 +14,31 @@ namespace tests { namespace PredefinedTypeCollection { typedef uint8_t TestUInt8; + typedef uint16_t TestUInt16; + typedef uint32_t TestUInt32; + typedef uint64_t TestUInt64; + typedef int8_t TestInt8; + typedef int16_t TestInt16; + typedef int32_t TestInt32; + typedef int64_t TestInt64; + typedef bool TestBoolean; + typedef CommonAPI::ByteBuffer TestByteBuffer; + typedef double TestDouble; + typedef float TestFloat; + typedef std::string TestString; - enum class WeirdStrangeAlienEnum: int32_t { - WEIRD, - STRANGE, - ALIEN - }; - // XXX Definition of a comparator still is necessary for GCC 4.4.1, topic is fixed since 4.5.1 - struct WeirdStrangeAlienEnumComparator; - -inline CommonAPI::InputStream& operator>>(CommonAPI::InputStream& inputStream, WeirdStrangeAlienEnum& enumValue) { - return inputStream.readEnumValue<int32_t>(enumValue); -} - -inline CommonAPI::OutputStream& operator<<(CommonAPI::OutputStream& outputStream, const WeirdStrangeAlienEnum& enumValue) { - return outputStream.writeEnumValue(static_cast<int32_t>(enumValue)); -} - -struct WeirdStrangeAlienEnumComparator { - inline bool operator()(const WeirdStrangeAlienEnum& lhs, const WeirdStrangeAlienEnum& rhs) const { - return static_cast<int32_t>(lhs) < static_cast<int32_t>(rhs); - } -}; @@ -65,37 +54,11 @@ static inline const char* getTypeCollectionName() { namespace CommonAPI { - template<> - struct BasicTypeWriter<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum> { - inline static void writeType (CommonAPI::TypeOutputStream& typeStream) { - typeStream.writeInt32EnumType(); - } - }; - - template<> - struct InputStreamVectorHelper<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum> { - static void beginReadVector(InputStream& inputStream, const std::vector<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum>& vectorValue) { - inputStream.beginReadInt32EnumVector(); - } - }; - - template <> - struct OutputStreamVectorHelper<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum> { - static void beginWriteVector(OutputStream& outputStream, const std::vector<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum>& vectorValue) { - outputStream.beginWriteInt32EnumVector(vectorValue.size()); - } - }; } namespace std { - template<> - struct hash<commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum> { - inline size_t operator()(const commonapi::tests::PredefinedTypeCollection::WeirdStrangeAlienEnum& weirdStrangeAlienEnum) const { - return static_cast<int32_t>(weirdStrangeAlienEnum); - } - }; } #endif // COMMONAPI_TESTS_PREDEFINED_TYPE_COLLECTION_H_ diff --git a/src/test/commonapi/tests/TestInterfaceDBusProxy.cpp b/src/test/commonapi/tests/TestInterfaceDBusProxy.cpp index 34981e0..f5460d1 100644 --- a/src/test/commonapi/tests/TestInterfaceDBusProxy.cpp +++ b/src/test/commonapi/tests/TestInterfaceDBusProxy.cpp @@ -28,7 +28,7 @@ TestInterfaceDBusProxy::TestInterfaceDBusProxy( const std::shared_ptr<CommonAPI::DBus::DBusProxyConnection>& dbusProxyconnection): CommonAPI::DBus::DBusProxy(commonApiAddress, interfaceName, busName, objectPath, dbusProxyconnection) , testPredefinedTypeAttribute_(*this, "onTestPredefinedTypeAttributeAttributeChanged", "setTestPredefinedTypeAttributeAttribute", "u", "getTestPredefinedTypeAttributeAttribute"), - testDerivedStructAttribute_(*this, "onTestDerivedStructAttributeAttributeChanged", "setTestDerivedStructAttributeAttribute", "(sqii)", "getTestDerivedStructAttributeAttribute"), + testDerivedStructAttribute_(*this, "onTestDerivedStructAttributeAttributeChanged", "setTestDerivedStructAttributeAttribute", "(sqi)", "getTestDerivedStructAttributeAttribute"), testDerivedArrayAttribute_(*this, "onTestDerivedArrayAttributeAttributeChanged", "setTestDerivedArrayAttributeAttribute", "at", "getTestDerivedArrayAttributeAttribute") , testPredefinedTypeBroadcast_(*this, "TestPredefinedTypeBroadcast", "us") { @@ -48,6 +48,23 @@ TestInterfaceDBusProxy::TestPredefinedTypeBroadcastEvent& TestInterfaceDBusProxy return testPredefinedTypeBroadcast_; } +void TestInterfaceDBusProxy::testEmptyMethod(CommonAPI::CallStatus& callStatus) { + CommonAPI::DBus::DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<>, + CommonAPI::DBus::DBusSerializableArguments<> >::callMethodWithReply( + *this, + "testEmptyMethod", + "", + callStatus + ); +} +std::future<CommonAPI::CallStatus> TestInterfaceDBusProxy::testEmptyMethodAsync(TestEmptyMethodAsyncCallback callback) { + return CommonAPI::DBus::DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<>, + CommonAPI::DBus::DBusSerializableArguments<> >::callMethodAsync( + *this, + "testEmptyMethod", + "", + std::move(callback)); +} void TestInterfaceDBusProxy::testVoidPredefinedTypeMethod(const uint32_t& uint32Value, const std::string& stringValue, CommonAPI::CallStatus& callStatus) { CommonAPI::DBus::DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<uint32_t, std::string>, CommonAPI::DBus::DBusSerializableArguments<> >::callMethodWithReply( diff --git a/src/test/commonapi/tests/TestInterfaceDBusProxy.h b/src/test/commonapi/tests/TestInterfaceDBusProxy.h index cf3fd76..1ec27be 100644 --- a/src/test/commonapi/tests/TestInterfaceDBusProxy.h +++ b/src/test/commonapi/tests/TestInterfaceDBusProxy.h @@ -4,7 +4,7 @@ #ifndef COMMONAPI_TESTS_TEST_INTERFACE_DBUS_PROXY_H_ #define COMMONAPI_TESTS_TEST_INTERFACE_DBUS_PROXY_H_ -#include "TestInterfaceProxyBase.h" +#include <commonapi/tests/TestInterfaceProxyBase.h> #include <CommonAPI/DBus/DBusFactory.h> #include <CommonAPI/DBus/DBusProxy.h> #include <CommonAPI/DBus/DBusAttribute.h> @@ -24,7 +24,7 @@ class TestInterfaceDBusProxy: virtual public TestInterfaceProxyBase, virtual pub const std::string& objectPath, const std::shared_ptr<CommonAPI::DBus::DBusProxyConnection>& dbusProxyconnection); - virtual ~TestInterfaceDBusProxy() { } + virtual ~TestInterfaceDBusProxy() {} virtual TestPredefinedTypeAttributeAttribute& getTestPredefinedTypeAttributeAttribute(); virtual TestDerivedStructAttributeAttribute& getTestDerivedStructAttributeAttribute(); @@ -32,19 +32,17 @@ class TestInterfaceDBusProxy: virtual public TestInterfaceProxyBase, virtual pub virtual TestPredefinedTypeBroadcastEvent& getTestPredefinedTypeBroadcastEvent(); - + virtual void testEmptyMethod(CommonAPI::CallStatus& callStatus); + virtual std::future<CommonAPI::CallStatus> testEmptyMethodAsync(TestEmptyMethodAsyncCallback callback); virtual void testVoidPredefinedTypeMethod(const uint32_t& uint32Value, const std::string& stringValue, CommonAPI::CallStatus& callStatus); virtual std::future<CommonAPI::CallStatus> testVoidPredefinedTypeMethodAsync(const uint32_t& uint32Value, const std::string& stringValue, TestVoidPredefinedTypeMethodAsyncCallback callback); - virtual void testPredefinedTypeMethod(const uint32_t& uint32InValue, const std::string& stringInValue, CommonAPI::CallStatus& callStatus, uint32_t& uint32OutValue, std::string& stringOutValue); virtual std::future<CommonAPI::CallStatus> testPredefinedTypeMethodAsync(const uint32_t& uint32InValue, const std::string& stringInValue, TestPredefinedTypeMethodAsyncCallback callback); - virtual void testVoidDerivedTypeMethod(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2Value, const DerivedTypeCollection::TestMap& testMapValue, CommonAPI::CallStatus& callStatus); virtual std::future<CommonAPI::CallStatus> testVoidDerivedTypeMethodAsync(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2Value, const DerivedTypeCollection::TestMap& testMapValue, TestVoidDerivedTypeMethodAsyncCallback callback); - virtual void testDerivedTypeMethod(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2InValue, const DerivedTypeCollection::TestMap& testMapInValue, CommonAPI::CallStatus& callStatus, DerivedTypeCollection::TestEnumExtended2& testEnumExtended2OutValue, DerivedTypeCollection::TestMap& testMapOutValue); virtual std::future<CommonAPI::CallStatus> testDerivedTypeMethodAsync(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2InValue, const DerivedTypeCollection::TestMap& testMapInValue, TestDerivedTypeMethodAsyncCallback callback); - + virtual void getOwnVersion(uint16_t& ownVersionMajor, uint16_t& ownVersionMinor) const; private: diff --git a/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp b/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp index 869560e..9145d2c 100644 --- a/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp +++ b/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.cpp @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "TestInterfaceDBusStubAdapter.h" -#include "TestInterface.h" +#include <commonapi/tests/TestInterface.h> namespace commonapi { namespace tests { @@ -45,14 +45,14 @@ const char* TestInterfaceDBusStubAdapter::getMethodsDBusIntrospectionXmlData() c "<arg name=\"changedValue\" type=\"u\" />\n" "</signal>\n" "<method name=\"getTestDerivedStructAttributeAttribute\">\n" - "<arg name=\"value\" type=\"(sqii)\" direction=\"out\" />" + "<arg name=\"value\" type=\"(sqi)\" direction=\"out\" />" "</method>\n" "<method name=\"setTestDerivedStructAttributeAttribute\">\n" - "<arg name=\"requestedValue\" type=\"(sqii)\" direction=\"in\" />\n" - "<arg name=\"setValue\" type=\"(sqii)\" direction=\"out\" />\n" + "<arg name=\"requestedValue\" type=\"(sqi)\" direction=\"in\" />\n" + "<arg name=\"setValue\" type=\"(sqi)\" direction=\"out\" />\n" "</method>\n" "<signal name=\"onTestDerivedStructAttributeAttributeChanged\">\n" - "<arg name=\"changedValue\" type=\"(sqii)\" />\n" + "<arg name=\"changedValue\" type=\"(sqi)\" />\n" "</signal>\n" "<method name=\"getTestDerivedArrayAttributeAttribute\">\n" "<arg name=\"value\" type=\"at\" direction=\"out\" />" @@ -68,6 +68,8 @@ const char* TestInterfaceDBusStubAdapter::getMethodsDBusIntrospectionXmlData() c "<arg name=\"uint32Value\" type=\"u\" />\n" "<arg name=\"stringValue\" type=\"s\" />\n" "</signal>\n" + "<method name=\"testEmptyMethod\">\n" + "</method>\n" "<method name=\"testVoidPredefinedTypeMethod\">\n" "<arg name=\"uint32Value\" type=\"u\" direction=\"in\" />\n" "<arg name=\"stringValue\" type=\"s\" direction=\"in\" />\n" @@ -109,7 +111,7 @@ static CommonAPI::DBus::DBusSetObservableAttributeStubDispatcher< static CommonAPI::DBus::DBusGetAttributeStubDispatcher< TestInterfaceStub, DerivedTypeCollection::TestStructExtended - > getTestDerivedStructAttributeAttributeStubDispatcher(&TestInterfaceStub::getTestDerivedStructAttributeAttribute, "(sqii)"); + > getTestDerivedStructAttributeAttributeStubDispatcher(&TestInterfaceStub::getTestDerivedStructAttributeAttribute, "(sqi)"); static CommonAPI::DBus::DBusSetObservableAttributeStubDispatcher< TestInterfaceStub, DerivedTypeCollection::TestStructExtended @@ -118,7 +120,7 @@ static CommonAPI::DBus::DBusSetObservableAttributeStubDispatcher< &TestInterfaceStubRemoteEvent::onRemoteSetTestDerivedStructAttributeAttribute, &TestInterfaceStubRemoteEvent::onRemoteTestDerivedStructAttributeAttributeChanged, &TestInterfaceStubAdapter::fireTestDerivedStructAttributeAttributeChanged, - "(sqii)"); + "(sqi)"); static CommonAPI::DBus::DBusGetAttributeStubDispatcher< TestInterfaceStub, @@ -137,6 +139,12 @@ static CommonAPI::DBus::DBusSetObservableAttributeStubDispatcher< static CommonAPI::DBus::DBusMethodWithReplyStubDispatcher< TestInterfaceStub, + std::tuple<>, + std::tuple<> + > testEmptyMethodStubDispatcher(&TestInterfaceStub::testEmptyMethod, ""); + +static CommonAPI::DBus::DBusMethodWithReplyStubDispatcher< + TestInterfaceStub, std::tuple<uint32_t, std::string>, std::tuple<> > testVoidPredefinedTypeMethodStubDispatcher(&TestInterfaceStub::testVoidPredefinedTypeMethod, ""); @@ -165,10 +173,11 @@ const TestInterfaceDBusStubAdapterHelper::StubDispatcherTable TestInterfaceDBusS { { "getTestPredefinedTypeAttributeAttribute", "" }, &commonapi::tests::getTestPredefinedTypeAttributeAttributeStubDispatcher } , { { "setTestPredefinedTypeAttributeAttribute", "u" }, &commonapi::tests::setTestPredefinedTypeAttributeAttributeStubDispatcher }, { { "getTestDerivedStructAttributeAttribute", "" }, &commonapi::tests::getTestDerivedStructAttributeAttributeStubDispatcher } - , { { "setTestDerivedStructAttributeAttribute", "(sqii)" }, &commonapi::tests::setTestDerivedStructAttributeAttributeStubDispatcher }, + , { { "setTestDerivedStructAttributeAttribute", "(sqi)" }, &commonapi::tests::setTestDerivedStructAttributeAttributeStubDispatcher }, { { "getTestDerivedArrayAttributeAttribute", "" }, &commonapi::tests::getTestDerivedArrayAttributeAttributeStubDispatcher } , { { "setTestDerivedArrayAttributeAttribute", "at" }, &commonapi::tests::setTestDerivedArrayAttributeAttributeStubDispatcher } , + { { "testEmptyMethod", "" }, &commonapi::tests::testEmptyMethodStubDispatcher }, { { "testVoidPredefinedTypeMethod", "us" }, &commonapi::tests::testVoidPredefinedTypeMethodStubDispatcher }, { { "testPredefinedTypeMethod", "us" }, &commonapi::tests::testPredefinedTypeMethodStubDispatcher }, { { "testVoidDerivedTypeMethod", "ia{ua(sq)}" }, &commonapi::tests::testVoidDerivedTypeMethodStubDispatcher }, @@ -189,7 +198,7 @@ void TestInterfaceDBusStubAdapter::fireTestDerivedStructAttributeAttributeChange ::sendSignal( *this, "onTestDerivedStructAttributeAttributeChanged", - "(sqii)", + "(sqi)", value ); } diff --git a/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.h b/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.h index 7a809ad..651a22b 100644 --- a/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.h +++ b/src/test/commonapi/tests/TestInterfaceDBusStubAdapter.h @@ -4,7 +4,7 @@ #ifndef COMMONAPI_TESTS_TEST_INTERFACE_DBUS_STUB_ADAPTER_H_ #define COMMONAPI_TESTS_TEST_INTERFACE_DBUS_STUB_ADAPTER_H_ -#include "TestInterfaceStub.h" +#include <commonapi/tests/TestInterfaceStub.h> #include <CommonAPI/DBus/DBusStubAdapterHelper.h> #include <CommonAPI/DBus/DBusFactory.h> diff --git a/src/test/commonapi/tests/TestInterfaceProxy.h b/src/test/commonapi/tests/TestInterfaceProxy.h index 0e0c54c..7ab5cdc 100644 --- a/src/test/commonapi/tests/TestInterfaceProxy.h +++ b/src/test/commonapi/tests/TestInterfaceProxy.h @@ -17,31 +17,153 @@ class TestInterfaceProxy: virtual public TestInterface, virtual public TestInter TestInterfaceProxy(std::shared_ptr<CommonAPI::Proxy> delegate); ~TestInterfaceProxy(); + /// Returns the wrapper class that provides access to the attribute TestPredefinedTypeAttribute. virtual TestPredefinedTypeAttributeAttribute& getTestPredefinedTypeAttributeAttribute(); + /// Returns the wrapper class that provides access to the attribute TestDerivedStructAttribute. virtual TestDerivedStructAttributeAttribute& getTestDerivedStructAttributeAttribute(); + /// Returns the wrapper class that provides access to the attribute TestDerivedArrayAttribute. virtual TestDerivedArrayAttributeAttribute& getTestDerivedArrayAttributeAttribute(); + /// Returns the wrapper class that provides access to the broadcast TestPredefinedTypeBroadcast. virtual TestPredefinedTypeBroadcastEvent& getTestPredefinedTypeBroadcastEvent(); + /** + * Calls testEmptyMethod with synchronous semantics. + * + * The CallStatus will be filled when the method returns and indicate either + * "SUCCESS" or which type of error has occurred. In case of an error, ONLY the CallStatus + * will be set. + * Synchronous calls are not supported (will block indefinitely) when mainloop integration is used. + */ + virtual void testEmptyMethod(CommonAPI::CallStatus& callStatus); + /** + * Calls testEmptyMethod with asynchronous semantics. + * + * The provided callback will be called when the reply to this call arrives or + * an error occurs during the call. The CallStatus will indicate either "SUCCESS" + * or which type of error has occurred. In case of any error, ONLY the CallStatus + * will have a defined value. + * The std::future returned by this method will be fulfilled at arrival of the reply. + * It will provide the same value for CallStatus as will be handed to the callback. + */ + virtual std::future<CommonAPI::CallStatus> testEmptyMethodAsync(TestEmptyMethodAsyncCallback callback); + + /** + * Calls testVoidPredefinedTypeMethod with synchronous semantics. + * + * All const parameters are input parameters to this method. + * The CallStatus will be filled when the method returns and indicate either + * "SUCCESS" or which type of error has occurred. In case of an error, ONLY the CallStatus + * will be set. + * Synchronous calls are not supported (will block indefinitely) when mainloop integration is used. + */ virtual void testVoidPredefinedTypeMethod(const uint32_t& uint32Value, const std::string& stringValue, CommonAPI::CallStatus& callStatus); + /** + * Calls testVoidPredefinedTypeMethod with asynchronous semantics. + * + * The provided callback will be called when the reply to this call arrives or + * an error occurs during the call. The CallStatus will indicate either "SUCCESS" + * or which type of error has occurred. In case of any error, ONLY the CallStatus + * will have a defined value. + * The std::future returned by this method will be fulfilled at arrival of the reply. + * It will provide the same value for CallStatus as will be handed to the callback. + */ virtual std::future<CommonAPI::CallStatus> testVoidPredefinedTypeMethodAsync(const uint32_t& uint32Value, const std::string& stringValue, TestVoidPredefinedTypeMethodAsyncCallback callback); + /** + * Calls testPredefinedTypeMethod with synchronous semantics. + * + * All const parameters are input parameters to this method. + * All non-const parameters will be filled with the returned values. + * The CallStatus will be filled when the method returns and indicate either + * "SUCCESS" or which type of error has occurred. In case of an error, ONLY the CallStatus + * will be set. + * Synchronous calls are not supported (will block indefinitely) when mainloop integration is used. + */ virtual void testPredefinedTypeMethod(const uint32_t& uint32InValue, const std::string& stringInValue, CommonAPI::CallStatus& callStatus, uint32_t& uint32OutValue, std::string& stringOutValue); + /** + * Calls testPredefinedTypeMethod with asynchronous semantics. + * + * The provided callback will be called when the reply to this call arrives or + * an error occurs during the call. The CallStatus will indicate either "SUCCESS" + * or which type of error has occurred. In case of any error, ONLY the CallStatus + * will have a defined value. + * The std::future returned by this method will be fulfilled at arrival of the reply. + * It will provide the same value for CallStatus as will be handed to the callback. + */ virtual std::future<CommonAPI::CallStatus> testPredefinedTypeMethodAsync(const uint32_t& uint32InValue, const std::string& stringInValue, TestPredefinedTypeMethodAsyncCallback callback); + /** + * Calls testVoidDerivedTypeMethod with synchronous semantics. + * + * All const parameters are input parameters to this method. + * The CallStatus will be filled when the method returns and indicate either + * "SUCCESS" or which type of error has occurred. In case of an error, ONLY the CallStatus + * will be set. + * Synchronous calls are not supported (will block indefinitely) when mainloop integration is used. + */ virtual void testVoidDerivedTypeMethod(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2Value, const DerivedTypeCollection::TestMap& testMapValue, CommonAPI::CallStatus& callStatus); + /** + * Calls testVoidDerivedTypeMethod with asynchronous semantics. + * + * The provided callback will be called when the reply to this call arrives or + * an error occurs during the call. The CallStatus will indicate either "SUCCESS" + * or which type of error has occurred. In case of any error, ONLY the CallStatus + * will have a defined value. + * The std::future returned by this method will be fulfilled at arrival of the reply. + * It will provide the same value for CallStatus as will be handed to the callback. + */ virtual std::future<CommonAPI::CallStatus> testVoidDerivedTypeMethodAsync(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2Value, const DerivedTypeCollection::TestMap& testMapValue, TestVoidDerivedTypeMethodAsyncCallback callback); + /** + * Calls testDerivedTypeMethod with synchronous semantics. + * + * All const parameters are input parameters to this method. + * All non-const parameters will be filled with the returned values. + * The CallStatus will be filled when the method returns and indicate either + * "SUCCESS" or which type of error has occurred. In case of an error, ONLY the CallStatus + * will be set. + * Synchronous calls are not supported (will block indefinitely) when mainloop integration is used. + */ virtual void testDerivedTypeMethod(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2InValue, const DerivedTypeCollection::TestMap& testMapInValue, CommonAPI::CallStatus& callStatus, DerivedTypeCollection::TestEnumExtended2& testEnumExtended2OutValue, DerivedTypeCollection::TestMap& testMapOutValue); + /** + * Calls testDerivedTypeMethod with asynchronous semantics. + * + * The provided callback will be called when the reply to this call arrives or + * an error occurs during the call. The CallStatus will indicate either "SUCCESS" + * or which type of error has occurred. In case of any error, ONLY the CallStatus + * will have a defined value. + * The std::future returned by this method will be fulfilled at arrival of the reply. + * It will provide the same value for CallStatus as will be handed to the callback. + */ virtual std::future<CommonAPI::CallStatus> testDerivedTypeMethodAsync(const DerivedTypeCollection::TestEnumExtended2& testEnumExtended2InValue, const DerivedTypeCollection::TestMap& testMapInValue, TestDerivedTypeMethodAsyncCallback callback); + /// Returns the CommonAPI address of the remote partner this proxy communicates with. virtual std::string getAddress() const; + + /// Returns the domain of the remote partner this proxy communicates with. virtual const std::string& getDomain() const; + + /// Returns the service ID of the remote partner this proxy communicates with. virtual const std::string& getServiceId() const; + + /// Returns the instance ID of the remote partner this proxy communicates with. virtual const std::string& getInstanceId() const; + + /// Returns true if the remote partner for this proxy is available. virtual bool isAvailable() const; + + /** + * Returns the wrapper class that is used to (de-)register for notifications about + * the availability of the remote partner of this proxy. + */ virtual CommonAPI::ProxyStatusEvent& getProxyStatusEvent(); + + /** + * Returns the wrapper class that is used to access version information of the remote + * partner of this proxy. + */ virtual CommonAPI::InterfaceVersionAttribute& getInterfaceVersionAttribute(); private: @@ -144,6 +266,16 @@ typename TestInterfaceProxy<_AttributeExtensions...>::TestPredefinedTypeBroadcas template <typename ... _AttributeExtensions> +void TestInterfaceProxy<_AttributeExtensions...>::testEmptyMethod(CommonAPI::CallStatus& callStatus) { + delegate_->testEmptyMethod(callStatus); +} + +template <typename ... _AttributeExtensions> +std::future<CommonAPI::CallStatus> TestInterfaceProxy<_AttributeExtensions...>::testEmptyMethodAsync(TestEmptyMethodAsyncCallback callback) { + return delegate_->testEmptyMethodAsync(callback); +} + +template <typename ... _AttributeExtensions> void TestInterfaceProxy<_AttributeExtensions...>::testVoidPredefinedTypeMethod(const uint32_t& uint32Value, const std::string& stringValue, CommonAPI::CallStatus& callStatus) { delegate_->testVoidPredefinedTypeMethod(uint32Value, stringValue, callStatus); } diff --git a/src/test/commonapi/tests/TestInterfaceProxyBase.h b/src/test/commonapi/tests/TestInterfaceProxyBase.h index 4210e25..6ae5263 100644 --- a/src/test/commonapi/tests/TestInterfaceProxyBase.h +++ b/src/test/commonapi/tests/TestInterfaceProxyBase.h @@ -7,8 +7,7 @@ #include "TestInterface.h" #include <unordered_map> #include <cstdint> -#include "PredefinedTypeCollection.h" -#include "DerivedTypeCollection.h" +#include <commonapi/tests/DerivedTypeCollection.h> #include <CommonAPI/InputStream.h> #include <vector> #include <CommonAPI/OutputStream.h> @@ -27,6 +26,7 @@ class TestInterfaceProxyBase: virtual public CommonAPI::Proxy { typedef CommonAPI::ObservableAttribute<DerivedTypeCollection::TestStructExtended> TestDerivedStructAttributeAttribute; typedef CommonAPI::ObservableAttribute<DerivedTypeCollection::TestArrayUInt64> TestDerivedArrayAttributeAttribute; typedef CommonAPI::Event<uint32_t, std::string> TestPredefinedTypeBroadcastEvent; + typedef std::function<void(const CommonAPI::CallStatus&)> TestEmptyMethodAsyncCallback; typedef std::function<void(const CommonAPI::CallStatus&)> TestVoidPredefinedTypeMethodAsyncCallback; typedef std::function<void(const CommonAPI::CallStatus&, const uint32_t&, const std::string&)> TestPredefinedTypeMethodAsyncCallback; typedef std::function<void(const CommonAPI::CallStatus&)> TestVoidDerivedTypeMethodAsyncCallback; @@ -39,6 +39,9 @@ class TestInterfaceProxyBase: virtual public CommonAPI::Proxy { virtual TestPredefinedTypeBroadcastEvent& getTestPredefinedTypeBroadcastEvent() = 0; + virtual void testEmptyMethod(CommonAPI::CallStatus& callStatus) = 0; + virtual std::future<CommonAPI::CallStatus> testEmptyMethodAsync(TestEmptyMethodAsyncCallback callback) = 0; + virtual void testVoidPredefinedTypeMethod(const uint32_t& uint32Value, const std::string& stringValue, CommonAPI::CallStatus& callStatus) = 0; virtual std::future<CommonAPI::CallStatus> testVoidPredefinedTypeMethodAsync(const uint32_t& uint32Value, const std::string& stringValue, TestVoidPredefinedTypeMethodAsyncCallback callback) = 0; diff --git a/src/test/commonapi/tests/TestInterfaceStub.h b/src/test/commonapi/tests/TestInterfaceStub.h index ac34f79..6d078ed 100644 --- a/src/test/commonapi/tests/TestInterfaceStub.h +++ b/src/test/commonapi/tests/TestInterfaceStub.h @@ -6,8 +6,7 @@ #include <unordered_map> #include <cstdint> -#include "PredefinedTypeCollection.h" -#include "DerivedTypeCollection.h" +#include <commonapi/tests/DerivedTypeCollection.h> #include <CommonAPI/InputStream.h> #include <vector> #include <CommonAPI/OutputStream.h> @@ -17,45 +16,92 @@ namespace commonapi { namespace tests { +/** + * Receives messages from remote and handles all dispatching of deserialized calls + * to a stub for the service TestInterface. Also provides means to send broadcasts + * and attribute-changed-notifications of observable attributes as defined by this service. + * An application developer should not need to bother with this class. + */ class TestInterfaceStubAdapter: virtual public CommonAPI::StubAdapter, public TestInterface { public: + ///Notifies all remote listeners about a change of value of the attribute TestPredefinedTypeAttribute. virtual void fireTestPredefinedTypeAttributeAttributeChanged(const uint32_t& TestPredefinedTypeAttribute) = 0; + ///Notifies all remote listeners about a change of value of the attribute TestDerivedStructAttribute. virtual void fireTestDerivedStructAttributeAttributeChanged(const DerivedTypeCollection::TestStructExtended& TestDerivedStructAttribute) = 0; + ///Notifies all remote listeners about a change of value of the attribute TestDerivedArrayAttribute. virtual void fireTestDerivedArrayAttributeAttributeChanged(const DerivedTypeCollection::TestArrayUInt64& TestDerivedArrayAttribute) = 0; + /** + * Sends a broadcast event for TestPredefinedTypeBroadcast. Should not be called directly. + * Instead, the "fire<broadcastName>Event" methods of the stub should be used. + */ virtual void fireTestPredefinedTypeBroadcastEvent(const uint32_t& uint32Value, const std::string& stringValue) = 0; }; +/** + * Defines the necessary callbacks to handle remote set events related to the attributes + * defined in the IDL description for TestInterface. + * For each attribute two callbacks are defined: + * - a verification callback that allows to verify the requested value and to prevent setting + * e.g. an invalid value ("onRemoteSet<AttributeName>"). + * - an action callback to do local work after the attribute value has been changed + * ("onRemote<AttributeName>Changed"). + * + * This class and the one below are the ones an application developer needs to have + * a look at if he wants to implement a service. + */ class TestInterfaceStubRemoteEvent { public: virtual ~TestInterfaceStubRemoteEvent() { } + /// Verification callback for remote set requests on the attribute TestPredefinedTypeAttribute. virtual bool onRemoteSetTestPredefinedTypeAttributeAttribute(uint32_t TestPredefinedTypeAttribute) = 0; + /// Action callback for remote set requests on the attribute TestPredefinedTypeAttribute. virtual void onRemoteTestPredefinedTypeAttributeAttributeChanged() = 0; + /// Verification callback for remote set requests on the attribute TestDerivedStructAttribute. virtual bool onRemoteSetTestDerivedStructAttributeAttribute(DerivedTypeCollection::TestStructExtended TestDerivedStructAttribute) = 0; + /// Action callback for remote set requests on the attribute TestDerivedStructAttribute. virtual void onRemoteTestDerivedStructAttributeAttributeChanged() = 0; + /// Verification callback for remote set requests on the attribute TestDerivedArrayAttribute. virtual bool onRemoteSetTestDerivedArrayAttributeAttribute(DerivedTypeCollection::TestArrayUInt64 TestDerivedArrayAttribute) = 0; + /// Action callback for remote set requests on the attribute TestDerivedArrayAttribute. virtual void onRemoteTestDerivedArrayAttributeAttributeChanged() = 0; }; +/** + * Defines the interface that must be implemented by any class that should provide + * the service TestInterface to remote clients. + * This class and the one above are the ones an application developer needs to have + * a look at if he wants to implement a service. + */ class TestInterfaceStub : public CommonAPI::Stub<TestInterfaceStubAdapter , TestInterfaceStubRemoteEvent> { public: virtual ~TestInterfaceStub() { } + /// Provides getter access to the attribute TestPredefinedTypeAttribute. virtual const uint32_t& getTestPredefinedTypeAttributeAttribute() = 0; + /// Provides getter access to the attribute TestDerivedStructAttribute. virtual const DerivedTypeCollection::TestStructExtended& getTestDerivedStructAttributeAttribute() = 0; + /// Provides getter access to the attribute TestDerivedArrayAttribute. virtual const DerivedTypeCollection::TestArrayUInt64& getTestDerivedArrayAttributeAttribute() = 0; + /// This is the method that will be called on remote calls on the method testEmptyMethod. + virtual void testEmptyMethod() = 0; + /// This is the method that will be called on remote calls on the method testVoidPredefinedTypeMethod. virtual void testVoidPredefinedTypeMethod(uint32_t uint32Value, std::string stringValue) = 0; + /// This is the method that will be called on remote calls on the method testPredefinedTypeMethod. virtual void testPredefinedTypeMethod(uint32_t uint32InValue, std::string stringInValue, uint32_t& uint32OutValue, std::string& stringOutValue) = 0; + /// This is the method that will be called on remote calls on the method testVoidDerivedTypeMethod. virtual void testVoidDerivedTypeMethod(DerivedTypeCollection::TestEnumExtended2 testEnumExtended2Value, DerivedTypeCollection::TestMap testMapValue) = 0; + /// This is the method that will be called on remote calls on the method testDerivedTypeMethod. virtual void testDerivedTypeMethod(DerivedTypeCollection::TestEnumExtended2 testEnumExtended2InValue, DerivedTypeCollection::TestMap testMapInValue, DerivedTypeCollection::TestEnumExtended2& testEnumExtended2OutValue, DerivedTypeCollection::TestMap& testMapOutValue) = 0; + /// Sends a broadcast event for TestPredefinedTypeBroadcast. virtual void fireTestPredefinedTypeBroadcastEvent(const uint32_t& uint32Value, const std::string& stringValue) = 0; }; diff --git a/src/test/commonapi/tests/TestInterfaceStubDefault.cpp b/src/test/commonapi/tests/TestInterfaceStubDefault.cpp index c5e7e35..d852c0c 100644 --- a/src/test/commonapi/tests/TestInterfaceStubDefault.cpp +++ b/src/test/commonapi/tests/TestInterfaceStubDefault.cpp @@ -1,7 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "TestInterfaceStubDefault.h" +#include <commonapi/tests/TestInterfaceStubDefault.h> namespace commonapi { namespace tests { @@ -15,10 +15,6 @@ TestInterfaceStubRemoteEvent* TestInterfaceStubDefault::initStubAdapter(const st return &remoteEventHandler_; } -void TestInterfaceStubDefault::deinitStubAdapter() { - stubAdapter_.reset(); -} - const uint32_t& TestInterfaceStubDefault::getTestPredefinedTypeAttributeAttribute() { return testPredefinedTypeAttributeAttributeValue_; } @@ -46,6 +42,14 @@ bool TestInterfaceStubDefault::validateTestPredefinedTypeAttributeAttributeReque return true; } +bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestPredefinedTypeAttributeAttribute(uint32_t value) { + return defaultStub_->trySetTestPredefinedTypeAttributeAttribute(std::move(value)); +} + +void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestPredefinedTypeAttributeAttributeChanged() { + defaultStub_->onRemoteTestPredefinedTypeAttributeAttributeChanged(); +} + const DerivedTypeCollection::TestStructExtended& TestInterfaceStubDefault::getTestDerivedStructAttributeAttribute() { return testDerivedStructAttributeAttributeValue_; } @@ -73,6 +77,14 @@ bool TestInterfaceStubDefault::validateTestDerivedStructAttributeAttributeReques return true; } +bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestDerivedStructAttributeAttribute(DerivedTypeCollection::TestStructExtended value) { + return defaultStub_->trySetTestDerivedStructAttributeAttribute(std::move(value)); +} + +void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestDerivedStructAttributeAttributeChanged() { + defaultStub_->onRemoteTestDerivedStructAttributeAttributeChanged(); +} + const DerivedTypeCollection::TestArrayUInt64& TestInterfaceStubDefault::getTestDerivedArrayAttributeAttribute() { return testDerivedArrayAttributeAttributeValue_; } @@ -100,6 +112,18 @@ bool TestInterfaceStubDefault::validateTestDerivedArrayAttributeAttributeRequest return true; } +bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestDerivedArrayAttributeAttribute(DerivedTypeCollection::TestArrayUInt64 value) { + return defaultStub_->trySetTestDerivedArrayAttributeAttribute(std::move(value)); +} + +void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestDerivedArrayAttributeAttributeChanged() { + defaultStub_->onRemoteTestDerivedArrayAttributeAttributeChanged(); +} + + +void TestInterfaceStubDefault::testEmptyMethod() { + // No operation in default +} void TestInterfaceStubDefault::testVoidPredefinedTypeMethod(uint32_t uint32Value, std::string stringValue) { // No operation in default @@ -126,30 +150,5 @@ TestInterfaceStubDefault::RemoteEventHandler::RemoteEventHandler(TestInterfaceSt defaultStub_(defaultStub) { } -bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestPredefinedTypeAttributeAttribute(uint32_t value) { - return defaultStub_->trySetTestPredefinedTypeAttributeAttribute(std::move(value)); -} - -void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestPredefinedTypeAttributeAttributeChanged() { - defaultStub_->onRemoteTestPredefinedTypeAttributeAttributeChanged(); -} - -bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestDerivedStructAttributeAttribute(DerivedTypeCollection::TestStructExtended value) { - return defaultStub_->trySetTestDerivedStructAttributeAttribute(std::move(value)); -} - -void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestDerivedStructAttributeAttributeChanged() { - defaultStub_->onRemoteTestDerivedStructAttributeAttributeChanged(); -} - -bool TestInterfaceStubDefault::RemoteEventHandler::onRemoteSetTestDerivedArrayAttributeAttribute(DerivedTypeCollection::TestArrayUInt64 value) { - return defaultStub_->trySetTestDerivedArrayAttributeAttribute(std::move(value)); -} - -void TestInterfaceStubDefault::RemoteEventHandler::onRemoteTestDerivedArrayAttributeAttributeChanged() { - defaultStub_->onRemoteTestDerivedArrayAttributeAttributeChanged(); -} - - } // namespace tests } // namespace commonapi diff --git a/src/test/commonapi/tests/TestInterfaceStubDefault.h b/src/test/commonapi/tests/TestInterfaceStubDefault.h index bc5cdff..3f0aeff 100644 --- a/src/test/commonapi/tests/TestInterfaceStubDefault.h +++ b/src/test/commonapi/tests/TestInterfaceStubDefault.h @@ -4,17 +4,26 @@ #ifndef COMMONAPI_TESTS_TEST_INTERFACE_STUB_DEFAULT_H_ #define COMMONAPI_TESTS_TEST_INTERFACE_STUB_DEFAULT_H_ -#include "TestInterfaceStub.h" +#include <commonapi/tests/TestInterfaceStub.h> namespace commonapi { namespace tests { +/** + * Provides a default implementation for TestInterfaceStubRemoteEvent and + * TestInterfaceStub. Method callbacks have an empty implementation, + * remote set calls on attributes will always change the value of the attribute + * to the one received. + * + * Override this stub if you only want to provide a subset of the functionality + * that would be defined for this service, and/or if you do not need any non-default + * behaviour. + */ class TestInterfaceStubDefault : public TestInterfaceStub { public: TestInterfaceStubDefault(); TestInterfaceStubRemoteEvent* initStubAdapter(const std::shared_ptr<TestInterfaceStubAdapter>& stubAdapter); - void deinitStubAdapter(); virtual const uint32_t& getTestPredefinedTypeAttributeAttribute(); virtual void setTestPredefinedTypeAttributeAttribute(uint32_t value); @@ -26,6 +35,8 @@ class TestInterfaceStubDefault : public TestInterfaceStub { virtual void setTestDerivedArrayAttributeAttribute(DerivedTypeCollection::TestArrayUInt64 value); + virtual void testEmptyMethod(); + virtual void testVoidPredefinedTypeMethod(uint32_t uint32Value, std::string stringValue); virtual void testPredefinedTypeMethod(uint32_t uint32InValue, std::string stringInValue, uint32_t& uint32OutValue, std::string& stringOutValue); diff --git a/src/test/fakeLegacyService/sendToFakeLegacyService.py b/src/test/fakeLegacyService/sendToFakeLegacyService.py index ea23a74..79c1445 100644 --- a/src/test/fakeLegacyService/sendToFakeLegacyService.py +++ b/src/test/fakeLegacyService/sendToFakeLegacyService.py @@ -13,11 +13,21 @@ import dbus import dbus.service def finish(): - bus = dbus.SessionBus() - remote_object = bus.get_object('fake.legacy.service.connection','/some/legacy/path/6259504') - iface = dbus.Interface(remote_object, 'fake.legacy.service.LegacyInterface') - iface.finish() + try: + bus = dbus.SessionBus() + remote_object = bus.get_object('fake.legacy.service.connection','/some/legacy/path/6259504') + iface = dbus.Interface(remote_object, 'fake.legacy.service.LegacyInterface') + iface.finish() + return 0 + except: + print "Service not existing, therefore could not be stopped" + return 1 -command=sys.argv[1] -if command=="finish": - finish() +def main(): + command=sys.argv[1] + if command=="finish": + return finish() + + return 0 + +sys.exit(main())
\ No newline at end of file diff --git a/src/test/test-derived-types.fidl b/src/test/test-derived-types.fidl index 7b8c477..da82e80 100644 --- a/src/test/test-derived-types.fidl +++ b/src/test/test-derived-types.fidl @@ -6,6 +6,15 @@ package commonapi.tests import commonapi.tests.* from "test-predefined-types.fidl" typeCollection DerivedTypeCollection { + + map TestMap { UInt32 to TestArrayTestStruct } + + struct TestStructExtended extends TestStruct { + TestEnumExtended2 testEnumExtended2 + } + + map TestEnumMap { TestEnum to String } + <** @description : Common errors. **> enumeration TestEnum { <** @description : default **> @@ -18,6 +27,13 @@ typeCollection DerivedTypeCollection { E_NOT_USED = "0x03" } + array TestArrayTestStruct of TestStruct + + enumeration TestEnumExtended2 extends TestEnumExtended { + <** @description : new error **> + E_NEW2 = "0x05" + } + enumeration TestEnumMissingValue { <** @description : default **> E1 = "A" @@ -29,11 +45,8 @@ typeCollection DerivedTypeCollection { <** @description : new error **> E_NEW = "0x04" } - - enumeration TestEnumExtended2 extends TestEnumExtended { - <** @description : new error **> - E_NEW2 = "0x05" - } + + array TestArrayUInt64 of UInt64 struct TestStruct { <** @description : the name of the property **> @@ -42,15 +55,6 @@ typeCollection DerivedTypeCollection { <** @description : the actual value **> UInt16 uintValue } - - struct TestStructExtended extends TestStruct { - TestEnumExtended2 testEnumExtended2 - } - - array TestArrayUInt64 of UInt64 - array TestArrayTestStruct of TestStruct - - map TestMap { UInt32 to TestArrayTestStruct } } diff --git a/src/test/test-interface-proxy.fidl b/src/test/test-interface-proxy.fidl index 88d4874..774c1a8 100644 --- a/src/test/test-interface-proxy.fidl +++ b/src/test/test-interface-proxy.fidl @@ -12,6 +12,9 @@ interface TestInterface { attribute DerivedTypeCollection.TestStructExtended TestDerivedStructAttribute attribute DerivedTypeCollection.TestArrayUInt64 TestDerivedArrayAttribute + method testEmptyMethod { + } + method testVoidPredefinedTypeMethod { in { UInt32 uint32Value |