diff options
author | Juergen Gehring <juergen.gehring@bmw.de> | 2017-06-19 07:53:03 -0700 |
---|---|---|
committer | Juergen Gehring <juergen.gehring@bmw.de> | 2017-06-19 07:53:03 -0700 |
commit | 5f694be78a2520cbdea31e8ba82cb579ebf893f9 (patch) | |
tree | fe4e62f3a28b59e5783c492088bf73a9ad2cb07b | |
parent | 44103948d4b052603c0b361448ecb4ef7d954f79 (diff) | |
download | genivi-common-api-dbus-runtime-5f694be78a2520cbdea31e8ba82cb579ebf893f9.tar.gz |
CommonAPI-D-Bus 3.1.123.1.12
26 files changed, 583 insertions, 409 deletions
@@ -1,5 +1,12 @@ Changes ======= +v3.1.12 +- Support DBus type DBUS_TYPE_UNIX_FD as deployment for ints +- DBus deployment: IsObjectPath for all string locations + +v3.1.11.2 +- Fixed availability problems when deleting and recreating proxies multiple times + v3.1.11.1 - Support deployment for anonymous arrays - Fixed concurrency problem / segfault in unregisterStub() diff --git a/CMakeLists.txt b/CMakeLists.txt index b40aa56..f0e1c59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ PROJECT(libcommonapi-dbus) # version of CommonAPI-DBus SET( LIBCOMMONAPI_DBUS_MAJOR_VERSION 3 ) SET( LIBCOMMONAPI_DBUS_MINOR_VERSION 1 ) -SET( LIBCOMMONAPI_DBUS_PATCH_VERSION 11 ) +SET( LIBCOMMONAPI_DBUS_PATCH_VERSION 12 ) message(STATUS "Project name: ${PROJECT_NAME}") @@ -123,9 +123,9 @@ message(STATUS "CMAKE_FIND_ROOT_PATH: ${CMAKE_FIND_ROOT_PATH}") FIND_PACKAGE(PkgConfig) FIND_PACKAGE(Threads REQUIRED) if ("${USE_INSTALLED_COMMONAPI}" STREQUAL "ON") - FIND_PACKAGE(CommonAPI 3.1.11 REQUIRED CONFIG NO_CMAKE_PACKAGE_REGISTRY) + FIND_PACKAGE(CommonAPI 3.1.12 REQUIRED CONFIG NO_CMAKE_PACKAGE_REGISTRY) else() - FIND_PACKAGE(CommonAPI 3.1.11 REQUIRED CONFIG NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) + FIND_PACKAGE(CommonAPI 3.1.12 REQUIRED CONFIG NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() message(STATUS "CommonAPI_CONSIDERED_CONFIGS: ${CommonAPI_CONSIDERED_CONFIGS}") diff --git a/include/CommonAPI/DBus/DBusConnection.hpp b/include/CommonAPI/DBus/DBusConnection.hpp index a382bae..b5c75dd 100644 --- a/include/CommonAPI/DBus/DBusConnection.hpp +++ b/include/CommonAPI/DBus/DBusConnection.hpp @@ -158,7 +158,7 @@ public: COMMONAPI_EXPORT virtual bool addObjectManagerSignalMemberHandler(const std::string& dbusBusName, std::weak_ptr<DBusSignalHandler> dbusSignalHandler); COMMONAPI_EXPORT virtual bool removeObjectManagerSignalMemberHandler(const std::string& dbusBusName, - DBusSignalHandler* dbusSignalHandler); + const DBusSignalHandler* dbusSignalHandler); COMMONAPI_EXPORT DBusSignalHandlerToken addSignalMemberHandler(const std::string& objectPath, const std::string& interfaceName, @@ -223,6 +223,16 @@ public: inline std::weak_ptr<DBusMainloop> getLoop() { return loop_; } #endif + COMMONAPI_EXPORT virtual void addSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _subscription); + + COMMONAPI_EXPORT virtual void removeSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _tag, bool _remove_all); + + COMMONAPI_EXPORT virtual void handleSignalStates(); + 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; @@ -386,7 +396,7 @@ public: mutable std::mutex enforceTimeoutMutex_; mutable std::condition_variable_any enforceTimeoutCondition_; - mutable std::shared_ptr<std::thread> enforcerThread_; + mutable std::thread* enforcerThread_; mutable std::recursive_mutex enforcerThreadMutex_; bool enforcerThreadCancelled_; ConnectionId_t connectionId_; @@ -409,6 +419,9 @@ public: std::vector<DBusMessageReplyAsyncHandler*> asyncHandlersToDelete_; std::mutex asyncHandlersToDeleteMutex_; + + std::map<std::shared_ptr<DBusProxyConnection::DBusSignalHandler>, std::set<uint32_t>> signalStateHandlers_; + std::mutex signalStateHandlersMutex_; }; template<class Function, class... Arguments> diff --git a/include/CommonAPI/DBus/DBusDeployment.hpp b/include/CommonAPI/DBus/DBusDeployment.hpp index b12d67c..9eec01f 100644 --- a/include/CommonAPI/DBus/DBusDeployment.hpp +++ b/include/CommonAPI/DBus/DBusDeployment.hpp @@ -35,6 +35,13 @@ struct StringDeployment : CommonAPI::Deployment<> { bool isObjectPath_; }; +struct IntegerDeployment : CommonAPI::Deployment<> { + IntegerDeployment(bool _isUnixFD) + : isUnixFD_(_isUnixFD) {}; + + bool isUnixFD_; +}; + template<typename... Types_> struct StructDeployment : CommonAPI::Deployment<Types_...> { StructDeployment(Types_*... t) diff --git a/include/CommonAPI/DBus/DBusEvent.hpp b/include/CommonAPI/DBus/DBusEvent.hpp index 4d53d23..c954a88 100644 --- a/include/CommonAPI/DBus/DBusEvent.hpp +++ b/include/CommonAPI/DBus/DBusEvent.hpp @@ -31,7 +31,7 @@ public: const std::string &_name, const std::string &_signature, std::tuple<Arguments_...> _arguments) : proxy_(_proxy), - signalHandler_(std::make_shared<SignalHandler>(_proxy, this)), + signalHandler_(), name_(_name), signature_(_signature), getMethodName_(""), arguments_(_arguments) { @@ -45,7 +45,7 @@ public: const std::string &_path, const std::string &_interface, std::tuple<Arguments_...> _arguments) : proxy_(_proxy), - signalHandler_(std::make_shared<SignalHandler>(_proxy, this)), + signalHandler_(), name_(_name), signature_(_signature), path_(_path), interface_(_interface), getMethodName_(""), @@ -58,7 +58,7 @@ public: const std::string &_getMethodName, std::tuple<Arguments_...> _arguments) : proxy_(_proxy), - signalHandler_(std::make_shared<SignalHandler>(_proxy, this)), + signalHandler_(), name_(_name), signature_(_signature), getMethodName_(_getMethodName), @@ -69,6 +69,7 @@ public: } virtual ~DBusEvent() { + proxy_.removeSignalStateHandler(signalHandler_, 0, true); proxy_.removeSignalMemberHandler(subscription_, signalHandler_.get()); } @@ -77,8 +78,7 @@ public: } virtual void onSpecificError(const CommonAPI::CallStatus status, const uint32_t tag) { - (void)status; - (void)tag; + this->notifySpecificError(tag, status); } virtual void setSubscriptionToken(const DBusProxyConnection::DBusSignalHandlerToken token, const uint32_t tag) { @@ -93,34 +93,43 @@ public: public: SignalHandler(DBusProxyBase&_proxy, DBusEvent<Event_, Arguments_ ...>* _dbusEvent) : - proxy_(_proxy), + proxy_(_proxy.getWeakPtr()), dbusEvent_(_dbusEvent) { } virtual void onSignalDBusMessage(const DBusMessage &_message) { - dbusEvent_->handleSignalDBusMessage(_message, typename make_sequence<sizeof...(Arguments_)>::type()); + if(auto itsProxy = proxy_.lock()) { + dbusEvent_->handleSignalDBusMessage(_message, typename make_sequence<sizeof...(Arguments_)>::type()); + } } virtual void onInitialValueSignalDBusMessage(const DBusMessage&_message, const uint32_t tag) { - dbusEvent_->handleSignalDBusMessage(tag, _message, typename make_sequence<sizeof...(Arguments_)>::type()); + if(auto itsProxy = proxy_.lock()) { + dbusEvent_->handleSignalDBusMessage(tag, _message, typename make_sequence<sizeof...(Arguments_)>::type()); + } } virtual void onSpecificError(const CommonAPI::CallStatus status, const uint32_t tag) { - dbusEvent_->onSpecificError(status, tag); + if(auto itsProxy = proxy_.lock()) { + dbusEvent_->onSpecificError(status, tag); + } } virtual void setSubscriptionToken(const DBusProxyConnection::DBusSignalHandlerToken token, const uint32_t tag) { - dbusEvent_->setSubscriptionToken(token, tag); + if(auto itsProxy = proxy_.lock()) { + dbusEvent_->setSubscriptionToken(token, tag); + } } private : - DBusProxyBase& proxy_; + std::weak_ptr<DBusProxyBase> proxy_; DBusEvent<Event_, Arguments_ ...>* dbusEvent_; }; virtual void onFirstListenerAdded(const Listener &_listener) { (void)_listener; + init(); subscription_ = proxy_.addSignalMemberHandler( path_, interface_, name_, signature_, getMethodName_, signalHandler_, false); } @@ -130,6 +139,12 @@ public: if ("" != getMethodName_) { proxy_.getCurrentValueForSignalListener(getMethodName_, signalHandler_, subscription); } + proxy_.addSignalStateHandler(signalHandler_, subscription); + } + + virtual void onListenerRemoved(const Listener &_listener, const Subscription _subscription) { + (void)_listener; + proxy_.removeSignalStateHandler(signalHandler_, _subscription); } virtual void onLastListenerRemoved(const Listener&) { @@ -160,6 +175,12 @@ public: } } + virtual void init() { + if (!signalHandler_) { + signalHandler_ = std::make_shared<SignalHandler>(proxy_, this); + } + } + DBusProxyBase &proxy_; std::shared_ptr<SignalHandler> signalHandler_; diff --git a/include/CommonAPI/DBus/DBusInputStream.hpp b/include/CommonAPI/DBus/DBusInputStream.hpp index fab82dd..568dc4d 100644 --- a/include/CommonAPI/DBus/DBusInputStream.hpp +++ b/include/CommonAPI/DBus/DBusInputStream.hpp @@ -69,7 +69,14 @@ public: (void)_depl; return readValue(_value, static_cast<EmptyDeployment *>(nullptr)); } - + COMMONAPI_EXPORT InputStream &readValue(int32_t &_value, const CommonAPI::DBus::IntegerDeployment* _depl) { + (void)_depl; + return readValue(_value, static_cast<EmptyDeployment *>(nullptr)); + } + COMMONAPI_EXPORT InputStream &readValue(uint32_t &_value, const CommonAPI::DBus::IntegerDeployment* _depl) { + (void)_depl; + return readValue(_value, static_cast<EmptyDeployment *>(nullptr)); + } COMMONAPI_EXPORT InputStream &readValue(Version &_value, const EmptyDeployment *_depl); COMMONAPI_EXPORT void beginReadMapOfSerializableStructs() { @@ -81,7 +88,7 @@ public: } COMMONAPI_EXPORT bool readMapCompleted() { - return (sizes_.top() <= (current_ - positions_.top())); + return (sizes_.back() <= (current_ - positions_.back())); } COMMONAPI_EXPORT void endReadMapOfSerializableStructs() { @@ -93,8 +100,8 @@ public: uint32_t itsSize(0); _readValue(itsSize); align(8); /* skip padding (if any) */ - if (itsSize > (sizes_.top() + positions_.top() - current_)) { - COMMONAPI_ERROR(std::string(__FUNCTION__) + ": size ", itsSize, " exceeds remaining ", (sizes_.top() + positions_.top() - current_)); + if (itsSize > (sizes_.back() + positions_.back() - current_)) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": size ", itsSize, " exceeds remaining ", (sizes_.back() + positions_.back() - current_)); } _readRaw(itsSize); return (*this); @@ -177,7 +184,7 @@ public: if (_depl != nullptr && _depl->isDBus_) { // Read signature - uint8_t signatureLength; + uint8_t signatureLength(0); readValue(signatureLength, static_cast<EmptyDeployment *>(nullptr)); char * raw = _readRaw(signatureLength+1); if (hasError()) { @@ -233,7 +240,7 @@ public: pushPosition(); _value.clear(); - while (sizes_.top() > current_ - positions_.top()) { + while (sizes_.back() > current_ - positions_.back()) { ElementType_ itsElement; readValue(itsElement, static_cast<EmptyDeployment *>(nullptr)); @@ -279,7 +286,7 @@ public: pushPosition(); _value.clear(); - while (sizes_.top() > current_ - positions_.top()) { + while (sizes_.back() > current_ - positions_.back()) { ElementType_ itsElement; readValue(itsElement, (_depl ? _depl->elementDepl_ : nullptr)); @@ -310,7 +317,7 @@ public: pushPosition(); _value.clear(); - while (sizes_.top() > current_ - positions_.top()) { + while (sizes_.back() > current_ - positions_.back()) { KeyType_ itsKey; ValueType_ itsValue; @@ -345,7 +352,7 @@ public: pushPosition(); _value.clear(); - while (sizes_.top() > current_ - positions_.top()) { + while (sizes_.back() > current_ - positions_.back()) { KeyType_ itsKey; ValueType_ itsValue; @@ -514,8 +521,8 @@ private: CommonAPI::DBus::DBusError* exception_; CommonAPI::DBus::DBusMessage message_; - std::stack<uint32_t> sizes_; - std::stack<size_t> positions_; + std::vector<uint32_t> sizes_; + std::vector<size_t> positions_; }; } // namespace DBus diff --git a/include/CommonAPI/DBus/DBusMessage.hpp b/include/CommonAPI/DBus/DBusMessage.hpp index 98a668d..b30749e 100644 --- a/include/CommonAPI/DBus/DBusMessage.hpp +++ b/include/CommonAPI/DBus/DBusMessage.hpp @@ -95,6 +95,8 @@ public: void setSerial(const unsigned int serial) const; + void setNoReplyExpected(const uint32_t replyNotExpected) const; + private: ::DBusMessage *message_; diff --git a/include/CommonAPI/DBus/DBusOutputStream.hpp b/include/CommonAPI/DBus/DBusOutputStream.hpp index 3cd9cb6..8719146 100644 --- a/include/CommonAPI/DBus/DBusOutputStream.hpp +++ b/include/CommonAPI/DBus/DBusOutputStream.hpp @@ -81,12 +81,14 @@ public: (void)_depl; return _writeValue(_value); } - + COMMONAPI_EXPORT OutputStream &writeValue(const int32_t &_value, const CommonAPI::DBus::IntegerDeployment* _depl) { + (void)_depl; + return _writeValue(_value); + } COMMONAPI_EXPORT OutputStream &writeValue(const int64_t &_value, const EmptyDeployment *_depl) { (void)_depl; return _writeValue(_value); } - COMMONAPI_EXPORT OutputStream &writeValue(const uint8_t &_value, const EmptyDeployment *_depl) { (void)_depl; return _writeValue(_value); @@ -101,12 +103,14 @@ public: (void)_depl; return _writeValue(_value); } - + COMMONAPI_EXPORT OutputStream &writeValue(const uint32_t &_value, const CommonAPI::DBus::IntegerDeployment* _depl) { + (void)_depl; + return _writeValue(_value); + } COMMONAPI_EXPORT OutputStream &writeValue(const uint64_t &_value, const EmptyDeployment *_depl) { (void)_depl; return _writeValue(_value); } - COMMONAPI_EXPORT OutputStream &writeValue(const float &_value, const EmptyDeployment *_depl) { (void)_depl; return _writeValue(static_cast<double>(_value)); @@ -458,7 +462,7 @@ private: DBusError dbusError_; DBusMessage dbusMessage_; - std::stack<size_t> positions_; + std::vector<size_t> positions_; }; } // namespace DBus diff --git a/include/CommonAPI/DBus/DBusProxy.hpp b/include/CommonAPI/DBus/DBusProxy.hpp index feedb12..f40c4d8 100644 --- a/include/CommonAPI/DBus/DBusProxy.hpp +++ b/include/CommonAPI/DBus/DBusProxy.hpp @@ -171,6 +171,8 @@ private: std::promise<AvailabilityStatus> > AvailabilityTimeout_t; mutable std::list<AvailabilityTimeout_t> timeouts_; + + std::atomic<bool> everAvailable_; }; diff --git a/include/CommonAPI/DBus/DBusProxyBase.hpp b/include/CommonAPI/DBus/DBusProxyBase.hpp index 5a24de4..fd9c33d 100644 --- a/include/CommonAPI/DBus/DBusProxyBase.hpp +++ b/include/CommonAPI/DBus/DBusProxyBase.hpp @@ -76,6 +76,16 @@ public: COMMONAPI_EXPORT virtual void init() = 0; + COMMONAPI_EXPORT void addSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _subscription); + + COMMONAPI_EXPORT void removeSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _tag, bool _remove_all = false); + + COMMONAPI_EXPORT std::weak_ptr<DBusProxyBase> getWeakPtr(); + protected: COMMONAPI_EXPORT DBusProxyBase(const DBusProxyBase &) = delete; diff --git a/include/CommonAPI/DBus/DBusProxyConnection.hpp b/include/CommonAPI/DBus/DBusProxyConnection.hpp index 41797e0..4d9f3e0 100644 --- a/include/CommonAPI/DBus/DBusProxyConnection.hpp +++ b/include/CommonAPI/DBus/DBusProxyConnection.hpp @@ -62,9 +62,9 @@ class DBusProxyConnection { // objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature typedef std::tuple<std::string, std::string, std::string, std::string> DBusSignalHandlerPath; typedef std::unordered_map<DBusSignalHandlerPath, - std::map<DBusSignalHandler*, + std::map<const DBusSignalHandler*, std::weak_ptr<DBusProxyConnection::DBusSignalHandler>>> DBusSignalHandlerTable; - typedef std::unordered_multimap<std::string, std::pair<DBusSignalHandler*, + typedef std::unordered_multimap<std::string, std::pair<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>>> DBusOMSignalHandlerTable; typedef DBusSignalHandlerPath DBusSignalHandlerToken; @@ -124,7 +124,7 @@ class DBusProxyConnection { virtual bool addObjectManagerSignalMemberHandler(const std::string& dbusBusName, std::weak_ptr<DBusSignalHandler> dbusSignalHandler) = 0; virtual bool removeObjectManagerSignalMemberHandler(const std::string& dbusBusName, - DBusSignalHandler* dbusSignalHandler) = 0; + const DBusSignalHandler* dbusSignalHandler) = 0; virtual const std::shared_ptr<DBusObjectManager> getDBusObjectManager() = 0; @@ -153,6 +153,16 @@ class DBusProxyConnection { void proxyPushFunctionToMainLoop(Function&& _function, Arguments&& ... _args) { static_cast<DBusConnection*>(this)->proxyPushFunctionToMainLoop(std::forward<Function>(_function), std::forward<Arguments>(_args) ...); } + + virtual void addSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _subscription) = 0; + + virtual void removeSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _tag, bool _remove_all) = 0; + + virtual void handleSignalStates() = 0; }; } // namespace DBus diff --git a/include/CommonAPI/DBus/DBusProxyHelper.hpp b/include/CommonAPI/DBus/DBusProxyHelper.hpp index 43655f4..7113d9d 100644 --- a/include/CommonAPI/DBus/DBusProxyHelper.hpp +++ b/include/CommonAPI/DBus/DBusProxyHelper.hpp @@ -58,6 +58,7 @@ struct DBusProxyHelper<In_<DBusInputStream, DBusOutputStream, InArgs_...>, if (_proxy.isAvailable()) { DBusMessage message = _proxy.createMethodCall(_method, _signature); + message.setNoReplyExpected(1); if (sizeof...(InArgs_) > 0) { DBusOutputStream output(message); if (!DBusSerializableArguments<InArgs_...>::serialize(output, _in...)) { diff --git a/include/CommonAPI/DBus/DBusSelectiveEvent.hpp b/include/CommonAPI/DBus/DBusSelectiveEvent.hpp index 075b819..da140b0 100644 --- a/include/CommonAPI/DBus/DBusSelectiveEvent.hpp +++ b/include/CommonAPI/DBus/DBusSelectiveEvent.hpp @@ -47,7 +47,7 @@ public: protected: void onFirstListenerAdded(const Listener &) { - + this->init(); } void onListenerAdded(const Listener &_listener, const uint32_t subscription) { diff --git a/include/CommonAPI/DBus/DBusServiceRegistry.hpp b/include/CommonAPI/DBus/DBusServiceRegistry.hpp index 3181226..61a4ac5 100644 --- a/include/CommonAPI/DBus/DBusServiceRegistry.hpp +++ b/include/CommonAPI/DBus/DBusServiceRegistry.hpp @@ -73,7 +73,7 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist typedef std::function<void(const DBusObjectManagerStub::DBusObjectPathAndInterfacesDict)> GetAvailableServiceInstancesCallback; - static std::shared_ptr<DBusServiceRegistry> get(std::shared_ptr<DBusProxyConnection> _connection); + static std::shared_ptr<DBusServiceRegistry> get(std::shared_ptr<DBusProxyConnection> _connection, bool _insert=true); static void remove(std::shared_ptr<DBusProxyConnection> _connection); DBusServiceRegistry(std::shared_ptr<DBusProxyConnection> dbusProxyConnection); @@ -117,13 +117,6 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist nextSubscriptionKey(0) { } - DBusInterfaceNameListenersRecord(DBusInterfaceNameListenersRecord &&_other) - : state(_other.state), - listenerList(std::move(_other.listenerList)), - listenersToRemove(std::move(_other.listenersToRemove)), - nextSubscriptionKey(_other.nextSubscriptionKey){ - } - DBusRecordState state; DBusServiceListenerList listenerList; std::list<DBusServiceSubscription> listenersToRemove; @@ -135,24 +128,16 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist struct DBusServiceListenersRecord { DBusServiceListenersRecord() : uniqueBusNameState(DBusRecordState::UNKNOWN), + promiseOnResolve(std::make_shared<std::promise<DBusRecordState>>()), mutexOnResolve() { } - DBusServiceListenersRecord(DBusServiceListenersRecord&& other) - : uniqueBusNameState(other.uniqueBusNameState), - uniqueBusName(std::move(other.uniqueBusName)), - promiseOnResolve(std::move(other.promiseOnResolve)), - futureOnResolve(std::move(other.futureOnResolve)), - mutexOnResolve(std::move(other.mutexOnResolve)), - dbusObjectPathListenersMap(std::move(other.dbusObjectPathListenersMap)) { - } - ~DBusServiceListenersRecord() {}; DBusRecordState uniqueBusNameState; std::string uniqueBusName; - std::promise<DBusRecordState> promiseOnResolve; + std::shared_ptr<std::promise<DBusRecordState>> promiseOnResolve; std::shared_future<DBusRecordState> futureOnResolve; std::unique_lock<std::mutex>* mutexOnResolve; @@ -165,27 +150,21 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist struct DBusObjectPathCache { DBusObjectPathCache() : referenceCount(0), - state(DBusRecordState::UNKNOWN){ - } - - DBusObjectPathCache(DBusObjectPathCache&& other) - : referenceCount(other.referenceCount), - state(other.state), - promiseOnResolve(std::move(other.promiseOnResolve)), - futureOnResolve(std::move(other.futureOnResolve)), - serviceName(std::move(other.serviceName)), - dbusInterfaceNamesCache(std::move(other.dbusInterfaceNamesCache)){ + state(DBusRecordState::UNKNOWN), + promiseOnResolve(std::make_shared<std::promise<DBusRecordState>>()), + pendingObjectManagerCalls(0) { } ~DBusObjectPathCache() {} size_t referenceCount; DBusRecordState state; - std::promise<DBusRecordState> promiseOnResolve; + std::shared_ptr<std::promise<DBusRecordState>> promiseOnResolve; std::shared_future<DBusRecordState> futureOnResolve; std::string serviceName; std::unordered_set<std::string> dbusInterfaceNamesCache; + uint8_t pendingObjectManagerCalls; }; struct DBusUniqueNameRecord { @@ -193,13 +172,6 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist : objectPathsState(DBusRecordState::UNKNOWN) { } - DBusUniqueNameRecord(DBusUniqueNameRecord&& other) - : uniqueName(std::move(other.uniqueName)), - objectPathsState(other.objectPathsState), - ownedBusNames(std::move(other.ownedBusNames)), - dbusObjectPathsCache(std::move(other.dbusObjectPathsCache)) { - } - std::string uniqueName; DBusRecordState objectPathsState; std::unordered_set<std::string> ownedBusNames; @@ -232,10 +204,9 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist const std::string& dbusServiceUniqueName, DBusUniqueNameRecord& dbusUniqueNameRecord); - void releaseDBusObjectPathCacheReference(const std::string& dbusObjectPath, - const DBusServiceListenersRecord& dbusServiceListenersRecord); - - bool resolveObjectPathWithObjectManager(const std::string& dbusServiceUniqueName, const std::string& dbusObjectPath); + bool resolveObjectPathWithObjectManager(DBusObjectPathCache& dbusObjectPathRecord, + const std::string& dbusServiceUniqueName, + const std::string& dbusObjectPath); typedef std::function<void(const CallStatus&, const DBusObjectManagerStub::DBusObjectPathAndInterfacesDict, @@ -255,10 +226,6 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist const std::string& dbusServiceUniqueName, const std::string& dbusObjectPath); - void processManagedObject(const std::string& dbusObjectPath, - const std::string& dbusServiceUniqueName, - const std::string& interfaceName); - void onDBusDaemonProxyNameOwnerChangedEvent(const std::string& name, const std::string& oldOwner, const std::string& newOwner); @@ -276,6 +243,11 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist void onDBusServiceNotAvailable(DBusServiceListenersRecord& dbusServiceListenersRecord, const std::string &_serviceName = ""); + void notifyDBusServiceListenersLocked(const DBusUniqueNameRecord _dbusUniqueNameRecord, + const std::string _dbusObjectPath, + const std::unordered_set<std::string> _dbusInterfaceNames, + const DBusRecordState _dbusInterfaceNamesState); + void notifyDBusServiceListeners(const DBusUniqueNameRecord& dbusUniqueNameRecord, const std::string& dbusObjectPath, @@ -314,7 +286,7 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist std::unordered_set<std::string> dbusPredefinedServices_; private: - typedef std::map<std::shared_ptr<DBusProxyConnection>, std::shared_ptr<DBusServiceRegistry>> RegistryMap_t; + typedef std::map<DBusProxyConnection*, std::shared_ptr<DBusServiceRegistry>> RegistryMap_t; static std::shared_ptr<RegistryMap_t> getRegistryMap() { static std::shared_ptr<RegistryMap_t> registries(new RegistryMap_t); return registries; diff --git a/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp b/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp index 50ba9ae..643109f 100644 --- a/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp +++ b/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp @@ -903,6 +903,7 @@ class DBusGetAttributeStubDispatcher: public virtual StubDispatcher<StubClass_> std::shared_ptr<DBusClientId> clientId = std::make_shared<DBusClientId>(std::string(dbusMessage.getSender())); dbusOutputStream << CommonAPI::Deployable<AttributeType_, AttributeDepl_>((stub.get()->*getStubFunctor_)(clientId), depl_); + dbusOutputStream.flush(); if (std::shared_ptr<DBusProxyConnection> connection = connection_.lock()) { bool isSuccessful = connection->sendDBusMessage(dbusMessageReply); diff --git a/include/CommonAPI/DBus/DBusTypeOutputStream.hpp b/include/CommonAPI/DBus/DBusTypeOutputStream.hpp index 6cab51f..b821af9 100644 --- a/include/CommonAPI/DBus/DBusTypeOutputStream.hpp +++ b/include/CommonAPI/DBus/DBusTypeOutputStream.hpp @@ -34,7 +34,14 @@ public: signature_.append("i"); return (*this); } - + TypeOutputStream &writeType(const int32_t &, const IntegerDeployment *_depl) { + if ((_depl != nullptr) && _depl->isUnixFD_) { + signature_.append("h"); + } else { + signature_.append("i"); + } + return (*this); + } TypeOutputStream &writeType(const int64_t &, const EmptyDeployment *) { signature_.append("x"); return (*this); @@ -54,7 +61,14 @@ public: signature_.append("u"); return (*this); } - + TypeOutputStream &writeType(const uint32_t &, const IntegerDeployment *_depl) { + if ((_depl != nullptr) && _depl->isUnixFD_) { + signature_.append("h"); + } else { + signature_.append("u"); + } + return (*this); + } TypeOutputStream &writeType(const uint64_t &, const EmptyDeployment *) { signature_.append("t"); return (*this); @@ -154,7 +168,7 @@ public: (void)_value; signature_.append("a"); ElementType_ dummyElement; - writeType(dummyElement, (_depl ? _depl->elementDepl_ : nullptr)); + writeType(dummyElement, (_depl ? _depl->elementDepl_ : nullptr)); return (*this); } @@ -175,7 +189,7 @@ public: (void)_value; signature_.append("a{"); KeyType_ dummyKey; - writeType(dummyKey, (_depl ? _depl->key_ : nullptr)); + writeType(dummyKey, (_depl ? _depl->key_ : nullptr)); ValueType_ dummyValue; writeType(dummyValue, (_depl ? _depl->value_ : nullptr)); signature_.append("}"); @@ -194,4 +208,3 @@ private: } // namespace CommonAPI #endif // COMMONAPI_DBUS_DBUSTYPEOUTPUTSTREAM_HPP_ - diff --git a/src/CommonAPI/DBus/DBusAddressTranslator.cpp b/src/CommonAPI/DBus/DBusAddressTranslator.cpp index 49f42d4..5a087b2 100644 --- a/src/CommonAPI/DBus/DBusAddressTranslator.cpp +++ b/src/CommonAPI/DBus/DBusAddressTranslator.cpp @@ -43,6 +43,11 @@ DBusAddressTranslator::init() { const char *config = getenv("COMMONAPI_DBUS_CONFIG"); if (config) { defaultConfig_ = config; + struct stat s; + if (stat(defaultConfig_.c_str(), &s) != 0) { + COMMONAPI_ERROR("Failed to load ini file passed via " + "COMMONAPI_DBUS_CONFIG environment: ", defaultConfig_); + } } else { defaultConfig_ = COMMONAPI_DBUS_DEFAULT_CONFIG_FOLDER; defaultConfig_ += "/"; @@ -96,8 +101,10 @@ DBusAddressTranslator::translate(const CommonAPI::Address &_key, DBusAddress &_v // check if interface needs to be compatible to newer/older version auto it = compatibility_.find(_key.getInterface()); if(it != compatibility_.end()) { - _value.setInterface(it->second); - _value.setService(it->second + "_" + _key.getInstance()); + interfaceName = it->second; + std::replace(interfaceName.begin(), interfaceName.end(), ':', '.'); + _value.setInterface(interfaceName); + _value.setService(interfaceName + "_" + _key.getInstance()); } else { _value.setInterface(interfaceName); _value.setService(service); @@ -222,6 +229,7 @@ bool DBusAddressTranslator::readConfiguration() { #define MAX_PATH_LEN 255 std::string config; + bool tryLoadConfig(true); char currentDirectory[MAX_PATH_LEN]; #ifdef _WIN32 if (GetCurrentDirectory(MAX_PATH_LEN, currentDirectory)) { @@ -235,11 +243,14 @@ DBusAddressTranslator::readConfiguration() { struct stat s; if (stat(config.c_str(), &s) != 0) { config = defaultConfig_; + if (stat(config.c_str(), &s) != 0) { + tryLoadConfig = false; + } } } IniFileReader reader; - if (!reader.load(config)) + if (tryLoadConfig && !reader.load(config)) return false; for (auto itsMapping : reader.getSections()) { @@ -428,7 +439,7 @@ bool DBusAddressTranslator::isValidVersion(const std::string& _version) const { return false; for (auto it = _version.begin()+1; it != _version.end(); ++it) { - if (!isdigit(*it) && *it != '_') + if (!isdigit(static_cast<unsigned char>(*it)) && *it != '_') return false; } return true; diff --git a/src/CommonAPI/DBus/DBusConnection.cpp b/src/CommonAPI/DBus/DBusConnection.cpp index 0ce70bc..003aea9 100644 --- a/src/CommonAPI/DBus/DBusConnection.cpp +++ b/src/CommonAPI/DBus/DBusConnection.cpp @@ -16,7 +16,6 @@ #include <CommonAPI/DBus/DBusProxy.hpp> #include <CommonAPI/DBus/DBusAddressTranslator.hpp> - namespace CommonAPI { namespace DBus { @@ -46,6 +45,93 @@ void DBusConnectionStatusEvent::onListenerAdded(const Listener &_listener, const _listener(AvailabilityStatus::AVAILABLE); } +// Helper class to ensure that CommonAPI::Runtime (static instance) is not destroyed unless last +// connection is closed. Also tries to safely join dispatch threads (~CompletionHelper will be +// executed in main thread's context on program exit), in case DBusConnection::disconnect() has +// been invoked from dispatch thread itself, thus "self-joining" would have raised an exception. +class CompletionHelper { +public: + + static std::unique_ptr<CompletionHelper> & get() { + static std::unique_ptr<CompletionHelper> theCompleter = std::unique_ptr<CompletionHelper>(new CompletionHelper()); + return theCompleter; + } + + ~CompletionHelper() { + destructing_ = true; + + std::set<std::uintptr_t>::size_type activeConnections(connections_.max_size()); + { + std::lock_guard<std::mutex> lock(mutex_); + activeConnections = connections_.size(); + } + + bool forceDetach(false); + if (0u != activeConnections) { + std::future<bool> ready = readyToCleanup_.get_future(); + if (ready.valid()) { + const std::future_status status = ready.wait_for(std::chrono::seconds(1)); + forceDetach = (std::future_status::ready != status); + } + } + + { + std::lock_guard<std::mutex> lock(mutex_); + for (std::thread * p : threads_) { + if (nullptr != p) { + if (!forceDetach && p->joinable()) { + p->join(); + } else { + p->detach(); + } + delete p; + } + } + } + }; + + void registerConnection(std::uintptr_t conn) { + std::lock_guard<std::mutex> lock(mutex_); + connections_.insert(conn); + } + + void unregisterConnection(std::uintptr_t conn) { + std::lock_guard<std::mutex> lock(mutex_); + if ((1u == connections_.erase(conn)) && (0u == connections_.size()) && destructing_) { + readyToCleanup_.set_value(true); + } + } + + void joinOnExit(std::uintptr_t conn, std::thread & t) { + std::lock_guard<std::mutex> lock(mutex_); + if (connections_.end() != connections_.find(conn)) { + bool found(false); + std::vector<std::thread*>::const_iterator it = threads_.begin(); + while (!found && it != threads_.end()) { + found = (&t == *it++); + } + if (!found) { + threads_.push_back(&t); + } + } + } + +private: + + CompletionHelper() + : destructing_(false) { + } + + CompletionHelper(CompletionHelper const &) = delete; + void operator= (CompletionHelper const &) = delete; + + std::mutex mutex_; + std::vector<std::thread *> threads_; + std::set<std::uintptr_t> connections_; + + std::promise<bool> readyToCleanup_; + std::atomic<bool> destructing_; +}; const DBusObjectPathVTable* DBusConnection::getDBusObjectPathVTable() { static const DBusObjectPathVTable libdbusObjectPathVTable = { @@ -130,57 +216,6 @@ DBusConnection::~DBusConnection() { delete watchContext_; delete timeoutContext_; } - - //Assert that the enforcerThread_ is in a position to finish itself correctly even after destruction - //of the DBusConnection. Also assert all resources are cleaned up. - auto it = timeoutMap_.begin(); - while (it != timeoutMap_.end()) { - DBusMessageReplyAsyncHandler* asyncHandler = std::get<1>(it->second); - DBusPendingCall* libdbusPendingCall = it->first; - - asyncHandler->lock(); - bool executionStarted = asyncHandler->getExecutionStarted(); - bool executionFinished = asyncHandler->getExecutionFinished(); - if (executionStarted && !executionFinished) { - asyncHandler->setHasToBeDeleted(); - it = timeoutMap_.erase(it); - asyncHandler->unlock(); - continue; - } - if (!executionStarted && !executionFinished && !dbus_pending_call_get_completed(libdbusPendingCall)) { - dbus_pending_call_cancel(libdbusPendingCall); - } - asyncHandler->unlock(); - - if (!executionStarted && !executionFinished) { - DBusMessage& dbusMessageCall = std::get<2>(it->second); - - asyncHandler->onDBusMessageReply(CallStatus::REMOTE_ERROR, dbusMessageCall.createMethodError(DBUS_ERROR_TIMEOUT)); - - dbus_pending_call_unref(libdbusPendingCall); - } - it = timeoutMap_.erase(it); - delete asyncHandler; - } - - auto itTimeoutInf = timeoutInfiniteAsyncHandlers_.begin(); - while (itTimeoutInf != timeoutInfiniteAsyncHandlers_.end()) { - DBusMessageReplyAsyncHandler* asyncHandler = (*itTimeoutInf); - - asyncHandler->lock(); - bool executionStarted = asyncHandler->getExecutionStarted(); - bool executionFinished = asyncHandler->getExecutionFinished(); - if (executionStarted && !executionFinished) { - asyncHandler->setHasToBeDeleted(); - itTimeoutInf = timeoutInfiniteAsyncHandlers_.erase(itTimeoutInf); - asyncHandler->unlock(); - continue; - } - asyncHandler->unlock(); - - itTimeoutInf = timeoutInfiniteAsyncHandlers_.erase(itTimeoutInf); - delete asyncHandler; - } } bool DBusConnection::attachMainLoopContext(std::weak_ptr<MainLoopContext> mainLoopContext) { @@ -402,8 +437,7 @@ bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { initLibdbusSignalFilterAfterConnect(); - enforcerThread_ = std::make_shared<std::thread>( - std::bind(&DBusConnection::enforceAsynchronousTimeouts, shared_from_this())); + enforcerThread_ = new std::thread(std::bind(&DBusConnection::enforceAsynchronousTimeouts, shared_from_this())); dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::AVAILABLE); @@ -415,6 +449,11 @@ bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { dispatchThread_ = new std::thread(std::bind(&DBusConnection::dispatch, shared_from_this())); } + std::unique_ptr<CompletionHelper> & helper = CompletionHelper::get(); + if (helper) { + helper->registerConnection(reinterpret_cast<std::uintptr_t>(this)); + } + return true; } @@ -452,16 +491,21 @@ void DBusConnection::disconnect() { dbus_connection_close(connection_); + std::unique_ptr<CompletionHelper> & helper = CompletionHelper::get(); + if(dispatchThread_) { loop_->stop(); //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(); + delete dispatchThread_; + } else if (helper) { + helper->joinOnExit(reinterpret_cast<std::uintptr_t>(this), *dispatchThread_); } else { dispatchThread_->detach(); + delete dispatchThread_; } - delete dispatchThread_; dispatchThread_ = NULL; } @@ -474,10 +518,17 @@ void DBusConnection::disconnect() { if (enforcerThread_->joinable() && std::this_thread::get_id() != enforcerThread_->get_id()) { enforcerThread_->join(); + delete enforcerThread_; + } else if(helper) { + helper->joinOnExit(reinterpret_cast<std::uintptr_t>(this), *enforcerThread_); } else { enforcerThread_->detach(); } + if (helper) { + helper->unregisterConnection(reinterpret_cast<std::uintptr_t>(this)); + } + // remote mainloop watchers dbus_connection_set_watch_functions(connection_, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_timeout_functions(connection_, NULL, NULL, NULL, NULL, NULL); @@ -599,7 +650,7 @@ void DBusConnection::onLibdbusPendingCall(::DBusPendingCall* _libdbusPendingCall CallStatus callStatus = CallStatus::SUCCESS; if (_reply.isErrorType() || !_reply.isMethodReturnType()) { - if(strcmp(_reply.getError(), DBUS_ERROR_UNKNOWN_METHOD) == 0) { + if (std::string(_reply.getError()) == std::string(DBUS_ERROR_UNKNOWN_METHOD)) { callStatus = CallStatus::NOT_AVAILABLE; } else { callStatus = CallStatus::REMOTE_ERROR; @@ -810,6 +861,47 @@ void DBusConnection::enforceAsynchronousTimeouts() { } } + { + std::lock_guard<std::mutex> itsLock(enforceTimeoutMutex_); + auto it = timeoutMap_.begin(); + while (it != timeoutMap_.end()) { + DBusMessageReplyAsyncHandler* asyncHandler = std::get<1>(it->second); + + asyncHandler->lock(); + bool executionStarted = asyncHandler->getExecutionStarted(); + bool executionFinished = asyncHandler->getExecutionFinished(); + if (executionStarted && !executionFinished) { + asyncHandler->setHasToBeDeleted(); + it = timeoutMap_.erase(it); + asyncHandler->unlock(); + continue; + } + asyncHandler->unlock(); + + it = timeoutMap_.erase(it); + asyncHandlersToDelete_.push_back(asyncHandler); + } + + auto itTimeoutInf = timeoutInfiniteAsyncHandlers_.begin(); + while (itTimeoutInf != timeoutInfiniteAsyncHandlers_.end()) { + DBusMessageReplyAsyncHandler* asyncHandler = (*itTimeoutInf); + + asyncHandler->lock(); + bool executionStarted = asyncHandler->getExecutionStarted(); + bool executionFinished = asyncHandler->getExecutionFinished(); + if (executionStarted && !executionFinished) { + asyncHandler->setHasToBeDeleted(); + itTimeoutInf = timeoutInfiniteAsyncHandlers_.erase(itTimeoutInf); + asyncHandler->unlock(); + continue; + } + asyncHandler->unlock(); + + itTimeoutInf = timeoutInfiniteAsyncHandlers_.erase(itTimeoutInf); + asyncHandlersToDelete_.push_back(asyncHandler); + } + } + // delete left async handlers that could not be deleted by the main loop deleteAsyncHandlers(); } @@ -1159,7 +1251,7 @@ DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandl if(signalHandlerPathToAddIt == dbusSignalHandlersToAdd_.end()) { // is first signal member handler for this 'dbusSignalHandlerPath' --> add - std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + std::map<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; handlerList[itsHandler.get()] = dbusSignalHandler; dbusSignalHandlersToAdd_.insert( { @@ -1210,7 +1302,7 @@ bool DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken &dbu //check if signal handler is already added auto signalHandlerPathIt = dbusSignalHandlers_.find(dbusSignalHandlerToken); if(signalHandlerPathIt != dbusSignalHandlers_.end() && - signalHandlerPathIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)) != + signalHandlerPathIt->second.find(dbusSignalHandler) != signalHandlerPathIt->second.end()) { // signal handler is already added @@ -1218,19 +1310,19 @@ bool DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken &dbu auto signalHandlerPathToRemoveIt = dbusSignalHandlersToRemove_.find(dbusSignalHandlerToken); if(signalHandlerPathToRemoveIt != dbusSignalHandlersToRemove_.end()) { - auto it = signalHandlerPathToRemoveIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)); + auto it = signalHandlerPathToRemoveIt->second.find(dbusSignalHandler); if(it == signalHandlerPathToRemoveIt->second.end()) { // handler is not going to be removed yet --> remove - signalHandlerPathToRemoveIt->second[const_cast<DBusSignalHandler*>(dbusSignalHandler)] = + signalHandlerPathToRemoveIt->second[dbusSignalHandler] = std::weak_ptr<DBusSignalHandler>(); } } else { // handler is not going to be removed yet. No dbus signal handler token found --> insert with handler to remove - std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; - handlerList[const_cast<DBusSignalHandler*>(dbusSignalHandler)] = + std::map<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + handlerList[dbusSignalHandler] = std::weak_ptr<DBusSignalHandler>(); dbusSignalHandlersToRemove_.insert( { @@ -1245,7 +1337,7 @@ bool DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken &dbu auto signalHandlerPathToAddIt = dbusSignalHandlersToAdd_.find(dbusSignalHandlerToken); if(signalHandlerPathToAddIt != dbusSignalHandlersToAdd_.end()) { - auto handlersToAddEntry = signalHandlerPathToAddIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)); + auto handlersToAddEntry = signalHandlerPathToAddIt->second.find(dbusSignalHandler); if(handlersToAddEntry != signalHandlerPathToAddIt->second.end()) { // handler is planned to be added --> erase @@ -1287,7 +1379,7 @@ bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbus if(signalHandlerPathToAddIt == dbusOMSignalHandlersToAdd_.end()) { // is first signal member handler --> add to list and add match rule - std::pair<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = + std::pair<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = std::make_pair(itsHandler.get(), dbusSignalHandler); dbusOMSignalHandlersToAdd_.insert( { @@ -1321,7 +1413,7 @@ bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbus } bool DBusConnection::removeObjectManagerSignalMemberHandler(const std::string& dbusBusName, - DBusSignalHandler* dbusSignalHandler) { + const DBusSignalHandler* dbusSignalHandler) { if (dbusBusName.empty()) { COMMONAPI_ERROR(std::string(__FUNCTION__), " empty dbusBusName"); return false; @@ -1346,7 +1438,7 @@ bool DBusConnection::removeObjectManagerSignalMemberHandler(const std::string& d } } else { // no dbus signal handler found for 'dbusBusName' --> insert with handler - std::pair<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = + std::pair<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = std::make_pair(dbusSignalHandler, std::weak_ptr<DBusSignalHandler>()); dbusOMSignalHandlersToRemove_.insert( { @@ -1651,23 +1743,23 @@ void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath, if (!matchRuleFound) { COMMONAPI_ERROR(std::string(__FUNCTION__), " no match rule found for path: ", objectPath, "interface: ", interfaceName, " member: ", interfaceMemberName); - } - - uint32_t& matchRuleReferenceCount = matchRuleIterator->second.first; - if (matchRuleReferenceCount > 1) { - matchRuleReferenceCount--; - return; - } + } else { + uint32_t& matchRuleReferenceCount = matchRuleIterator->second.first; + if (matchRuleReferenceCount > 1) { + matchRuleReferenceCount--; + return; + } - if (isConnected()) { - const std::string& matchRuleString = matchRuleIterator->second.second; - const bool libdbusSuccess = removeLibdbusSignalMatchRule(matchRuleString); - if (!libdbusSuccess) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " removeLibdbusSignalMatchRule failed ", matchRuleString); + if (isConnected()) { + const std::string& matchRuleString = matchRuleIterator->second.second; + const bool libdbusSuccess = removeLibdbusSignalMatchRule(matchRuleString); + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " removeLibdbusSignalMatchRule failed ", matchRuleString); + } } - } - dbusSignalMatchRulesMap_.erase(matchRuleIterator); + dbusSignalMatchRulesMap_.erase(matchRuleIterator); + } } void DBusConnection::initLibdbusObjectPathHandlerAfterConnect() { @@ -1787,7 +1879,7 @@ void DBusConnection::notifyDBusSignalHandlers(DBusSignalHandlerPath handlerPath, auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); if(signalHandlerPathIt == dbusSignalHandlers_.end()) { - std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + std::map<const DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; handlerList[handlerToAddIt->first] = handlerToAddIt->second; dbusSignalHandlers_.insert( { @@ -1803,7 +1895,7 @@ void DBusConnection::notifyDBusSignalHandlers(DBusSignalHandlerPath handlerPath, } // ensure, the registry survives - std::shared_ptr<DBusServiceRegistry> itsRegistry_ = DBusServiceRegistry::get(shared_from_this()); + std::shared_ptr<DBusServiceRegistry> itsRegistry_ = DBusServiceRegistry::get(shared_from_this(), false); // notify auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); @@ -2041,5 +2133,50 @@ uint32_t DBusConnection::getNumberOfSignalMemberHandlers(DBusSignalHandlerPath h return handlers - handlersToRemove + handlersToAdd; } +void DBusConnection::addSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _subscription) { + { + std::lock_guard<std::mutex> itsLock(signalStateHandlersMutex_); + signalStateHandlers_[_handler].insert(_subscription); + } + auto function = std::bind(&DBusProxyConnection::DBusSignalHandler::onSpecificError, + _handler, std::placeholders::_1, std::placeholders::_2); + + proxyPushFunctionToMainLoop(function, CommonAPI::CallStatus::SUCCESS, _subscription); +} + +void DBusConnection::removeSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _tag, bool _remove_all) { + { + std::lock_guard<std::mutex> itsLock(signalStateHandlersMutex_); + if (_remove_all) { + signalStateHandlers_.erase(_handler); + } else { + auto itsHandler = signalStateHandlers_.find(_handler); + if (itsHandler != signalStateHandlers_.end()) { + itsHandler->second.erase(_tag); + if (itsHandler->second.size() == 0) { + signalStateHandlers_.erase(_handler); + } + } + } + } +} + +void DBusConnection::handleSignalStates() { + std::map<std::shared_ptr<DBusProxyConnection::DBusSignalHandler>, std::set<uint32_t>> tmpHandlers; + { + std::lock_guard<std::mutex> itsLock(signalStateHandlersMutex_); + tmpHandlers = signalStateHandlers_; + } + for (auto itsHandler : tmpHandlers) { + for (uint32_t tag : itsHandler.second) { + itsHandler.first->onSpecificError(CommonAPI::CallStatus::SUCCESS, tag); + } + } +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusFunctionalHash.cpp b/src/CommonAPI/DBus/DBusFunctionalHash.cpp index c02150a..7e5dad0 100644 --- a/src/CommonAPI/DBus/DBusFunctionalHash.cpp +++ b/src/CommonAPI/DBus/DBusFunctionalHash.cpp @@ -3,8 +3,6 @@ // 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 <cstring> - #include <murmurhash/MurmurHash3.h> #include <CommonAPI/Logger.hpp> @@ -33,10 +31,10 @@ size_t hash<pair<const char*, const char*> >::operator()(const pair<const char*, uint32_t seed = static_cast<uint32_t>(SMHASHER_SEED_VALUE); if (NULL != a) { - MurmurHash3_x86_32(a, static_cast<unsigned int>(strlen(a)), seed, &seed); + MurmurHash3_x86_32(a, static_cast<unsigned int>(std::string(a).length()), seed, &seed); } if (NULL != b) { - MurmurHash3_x86_32(b, static_cast<unsigned int>(strlen(b)), seed, &seed); + MurmurHash3_x86_32(b, static_cast<unsigned int>(std::string(b).length()), seed, &seed); } return static_cast<size_t>(seed); @@ -44,7 +42,7 @@ size_t hash<pair<const char*, const char*> >::operator()(const pair<const char*, size_t hash<const char*>::operator()(const char* const t) const { uint32_t seed = static_cast<uint32_t>(SMHASHER_SEED_VALUE); - MurmurHash3_x86_32(t, static_cast<unsigned int>(strlen(t)), seed, &seed); + MurmurHash3_x86_32(t, static_cast<unsigned int>(std::string(t).length()), seed, &seed); return static_cast<size_t>(seed); } @@ -122,7 +120,7 @@ bool equal_to<pair<const char*, const char*> >::operator()(const pair<const char if (a.first == b.first && a.second == b.second) return true; - return !strcmp(a.first, b.first) && !strcmp(a.second, b.second); + return (std::string(a.first) == std::string(b.first)) && (std::string(a.second) == std::string(b.second)); } } // namespace std diff --git a/src/CommonAPI/DBus/DBusInputStream.cpp b/src/CommonAPI/DBus/DBusInputStream.cpp index c13353e..1bede6f 100644 --- a/src/CommonAPI/DBus/DBusInputStream.cpp +++ b/src/CommonAPI/DBus/DBusInputStream.cpp @@ -53,27 +53,27 @@ void DBusInputStream::setError() { } void DBusInputStream::pushPosition() { - positions_.push(current_); + positions_.push_back(current_); } size_t DBusInputStream::popPosition() { - size_t itsPosition = positions_.top(); - positions_.pop(); + size_t itsPosition = positions_.back(); + positions_.pop_back(); return itsPosition; } void DBusInputStream::pushSize(size_t _size) { - sizes_.push(static_cast<unsigned int>(_size)); + sizes_.push_back(static_cast<unsigned int>(_size)); } size_t DBusInputStream::popSize() { - size_t itsSize = sizes_.top(); - sizes_.pop(); + size_t itsSize = sizes_.back(); + sizes_.pop_back(); return itsSize; } InputStream<DBusInputStream> &DBusInputStream::readValue(bool &_value, const EmptyDeployment *_depl) { - uint32_t tmp; + uint32_t tmp(2); readValue(tmp, _depl); if (tmp > 1) setError(); diff --git a/src/CommonAPI/DBus/DBusMessage.cpp b/src/CommonAPI/DBus/DBusMessage.cpp index 9321315..4bdf760 100644 --- a/src/CommonAPI/DBus/DBusMessage.cpp +++ b/src/CommonAPI/DBus/DBusMessage.cpp @@ -3,8 +3,6 @@ // 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 <cstring> - #include <CommonAPI/Logger.hpp> #include <CommonAPI/DBus/DBusAddress.hpp> #include <CommonAPI/DBus/DBusMessage.hpp> @@ -197,7 +195,7 @@ DBusMessage::hasObjectPath(const char *_path) const { COMMONAPI_ERROR(std::string(__FUNCTION__), " path == NULL"); } - return (((NULL != path) && (NULL != _path))? !strcmp(path, _path) : false); + return (((NULL != path) && (NULL != _path))? (std::string(path) == std::string(_path)) : false); } bool DBusMessage::hasInterfaceName(const char *_interface) const { @@ -210,7 +208,7 @@ bool DBusMessage::hasInterfaceName(const char *_interface) const { COMMONAPI_ERROR(std::string(__FUNCTION__), " interface == NULL"); } - return (((NULL != interface) && (NULL != _interface))? !strcmp(interface, _interface) : false); + return (((NULL != interface) && (NULL != _interface))? (std::string(interface) == std::string(_interface)) : false); } bool DBusMessage::hasMemberName(const char *_member) const { @@ -223,7 +221,7 @@ bool DBusMessage::hasMemberName(const char *_member) const { COMMONAPI_ERROR(std::string(__FUNCTION__), " member == NULL"); } - return (((NULL != member) && (NULL != _member))? !strcmp(member, _member) : false); + return (((NULL != member) && (NULL != _member))? (std::string(member) == std::string(_member)) : false); } bool DBusMessage::hasSignature(const char *_signature) const { @@ -236,7 +234,7 @@ bool DBusMessage::hasSignature(const char *_signature) const { COMMONAPI_ERROR(std::string(__FUNCTION__), " signature == NULL"); } - return (((NULL != signature) && (NULL != _signature))? !strcmp(signature, _signature) : false); + return (((NULL != signature) && (NULL != _signature))? (std::string(signature) == std::string(_signature)) : false); } DBusMessage::Type DBusMessage::getType() const { @@ -292,5 +290,9 @@ bool DBusMessage::isSignalType() const { return (getType() == Type::Signal); } +void DBusMessage::setNoReplyExpected(const uint32_t replyNotExpected) const { + dbus_message_set_no_reply(message_, replyNotExpected); +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusOutputStream.cpp b/src/CommonAPI/DBus/DBusOutputStream.cpp index ae42e36..3f77c8f 100644 --- a/src/CommonAPI/DBus/DBusOutputStream.cpp +++ b/src/CommonAPI/DBus/DBusOutputStream.cpp @@ -25,12 +25,12 @@ size_t DBusOutputStream::getPosition() { } void DBusOutputStream::pushPosition() { - positions_.push(payload_.size()); + positions_.push_back(payload_.size()); } size_t DBusOutputStream::popPosition() { - size_t itsPosition = positions_.top(); - positions_.pop(); + size_t itsPosition = positions_.back(); + positions_.pop_back(); return itsPosition; } diff --git a/src/CommonAPI/DBus/DBusProxy.cpp b/src/CommonAPI/DBus/DBusProxy.cpp index ef6388b..eef22b4 100644 --- a/src/CommonAPI/DBus/DBusProxy.cpp +++ b/src/CommonAPI/DBus/DBusProxy.cpp @@ -15,6 +15,8 @@ namespace CommonAPI { namespace DBus { +static std::weak_ptr<Factory> factory__(Factory::get()); + DBusProxyStatusEvent::DBusProxyStatusEvent(DBusProxy *_dbusProxy) : dbusProxy_(_dbusProxy) { } @@ -184,7 +186,8 @@ DBusProxy::DBusProxy(const DBusAddress &_dbusAddress, dbusProxyStatusEvent_(this), availabilityStatus_(AvailabilityStatus::UNKNOWN), interfaceVersionAttribute_(*this, "uu", "getInterfaceVersion"), - dbusServiceRegistry_(DBusServiceRegistry::get(_connection)) + dbusServiceRegistry_(DBusServiceRegistry::get(_connection)), + everAvailable_(false) { } @@ -204,7 +207,9 @@ DBusProxy::~DBusProxy() { dbusServiceRegistry_->unsubscribeAvailabilityListener( getAddress().getAddress(), dbusServiceRegistrySubscription_); - Factory::get()->decrementConnection(connection_); + if (auto ptr = factory__.lock()) { + ptr->decrementConnection(connection_); + } } bool DBusProxy::isAvailable() const { @@ -344,7 +349,12 @@ void DBusProxy::onDBusServiceInstanceStatus(std::shared_ptr<DBusProxy> _proxy, dbusProxyStatusEvent_.notifySpecificListener(listenerIt.first, availabilityStatus_); } + bool handleSignalState(false); if (availabilityStatus == AvailabilityStatus::AVAILABLE) { + if (everAvailable_) { + handleSignalState = true; + } + everAvailable_ = true; std::lock_guard < std::mutex > queueLock(signalMemberHandlerQueueMutex_); for(auto signalMemberHandlerIterator = signalMemberHandlerQueue_.begin(); @@ -387,6 +397,9 @@ void DBusProxy::onDBusServiceInstanceStatus(std::shared_ptr<DBusProxy> _proxy, std::get<2>(selectiveBroadcasts.second)); } } + if (handleSignalState) { + connection_->proxyPushFunctionToMainLoop<DBusConnection>(std::bind(&DBusProxyConnection::handleSignalStates, connection_)); + } } else { std::lock_guard < std::mutex > queueLock(signalMemberHandlerQueueMutex_); @@ -635,6 +648,5 @@ void DBusProxy::freeDesktopGetCurrentValueForSignalListener( availabilityMutex_.unlock(); } } - } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusProxyBase.cpp b/src/CommonAPI/DBus/DBusProxyBase.cpp index d24e58b..f4add0e 100644 --- a/src/CommonAPI/DBus/DBusProxyBase.cpp +++ b/src/CommonAPI/DBus/DBusProxyBase.cpp @@ -7,6 +7,8 @@ #include <CommonAPI/DBus/DBusAddressTranslator.hpp> #include <CommonAPI/DBus/DBusProxyBase.hpp> #include <CommonAPI/DBus/DBusMessage.hpp> +#include <CommonAPI/DBus/DBusProxy.hpp> +#include <CommonAPI/DBus/DBusDaemonProxy.hpp> namespace CommonAPI { namespace DBus { @@ -74,5 +76,26 @@ bool DBusProxyBase::removeSignalMemberHandler(const DBusProxyConnection::DBusSig return connection_->removeSignalMemberHandler(_dbusSignalHandlerToken, _dbusSignalHandler); } +void DBusProxyBase::addSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _subscription) { + connection_->addSignalStateHandler(_handler, _subscription); +} + +void DBusProxyBase::removeSignalStateHandler( + std::shared_ptr<DBusProxyConnection::DBusSignalHandler> _handler, + const uint32_t _tag, bool _remove_all) { + connection_->removeSignalStateHandler(_handler, _tag, _remove_all); +} + +std::weak_ptr<DBusProxyBase> DBusProxyBase::getWeakPtr() { + if(auto p = dynamic_cast<DBusProxy*>(this)) { + return p->shared_from_this(); + } else if (auto p = dynamic_cast<DBusDaemonProxy*>(this)) { + return p->shared_from_this(); + } + return std::weak_ptr<DBusProxyBase>(); +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusServiceRegistry.cpp b/src/CommonAPI/DBus/DBusServiceRegistry.cpp index 4ef9fbc..6a6177e 100644 --- a/src/CommonAPI/DBus/DBusServiceRegistry.cpp +++ b/src/CommonAPI/DBus/DBusServiceRegistry.cpp @@ -13,6 +13,8 @@ #include <CommonAPI/DBus/DBusServiceRegistry.hpp> #include <CommonAPI/DBus/DBusTypes.hpp> #include <CommonAPI/DBus/DBusUtils.hpp> +#include <CommonAPI/DBus/DBusProxy.hpp> +#include <CommonAPI/DBus/DBusConnection.hpp> namespace CommonAPI { namespace DBus { @@ -21,17 +23,19 @@ std::mutex DBusServiceRegistry::registriesMutex_; static CommonAPI::CallInfo serviceRegistryInfo(10000); std::shared_ptr<DBusServiceRegistry> -DBusServiceRegistry::get(std::shared_ptr<DBusProxyConnection> _connection) { +DBusServiceRegistry::get(std::shared_ptr<DBusProxyConnection> _connection, bool _insert) { std::unique_lock<std::mutex> itsGuard(registriesMutex_); auto registries = getRegistryMap(); - auto registryIterator = registries->find(_connection); + auto registryIterator = registries->find(_connection.get()); if (registryIterator != registries->end()) return registryIterator->second; std::shared_ptr<DBusServiceRegistry> registry = std::make_shared<DBusServiceRegistry>(_connection); if (registry) { - registries->insert( { _connection, registry } ); + if(_insert) { + registries->insert( { _connection.get(), registry } ); + } itsGuard.unlock(); registry->init(); } @@ -42,7 +46,7 @@ void DBusServiceRegistry::remove(std::shared_ptr<DBusProxyConnection> _connection) { std::lock_guard<std::mutex> itsGuard(registriesMutex_); auto registries = getRegistryMap(); - registries->erase(_connection); + registries->erase(_connection.get()); } DBusServiceRegistry::DBusServiceRegistry(std::shared_ptr<DBusProxyConnection> dbusProxyConnection) : @@ -110,6 +114,12 @@ DBusServiceRegistry::subscribeAvailabilityListener( translator_->translate(_address, dbusAddress); dbusServicesMutex_.lock(); + + COMMONAPI_INFO(std::string(__FUNCTION__), + " service: ", dbusAddress.getService(), + " objectPath: ", dbusAddress.getObjectPath(), + " interface: ", dbusAddress.getInterface()); + if (notificationThread_ == std::this_thread::get_id()) { COMMONAPI_ERROR( "You must not build proxies in callbacks of ProxyStatusEvent.", @@ -136,7 +146,7 @@ DBusServiceRegistry::subscribeAvailabilityListener( } else if (dbusServiceListenersRecord.uniqueBusNameState != DBusRecordState::RESOLVING && dbusInterfaceNameListenersRecord.state == DBusRecordState::UNKNOWN) { if(dbusPredefinedServices_.find(dbusAddress.getService()) != dbusPredefinedServices_.end()) { - //service is predefined -> notify service listeners about availability + //service is predefined l-> notify service listeners about availability auto dbusServiceNameMapIterator = dbusServiceNameMap_.find(dbusAddress.getService()); if(dbusServiceNameMapIterator != dbusServiceNameMap_.end()) { std::unordered_set<std::string> dbusInterfaceNames; @@ -145,7 +155,20 @@ DBusServiceRegistry::subscribeAvailabilityListener( ++dbusInterfaceNameListenerRecordIterator) { dbusInterfaceNames.insert(dbusInterfaceNameListenerRecordIterator->first); } - notifyDBusServiceListeners(*dbusServiceNameMapIterator->second, dbusAddress.getObjectPath(), dbusInterfaceNames, DBusRecordState::AVAILABLE); + if(auto itsProxy = _proxy.lock()) { + // notify service listeners with main loop thread + itsProxy->getDBusConnection()->proxyPushFunctionToMainLoop<DBusConnection>( + std::bind(&DBusServiceRegistry::notifyDBusServiceListenersLocked, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4), + *dbusServiceNameMapIterator->second, + dbusAddress.getObjectPath(), + dbusInterfaceNames, + DBusRecordState::AVAILABLE); + } } } else { dbusInterfaceNameListenersRecord.state = resolveDBusInterfaceNameState(dbusAddress, dbusServiceListenersRecord); @@ -180,7 +203,7 @@ DBusServiceRegistry::subscribeAvailabilityListener( std::shared_ptr<DBusServiceListenerInfo> info = std::make_shared<DBusServiceListenerInfo>(); info->listener = std::move(serviceListener); info->proxy = _proxy; - dbusInterfaceNameListenersRecord.listenerList.insert(std::make_pair(subscriptionKey, info)); + dbusInterfaceNameListenersRecord.listenerList.insert(std::make_pair(subscriptionKey, std::move(info))); dbusInterfaceNameListenersRecord.listenersToRemove.remove(subscriptionKey); dbusServicesMutex_.unlock(); @@ -194,6 +217,12 @@ DBusServiceRegistry::unsubscribeAvailabilityListener( translator_->translate(_address, dbusAddress); dbusServicesMutex_.lock(); + + COMMONAPI_INFO(std::string(__FUNCTION__), + " service: ", dbusAddress.getService(), + " objectPath: ", dbusAddress.getObjectPath(), + " interface: ", dbusAddress.getInterface()); + auto dbusServiceListenersIterator = dbusServiceListenersMap.find(dbusAddress.getService()); const bool isDBusServiceListenersRecordFound = (dbusServiceListenersIterator != dbusServiceListenersMap.end()); @@ -255,7 +284,7 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac DBusServiceListenersRecord dbusServiceListenersRecord; dbusServiceListenersRecord.uniqueBusNameState = DBusRecordState::RESOLVING; - dbusServiceListenersRecord.futureOnResolve = dbusServiceListenersRecord.promiseOnResolve.get_future(); + dbusServiceListenersRecord.futureOnResolve = dbusServiceListenersRecord.promiseOnResolve->get_future(); std::unordered_map<std::string, DBusServiceListenersRecord>::value_type value(dbusServiceName, std::move(dbusServiceListenersRecord)); auto insertedDbusServiceListenerRecord = dbusServiceListenersMap.insert(std::move(value)); @@ -312,14 +341,13 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac if(dbusObjectPathCacheIterator != dbusObjectPathsCache.end()) { dbusObjectPathCache = &(dbusObjectPathCacheIterator->second); if (dbusObjectPathCache->state != DBusRecordState::RESOLVED) { - dbusObjectPathCache->state = DBusRecordState::RESOLVING; - dbusObjectPathCache = &(dbusObjectPathCacheIterator->second); - std::future<DBusRecordState> futureObjectPathResolved = dbusObjectPathCache->promiseOnResolve.get_future(); + std::future<DBusRecordState> futureObjectPathResolved = dbusObjectPathCache->promiseOnResolve->get_future(); + + resolveObjectPathWithObjectManager(dbusObjectPathCacheIterator->second, uniqueName, dbusObjectPath); dbusServicesMutex_.unlock(); - resolveObjectPathWithObjectManager(uniqueName, dbusObjectPath); futureObjectPathResolved.wait_for(timeout); } else { dbusServicesMutex_.unlock(); @@ -328,7 +356,6 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac else { // try to resolve object paths DBusObjectPathCache newDbusObjectPathCache; - newDbusObjectPathCache.state = DBusRecordState::RESOLVING; newDbusObjectPathCache.serviceName = dbusServiceName; dbusObjectPathsCache.insert(std::make_pair(dbusObjectPath, std::move(newDbusObjectPathCache))); @@ -337,11 +364,12 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac dbusObjectPathCache = &(dbusObjectPathCacheIterator->second); - newDbusObjectPathCache.futureOnResolve = dbusObjectPathCache->promiseOnResolve.get_future(); + dbusObjectPathCache->futureOnResolve = dbusObjectPathCache->promiseOnResolve->get_future(); + + resolveObjectPathWithObjectManager(dbusObjectPathCacheIterator->second, uniqueName, dbusObjectPath); dbusServicesMutex_.unlock(); - resolveObjectPathWithObjectManager(uniqueName, dbusObjectPath); - newDbusObjectPathCache.futureOnResolve.wait_for(timeout); + dbusObjectPathCache->futureOnResolve.wait_for(timeout); } if (NULL == dbusObjectPathCache) { @@ -554,12 +582,12 @@ void DBusServiceRegistry::onGetNameOwnerCallback(const CallStatus& status, if (status == CallStatus::SUCCESS) { onDBusServiceAvailable(dbusServiceName, dbusServiceUniqueName); if(dbusServiceListenersRecord.futureOnResolve.valid()) { - dbusServiceListenersRecord.promiseOnResolve.set_value(DBusRecordState(dbusServiceListenersRecord.uniqueBusNameState)); + dbusServiceListenersRecord.promiseOnResolve->set_value(DBusRecordState(dbusServiceListenersRecord.uniqueBusNameState)); } } else { // try to fulfill open promises if(dbusServiceListenersRecord.futureOnResolve.valid()) { - dbusServiceListenersRecord.promiseOnResolve.set_value(DBusRecordState::NOT_AVAILABLE); + dbusServiceListenersRecord.promiseOnResolve->set_value(DBusRecordState::NOT_AVAILABLE); } onDBusServiceNotAvailable(dbusServiceListenersRecord, dbusServiceName); @@ -630,66 +658,24 @@ DBusServiceRegistry::getDBusObjectPathCacheReference( dbusObjectPathCacheIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); } - if (dbusObjectPathCacheIterator->second.state == DBusRecordState::UNKNOWN - && resolveObjectPathWithObjectManager(dbusServiceUniqueName, dbusObjectPath)) { - dbusObjectPathCacheIterator->second.state = DBusRecordState::RESOLVING; + if ((dbusUniqueNameRecord.dbusObjectPathsCache.end() != dbusObjectPathCacheIterator) && + (dbusObjectPathCacheIterator->second.state == DBusRecordState::UNKNOWN)) { + resolveObjectPathWithObjectManager(dbusObjectPathCacheIterator->second, dbusServiceUniqueName, dbusObjectPath); } - return dbusObjectPathCacheIterator->second; + static DBusObjectPathCache sDummy; + return (dbusUniqueNameRecord.dbusObjectPathsCache.end() != dbusObjectPathCacheIterator)?dbusObjectPathCacheIterator->second:sDummy; } -void DBusServiceRegistry::releaseDBusObjectPathCacheReference(const std::string& dbusObjectPath, - const DBusServiceListenersRecord& dbusServiceListenersRecord) { - if (!dbusDaemonProxy_->isAvailable()) { - return; - } - - if (dbusServiceListenersRecord.uniqueBusNameState != DBusRecordState::RESOLVED) { - return; - } - - if (dbusServiceListenersRecord.uniqueBusName.empty()) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " unique bus name is empty"); - } - - auto& dbusUniqueNameRecord = dbusUniqueNamesMap_[dbusServiceListenersRecord.uniqueBusName]; - if (dbusServiceListenersRecord.uniqueBusName.empty()) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " empty ownedBusNames"); - } - if (dbusUniqueNameRecord.dbusObjectPathsCache.empty()) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " empty dbusObjectPathsCache"); - } - - auto dbusObjectPathCacheIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); - const bool isDBusObjectPathCacheFound = (dbusObjectPathCacheIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); - if (!isDBusObjectPathCacheFound) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " no object path cache entry found for ", dbusObjectPath); - } +bool DBusServiceRegistry::resolveObjectPathWithObjectManager(DBusObjectPathCache& dbusObjectPathRecord, + const std::string& dbusServiceUniqueName, + const std::string& dbusObjectPath) { - auto& dbusObjectPathCache = dbusObjectPathCacheIterator->second; - if (0 == dbusObjectPathCache.referenceCount) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " reference count is 0"); - } + // resolving of 'dbusObjectPath' with object mnager starts + // set object path cache state and increment 'pendingObjectManagerCalls' + dbusObjectPathRecord.state = DBusRecordState::RESOLVING; + dbusObjectPathRecord.pendingObjectManagerCalls++; - dbusObjectPathCache.referenceCount--; - - if (dbusObjectPathCache.referenceCount == 0) { - dbusUniqueNameRecord.dbusObjectPathsCache.erase(dbusObjectPathCacheIterator); - - const bool isLastDBusObjectPathCache = dbusUniqueNameRecord.dbusObjectPathsCache.empty(); - if (isLastDBusObjectPathCache) { - auto dbusProxyConnection = dbusDaemonProxy_->getDBusConnection(); - const bool isSubscriptionCancelled = dbusProxyConnection->removeObjectManagerSignalMemberHandler( - dbusServiceListenersRecord.uniqueBusName, - this); - if (!isSubscriptionCancelled) { - COMMONAPI_ERROR(std::string(__FUNCTION__), ": still subscribed too ", dbusServiceListenersRecord.uniqueBusName); - } - } - } -} - -bool DBusServiceRegistry::resolveObjectPathWithObjectManager(const std::string& dbusServiceUniqueName, const std::string& dbusObjectPath) { // get managed objects from root object manager auto getManagedObjectsCallback = std::bind( &DBusServiceRegistry::onGetManagedObjectsCallbackResolve, @@ -778,6 +764,28 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolve(const CallStatus& c const std::string& dbusObjectPath) { dbusServicesMutex_.lock(); + + // find object path record for 'dbusServiceUniqueName' and 'dbusObjectPath' + auto dbusServiceUniqueNameIterator = dbusUniqueNamesMap_.find(dbusServiceUniqueName); + const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); + + if (!isDBusServiceUniqueNameFound) { + dbusServicesMutex_.unlock(); + return; + } + + DBusUniqueNameRecord& dbusUniqueNameRecord = dbusServiceUniqueNameIterator->second; + auto dbusObjectPathIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); + const bool isDBusObjectPathFound = (dbusObjectPathIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); + + if (!isDBusObjectPathFound) { + dbusServicesMutex_.unlock(); + return; + } + + DBusObjectPathCache& dbusObjectPathRecord = dbusObjectPathIterator->second; + dbusObjectPathRecord.pendingObjectManagerCalls--; + if(callStatus == CallStatus::SUCCESS) { //has object manager for(auto objectPathDict : availableServiceInstances) @@ -790,13 +798,17 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolve(const CallStatus& c CommonAPI::DBus::DBusObjectManagerStub::DBusInterfacesAndPropertiesDict interfacesAndPropertiesDict = objectPathDict.second; for(auto interfaceDict : interfacesAndPropertiesDict) { + // add interface to cache and notify listeners std::string interfaceName = interfaceDict.first; - processManagedObject(dbusObjectPath, dbusServiceUniqueName, interfaceName); + if(!isOrgFreedesktopDBusInterface(interfaceName)) { + dbusObjectPathRecord.dbusInterfaceNamesCache.insert(interfaceName); + } else if (translator_->isOrgFreedesktopDBusPeerMapped() && (interfaceName == "org.freedesktop.DBus.Peer")) { + dbusObjectPathRecord.dbusInterfaceNamesCache.insert(interfaceName); + } } } // resolve further interfaces with the help of the manager - bool managerFound = false; std::string objectPathManager = dbusObjectPath.substr(0, dbusObjectPath.find_last_of("\\/")); for(auto objectPathDict : availableServiceInstances) { @@ -815,7 +827,7 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolve(const CallStatus& c if (delimiter != '\\' && delimiter != '/') continue; - managerFound = true; + dbusObjectPathRecord.pendingObjectManagerCalls++; auto getManagedObjectsCallback = std::bind( &DBusServiceRegistry::onGetManagedObjectsCallbackResolve, @@ -827,71 +839,28 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolve(const CallStatus& c getManagedObjectsAsync(dbusServiceUniqueName, objectPathManager, getManagedObjectsCallback); } } - - if(!managerFound) { - //mark object path as resolved - - auto dbusServiceUniqueNameIterator = dbusUniqueNamesMap_.find(dbusServiceUniqueName); - const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); - - if (!isDBusServiceUniqueNameFound) { - dbusServicesMutex_.unlock(); - return; - } - - DBusUniqueNameRecord& dbusUniqueNameRecord = dbusServiceUniqueNameIterator->second; - auto dbusObjectPathIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); - const bool isDBusObjectPathFound = (dbusObjectPathIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); - - if (!isDBusObjectPathFound) { - dbusServicesMutex_.unlock(); - return; - } - - DBusObjectPathCache& dbusObjectPathRecord = dbusObjectPathIterator->second; - - dbusObjectPathRecord.state = DBusRecordState::RESOLVED; - if(dbusObjectPathRecord.futureOnResolve.valid()) - dbusObjectPathRecord.promiseOnResolve.set_value(dbusObjectPathRecord.state); - - dbusUniqueNameRecord.objectPathsState = DBusRecordState::RESOLVED; - } } else { - COMMONAPI_ERROR("There is no Object Manager that manages " + dbusObjectPath + ". Resolving failed!"); + COMMONAPI_INFO("The DBus service " + dbusServiceUniqueName + " has no Object Manager that manages " + dbusObjectPath); } - dbusServicesMutex_.unlock(); -} -void DBusServiceRegistry::processManagedObject(const std::string& dbusObjectPath, - const std::string& dbusServiceUniqueName, - const std::string& interfaceName) { + if(dbusObjectPathRecord.pendingObjectManagerCalls == 0) { + // there is no pending object manager call so notify dbus service listeners + // and mark object path as resolved - auto dbusServiceUniqueNameIterator = dbusUniqueNamesMap_.find(dbusServiceUniqueName); - const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); + dbusObjectPathRecord.state = DBusRecordState::RESOLVED; + if(dbusObjectPathRecord.futureOnResolve.valid()) + dbusObjectPathRecord.promiseOnResolve->set_value(dbusObjectPathRecord.state); - if (!isDBusServiceUniqueNameFound) - return; + dbusUniqueNameRecord.objectPathsState = DBusRecordState::RESOLVED; - DBusUniqueNameRecord& dbusUniqueNameRecord = dbusServiceUniqueNameIterator->second; - auto dbusObjectPathIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); - const bool isDBusObjectPathFound = (dbusObjectPathIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); - - if (!isDBusObjectPathFound) - return; - - DBusObjectPathCache& dbusObjectPathRecord = dbusObjectPathIterator->second; - - if(!isOrgFreedesktopDBusInterface(interfaceName)) { - dbusObjectPathRecord.dbusInterfaceNamesCache.insert(interfaceName); - } else if (translator_->isOrgFreedesktopDBusPeerMapped() && (interfaceName == "org.freedesktop.DBus.Peer")) { - dbusObjectPathRecord.dbusInterfaceNamesCache.insert(interfaceName); + notifyDBusServiceListeners( + dbusUniqueNameRecord, + dbusObjectPath, + dbusObjectPathRecord.dbusInterfaceNamesCache, + DBusRecordState::RESOLVED); } - notifyDBusServiceListeners( - dbusUniqueNameRecord, - dbusObjectPath, - dbusObjectPathRecord.dbusInterfaceNamesCache, - DBusRecordState::RESOLVED); + dbusServicesMutex_.unlock(); } void DBusServiceRegistry::checkDBusServiceWasAvailable(const std::string& dbusServiceName, @@ -949,13 +918,15 @@ void DBusServiceRegistry::onDBusServiceAvailable(const std::string& dbusServiceN if (!isDBusServiceNameObserved) { return; } + + std::unordered_map<std::string, std::unordered_set<std::string>> dbusObjectPathListenersToNotify; for (auto dbusObjectPathListenersIterator = dbusServiceListenersRecord.dbusObjectPathListenersMap.begin(); dbusObjectPathListenersIterator != dbusServiceListenersRecord.dbusObjectPathListenersMap.end();) { const std::string& listenersDBusObjectPath = dbusObjectPathListenersIterator->first; auto& dbusInterfaceNameListenersMap = dbusObjectPathListenersIterator->second; if(dbusPredefinedServices_.find(dbusServiceName) == dbusPredefinedServices_.end()) { - //service not predefined -> resolve object path and notify service listeners + //service not predefined -> resolve object path and notify listeners auto& dbusObjectPathRecord = getDBusObjectPathCacheReference( listenersDBusObjectPath, dbusServiceName, @@ -965,23 +936,34 @@ void DBusServiceRegistry::onDBusServiceAvailable(const std::string& dbusServiceN if (dbusObjectPathRecord.state == DBusRecordState::RESOLVED) { notifyDBusObjectPathResolved(dbusInterfaceNameListenersMap, dbusObjectPathRecord.dbusInterfaceNamesCache); } + + if (dbusInterfaceNameListenersMap.empty()) { + dbusObjectPathListenersIterator = dbusServiceListenersRecord.dbusObjectPathListenersMap.erase(dbusObjectPathListenersIterator); + } } else { - //service is predefined -> notify service listeners about availability + //service is predefined -> collect interface names for object path to notify dbus service listeners std::unordered_set<std::string> dbusInterfaceNames; for(auto dbusInterfaceNameListenerRecordIterator = dbusInterfaceNameListenersMap.begin(); dbusInterfaceNameListenerRecordIterator != dbusInterfaceNameListenersMap.end(); ++dbusInterfaceNameListenerRecordIterator) { dbusInterfaceNames.insert(dbusInterfaceNameListenerRecordIterator->first); } - notifyDBusServiceListeners(*dbusUniqueNameRecord, listenersDBusObjectPath, dbusInterfaceNames, DBusRecordState::AVAILABLE); + dbusObjectPathListenersToNotify[listenersDBusObjectPath] = std::move(dbusInterfaceNames); } - - if (dbusInterfaceNameListenersMap.empty()) { - dbusObjectPathListenersIterator = dbusServiceListenersRecord.dbusObjectPathListenersMap.erase( - dbusObjectPathListenersIterator); - } else { dbusObjectPathListenersIterator++; } + + if(dbusPredefinedServices_.find(dbusServiceName) != dbusPredefinedServices_.end()) { + //service is predefined -> notify service listeners about availability + for(auto dbusObjectPathListenersToNotifyIterator = dbusObjectPathListenersToNotify.begin(); + dbusObjectPathListenersToNotifyIterator != dbusObjectPathListenersToNotify.end(); + dbusObjectPathListenersToNotifyIterator++) { + notifyDBusServiceListeners( + *dbusUniqueNameRecord, + dbusObjectPathListenersToNotifyIterator->first, + dbusObjectPathListenersToNotifyIterator->second, + DBusRecordState::AVAILABLE); + } } } @@ -1023,6 +1005,15 @@ void DBusServiceRegistry::onDBusServiceNotAvailable(DBusServiceListenersRecord& } } +void DBusServiceRegistry::notifyDBusServiceListenersLocked(const DBusUniqueNameRecord _dbusUniqueNameRecord, + const std::string _dbusObjectPath, + const std::unordered_set<std::string> _dbusInterfaceNames, + const DBusRecordState _dbusInterfaceNamesState) { + dbusServicesMutex_.lock(); + notifyDBusServiceListeners(_dbusUniqueNameRecord, _dbusObjectPath, _dbusInterfaceNames, _dbusInterfaceNamesState); + dbusServicesMutex_.unlock(); +} + void DBusServiceRegistry::notifyDBusServiceListeners(const DBusUniqueNameRecord& dbusUniqueNameRecord, const std::string& dbusObjectPath, const std::unordered_set<std::string>& dbusInterfaceNames, @@ -1104,8 +1095,9 @@ void DBusServiceRegistry::notifyDBusObjectPathChanged(DBusInterfaceNameListeners auto& dbusInterfaceNameListenersRecord = dbusInterfaceNameListenersIterator->second; notifyDBusInterfaceNameListeners(dbusInterfaceNameListenersRecord, isDBusInterfaceNameAvailable); - if (dbusInterfaceNameListenersRecord.listenerList.empty()) + if (dbusInterfaceNameListenersRecord.listenerList.empty()) { dbusInterfaceNameListenersMap.erase(dbusInterfaceNameListenersIterator); + } } } } diff --git a/src/test/test-commonapi-dbus.ini b/src/test/test-commonapi-dbus.ini deleted file mode 100644 index 34683ef..0000000 --- a/src/test/test-commonapi-dbus.ini +++ /dev/null @@ -1,71 +0,0 @@ -[not#a$valid/address] -[] - 98t3hpgjvqpvnü0 t4b+qßk4 kv+üg4krgv+ß4krgv+ßkr -[too.short:address] -[incomplete:address:] -[:address:incomplete] -[]đwqervqerverver -[too:long:address:here] -jfgv2nqp3 riqpnvi39r[] -[local:no.nothing.service:no.nothing.instance] - -[local:service:instance] -service=service.name_connection.name -path=/path/to/object -interface=service.name - -[local:no.interface.service:no.interface.instance] -service=no.interface.connection -path=/no/interface/path - -[local:no.connection.service:no.connection.instance] -path=/no/connection/path -interface=no.connection.interface - -[local:no.object.service:no.object.instance] -service=no.object.connection -interface=no.object.interface - -[local:only.interface.service:only.interface.instance] -interface=only.interface.interface - -[local:only.connection.service:only.connection.instance] -service=only.connection.connection - -[local:only.object.service:only.object.instance] -path=/only/object/path - -[local:fake.legacy.service.LegacyInterface:fake.legacy.service] -service=fake.legacy.service.connection -path=/some/legacy/path/6259504 -interface=fake.legacy.service.LegacyInterface - -[local:fake.legacy.service.LegacyInterfaceNoObjectManager:fake.legacy.service] -service=fake.legacy.service.connection -path=/some/legacy/path/6259504 -interface=fake.legacy.service.LegacyInterfaceNoObjectManager - -[local:commonapi.tests.managed.RootInterface:commonapi.tests.managed.RootInterfaceOne] -service=commonapi.tests.managed.roots.on.same.object.path.RootInterfaceOne -path=/commonapi/tests/managed/RootInterface -interface=commonapi.tests.managed.RootInterface - -[local:commonapi.tests.managed.RootInterface:commonapi.tests.managed.RootInterfaceTwo] -service=commonapi.tests.managed.roots.on.same.object.path.RootInterfaceTwo -path=/commonapi/tests/managed/RootInterface -interface=commonapi.tests.managed.RootInterface - -[local:commonapi.tests.managed.RootInterface:commonapi.tests.managed.RootInterfaceThree] -service=commonapi.tests.managed.roots.on.same.object.path.RootInterfaceThree -path=/commonapi/tests/managed/RootInterface -interface=commonapi.tests.managed.RootInterface - -[local:commonapi.tests.managed.LeafInterface:commonapi.tests.managed.config.affects.LeafInterface.Unmanaged] -service=commonapi.tests.managed.config.affects.interface.unmanaged -path=/commonapi/tests/managed/RootInterface/LeafInterface/Unmanaged -interface=commonapi.tests.managed.LeafInterface - -[local:commonapi.tests.managed.LeafInterface:commonapi.tests.managed.config.affects.LeafInterface.Managed] -service=commonapi.tests.managed.config.affects.interface.managed -path=/commonapi/tests/managed/RootInterface/LeafInterface/Managed -interface=commonapi.tests.managed.LeafInterface |