diff options
author | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-10-11 03:30:13 -0700 |
---|---|---|
committer | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-10-11 03:30:13 -0700 |
commit | bdf7ab8cf3243619f0b8bc526f07e5b03624b94c (patch) | |
tree | 6ed18368c5fc5c70f3ad27525ab2515ee0817f37 /src/CommonAPI/DBus | |
parent | 3348a422ffc756b63de5890356383858a898e8b1 (diff) | |
download | genivi-common-api-dbus-runtime-bdf7ab8cf3243619f0b8bc526f07e5b03624b94c.tar.gz |
CommonAPI-D-Bus 3.1.83.1.8
Diffstat (limited to 'src/CommonAPI/DBus')
-rw-r--r-- | src/CommonAPI/DBus/DBusConnection.cpp | 618 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusDaemonProxy.cpp | 63 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusError.cpp | 1 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusFactory.cpp | 121 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusFreedesktopPropertiesStub.cpp | 35 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusFunctionalHash.cpp | 21 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusInputStream.cpp | 16 | ||||
-rwxr-xr-x | src/CommonAPI/DBus/DBusMainLoop.cpp | 179 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusMainLoopContext.cpp | 321 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusMessage.cpp | 73 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusObjectManager.cpp | 143 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusObjectManagerStub.cpp | 151 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusOutputStream.cpp | 36 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusProxy.cpp | 306 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusProxyManager.cpp | 5 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusServiceRegistry.cpp | 222 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusStubAdapter.cpp | 3 |
17 files changed, 1746 insertions, 568 deletions
diff --git a/src/CommonAPI/DBus/DBusConnection.cpp b/src/CommonAPI/DBus/DBusConnection.cpp index 47751cc..6071830 100644 --- a/src/CommonAPI/DBus/DBusConnection.cpp +++ b/src/CommonAPI/DBus/DBusConnection.cpp @@ -4,7 +4,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include <algorithm> -#include <cassert> #include <chrono> #include <future> #include <sstream> @@ -44,11 +43,6 @@ const DBusObjectPathVTable* DBusConnection::getDBusObjectPathVTable() { return &libdbusObjectPathVTable; } -//std::bind used to start the dispatch thread holds one reference, and the selfReference -//created within the thread is the second. If only those two remain, no one but the -//dispatch thread references the connection, which therefore can be finished. -const int32_t ownUseCount = 2; - void DBusConnection::dispatch() { loop_->run(); } @@ -56,10 +50,8 @@ void DBusConnection::dispatch() { DBusConnection::DBusConnection(DBusType_t busType, const ConnectionId_t& _connectionId) : dispatchThread_(NULL), - stopDispatching_(false), dispatchSource_(), watchContext_(NULL), - pauseDispatching_(false), connection_(NULL), busType_(busType), dbusConnectionStatusEvent_(this), @@ -68,7 +60,11 @@ DBusConnection::DBusConnection(DBusType_t busType, connectionNameCount_(), enforcerThread_(NULL), enforcerThreadCancelled_(false), - connectionId_(_connectionId) { + connectionId_(_connectionId), + activeConnections_(0), + isDisconnecting_(false), + isDispatching_(false), + isWaitingOnFinishedDispatching_(false) { dbus_threads_init_default(); } @@ -76,10 +72,8 @@ DBusConnection::DBusConnection(DBusType_t busType, DBusConnection::DBusConnection(::DBusConnection *_connection, const ConnectionId_t& _connectionId) : dispatchThread_(NULL), - stopDispatching_(false), dispatchSource_(), watchContext_(NULL), - pauseDispatching_(false), connection_(_connection), busType_(DBusType_t::WRAPPED), dbusConnectionStatusEvent_(this), @@ -88,7 +82,11 @@ DBusConnection::DBusConnection(::DBusConnection *_connection, connectionNameCount_(), enforcerThread_(NULL), enforcerThreadCancelled_(false), - connectionId_(_connectionId) { + connectionId_(_connectionId), + activeConnections_(0), + isDisconnecting_(false), + isDispatching_(false), + isWaitingOnFinishedDispatching_(false){ dbus_threads_init_default(); } @@ -108,14 +106,17 @@ DBusConnection::~DBusConnection() { dbus_connection_set_timeout_functions(connection_, NULL, NULL, NULL, NULL, NULL); } + lockedContext->deregisterWatch(msgWatch_); + lockedContext->deregisterDispatchSource(msgDispatchSource_); lockedContext->deregisterDispatchSource(dispatchSource_); delete watchContext_; - delete dispatchSource_; } // ensure, the registry survives until disconnecting is done... //std::shared_ptr<DBusServiceRegistry> itsRegistry = DBusServiceRegistry::get(shared_from_this()); - disconnect(); + + // Disconnecting not possible because of circular dependency, the destructor will be called AFTER disconnect anyway. + //disconnect(); //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. @@ -174,8 +175,14 @@ bool DBusConnection::attachMainLoopContext(std::weak_ptr<MainLoopContext> mainLo mainLoopContext_ = mainLoopContext; if (auto lockedContext = mainLoopContext_.lock()) { + msgWatch_ = new DBusMessageWatch(shared_from_this()); + msgDispatchSource_ = new DBusMessageDispatchSource(msgWatch_); + + lockedContext->registerDispatchSource(msgDispatchSource_); + lockedContext->registerWatch(msgWatch_); + dispatchSource_ = new DBusDispatchSource(this); - watchContext_ = new WatchContext(mainLoopContext_, dispatchSource_); + watchContext_ = new WatchContext(mainLoopContext_, dispatchSource_, shared_from_this()); lockedContext->registerDispatchSource(dispatchSource_); dbus_connection_set_wakeup_main_function( @@ -216,31 +223,39 @@ bool DBusConnection::attachMainLoopContext(std::weak_ptr<MainLoopContext> mainLo void DBusConnection::onWakeupMainContext(void* data) { std::weak_ptr<MainLoopContext>* mainloop = static_cast<std::weak_ptr<MainLoopContext>*>(data); - assert(mainloop); - if(auto lockedContext = mainloop->lock()) { + if (!mainloop) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "mainloop == nullptr"); + } else 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 (NULL == watchContext) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "watchContext == NULL"); + return FALSE; + } else { + DBusWatch* dbusWatch = new DBusWatch(libdbusWatch, watchContext->mainLoopContext_, watchContext->dbusConnection_); + dbusWatch->addDependentDispatchSource(watchContext->dispatchSource_); + dbus_watch_set_data(libdbusWatch, dbusWatch, NULL); - if (dbusWatch->isReadyToBeWatched()) { - dbusWatch->startWatching(); + if (dbusWatch->isReadyToBeWatched()) { + dbusWatch->startWatching(); + } else { + delete dbusWatch; + dbus_watch_set_data(libdbusWatch, NULL, NULL); + } } return TRUE; } void DBusConnection::onRemoveWatch(::DBusWatch* libdbusWatch, void* data) { - assert(static_cast<WatchContext*>(data)); - (void)data; + if (NULL == static_cast<WatchContext*>(data)) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "data (WatchContext) == NULL"); + } DBusWatch* dbusWatch = static_cast<DBusWatch*>(dbus_watch_get_data(libdbusWatch)); if (dbusWatch != NULL) { @@ -254,12 +269,16 @@ void DBusConnection::onRemoveWatch(::DBusWatch* libdbusWatch, void* data) { void DBusConnection::onToggleWatch(::DBusWatch* libdbusWatch, void* data) { WatchContext* watchContext = static_cast<WatchContext*>(data); - assert(watchContext); + + if (NULL == watchContext) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "watchContext == NULL"); + return; + } DBusWatch* dbusWatch = static_cast<DBusWatch*>(dbus_watch_get_data(libdbusWatch)); if (dbusWatch == NULL) { - DBusWatch* dbusWatch = new DBusWatch(libdbusWatch, watchContext->mainLoopContext_); + DBusWatch* dbusWatch = new DBusWatch(libdbusWatch, watchContext->mainLoopContext_, watchContext->dbusConnection_); dbusWatch->addDependentDispatchSource(watchContext->dispatchSource_); dbus_watch_set_data(libdbusWatch, dbusWatch, NULL); @@ -270,6 +289,8 @@ void DBusConnection::onToggleWatch(::DBusWatch* libdbusWatch, void* data) { if (!dbusWatch->isReadyToBeWatched()) { dbusWatch->stopWatching(); dbus_watch_set_data(libdbusWatch, NULL, NULL); + } else { + dbusWatch->startWatching(); } } } @@ -277,21 +298,28 @@ void DBusConnection::onToggleWatch(::DBusWatch* libdbusWatch, void* data) { dbus_bool_t DBusConnection::onAddTimeout(::DBusTimeout* libdbusTimeout, void* data) { std::weak_ptr<MainLoopContext>* mainloop = static_cast<std::weak_ptr<MainLoopContext>*>(data); - assert(mainloop); + if (NULL == mainloop) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "mainloop == NULL"); + return FALSE; + } DBusTimeout* dbusTimeout = new DBusTimeout(libdbusTimeout, *mainloop); dbus_timeout_set_data(libdbusTimeout, dbusTimeout, NULL); if (dbusTimeout->isReadyToBeMonitored()) { dbusTimeout->startMonitoring(); + } else { + delete dbusTimeout; + dbus_timeout_set_data(libdbusTimeout, NULL, NULL); } return TRUE; } void DBusConnection::onRemoveTimeout(::DBusTimeout* libdbusTimeout, void* data) { - assert(static_cast<std::weak_ptr<MainLoopContext>*>(data)); - (void)data; + if (NULL == static_cast<std::weak_ptr<MainLoopContext>*>(data)) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "MainLoopContext == NULL"); + } DBusTimeout* dbusTimeout = static_cast<DBusTimeout*>(dbus_timeout_get_data(libdbusTimeout)); if (dbusTimeout) { @@ -302,8 +330,9 @@ void DBusConnection::onRemoveTimeout(::DBusTimeout* libdbusTimeout, void* data) } void DBusConnection::onToggleTimeout(::DBusTimeout* dbustimeout, void* data) { - assert(static_cast<std::weak_ptr<MainLoopContext>*>(data)); - (void)data; + if (NULL == static_cast<std::weak_ptr<MainLoopContext>*>(data)) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "MainLoopContext == NULL"); + } DBusTimeout* timeout = static_cast<DBusTimeout*>(dbus_timeout_get_data(dbustimeout)); if (timeout->isReadyToBeMonitored()) { @@ -319,7 +348,11 @@ bool DBusConnection::connect(bool startDispatchThread) { } bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { - assert(!dbusError); + if (dbusError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "dbusError set"); + return false; + } + if (isConnected()) { return true; } @@ -340,7 +373,11 @@ bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { return false; } - assert(connection_); + if (NULL == connection_) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "connection_ == NULL"); + return false; + } + dbus_connection_set_exit_on_disconnect(connection_, false); initLibdbusObjectPathHandlerAfterConnect(); @@ -352,7 +389,7 @@ bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::AVAILABLE); - stopDispatching_ = !startDispatchThread; + isDisconnecting_ = false; if (startDispatchThread) { std::shared_ptr<MainLoopContext> itsContext = std::make_shared<MainLoopContext>(); loop_ = std::make_shared<DBusMainLoop>(itsContext); @@ -365,6 +402,10 @@ bool DBusConnection::connect(DBusError &dbusError, bool startDispatchThread) { void DBusConnection::disconnect() { std::lock_guard<std::mutex> dbusConnectionLock(connectionGuard_); + + std::unique_lock<std::mutex> dispatchLock(dispatchMutex_); + isDisconnecting_ = true; + if (isConnected()) { dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::NOT_AVAILABLE); @@ -375,7 +416,16 @@ void DBusConnection::disconnect() { connectionNameCount_.clear(); - stopDispatching_ = true; + //wait until dispatching is finished + auto it = dispatchThreads_.find(std::this_thread::get_id()); + if(it == dispatchThreads_.end()) { //wait only if disconnect is NOT triggered by main loop + while(isDispatching_) { + isWaitingOnFinishedDispatching_ = true; + dispatchCondition_.wait(dispatchLock); + isWaitingOnFinishedDispatching_ = false; + } + } + dispatchLock.unlock(); dbus_connection_close(connection_); @@ -394,7 +444,8 @@ void DBusConnection::disconnect() { enforcerThreadCancelled_ = true; enforceTimeoutCondition_.notify_one(); - if (enforcerThread_->joinable()) { + if (enforcerThread_->joinable() && + std::this_thread::get_id() != enforcerThread_->get_id()) { enforcerThread_->join(); } enforcerThreadCancelled_ = false; @@ -406,6 +457,10 @@ void DBusConnection::disconnect() { dbus_connection_unref(connection_); connection_ = nullptr; } + + if (std::shared_ptr<CommonAPI::MainLoopContext> mainLoopContext = mainLoopContext_.lock()) { + Factory::get()->releaseConnection(connectionId_, mainLoopContext.get()); + } } bool DBusConnection::isConnected() const { @@ -488,60 +543,87 @@ bool DBusConnection::releaseServiceName(const std::string& serviceName) const { } bool DBusConnection::sendDBusMessage(const DBusMessage &_message) const { - assert(_message); - assert(isConnected()); + if (!_message) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "message == NULL"); + return false; + } + if (!isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "not connected"); + return false; + } dbus_uint32_t dbusSerial; - bool result = 0 != dbus_connection_send(connection_, _message.message_, &dbusSerial); + const bool result = (0 != dbus_connection_send(connection_, _message.message_, &dbusSerial)); return result; } -DBusMessage DBusConnection::convertToDBusMessage(::DBusPendingCall* _libdbusPendingCall, - CallStatus& _callStatus) { - assert(_libdbusPendingCall); +DBusMessage DBusConnection::convertToDBusMessage(::DBusPendingCall* _libdbusPendingCall) { + if (NULL == _libdbusPendingCall) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "_libdbusPendingCall == NULL"); + return DBusMessage(); + } ::DBusMessage* libdbusMessage = dbus_pending_call_steal_reply(_libdbusPendingCall); const bool increaseLibdbusMessageReferenceCount = false; DBusMessage dbusMessage(libdbusMessage, increaseLibdbusMessageReferenceCount); - _callStatus = CallStatus::SUCCESS; - - if (!dbusMessage.isMethodReturnType()) { - _callStatus = CallStatus::REMOTE_ERROR; - } return dbusMessage; } -void DBusConnection::onLibdbusPendingCallNotifyThunk(::DBusPendingCall* _libdbusPendingCall, void *_userData) { - assert(_userData); - assert(_libdbusPendingCall); +void DBusConnection::onLibdbusPendingCall(::DBusPendingCall* _libdbusPendingCall, + const DBusMessage& _reply, + DBusMessageReplyAsyncHandler* _dbusMessageReplyAsyncHandler) const { - auto dbusMessageReplyAsyncHandler = reinterpret_cast<DBusMessageReplyAsyncHandler*>(_userData); + CallStatus callStatus = CallStatus::SUCCESS; + if (_reply.isErrorType() || !_reply.isMethodReturnType()) { + if(strcmp(_reply.getError(), DBUS_ERROR_UNKNOWN_METHOD) == 0) { + callStatus = CallStatus::NOT_AVAILABLE; + } else { + callStatus = CallStatus::REMOTE_ERROR; + } + } - dbusMessageReplyAsyncHandler->lock(); - bool processAsyncHandler = !dbusMessageReplyAsyncHandler->getTimeoutOccurred(); - dbusMessageReplyAsyncHandler->setExecutionStarted(); - dbusMessageReplyAsyncHandler->unlock(); + _dbusMessageReplyAsyncHandler->lock(); + bool processAsyncHandler = !_dbusMessageReplyAsyncHandler->getTimeoutOccurred(); + _dbusMessageReplyAsyncHandler->setExecutionStarted(); + _dbusMessageReplyAsyncHandler->unlock(); - if (processAsyncHandler) { - DBusMessage dbusMessage; - CallStatus callStatus; - dbusMessage = DBusConnection::convertToDBusMessage(_libdbusPendingCall, callStatus); + if (processAsyncHandler) + _dbusMessageReplyAsyncHandler->onDBusMessageReply(callStatus, _reply); - dbusMessageReplyAsyncHandler->onDBusMessageReply(callStatus, dbusMessage); - } + _dbusMessageReplyAsyncHandler->lock(); - dbusMessageReplyAsyncHandler->lock(); // libdbus calls the cleanup method below - dbus_pending_call_unref(_libdbusPendingCall); + if(_libdbusPendingCall) + dbus_pending_call_unref(_libdbusPendingCall); - dbusMessageReplyAsyncHandler->setExecutionFinished(); - if (dbusMessageReplyAsyncHandler->hasToBeDeleted()) { - dbusMessageReplyAsyncHandler->unlock(); - delete dbusMessageReplyAsyncHandler; + _dbusMessageReplyAsyncHandler->setExecutionFinished(); + if (_dbusMessageReplyAsyncHandler->hasToBeDeleted()) { + _dbusMessageReplyAsyncHandler->unlock(); + delete _dbusMessageReplyAsyncHandler; + } else { + _dbusMessageReplyAsyncHandler->unlock(); + } +} + +void DBusConnection::onLibdbusPendingCallNotifyThunk(::DBusPendingCall* _libdbusPendingCall, void *_userData) { + if (NULL == _libdbusPendingCall) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "_libdbusPendingCall == NULL"); return; } - dbusMessageReplyAsyncHandler->unlock(); + if (NULL == _userData) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "_userData == NULL"); + return; + } + + auto pendingCallNotificationData = reinterpret_cast<PendingCallNotificationData*>(_userData); + auto dbusMessageReplyAsyncHandler = pendingCallNotificationData->replyAsyncHandler_; + auto dbusConnection = pendingCallNotificationData->dbusConnection_; + delete pendingCallNotificationData; + + DBusMessage dbusMessage = DBusConnection::convertToDBusMessage(_libdbusPendingCall); + + dbusConnection->onLibdbusPendingCall(_libdbusPendingCall, dbusMessage, dbusMessageReplyAsyncHandler); } void DBusConnection::onLibdbusDataCleanup(void *_data) { @@ -608,15 +690,19 @@ void DBusConnection::enforceAsynchronousTimeouts() const { // => add asyncHandler to mainloopTimeouts list DBusMessage& dbusMessageCall = std::get<2>(it->second); - assert(mainLoopContext_.lock()); - { - std::lock_guard<std::mutex> itsLock(mainloopTimeoutsMutex_); - mainloopTimeouts_.push_back(std::make_tuple(asyncHandler, - dbusMessageCall.createMethodError(DBUS_ERROR_TIMEOUT), - CallStatus::REMOTE_ERROR, - nullptr)); + auto lockedContext = mainLoopContext_.lock(); + if (!lockedContext) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "lockedContext == nullptr"); + } else { + { + std::lock_guard<std::mutex> itsLock(mainloopTimeoutsMutex_); + mainloopTimeouts_.push_back(std::make_tuple(asyncHandler, + dbusMessageCall.createMethodError(DBUS_ERROR_TIMEOUT), + CallStatus::REMOTE_ERROR, + nullptr)); + } + lockedContext->wakeup(); } - mainLoopContext_.lock()->wakeup(); it = timeoutMap_.erase(it); //This unref MIGHT cause the destruction of the last callback object that references the DBusConnection. @@ -687,21 +773,34 @@ std::future<CallStatus> DBusConnection::sendDBusMessageWithReplyAsync( std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler, const CommonAPI::CallInfo *_info) const { - assert(dbusMessage); - assert(isConnected()); + if (!dbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "message == NULL"); + return std::future<CallStatus>(); + } + if (!isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "not connected"); + return std::future<CallStatus>(); + } DBusPendingCall* libdbusPendingCall; dbus_bool_t libdbusSuccess; DBusMessageReplyAsyncHandler* replyAsyncHandler = dbusMessageReplyAsyncHandler.release(); - std::future<CallStatus> callStatusFuture = replyAsyncHandler->getFuture(); + std::future<CallStatus> callStatusFuture; + try { + callStatusFuture = replyAsyncHandler->getFuture(); + } catch (std::exception& e) { + (void)e; + } + + PendingCallNotificationData* userData = new PendingCallNotificationData(this, replyAsyncHandler); libdbusSuccess = dbus_connection_send_with_reply_set_notify(connection_, dbusMessage.message_, &libdbusPendingCall, onLibdbusPendingCallNotifyThunk, - replyAsyncHandler, + userData, onLibdbusDataCleanup, _info->timeout_); @@ -743,7 +842,13 @@ std::future<CallStatus> DBusConnection::sendDBusMessageWithReplyAsync( }; enforceTimeoutMutex_.lock(); - timeoutMap_.insert( { libdbusPendingCall, toInsert } ); + auto ret = timeoutMap_.insert( { libdbusPendingCall, toInsert } ); + if (ret.second == false) { + // key has been reused + // update the map value with the new info + timeoutMap_.erase(ret.first); + timeoutMap_.insert( { libdbusPendingCall, toInsert } ); + } enforceTimeoutMutex_.unlock(); enforcerThreadMutex_.lock(); @@ -761,9 +866,14 @@ std::future<CallStatus> DBusConnection::sendDBusMessageWithReplyAsync( DBusMessage DBusConnection::sendDBusMessageWithReplyAndBlock(const DBusMessage& dbusMessage, DBusError& dbusError, const CommonAPI::CallInfo *_info) const { - assert(dbusMessage); - assert(!dbusError); - assert(isConnected()); + if (!dbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "message == NULL"); + return DBusMessage(); + } + if (!isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "not connected"); + return DBusMessage(); + } ::DBusMessage* libdbusMessageReply = dbus_connection_send_with_reply_and_block(connection_, dbusMessage.message_, @@ -775,6 +885,7 @@ DBusMessage DBusConnection::sendDBusMessageWithReplyAndBlock(const DBusMessage& } if (dbusError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "dbusError set"); return DBusMessage(); } @@ -782,6 +893,13 @@ DBusMessage DBusConnection::sendDBusMessageWithReplyAndBlock(const DBusMessage& return DBusMessage(libdbusMessageReply, increaseLibdbusMessageReferenceCount); } +void DBusConnection::dispatchDBusMessageReply(const DBusMessage& _reply, + DBusMessageReplyAsyncHandler* _dbusMessageReplyAsyncHandler) { + if(setDispatching(true)) { + onLibdbusPendingCall(NULL, _reply, _dbusMessageReplyAsyncHandler); + setDispatching(false); + } +} bool DBusConnection::singleDispatch() { { @@ -795,14 +913,25 @@ bool DBusConnection::singleDispatch() { } mainloopTimeouts_.clear(); } - - return (dbus_connection_dispatch(connection_) == DBUS_DISPATCH_DATA_REMAINS); + if(setDispatching(true)) { + bool dispatchStatus(connection_ && dbus_connection_dispatch(connection_) == DBUS_DISPATCH_DATA_REMAINS); + setDispatching(false); + return dispatchStatus; + } else { + return false; + } } bool DBusConnection::isDispatchReady() { std::lock_guard<std::mutex> itsLock(mainloopTimeoutsMutex_); - return (dbus_connection_get_dispatch_status(connection_) == DBUS_DISPATCH_DATA_REMAINS || + + if(setDispatching(true)) { + bool dispatchStatus((connection_ && dbus_connection_get_dispatch_status(connection_) == DBUS_DISPATCH_DATA_REMAINS) || !mainloopTimeouts_.empty()); + setDispatching(false); + return dispatchStatus; + } + return false; } bool DBusConnection::hasDispatchThread() { @@ -813,48 +942,95 @@ const ConnectionId_t& DBusConnection::getConnectionId() const { return connectionId_; } -bool DBusConnection::sendPendingSelectiveSubscription(DBusProxy* proxy, std::string methodName) { - bool subscriptionAccepted; - CommonAPI::CallStatus callStatus; - DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<>, - CommonAPI::DBus::DBusSerializableArguments<bool>>::callMethodWithReply( - *proxy, methodName.c_str(), "", &CommonAPI::DBus::defaultCallInfo, callStatus, subscriptionAccepted); +void DBusConnection::incrementConnection() { + std::lock_guard < std::mutex > lock(activeConnectionsMutex_); + activeConnections_++; +} + +void DBusConnection::decrementConnection() { + std::lock_guard < std::mutex > lock(activeConnectionsMutex_); + activeConnections_--; + + if (activeConnections_ <= 0) { + disconnect(); + } +} + +bool DBusConnection::setDispatching(bool _isDispatching) { + std::lock_guard<std::mutex> dispatchLock(dispatchMutex_); + + if(isDispatching_ == _isDispatching) + return true; - return subscriptionAccepted; + dispatchThreads_.insert(std::this_thread::get_id()); + if(isDisconnecting_) { // we want to disconnect and only accept unsetting the dispatch flag + if(!_isDispatching) { + isDispatching_ = _isDispatching; + if(isWaitingOnFinishedDispatching_) + dispatchCondition_.notify_one(); + return true; + } else { + return false; + } + } else { + isDispatching_ = _isDispatching; + return true; + } +} + +void DBusConnection::sendPendingSelectiveSubscription(DBusProxy* callingProxy, std::string methodName, + DBusSignalHandler* dbusSignalHandler, uint32_t tag) { + bool outarg; + DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<>, + CommonAPI::DBus::DBusSerializableArguments<bool>>::callMethodAsync( + *callingProxy, methodName.c_str(), "", + &CommonAPI::DBus::defaultCallInfo, + [this, dbusSignalHandler, callingProxy, tag] + (const CommonAPI::CallStatus& callStatus, const bool& accepted) { + + if (callStatus == CommonAPI::CallStatus::SUCCESS && accepted) { + dbusSignalHandler->onSpecificError(CommonAPI::CallStatus::SUCCESS, tag); + } else { + dbusSignalHandler->onSpecificError(CommonAPI::CallStatus::SUBSCRIPTION_REFUSED, tag); + } + }, std::make_tuple(outarg)); } -DBusProxyConnection::DBusSignalHandlerToken DBusConnection::subscribeForSelectiveBroadcast( - bool& subscriptionAccepted, +void DBusConnection::subscribeForSelectiveBroadcast( const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, const std::string& interfaceMemberSignature, DBusSignalHandler* dbusSignalHandler, - DBusProxy* callingProxy) { + DBusProxy* callingProxy, + uint32_t tag) { std::string methodName = "subscribeFor" + interfaceMemberName + "Selective"; - subscriptionAccepted = false; - - CommonAPI::CallStatus callStatus; + bool outarg; DBusProxyHelper<CommonAPI::DBus::DBusSerializableArguments<>, - CommonAPI::DBus::DBusSerializableArguments<bool>>::callMethodWithReply( - *callingProxy, methodName.c_str(), "", &CommonAPI::DBus::defaultCallInfo, callStatus, subscriptionAccepted); - - DBusProxyConnection::DBusSignalHandlerToken subscriptionToken; - if ((callStatus == CommonAPI::CallStatus::SUCCESS && subscriptionAccepted) || !callingProxy->isAvailable()) { - subscriptionToken = addSignalMemberHandler( - objectPath, - interfaceName, - interfaceMemberName, - interfaceMemberSignature, - dbusSignalHandler, - true - ); - subscriptionAccepted = true; - } - - return (subscriptionToken); + CommonAPI::DBus::DBusSerializableArguments<bool>>::callMethodAsync( + *callingProxy, methodName.c_str(), "", + &CommonAPI::DBus::defaultCallInfo, + [this, objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature, dbusSignalHandler, callingProxy, tag] + (const CommonAPI::CallStatus& callStatus, const bool& accepted) { + if ((callStatus == CommonAPI::CallStatus::SUCCESS && accepted) || !callingProxy->isAvailable()) { + DBusProxyConnection::DBusSignalHandlerToken token = addSignalMemberHandler( + objectPath, + interfaceName, + interfaceMemberName, + interfaceMemberSignature, + dbusSignalHandler, + true + ); + dbusSignalHandler->setSubscriptionToken(token, tag); + } + if (accepted) { + dbusSignalHandler->onSpecificError(CommonAPI::CallStatus::SUCCESS, tag); + } else { + dbusSignalHandler->onSpecificError(CommonAPI::CallStatus::SUBSCRIPTION_REFUSED, tag); + } + }, std::make_tuple(outarg)); } void DBusConnection::unsubscribeFromSelectiveBroadcast(const std::string& eventName, @@ -955,8 +1131,9 @@ bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbus if (!isInsertSuccessful) { if (isConnected()) { const bool isRemoveSignalMatchRuleSuccessful = removeObjectManagerSignalMatchRule(dbusBusName); - assert(isRemoveSignalMatchRuleSuccessful); - (void)isRemoveSignalMatchRuleSuccessful; + if (!isRemoveSignalMatchRuleSuccessful) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " removeObjectManagerSignalMatchRule", dbusBusName, " failed"); + } } return false; } @@ -973,7 +1150,10 @@ bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbus bool DBusConnection::removeObjectManagerSignalMemberHandler(const std::string& dbusBusName, DBusSignalHandler* dbusSignalHandler) { - assert(!dbusBusName.empty()); + if (dbusBusName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty dbusBusName"); + return false; + } std::lock_guard<std::mutex> dbusSignalLock(dbusObjectManagerSignalGuard_); @@ -996,8 +1176,11 @@ bool DBusConnection::removeObjectManagerSignalMemberHandler(const std::string& d size_t& dbusSignalMatchRuleReferenceCount = dbusSignalMatchRuleIterator->second; - assert(dbusSignalMatchRuleReferenceCount > 0); - dbusSignalMatchRuleReferenceCount--; + if (0 == dbusSignalMatchRuleReferenceCount) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "ref count == 0"); + } else { + dbusSignalMatchRuleReferenceCount--; + } const bool isLastDBusSignalMatchRuleReference = (dbusSignalMatchRuleReferenceCount == 0); if (isLastDBusSignalMatchRuleReference) { @@ -1083,8 +1266,14 @@ bool DBusConnection::removeLibdbusSignalMatchRule(const std::string& dbusMatchRu } void DBusConnection::registerObjectPath(const std::string& objectPath) { - assert(!objectPath.empty()); - assert(objectPath[0] == '/'); + if (objectPath.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty objectPath"); + return; + } + if ('/' != objectPath[0]) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid objectPath ", objectPath); + return; + } auto handlerIterator = libdbusRegisteredObjectPaths_.find(objectPath); const bool foundRegisteredObjectPathHandler = handlerIterator != libdbusRegisteredObjectPaths_.end(); @@ -1104,22 +1293,33 @@ void DBusConnection::registerObjectPath(const std::string& objectPath) { getDBusObjectPathVTable(), this, &dbusError.libdbusError_); - assert(libdbusSuccess); - assert(!dbusError); - (void)libdbusSuccess; - (void)dbusError; + + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_connection_try_register_object_path failed for ", objectPath); + } + if (dbusError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " name: ", dbusError.getName(), " message: ", dbusError.getMessage()); + } } } void DBusConnection::unregisterObjectPath(const std::string& objectPath) { - assert(!objectPath.empty()); - assert(objectPath[0] == '/'); + if (objectPath.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty objectPath"); + return; + } + if ('/' != objectPath[0]) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid objectPath ", objectPath); + return; + } auto handlerIterator = libdbusRegisteredObjectPaths_.find(objectPath); const bool foundRegisteredObjectPathHandler = handlerIterator != libdbusRegisteredObjectPaths_.end(); - assert(foundRegisteredObjectPathHandler); - (void)foundRegisteredObjectPathHandler; + if (!foundRegisteredObjectPathHandler) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no handler found for ", objectPath); + return; + } uint32_t& referenceCount = handlerIterator->second; if (referenceCount > 1) { @@ -1130,10 +1330,11 @@ void DBusConnection::unregisterObjectPath(const std::string& objectPath) { libdbusRegisteredObjectPaths_.erase(handlerIterator); if (isConnected()) { - dbus_bool_t libdbusSuccess + const dbus_bool_t libdbusSuccess = dbus_connection_unregister_object_path(connection_, objectPath.c_str()); - assert(libdbusSuccess); - (void)libdbusSuccess; + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_connection_unregister_object_path failed for ", objectPath); + } } } @@ -1166,8 +1367,10 @@ void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath, auto success = dbusSignalMatchRulesMap_.insert( DBusSignalMatchRulesMap::value_type(dbusSignalMatchRuleTuple, DBusSignalMatchRuleMapping(1, matchRuleString))); - assert(success.second); - (void)success; + if (!success.second) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "dbusSignalMatchRulesMap_.insert failed ", matchRuleString); + return; + } if (isConnected()) { bool libdbusSuccess = true; @@ -1180,7 +1383,9 @@ void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath, &onLibdbusSignalFilterThunk, this, NULL); - assert(libdbusSuccess); + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_connection_add_filter() failed"); + } } if (!justAddFilter) @@ -1188,8 +1393,10 @@ void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath, // finally add the match rule DBusError dbusError; dbus_bus_add_match(connection_, matchRuleString.c_str(), &dbusError.libdbusError_); - assert(!dbusError); - (void)dbusError; + + if (dbusError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " name: ", dbusError.getName(), " message: ", dbusError.getMessage()); + } } if (libdbusSuccess) { @@ -1206,8 +1413,10 @@ void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath, auto matchRuleIterator = dbusSignalMatchRulesMap_.find(dbusSignalMatchRuleTuple); const bool matchRuleFound = matchRuleIterator != dbusSignalMatchRulesMap_.end(); - assert(matchRuleFound); - (void)matchRuleFound; + 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) { @@ -1218,15 +1427,19 @@ void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath, if (isConnected()) { const std::string& matchRuleString = matchRuleIterator->second.second; const bool libdbusSuccess = removeLibdbusSignalMatchRule(matchRuleString); - assert(libdbusSuccess); - (void)libdbusSuccess; + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " removeLibdbusSignalMatchRule failed ", matchRuleString); + } } dbusSignalMatchRulesMap_.erase(matchRuleIterator); } void DBusConnection::initLibdbusObjectPathHandlerAfterConnect() { - assert(isConnected()); + if (!isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "not connected"); + return; + } // nothing to do if there aren't any registered object path handlers if (libdbusRegisteredObjectPaths_.empty()) { @@ -1248,37 +1461,46 @@ void DBusConnection::initLibdbusObjectPathHandlerAfterConnect() { getDBusObjectPathVTable(), this, &dbusError.libdbusError_); - assert(libdbusSuccess); - (void)libdbusSuccess; - - assert(!dbusError); + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_connection_try_register_object_path(", objectPath , ") failed "); + } + if (dbusError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " name: ", dbusError.getName(), " message: ", dbusError.getMessage()); + } } } void DBusConnection::initLibdbusSignalFilterAfterConnect() { - assert(isConnected()); + if (!isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "not connected"); + return; + } // proxy/stub match rules for (const auto& dbusSignalMatchRuleIterator : dbusSignalMatchRulesMap_) { const auto& dbusSignalMatchRuleMapping = dbusSignalMatchRuleIterator.second; const std::string& dbusMatchRuleString = dbusSignalMatchRuleMapping.second; const bool libdbusSuccess = addLibdbusSignalMatchRule(dbusMatchRuleString); - assert(libdbusSuccess); - (void)libdbusSuccess; + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " addLibdbusSignalMatchRule(", dbusMatchRuleString , ") failed "); + } } // object manager match rules (see DBusServiceRegistry) for (const auto& dbusObjectManagerSignalMatchRuleIterator : dbusObjectManagerSignalMatchRulesMap_) { const std::string& dbusBusName = dbusObjectManagerSignalMatchRuleIterator.first; const bool libdbusSuccess = addObjectManagerSignalMatchRule(dbusBusName); - assert(libdbusSuccess); - (void)libdbusSuccess; + if (!libdbusSuccess) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " addObjectManagerSignalMatchRule(", dbusBusName , ") failed "); + } } } ::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage) { - assert(libdbusMessage); - (void)libdbusMessage; + if (NULL == libdbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " libdbusMessage == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } // handle only method call messages if (dbus_message_get_type(libdbusMessage) != DBUS_MESSAGE_TYPE_METHOD_CALL) { @@ -1299,7 +1521,6 @@ void notifyDBusSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable, return; } - signalEntry->second.first->lock(); auto handlerEntry = signalEntry->second.second.begin(); while (handlerEntry != signalEntry->second.second.end()) { DBusProxyConnection::DBusSignalHandler* dbusSignalHandler = *handlerEntry; @@ -1307,7 +1528,6 @@ void notifyDBusSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable, handlerEntry++; } dbusHandlerResult = DBUS_HANDLER_RESULT_HANDLED; - signalEntry->second.first->unlock(); } template<typename DBusSignalHandlersTable> @@ -1329,7 +1549,10 @@ void notifyDBusOMSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable } ::DBusHandlerResult DBusConnection::onLibdbusSignalFilter(::DBusMessage* libdbusMessage) { - assert(libdbusMessage); + if (NULL == libdbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " libdbusMessage == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } auto selfReference = this->shared_from_this(); @@ -1343,10 +1566,10 @@ void notifyDBusOMSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable const char* interfaceMemberName = dbus_message_get_member(libdbusMessage); const char* interfaceMemberSignature = dbus_message_get_signature(libdbusMessage); - assert(objectPath); - assert(interfaceName); - assert(interfaceMemberName); - assert(interfaceMemberSignature); + if (NULL == objectPath || NULL == interfaceName || NULL == interfaceMemberName || NULL == interfaceMemberSignature ) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid message"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } DBusMessage dbusMessage(libdbusMessage); ::DBusHandlerResult dbusHandlerResult = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -1357,14 +1580,23 @@ void notifyDBusOMSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable interfaceName, interfaceMemberName, interfaceMemberSignature)); + + if(signalEntry != dbusSignalHandlerTable_.end()) + signalEntry->second.first->lock(); signalGuard_.unlock(); notifyDBusSignalHandlers(dbusSignalHandlerTable_, signalEntry, dbusMessage, dbusHandlerResult); + if(signalEntry != dbusSignalHandlerTable_.end()) + signalEntry->second.first->unlock(); + if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")) { const char* dbusSenderName = dbusMessage.getSender(); - assert(dbusSenderName); + if (NULL == dbusSenderName) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusSenderName == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } dbusObjectManagerSignalGuard_.lock(); auto dbusObjectManagerSignalHandlerIteratorPair = dbusObjectManagerSignalHandlerTable_.equal_range(dbusSenderName); @@ -1381,26 +1613,50 @@ void notifyDBusOMSignalHandlers(DBusSignalHandlersTable& dbusSignalHandlerstable ::DBusHandlerResult DBusConnection::onLibdbusSignalFilterThunk(::DBusConnection *_dbusConnection, ::DBusMessage* libdbusMessage, void* userData) { - assert(_dbusConnection); - assert(libdbusMessage); - assert(userData); - (void)_dbusConnection; + if (NULL == _dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _dbusConnection == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + if (NULL == libdbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " libdbusMessage == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + if (NULL == userData) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " userData == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData); - assert(dbusConnection->connection_ == _dbusConnection); + if (dbusConnection->connection_ != _dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " wrong connection!?"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + return dbusConnection->onLibdbusSignalFilter(libdbusMessage); } ::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessageThunk(::DBusConnection *_dbusConnection, ::DBusMessage* libdbusMessage, void* userData) { - assert(_dbusConnection); - assert(libdbusMessage); - assert(userData); - (void)_dbusConnection; + if (NULL == _dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _dbusConnection == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + if (NULL == libdbusMessage) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " libdbusMessage == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + if (NULL == userData) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " userData == NULL"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData); - assert(dbusConnection->connection_ == _dbusConnection); + if (dbusConnection->connection_ != _dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " wrong connection!?"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + return dbusConnection->onLibdbusObjectPathMessage(libdbusMessage); } @@ -1412,5 +1668,15 @@ std::shared_ptr<DBusConnection> DBusConnection::wrap(::DBusConnection *_connecti return std::make_shared<DBusConnection>(_connection, _connectionId); } +void DBusConnection::pushDBusMessageReply(const DBusMessage& _reply, + std::unique_ptr<DBusMessageReplyAsyncHandler> _dbusMessageReplyAsyncHandler) { + // push message to the message queue + DBusMessageReplyAsyncHandler* replyAsyncHandler = _dbusMessageReplyAsyncHandler.release(); + replyAsyncHandler->setHasToBeDeleted(); + std::shared_ptr<DBusMessageWatch::MsgReplyQueueEntry> msgReplyQueueEntry = std::make_shared<DBusMessageWatch::MsgReplyQueueEntry>( + replyAsyncHandler, _reply); + msgWatch_->pushMsgQueue(msgReplyQueueEntry); +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusDaemonProxy.cpp b/src/CommonAPI/DBus/DBusDaemonProxy.cpp index ee434b1..58ee08f 100644 --- a/src/CommonAPI/DBus/DBusDaemonProxy.cpp +++ b/src/CommonAPI/DBus/DBusDaemonProxy.cpp @@ -39,7 +39,6 @@ static const char *DAEMON_DBUS_INTERFACE = DBusDaemonProxy::getInterfaceId(); static const char *DAEMON_DBUS_OBJECT_PATH = "/org/freedesktop/DBus"; static const char *DAEMON_DBUS_BUS = "org.freedesktop.DBus"; static DBusAddress dbusProxyAddress(DAEMON_DBUS_INTERFACE, DAEMON_DBUS_OBJECT_PATH, DAEMON_DBUS_BUS); -static CommonAPI::CallInfo daemonProxyInfo(30000); DBusDaemonProxy::DBusDaemonProxy(const std::shared_ptr<DBusProxyConnection>& dbusConnection): DBusProxyBase(dbusProxyAddress, dbusConnection), @@ -60,6 +59,12 @@ bool DBusDaemonProxy::isAvailableBlocking() const { return isAvailable(); } +std::future<AvailabilityStatus> DBusDaemonProxy::isAvailableAsync( + isAvailableAsyncCallback _callback, + const CallInfo *_info) const { + return isAvailableAsync(_callback, _info); +} + ProxyStatusEvent& DBusDaemonProxy::getProxyStatusEvent() { return getDBusConnection()->getConnectionStatusEvent(); } @@ -94,14 +99,6 @@ void DBusDaemonProxy::listNames(CommonAPI::CallStatus& callStatus, std::vector<s callStatus = CallStatus::SUCCESS; } -std::future<CallStatus> DBusDaemonProxy::listNamesAsync(ListNamesAsyncCallback listNamesAsyncCallback) const { - DBusMessage dbusMessage = createMethodCall("ListNames", ""); - return getDBusConnection()->sendDBusMessageWithReplyAsync( - dbusMessage, - DBusProxyAsyncCallbackHandler<std::vector<std::string>>::create(listNamesAsyncCallback, std::tuple<std::vector<std::string>>()), - &daemonProxyInfo); -} - void DBusDaemonProxy::nameHasOwner(const std::string& busName, CommonAPI::CallStatus& callStatus, bool& hasOwner) const { DBusMessage dbusMethodCall = createMethodCall("NameHasOwner", "s"); @@ -132,54 +129,6 @@ void DBusDaemonProxy::nameHasOwner(const std::string& busName, CommonAPI::CallSt callStatus = CallStatus::SUCCESS; } -std::future<CallStatus> DBusDaemonProxy::nameHasOwnerAsync(const std::string& busName, NameHasOwnerAsyncCallback nameHasOwnerAsyncCallback) const { - DBusMessage dbusMessage = createMethodCall("NameHasOwner", "s"); - - DBusOutputStream outputStream(dbusMessage); - const bool success = DBusSerializableArguments<std::string>::serialize(outputStream, busName); - if (!success) { - std::promise<CallStatus> promise; - promise.set_value(CallStatus::OUT_OF_MEMORY); - return promise.get_future(); - } - outputStream.flush(); - - return getDBusConnection()->sendDBusMessageWithReplyAsync( - dbusMessage, - DBusProxyAsyncCallbackHandler<bool>::create(nameHasOwnerAsyncCallback, std::tuple<bool>()), - &daemonProxyInfo); -} - -std::future<CallStatus> DBusDaemonProxy::getManagedObjectsAsync(const std::string& forDBusServiceName, GetManagedObjectsAsyncCallback callback) const { - static DBusAddress address(forDBusServiceName, "/", "org.freedesktop.DBus.ObjectManager"); - auto dbusMethodCallMessage = DBusMessage::createMethodCall(address, "GetManagedObjects", ""); - - return getDBusConnection()->sendDBusMessageWithReplyAsync( - dbusMethodCallMessage, - DBusProxyAsyncCallbackHandler<DBusObjectToInterfaceDict>::create( - callback, std::tuple<DBusObjectToInterfaceDict>() - ), - &daemonProxyInfo); -} - -std::future<CallStatus> DBusDaemonProxy::getNameOwnerAsync(const std::string& busName, GetNameOwnerAsyncCallback getNameOwnerAsyncCallback) const { - DBusMessage dbusMessage = createMethodCall("GetNameOwner", "s"); - - DBusOutputStream outputStream(dbusMessage); - const bool success = DBusSerializableArguments<std::string>::serialize(outputStream, busName); - if (!success) { - std::promise<CallStatus> promise; - promise.set_value(CallStatus::OUT_OF_MEMORY); - return promise.get_future(); - } - outputStream.flush(); - - return getDBusConnection()->sendDBusMessageWithReplyAsync( - dbusMessage, - DBusProxyAsyncCallbackHandler<std::string>::create(getNameOwnerAsyncCallback, std::tuple<std::string>()), - &daemonProxyInfo); -} - const char* DBusDaemonProxy::getInterfaceId() { static const char interfaceId[] = "org.freedesktop.DBus"; return interfaceId; diff --git a/src/CommonAPI/DBus/DBusError.cpp b/src/CommonAPI/DBus/DBusError.cpp index b5f5d5c..884f23b 100644 --- a/src/CommonAPI/DBus/DBusError.cpp +++ b/src/CommonAPI/DBus/DBusError.cpp @@ -3,7 +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 <cassert> #include <cstring> #include <CommonAPI/DBus/DBusError.hpp> diff --git a/src/CommonAPI/DBus/DBusFactory.cpp b/src/CommonAPI/DBus/DBusFactory.cpp index 40da41f..d7fa84c 100644 --- a/src/CommonAPI/DBus/DBusFactory.cpp +++ b/src/CommonAPI/DBus/DBusFactory.cpp @@ -27,13 +27,37 @@ Factory::get() { return theFactory; } -Factory::Factory() { +Factory::Factory() : isInitialized_(false) { } Factory::~Factory() { } void +Factory::init() { +#ifndef WIN32 + std::lock_guard<std::mutex> itsLock(initializerMutex_); +#endif + if (!isInitialized_) { + for (auto i : initializers_) i(); + initializers_.clear(); // Not needed anymore + isInitialized_ = true; + } +} + +void +Factory::registerInterface(InterfaceInitFunction _function) { + std::lock_guard<std::mutex> itsLock(initializerMutex_); + if (isInitialized_) { + // We are already running --> initialize the interface library! + _function(); + } else { + // We are not initialized --> save the initializer + initializers_.push_back(_function); + } +} + +void Factory::registerProxyCreateMethod( const std::string &_interface, ProxyCreateFunction _function) { proxyCreateFunctions_[_interface] = _function; @@ -222,13 +246,14 @@ Factory::unregisterStubAdapter(std::shared_ptr<DBusStubAdapter> _adapter) { std::shared_ptr<DBusConnection> Factory::getConnection(const ConnectionId_t &_connectionId) { + std::lock_guard<std::mutex> itsGuard(connectionsMutex_); auto itsConnectionIterator = connections_.find(_connectionId); if (itsConnectionIterator != connections_.end()) { return itsConnectionIterator->second; } // No connection found, lets create and initialize one - DBusType_t dbusType = DBusAddressTranslator::get()->getDBusBusType(_connectionId); + const DBusType_t dbusType = DBusAddressTranslator::get()->getDBusBusType(_connectionId); std::shared_ptr<DBusConnection> itsConnection = std::make_shared<DBusConnection>(dbusType, _connectionId); connections_.insert({ _connectionId, itsConnection }); @@ -242,14 +267,16 @@ Factory::getConnection(std::shared_ptr<MainLoopContext> _context) { if (!_context) return getConnection(DEFAULT_CONNECTION_ID); + std::lock_guard<std::mutex> itsGuard(contextConnectionsMutex_); auto itsConnectionIterator = contextConnections_.find(_context.get()); if (itsConnectionIterator != contextConnections_.end()) { return itsConnectionIterator->second; } // No connection found, lets create and initialize one + const DBusType_t dbusType = DBusAddressTranslator::get()->getDBusBusType(_context->getName()); std::shared_ptr<DBusConnection> itsConnection - = std::make_shared<DBusConnection>(DBusType_t::SESSION, _context->getName()); + = std::make_shared<DBusConnection>(dbusType, _context->getName()); contextConnections_.insert({ _context.get(), itsConnection } ); itsConnection->connect(false); @@ -310,9 +337,9 @@ Factory::registerManagedService(const std::shared_ptr<DBusStubAdapter> &_stubAda const bool isAcquired = connection->requestServiceNameAndBlock(serviceName); if (!isAcquired) { const bool isDeregistered = objectManager->unregisterDBusStubAdapter(_stubAdapter); - assert(isDeregistered); - (void)isDeregistered; - + if (!isDeregistered) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " couldn't deregister ", serviceName); + } services_.erase(insertResult.first); } @@ -348,5 +375,87 @@ Factory::unregisterManagedService(const ServicesMap::iterator &iterator) { return isUnregistered; } +void Factory::incrementConnection(std::shared_ptr<DBusProxyConnection> _connection) { + std::shared_ptr<DBusConnection> connection; + { + std::lock_guard<std::mutex> itsConnectionGuard(connectionsMutex_); + for (auto itsConnectionIterator = connections_.begin(); itsConnectionIterator != connections_.end(); itsConnectionIterator++) { + if (itsConnectionIterator->second == _connection) { + connection = itsConnectionIterator->second; + break; + } + } + } + + if(connection) + connection->incrementConnection(); + + std::shared_ptr<DBusConnection> contextConnection; + { + std::lock_guard<std::mutex> itsContextConnectionGuard(contextConnectionsMutex_); + for (auto itsConnectionIterator = contextConnections_.begin(); itsConnectionIterator != contextConnections_.end(); itsConnectionIterator++) { + if (itsConnectionIterator->second == _connection) { + contextConnection = itsConnectionIterator->second; + break; + } + } + } + + if(contextConnection) + contextConnection->incrementConnection(); +} + +void Factory::decrementConnection(std::shared_ptr<DBusProxyConnection> _connection) { + std::shared_ptr<DBusConnection> connection; + { + std::lock_guard<std::mutex> itsConnectionGuard(connectionsMutex_); + for (auto itsConnectionIterator = connections_.begin(); itsConnectionIterator != connections_.end(); itsConnectionIterator++) { + if (itsConnectionIterator->second == _connection) { + connection = itsConnectionIterator->second; + break; + } + } + } + + if(connection) + connection->decrementConnection(); + + std::shared_ptr<DBusConnection> contextConnection; + { + std::lock_guard<std::mutex> itsContextConnectionGuard(contextConnectionsMutex_); + for (auto itsConnectionIterator = contextConnections_.begin(); itsConnectionIterator != contextConnections_.end(); itsConnectionIterator++) { + if (itsConnectionIterator->second == _connection) { + contextConnection = itsConnectionIterator->second; + break; + } + } + } + + if(contextConnection) + contextConnection->decrementConnection(); +} + +void Factory::releaseConnection(const ConnectionId_t& _connectionId, MainLoopContext* _mainloopContext) { + { + std::lock_guard<std::mutex> itsConnectionGuard(connectionsMutex_); + auto connection = connections_.find(_connectionId); + + if (connection != connections_.end()) { + DBusServiceRegistry::remove(connection->second); + connections_.erase(_connectionId); + } + } + + { + std::lock_guard<std::mutex> itsContextConnectionGuard(contextConnectionsMutex_); + auto connectionContext = contextConnections_.find(_mainloopContext); + + if (connectionContext != contextConnections_.end()) { + DBusServiceRegistry::remove(connectionContext->second); + contextConnections_.erase(_mainloopContext); + } + } +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusFreedesktopPropertiesStub.cpp b/src/CommonAPI/DBus/DBusFreedesktopPropertiesStub.cpp index 75fc0b5..f41b77e 100644 --- a/src/CommonAPI/DBus/DBusFreedesktopPropertiesStub.cpp +++ b/src/CommonAPI/DBus/DBusFreedesktopPropertiesStub.cpp @@ -3,8 +3,8 @@ // 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 <cassert> #include <vector> +#include <algorithm> #include <CommonAPI/DBus/DBusFreedesktopPropertiesStub.hpp> #include <CommonAPI/DBus/DBusStubAdapter.hpp> @@ -21,14 +21,30 @@ DBusFreedesktopPropertiesStub::DBusFreedesktopPropertiesStub( : path_(_path), connection_(_connection), adapter_(_adapter) { - assert(!path_.empty()); - assert(path_[0] == '/'); - assert(_connection); + if (path_.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty _path"); + } + if ('/' != path_[0]) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid _path ", _path); + } + if (!_connection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid _connection"); + } dbusInterfacesLock_.lock(); - if(managedInterfaces_.find(_interface) == managedInterfaces_.end()) { - managedInterfaces_.insert({ _interface, _adapter }); + + const auto& it = managedInterfaces_.find(_interface); + if (it != managedInterfaces_.end()) { + auto& adapters = it->second; + if (find(adapters.begin(), adapters.end(), _adapter) == adapters.end()) { + adapters.push_back(_adapter); + it->second = adapters; + } } + else { + managedInterfaces_.insert({ _interface, std::vector<std::shared_ptr<DBusStubAdapter>> ({_adapter}) }); + } + dbusInterfacesLock_.unlock(); } @@ -86,7 +102,12 @@ DBusFreedesktopPropertiesStub::onInterfaceDBusMessage(const DBusMessage &_messag return false; } - return it->second->onInterfaceDBusFreedesktopPropertiesMessage(_message); + for (auto& adapter : it->second) { + adapter->onInterfaceDBusFreedesktopPropertiesMessage(_message); + } + + // errors are ignored. + return true; } bool DBusFreedesktopPropertiesStub::hasFreedesktopProperties() { diff --git a/src/CommonAPI/DBus/DBusFunctionalHash.cpp b/src/CommonAPI/DBus/DBusFunctionalHash.cpp index 00b5da6..e82d578 100644 --- a/src/CommonAPI/DBus/DBusFunctionalHash.cpp +++ b/src/CommonAPI/DBus/DBusFunctionalHash.cpp @@ -3,11 +3,11 @@ // 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 <cassert> #include <cstring> #include <murmurhash/MurmurHash3.h> +#include <CommonAPI/Logger.hpp> #include <CommonAPI/DBus/DBusFunctionalHash.hpp> /* @@ -15,18 +15,29 @@ */ #define SMHASHER_SEED_VALUE 0xc70f6907UL +using namespace CommonAPI; + namespace std { size_t hash<pair<const char*, const char*> >::operator()(const pair<const char*, const char*>& t) const { const char* a = t.first; const char* b = t.second; - assert(a); - assert(b); + if (NULL == a) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " t.first is NULL"); + } + if (NULL == b) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " t.second is NULL"); + } uint32_t seed = static_cast<uint32_t>(SMHASHER_SEED_VALUE); - MurmurHash3_x86_32(a, static_cast<int>(strlen(a)), seed, &seed); - MurmurHash3_x86_32(b, static_cast<int>(strlen(b)), seed, &seed); + + if (NULL != a) { + MurmurHash3_x86_32(a, static_cast<int>(strlen(a)), seed, &seed); + } + if (NULL != b) { + MurmurHash3_x86_32(b, static_cast<int>(strlen(b)), seed, &seed); + } return static_cast<size_t>(seed); } diff --git a/src/CommonAPI/DBus/DBusInputStream.cpp b/src/CommonAPI/DBus/DBusInputStream.cpp index ae2201a..0c838a0 100644 --- a/src/CommonAPI/DBus/DBusInputStream.cpp +++ b/src/CommonAPI/DBus/DBusInputStream.cpp @@ -13,7 +13,7 @@ namespace DBus { DBusInputStream::DBusInputStream(const CommonAPI::DBus::DBusMessage &_message) : begin_(_message.getBodyData()), current_(0), - size_(_message.getBodyLength()), + size_((size_t)(_message.getBodyLength())), exception_(nullptr), message_(_message) { } @@ -38,7 +38,10 @@ void DBusInputStream::align(const size_t _boundary) { } char *DBusInputStream::_readRaw(const size_t _size) { - assert(current_ + _size <= size_); + if ((current_ + _size) > size_) { + setError(); + return NULL; + } char *data = (char *) (begin_ + current_); current_ += _size; @@ -130,14 +133,15 @@ InputStream<DBusInputStream> &DBusInputStream::readValue(double &_value, const E InputStream<DBusInputStream> &DBusInputStream::readValue(std::string &_value, const EmptyDeployment *_depl) { (void)_depl; - uint32_t length; + uint32_t length(0); _readValue(length); // length field does not include terminating 0-byte, therefore length of data to read is +1 char *data = _readRaw(length + 1); - - // The string contained in a DBus-message is required to be 0-terminated, therefore the following line works - _value = data; + if (!hasError()) { + // The string contained in a DBus-message is required to be 0-terminated, therefore the following line works + _value = data; + } return (*this); } diff --git a/src/CommonAPI/DBus/DBusMainLoop.cpp b/src/CommonAPI/DBus/DBusMainLoop.cpp index a46072f..b9daea3 100755 --- a/src/CommonAPI/DBus/DBusMainLoop.cpp +++ b/src/CommonAPI/DBus/DBusMainLoop.cpp @@ -203,6 +203,8 @@ DBusMainLoop::~DBusMainLoop() { #else close(wakeFd_.fd); #endif + + cleanup(); } void DBusMainLoop::run(const int64_t& timeoutInterval) { @@ -228,9 +230,9 @@ void DBusMainLoop::doSingleIteration(const int64_t& timeout) { if (!(dispatchSourceIterator->second)->isExecuted_) { (dispatchSourceIterator->second)->mutex_->unlock(); bool contained = false; - for (std::set<DispatchSourceToDispatchStruct*>::iterator dispatchSourceIteratorInner = sourcesToDispatch_.begin(); + for (std::set<std::pair<DispatchPriority, DispatchSourceToDispatchStruct*>>::iterator dispatchSourceIteratorInner = sourcesToDispatch_.begin(); dispatchSourceIteratorInner != sourcesToDispatch_.end(); dispatchSourceIteratorInner++) { - if ((*dispatchSourceIteratorInner)->dispatchSource_ == (dispatchSourceIterator->second)->dispatchSource_) { + if (std::get<1>(*dispatchSourceIteratorInner)->dispatchSource_ == (dispatchSourceIterator->second)->dispatchSource_) { contained = true; break; } @@ -268,9 +270,9 @@ void DBusMainLoop::doSingleIteration(const int64_t& timeout) { if (!(timeoutIterator->second)->isExecuted_) { (timeoutIterator->second)->mutex_->unlock(); bool contained = false; - for (std::set<TimeoutToDispatchStruct*>::iterator timeoutIteratorInner = timeoutsToDispatch_.begin(); + for (std::set<std::pair<DispatchPriority, TimeoutToDispatchStruct*>>::iterator timeoutIteratorInner = timeoutsToDispatch_.begin(); timeoutIteratorInner != timeoutsToDispatch_.end(); timeoutIteratorInner++) { - if ((*timeoutIteratorInner)->timeout_ == (timeoutIterator->second)->timeout_) { + if (std::get<1>(*timeoutIteratorInner)->timeout_ == (timeoutIterator->second)->timeout_) { contained = true; break; } @@ -310,7 +312,7 @@ void DBusMainLoop::doSingleIteration(const int64_t& timeout) { bool contained = false; for (auto watchesIteratorInner = watchesToDispatch_.begin(); watchesIteratorInner != watchesToDispatch_.end(); watchesIteratorInner++) { - if ((*watchesIteratorInner)->watch_ == (watchesIterator->second)->watch_) { + if (std::get<1>(*watchesIteratorInner)->watch_ == (watchesIterator->second)->watch_) { contained = true; break; } @@ -350,20 +352,22 @@ void DBusMainLoop::doSingleIteration(const int64_t& timeout) { bool DBusMainLoop::prepare(const int64_t& timeout) { currentMinimalTimeoutInterval_ = timeout; - { - std::lock_guard<std::mutex> itsLock(dispatchSourcesMutex_); - for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); - dispatchSourceIterator != registeredDispatchSources_.end(); - dispatchSourceIterator++) { + dispatchSourcesMutex_.lock(); + for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); + dispatchSourceIterator != registeredDispatchSources_.end(); + dispatchSourceIterator++) { - int64_t dispatchTimeout = TIMEOUT_INFINITE; - if ((dispatchSourceIterator->second)->dispatchSource_->prepare(dispatchTimeout)) { - sourcesToDispatch_.insert(dispatchSourceIterator->second); - } else if (dispatchTimeout < currentMinimalTimeoutInterval_) { - currentMinimalTimeoutInterval_ = dispatchTimeout; - } + int64_t dispatchTimeout = TIMEOUT_INFINITE; + dispatchSourcesMutex_.unlock(); + if (!(dispatchSourceIterator->second->deleteObject_) && + (dispatchSourceIterator->second)->dispatchSource_->prepare(dispatchTimeout)) { + sourcesToDispatch_.insert(*dispatchSourceIterator); + } else if (dispatchTimeout > 0 && dispatchTimeout < currentMinimalTimeoutInterval_) { + currentMinimalTimeoutInterval_ = dispatchTimeout; } + dispatchSourcesMutex_.lock(); } + dispatchSourcesMutex_.unlock(); int64_t currentContextTime = getCurrentTimeInMs(); @@ -386,7 +390,7 @@ bool DBusMainLoop::prepare(const int64_t& timeout) { // set information that timeout is elapsed (timeoutPriorityRange->second)->timeoutElapsed_ = true; - timeoutsToDispatch_.insert(timeoutPriorityRange->second); + timeoutsToDispatch_.insert(*timeoutPriorityRange); currentMinimalTimeoutInterval_ = TIMEOUT_NONE; } else if (intervalToReady < currentMinimalTimeoutInterval_) { currentMinimalTimeoutInterval_ = intervalToReady; @@ -401,16 +405,18 @@ bool DBusMainLoop::prepare(const int64_t& timeout) { void DBusMainLoop::poll() { int managedFileDescriptorOffset = 0; - - for (auto fileDescriptor = managedFileDescriptors_.begin() + managedFileDescriptorOffset; fileDescriptor != managedFileDescriptors_.end(); ++fileDescriptor) { - (*fileDescriptor).revents = 0; + { + std::lock_guard<std::mutex> itsLock(fileDescriptorsMutex_); + for (auto fileDescriptor = managedFileDescriptors_.begin() + managedFileDescriptorOffset; fileDescriptor != managedFileDescriptors_.end(); ++fileDescriptor) { + (*fileDescriptor).revents = 0; + } } -#ifdef WIN32 - size_t numReadyFileDescriptors = WSAPoll(&managedFileDescriptors_[0], managedFileDescriptors_.size(), -1); +#ifdef WIN32 + int numReadyFileDescriptors = WSAPoll(&managedFileDescriptors_[0], managedFileDescriptors_.size(), int(currentMinimalTimeoutInterval_)); #else - size_t numReadyFileDescriptors = ::poll(&(managedFileDescriptors_[0]), - managedFileDescriptors_.size(), -1); + int numReadyFileDescriptors = ::poll(&(managedFileDescriptors_[0]), + managedFileDescriptors_.size(), int(currentMinimalTimeoutInterval_)); #endif if (!numReadyFileDescriptors) { int64_t currentContextTime = getCurrentTimeInMs(); @@ -435,7 +441,7 @@ void DBusMainLoop::poll() { // set information that timeout is elapsed (timeoutPriorityRange->second)->timeoutElapsed_ = true; - timeoutsToDispatch_.insert(timeoutPriorityRange->second); + timeoutsToDispatch_.insert(*timeoutPriorityRange); } } } @@ -450,7 +456,7 @@ void DBusMainLoop::poll() { } bool DBusMainLoop::check() { -//The first file descriptor always is the loop's wakeup-descriptor (but not for windows anymore). All others need to be linked to a watch. + //The first file descriptor always is the loop's wakeup-descriptor (but not for windows anymore). All others need to be linked to a watch. int managedFileDescriptorOffset = 1; { std::lock_guard<std::mutex> itsLock(fileDescriptorsMutex_); @@ -461,7 +467,7 @@ bool DBusMainLoop::check() { for (auto registeredWatchIterator = registeredWatches_.begin(); registeredWatchIterator != registeredWatches_.end(); registeredWatchIterator++) { - + (registeredWatchIterator->second)->mutex_->lock(); bool deleteObject = (registeredWatchIterator->second)->deleteObject_; (registeredWatchIterator->second)->mutex_->unlock(); @@ -469,23 +475,26 @@ bool DBusMainLoop::check() { if (!deleteObject) { if ((registeredWatchIterator->second)->fd_ == fileDescriptor->fd && fileDescriptor->revents) { - watchesToDispatch_.insert(registeredWatchIterator->second); + watchesToDispatch_.insert(*registeredWatchIterator); } } } } } } - { - std::lock_guard<std::mutex> itsLock(dispatchSourcesMutex_); - for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); - dispatchSourceIterator != registeredDispatchSources_.end(); - ++dispatchSourceIterator) { - if ((dispatchSourceIterator->second)->dispatchSource_->check()) { - sourcesToDispatch_.insert(dispatchSourceIterator->second); - } + + dispatchSourcesMutex_.lock(); + for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); + dispatchSourceIterator != registeredDispatchSources_.end(); + ++dispatchSourceIterator) { + dispatchSourcesMutex_.unlock(); + if (!dispatchSourceIterator->second->deleteObject_&& + dispatchSourceIterator->second->dispatchSource_->check()) { + sourcesToDispatch_.insert(*dispatchSourceIterator); } + dispatchSourcesMutex_.lock(); } + dispatchSourcesMutex_.unlock(); return (!timeoutsToDispatch_.empty() || !watchesToDispatch_.empty() || @@ -497,15 +506,16 @@ void DBusMainLoop::dispatch() { { for (auto timeoutIterator = timeoutsToDispatch_.begin(); timeoutIterator != timeoutsToDispatch_.end(); timeoutIterator++) { - (*timeoutIterator)->mutex_->lock(); - if (!(*timeoutIterator)->deleteObject_) { - (*timeoutIterator)->isExecuted_ = true; - (*timeoutIterator)->mutex_->unlock(); - (*timeoutIterator)->timeout_->dispatch(); - (*timeoutIterator)->mutex_->lock(); - (*timeoutIterator)->isExecuted_ = false; + auto timeoutToDispatchStruct = std::get<1>(*timeoutIterator); + timeoutToDispatchStruct->mutex_->lock(); + if (!timeoutToDispatchStruct->deleteObject_) { + timeoutToDispatchStruct->isExecuted_ = true; + timeoutToDispatchStruct->mutex_->unlock(); + timeoutToDispatchStruct->timeout_->dispatch(); + timeoutToDispatchStruct->mutex_->lock(); + timeoutToDispatchStruct->isExecuted_ = false; } - (*timeoutIterator)->mutex_->unlock(); + timeoutToDispatchStruct->mutex_->unlock(); } timeoutsToDispatch_.clear(); @@ -515,17 +525,18 @@ void DBusMainLoop::dispatch() { { for (auto watchIterator = watchesToDispatch_.begin(); watchIterator != watchesToDispatch_.end(); watchIterator++) { - (*watchIterator)->mutex_->lock(); - if (!(*watchIterator)->deleteObject_) { - (*watchIterator)->isExecuted_ = true; - (*watchIterator)->mutex_->unlock(); - Watch* watch = (*watchIterator)->watch_; - const unsigned int flags = watch->getAssociatedFileDescriptor().events; + auto watchToDispatchStruct = std::get<1>(*watchIterator); + watchToDispatchStruct->mutex_->lock(); + if (!watchToDispatchStruct->deleteObject_) { + watchToDispatchStruct->isExecuted_ = true; + watchToDispatchStruct->mutex_->unlock(); + Watch* watch = watchToDispatchStruct->watch_; + const unsigned int flags = (unsigned int)(watch->getAssociatedFileDescriptor().events); watch->dispatch(flags); - (*watchIterator)->mutex_->lock(); - (*watchIterator)->isExecuted_ = false; + watchToDispatchStruct->mutex_->lock(); + watchToDispatchStruct->isExecuted_ = false; } - (*watchIterator)->mutex_->unlock(); + watchToDispatchStruct->mutex_->unlock(); } watchesToDispatch_.clear(); } @@ -536,15 +547,17 @@ void DBusMainLoop::dispatch() { for (auto dispatchSourceIterator = sourcesToDispatch_.begin(); dispatchSourceIterator != sourcesToDispatch_.end() && !isBroken_; dispatchSourceIterator++) { - (*dispatchSourceIterator)->mutex_->lock(); - if (!(*dispatchSourceIterator)->deleteObject_) { - (*dispatchSourceIterator)->isExecuted_ = true; - (*dispatchSourceIterator)->mutex_->unlock(); - while ((*dispatchSourceIterator)->dispatchSource_->dispatch()); - (*dispatchSourceIterator)->mutex_->lock(); - (*dispatchSourceIterator)->isExecuted_ = false; + auto dispatchSourceToDispatchStruct = std::get<1>(*dispatchSourceIterator); + dispatchSourceToDispatchStruct->mutex_->lock(); + if (!dispatchSourceToDispatchStruct->deleteObject_) { + dispatchSourceToDispatchStruct->isExecuted_ = true; + dispatchSourceToDispatchStruct->mutex_->unlock(); + while(!dispatchSourceToDispatchStruct->deleteObject_ && + dispatchSourceToDispatchStruct->dispatchSource_->dispatch()); + dispatchSourceToDispatchStruct->mutex_->lock(); + dispatchSourceToDispatchStruct->isExecuted_ = false; } - (*dispatchSourceIterator)->mutex_->unlock(); + dispatchSourceToDispatchStruct->mutex_->unlock(); } { sourcesToDispatch_.clear(); @@ -597,6 +610,50 @@ void DBusMainLoop::wakeupAck() { #endif } +void DBusMainLoop::cleanup() { + { + std::lock_guard<std::mutex> itsLock(dispatchSourcesMutex_); + for (auto dispatchSourceIterator = registeredDispatchSources_.begin(); + dispatchSourceIterator != registeredDispatchSources_.end();) { + + delete (dispatchSourceIterator->second)->dispatchSource_; + (dispatchSourceIterator->second)->dispatchSource_ = NULL; + delete (dispatchSourceIterator->second)->mutex_; + (dispatchSourceIterator->second)->mutex_ = NULL; + delete dispatchSourceIterator->second; + dispatchSourceIterator = registeredDispatchSources_.erase(dispatchSourceIterator); + } + } + + { + std::lock_guard<std::mutex> itsLock(timeoutsMutex_); + for (auto timeoutIterator = registeredTimeouts_.begin(); + timeoutIterator != registeredTimeouts_.end();) { + + delete (timeoutIterator->second)->timeout_; + (timeoutIterator->second)->timeout_ = NULL; + delete (timeoutIterator->second)->mutex_; + (timeoutIterator->second)->mutex_ = NULL; + delete timeoutIterator->second; + timeoutIterator = registeredTimeouts_.erase(timeoutIterator); + } + } + + { + std::lock_guard<std::mutex> itsLock(watchesMutex_); + for (auto watchesIterator = registeredWatches_.begin(); + watchesIterator != registeredWatches_.end();) { + + delete (watchesIterator->second)->watch_; + (watchesIterator->second)->watch_ = NULL; + delete (watchesIterator->second)->mutex_; + (watchesIterator->second)->mutex_ = NULL; + delete watchesIterator->second; + watchesIterator = registeredWatches_.erase(watchesIterator); + } + } +} + void DBusMainLoop::registerFileDescriptor( const DBusMainLoopPollFd& fileDescriptor) { std::lock_guard<std::mutex> itsLock(fileDescriptorsMutex_); diff --git a/src/CommonAPI/DBus/DBusMainLoopContext.cpp b/src/CommonAPI/DBus/DBusMainLoopContext.cpp index 1c795ad..5c8afa5 100644 --- a/src/CommonAPI/DBus/DBusMainLoopContext.cpp +++ b/src/CommonAPI/DBus/DBusMainLoopContext.cpp @@ -7,8 +7,12 @@ #include <WinSock2.h> #else #include <poll.h> +#include <unistd.h> #endif +#include <fcntl.h> +#include <cstdio> + #include <chrono> #include <CommonAPI/DBus/DBusMainLoopContext.hpp> @@ -25,7 +29,7 @@ DBusDispatchSource::~DBusDispatchSource() { } bool DBusDispatchSource::prepare(int64_t &_timeout) { - (void)_timeout; + _timeout = -1; return dbusConnection_->isDispatchReady(); } @@ -37,11 +41,46 @@ bool DBusDispatchSource::dispatch() { return dbusConnection_->singleDispatch(); } +DBusMessageDispatchSource::DBusMessageDispatchSource(DBusMessageWatch* watch) : + watch_(watch) { + watch_->addDependentDispatchSource(this); +} + +DBusMessageDispatchSource::~DBusMessageDispatchSource() { + std::unique_lock<std::mutex> itsLock(watchMutex_); + watch_->removeDependentDispatchSource(this); +} + +bool DBusMessageDispatchSource::prepare(int64_t& timeout) { + std::unique_lock<std::mutex> itsLock(watchMutex_); + timeout = -1; + return !watch_->emptyMsgQueue(); +} + +bool DBusMessageDispatchSource::check() { + std::unique_lock<std::mutex> itsLock(watchMutex_); + return !watch_->emptyMsgQueue(); +} + +bool DBusMessageDispatchSource::dispatch() { + std::unique_lock<std::mutex> itsLock(watchMutex_); + if (!watch_->emptyMsgQueue()) { + auto queueEntry = watch_->frontMsgQueue(); + watch_->popMsgQueue(); + watch_->processMsgQueueEntry(queueEntry); + } -DBusWatch::DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext): + return !watch_->emptyMsgQueue(); +} + +DBusWatch::DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext, + std::weak_ptr<DBusConnection>& dbusConnection): libdbusWatch_(libdbusWatch), - mainLoopContext_(mainLoopContext) { - assert(libdbusWatch_); + mainLoopContext_(mainLoopContext), + dbusConnection_(dbusConnection) { + if (NULL == libdbusWatch_) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " libdbusWatch_ == NULL"); + } } bool DBusWatch::isReadyToBeWatched() { @@ -52,11 +91,8 @@ void DBusWatch::startWatching() { if(!dbus_watch_get_enabled(libdbusWatch_)) stopWatching(); unsigned int channelFlags_ = dbus_watch_get_flags(libdbusWatch_); -#ifdef WIN32 short int pollFlags = 0; -#else - short int pollFlags = POLLERR | POLLHUP; -#endif + if(channelFlags_ & DBUS_WATCH_READABLE) { pollFlags |= POLLIN; } @@ -76,8 +112,11 @@ void DBusWatch::startWatching() { pollFileDescriptor_.revents = 0; auto lockedContext = mainLoopContext_.lock(); - assert(lockedContext); - lockedContext->registerWatch(this); + if (NULL == lockedContext) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " lockedContext == NULL"); + } else { + lockedContext->registerWatch(this); + } } void DBusWatch::stopWatching() { @@ -120,10 +159,15 @@ void DBusWatch::dispatch(unsigned int eventFlags) { ((eventFlags & POLLERR) >> 1) | ((eventFlags & POLLHUP) >> 1); #endif - dbus_bool_t response = dbus_watch_handle(libdbusWatch_, dbusWatchFlags); - - if (!response) { - printf("dbus_watch_handle returned FALSE!"); + std::shared_ptr<DBusConnection> itsConnection = dbusConnection_.lock(); + if(itsConnection) { + if(itsConnection->setDispatching(true)) { + dbus_bool_t response = dbus_watch_handle(libdbusWatch_, dbusWatchFlags); + if (!response) { + printf("dbus_watch_handle returned FALSE!"); + } + itsConnection->setDispatching(false); + } } } @@ -135,6 +179,244 @@ void DBusWatch::addDependentDispatchSource(DispatchSource* dispatchSource) { dependentDispatchSources_.push_back(dispatchSource); } +void DBusMessageWatch::MsgReplyQueueEntry::process(std::shared_ptr<DBusConnection> _connection) { + _connection->dispatchDBusMessageReply(message_, replyAsyncHandler_); +} + +void DBusMessageWatch::MsgReplyQueueEntry::clear() { + delete replyAsyncHandler_; +} + +void DBusMessageWatch::MsgQueueEntry::clear() { + +} + +DBusMessageWatch::DBusMessageWatch(std::shared_ptr<DBusConnection> _connection) : pipeValue_(4) { +#ifdef WIN32 + std::string pipeName = "\\\\.\\pipe\\CommonAPI-DBus-"; + + UUID uuid; + CHAR* uuidString = NULL; + UuidCreate(&uuid); + UuidToString(&uuid, (RPC_CSTR*)&uuidString); + pipeName += uuidString; + RpcStringFree((RPC_CSTR*)&uuidString); + + HANDLE hPipe = ::CreateNamedPipe( + pipeName.c_str(), + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + 1, + 4096, + 4096, + 100, + nullptr); + + if (hPipe == INVALID_HANDLE_VALUE) { + if (GetLastError() != ERROR_PIPE_BUSY) + { + printf("Could not open pipe %d\n", GetLastError()); + } + + // All pipe instances are busy, so wait for sometime. + else if (!WaitNamedPipe(pipeName.c_str(), NMPWAIT_USE_DEFAULT_WAIT)) + { + printf("Could not open pipe: wait timed out.\n"); + } + } + + HANDLE hPipe2 = CreateFile( + pipeName.c_str(), // pipe name + GENERIC_READ | // read and write access + GENERIC_WRITE, + 0, // no sharing + NULL, // default security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file + + if (hPipe2 == INVALID_HANDLE_VALUE) { + if (GetLastError() != ERROR_PIPE_BUSY) + { + printf("Could not open pipe2 %d\n", GetLastError()); + } + + // All pipe instances are busy, so wait for sometime. + else if (!WaitNamedPipe(pipeName.c_str(), NMPWAIT_USE_DEFAULT_WAIT)) + { + printf("Could not open pipe2: wait timed out.\n"); + } + } + + pipeFileDescriptors_[0] = (int)hPipe; + pipeFileDescriptors_[1] = (int)hPipe2; + + wsaEvent_ = ::CreateEventW(nullptr, TRUE, FALSE, nullptr); + + if (wsaEvent_ == WSA_INVALID_EVENT) { + printf("Invalid Event Created!\n"); + } + + ov = { 0 }; + ov.hEvent = wsaEvent_; + + BOOL retVal = ::ConnectNamedPipe(hPipe, &ov); + + if (retVal == 0) { + int error = GetLastError(); + + if (error != 535) { + printf("ERROR: ConnectNamedPipe failed with (%d)\n", error); + } + } +#else + if(pipe2(pipeFileDescriptors_, O_NONBLOCK) == -1) { + std::perror(__func__); + } +#endif + pollFileDescriptor_.fd = pipeFileDescriptors_[0]; + pollFileDescriptor_.events = POLLIN; + + connection_ = _connection; +} + +DBusMessageWatch::~DBusMessageWatch() { +#ifdef WIN32 + BOOL retVal = DisconnectNamedPipe((HANDLE)pipeFileDescriptors_[0]); + + if (!retVal) { + printf(TEXT("DisconnectNamedPipe failed. GLE=%d\n"), GetLastError()); + } + + retVal = CloseHandle((HANDLE)pipeFileDescriptors_[0]); + + if (!retVal) { + printf(TEXT("CloseHandle failed. GLE=%d\n"), GetLastError()); + } + + retVal = CloseHandle((HANDLE)pipeFileDescriptors_[1]); + + if (!retVal) { + printf(TEXT("CloseHandle2 failed. GLE=%d\n"), GetLastError()); + } +#else + close(pipeFileDescriptors_[0]); + close(pipeFileDescriptors_[1]); +#endif + + std::unique_lock<std::mutex> itsLock(msgQueueMutex_); + while(!msgQueue_.empty()) { + auto queueEntry = msgQueue_.front(); + msgQueue_.pop(); + queueEntry->clear(); + } +} + +void DBusMessageWatch::dispatch(unsigned int) { +} + +const pollfd& DBusMessageWatch::getAssociatedFileDescriptor() { + return pollFileDescriptor_; +} + +#ifdef WIN32 +const HANDLE& DBusMessageWatch::getAssociatedEvent() { + return wsaEvent_; +} +#endif + +const std::vector<DispatchSource*>& DBusMessageWatch::getDependentDispatchSources() { + return dependentDispatchSources_; +} + +void DBusMessageWatch::addDependentDispatchSource(CommonAPI::DispatchSource* _dispatchSource) { + dependentDispatchSources_.push_back(_dispatchSource); +} + +void DBusMessageWatch::removeDependentDispatchSource(CommonAPI::DispatchSource* _dispatchSource) { + std::vector<CommonAPI::DispatchSource*>::iterator it; + + for (it = dependentDispatchSources_.begin(); it != dependentDispatchSources_.end(); it++) { + if ( (*it) == _dispatchSource ) { + dependentDispatchSources_.erase(it); + break; + } + } +} + +void DBusMessageWatch::pushMsgQueue(std::shared_ptr<MsgQueueEntry> _queueEntry) { + std::unique_lock<std::mutex> itsLock(msgQueueMutex_); + msgQueue_.push(_queueEntry); + +#ifdef WIN32 + char writeValue[sizeof(pipeValue_)]; + *reinterpret_cast<int*>(writeValue) = pipeValue_; + DWORD cbWritten; + + int fSuccess = WriteFile( + (HANDLE)pipeFileDescriptors_[1], // pipe handle + writeValue, // message + sizeof(pipeValue_), // message length + &cbWritten, // bytes written + &ov); // overlapped + + if (!fSuccess) + { + printf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()); + } +#else + if(write(pipeFileDescriptors_[1], &pipeValue_, sizeof(pipeValue_)) == -1) { + std::perror(__func__); + } +#endif +} + +void DBusMessageWatch::popMsgQueue() { + std::unique_lock<std::mutex> itsLock(msgQueueMutex_); + +#ifdef WIN32 + char readValue[sizeof(pipeValue_)]; + DWORD cbRead; + + int fSuccess = ReadFile( + (HANDLE)pipeFileDescriptors_[0], // pipe handle + readValue, // buffer to receive reply + sizeof(pipeValue_), // size of buffer + &cbRead, // number of bytes read + &ov); // overlapped + + if (!fSuccess) + { + printf(TEXT("ReadFile to pipe failed. GLE=%d\n"), GetLastError()); + } +#else + int readValue = 0; + if(read(pipeFileDescriptors_[0], &readValue, sizeof(readValue)) == -1) { + std::perror(__func__); + } +#endif + + msgQueue_.pop(); +} + +std::shared_ptr<DBusMessageWatch::MsgQueueEntry> DBusMessageWatch::frontMsgQueue() { + std::unique_lock<std::mutex> itsLock(msgQueueMutex_); + + return msgQueue_.front(); +} + +bool DBusMessageWatch::emptyMsgQueue() { + std::unique_lock<std::mutex> itsLock(msgQueueMutex_); + + return msgQueue_.empty(); +} + +void DBusMessageWatch::processMsgQueueEntry(std::shared_ptr<DBusMessageWatch::MsgQueueEntry> _queueEntry) { + std::shared_ptr<DBusConnection> itsConnection = connection_.lock(); + if(itsConnection) { + _queueEntry->process(itsConnection); + } +} DBusTimeout::DBusTimeout(::DBusTimeout* libdbusTimeout, std::weak_ptr<MainLoopContext>& mainLoopContext) : dueTimeInMs_(TIMEOUT_INFINITE), @@ -148,9 +430,12 @@ bool DBusTimeout::isReadyToBeMonitored() { void DBusTimeout::startMonitoring() { auto lockedContext = mainLoopContext_.lock(); - assert(lockedContext); - recalculateDueTime(); - lockedContext->registerTimeoutSource(this); + if (NULL == lockedContext) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " lockedContext == NULL"); + } else { + recalculateDueTime(); + lockedContext->registerTimeoutSource(this); + } } void DBusTimeout::stopMonitoring() { @@ -177,7 +462,7 @@ int64_t DBusTimeout::getReadyTime() const { void DBusTimeout::recalculateDueTime() { if(dbus_timeout_get_enabled(libdbusTimeout_)) { - unsigned int intervalInMs = dbus_timeout_get_interval(libdbusTimeout_); + int intervalInMs = dbus_timeout_get_interval(libdbusTimeout_); dueTimeInMs_ = getCurrentTimeInMs() + intervalInMs; } else { dueTimeInMs_ = TIMEOUT_INFINITE; diff --git a/src/CommonAPI/DBus/DBusMessage.cpp b/src/CommonAPI/DBus/DBusMessage.cpp index 5a6a549..09199dc 100644 --- a/src/CommonAPI/DBus/DBusMessage.cpp +++ b/src/CommonAPI/DBus/DBusMessage.cpp @@ -3,9 +3,9 @@ // 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 <cassert> #include <cstring> +#include <CommonAPI/Logger.hpp> #include <CommonAPI/DBus/DBusAddress.hpp> #include <CommonAPI/DBus/DBusMessage.hpp> @@ -21,8 +21,10 @@ DBusMessage::DBusMessage(::DBusMessage *_message) { } DBusMessage::DBusMessage(::DBusMessage *_message, bool reference) { - assert(_message); - message_ = (reference ? dbus_message_ref(message_) : _message); + if (NULL == _message) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " NULL _message"); + } + message_ = (_message != nullptr ? (reference ? dbus_message_ref(message_) : _message) : nullptr); } DBusMessage::DBusMessage(const DBusMessage &_source) { @@ -88,7 +90,9 @@ DBusMessage::createMethodCall( ::DBusMessage *methodCall = dbus_message_new_method_call( service.c_str(), path.c_str(), interface.c_str(), _method.c_str()); - assert(methodCall); + if (NULL == methodCall) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_message_new_method_call() returned NULL"); + } if ("" != _signature) dbus_message_set_signature(methodCall, _signature.c_str()); @@ -99,7 +103,9 @@ DBusMessage::createMethodCall( DBusMessage DBusMessage::createMethodReturn(const std::string &_signature) const { ::DBusMessage *methodReturn = dbus_message_new_method_return(message_); - assert(methodReturn); + if (NULL == methodReturn) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_message_new_method_return() returned NULL"); + } if ("" != _signature) dbus_message_set_signature(methodReturn, _signature.c_str()); @@ -113,7 +119,9 @@ DBusMessage::createMethodError( ::DBusMessage *methodError = dbus_message_new_error(message_, _code.c_str(), _info.c_str()); - assert(methodError); + if (NULL == methodError) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_message_new_error() returned NULL"); + } return DBusMessage(methodError, false); } @@ -125,7 +133,9 @@ DBusMessage::createSignal( ::DBusMessage *messageSignal = dbus_message_new_signal(_path.c_str(), _interface.c_str(), _signal.c_str()); - assert(messageSignal); + if (NULL == messageSignal) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbus_message_new_signal() returned NULL"); + } if ("" != _signature) dbus_message_set_signature(messageSignal, _signature.c_str()); @@ -160,7 +170,9 @@ DBusMessage::getSignature() const { const char * DBusMessage::getError() const { - assert(isErrorType()); + if (!isErrorType()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " !isErrorType"); + } return dbus_message_get_error_name(message_); } @@ -176,38 +188,53 @@ uint32_t DBusMessage::getSerial() const { bool DBusMessage::hasObjectPath(const char *_path) const { const char *path = getObjectPath(); + if (NULL == _path) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _path == NULL"); + } + if (NULL == path) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " path == NULL"); + } - assert(_path); - assert(path); - - return (!strcmp(path, _path)); + return (((NULL != path) && (NULL != _path))? !strcmp(path, _path) : false); } bool DBusMessage::hasInterfaceName(const char *_interface) const { const char *interface = getInterface(); - assert(_interface); - assert(interface); + if (NULL == _interface) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _interface == NULL"); + } + if (NULL == interface) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " interface == NULL"); + } - return (!strcmp(interface, _interface)); + return (((NULL != interface) && (NULL != _interface))? !strcmp(interface, _interface) : false); } bool DBusMessage::hasMemberName(const char *_member) const { const char *member = getMember(); - assert(_member); - assert(member); + if (NULL == _member) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _member == NULL"); + } + if (NULL == member) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " member == NULL"); + } - return (!strcmp(member, _member)); + return (((NULL != member) && (NULL != _member))? !strcmp(member, _member) : false); } bool DBusMessage::hasSignature(const char *_signature) const { const char *signature = getSignature(); - assert(_signature); - assert(signature); + if (NULL == _signature) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " _signature == NULL"); + } + if (NULL == signature) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signature == NULL"); + } - return (!strcmp(signature, _signature)); + return (((NULL != signature) && (NULL != _signature))? !strcmp(signature, _signature) : false); } DBusMessage::Type DBusMessage::getType() const { @@ -235,6 +262,10 @@ bool DBusMessage::setDestination(const char *_destination) return 0 != dbus_message_set_destination(message_, _destination); } +void DBusMessage::setSerial(const unsigned int _serial) const { + dbus_message_set_serial(message_, _serial); +} + bool DBusMessage::hasObjectPath(const std::string &_path) const { return hasObjectPath(_path.c_str()); } diff --git a/src/CommonAPI/DBus/DBusObjectManager.cpp b/src/CommonAPI/DBus/DBusObjectManager.cpp index 3d10c6d..c9484fd 100644 --- a/src/CommonAPI/DBus/DBusObjectManager.cpp +++ b/src/CommonAPI/DBus/DBusObjectManager.cpp @@ -3,9 +3,9 @@ // 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 <cassert> #include <sstream> #include <unordered_set> +#include <algorithm> #include <dbus/dbus-protocol.h> @@ -24,16 +24,15 @@ namespace DBus { DBusObjectManager::DBusObjectManager(const std::shared_ptr<DBusProxyConnection>& dbusConnection): rootDBusObjectManagerStub_(new DBusObjectManagerStub("/", dbusConnection)), dbusConnection_(dbusConnection){ - if (!dbusConnection->isObjectPathMessageHandlerSet()) { dbusConnection->setObjectPathMessageHandler( std::bind(&DBusObjectManager::handleMessage, this, std::placeholders::_1)); } dbusConnection->registerObjectPath("/"); - dbusRegisteredObjectsTable_.insert({ + addToRegisteredObjectsTable( DBusInterfaceHandlerPath("/", DBusObjectManagerStub::getInterfaceName()), - rootDBusObjectManagerStub_ }); + rootDBusObjectManagerStub_ ); } DBusObjectManager::~DBusObjectManager() { @@ -76,7 +75,9 @@ bool DBusObjectManager::registerDBusStubAdapter(std::shared_ptr<DBusStubAdapter> dbusStubAdapter->getDBusConnection() ); auto insertResult = managerStubs_.insert( {dbusStubAdapterObjectPath, {newManagerStub, 1} }); - assert(insertResult.second); + if (!insertResult.second) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " insertResult.second == nullptr"); + } managerStubIterator = insertResult.first; } else { uint32_t& countReferencesToManagerStub = std::get<1>(managerStubIterator->second); @@ -84,15 +85,21 @@ bool DBusObjectManager::registerDBusStubAdapter(std::shared_ptr<DBusStubAdapter> } std::shared_ptr<DBusObjectManagerStub> dbusObjectManagerStub = std::get<0>(managerStubIterator->second); - assert(dbusObjectManagerStub); - isRegistrationSuccessful = addDBusInterfaceHandler( - { dbusStubAdapterObjectPath, dbusObjectManagerStub->getInterfaceName() }, dbusObjectManagerStub); + if (!dbusObjectManagerStub) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusObjectManagerStub == nullptr"); + isRegistrationSuccessful = false; + } else { + isRegistrationSuccessful = addDBusInterfaceHandler( + { dbusStubAdapterObjectPath, dbusObjectManagerStub->getInterfaceName() }, dbusObjectManagerStub); + } if (!isRegistrationSuccessful) { const bool isDBusStubAdapterRemoved = removeDBusInterfaceHandler(dbusStubAdapterHandlerPath, dbusStubAdapter); - assert(isDBusStubAdapterRemoved); - (void)isDBusStubAdapterRemoved; + if (!isDBusStubAdapterRemoved) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " removeDBusInterfaceHandler failed path: ", + dbusStubAdapterObjectPath, " interface: ", dbusStubAdapterInterfaceName); + } } } @@ -119,20 +126,32 @@ bool DBusObjectManager::unregisterDBusStubAdapter(std::shared_ptr<DBusStubAdapte if (isDeregistrationSuccessful && dbusStubAdapter->isManaging()) { auto managerStubIterator = managerStubs_.find(dbusStubAdapterObjectPath); - assert(managerStubIterator != managerStubs_.end()); - - std::shared_ptr<DBusObjectManagerStub> dbusObjectManagerStub = std::get<0>(managerStubIterator->second); - assert(dbusObjectManagerStub); - - uint32_t& countReferencesToManagerStub = std::get<1>(managerStubIterator->second); - assert(countReferencesToManagerStub > 0); - --countReferencesToManagerStub; + if (managerStubs_.end() == managerStubIterator) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unknown DBusStubAdapter ", dbusStubAdapterObjectPath); + isDeregistrationSuccessful = false; + } else { + std::shared_ptr<DBusObjectManagerStub> dbusObjectManagerStub = std::get<0>(managerStubIterator->second); + if (!dbusObjectManagerStub) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusObjectManagerStub == nullptr ", dbusStubAdapterObjectPath); + isDeregistrationSuccessful = false; + } else { + uint32_t& countReferencesToManagerStub = std::get<1>(managerStubIterator->second); + if (0 == countReferencesToManagerStub) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " reference count == 0"); + isDeregistrationSuccessful = false; + } else { + --countReferencesToManagerStub; + } - if (countReferencesToManagerStub == 0) { - isDeregistrationSuccessful = removeDBusInterfaceHandler( - { dbusStubAdapterObjectPath, dbusObjectManagerStub->getInterfaceName() }, dbusObjectManagerStub); - managerStubs_.erase(managerStubIterator); - assert(isDeregistrationSuccessful); + if (countReferencesToManagerStub == 0) { + isDeregistrationSuccessful = removeDBusInterfaceHandler( + { dbusStubAdapterObjectPath, dbusObjectManagerStub->getInterfaceName() }, dbusObjectManagerStub); + managerStubs_.erase(managerStubIterator); + if (!isDeregistrationSuccessful) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unregister failed ", dbusStubAdapterObjectPath, " interface: ", dbusObjectManagerStub->getInterfaceName()); + } + } + } } } @@ -152,9 +171,9 @@ bool DBusObjectManager::unregisterDBusStubAdapter(std::shared_ptr<DBusStubAdapte bool DBusObjectManager::exportManagedDBusStubAdapter(const std::string& parentObjectPath, std::shared_ptr<DBusStubAdapter> dbusStubAdapter) { auto foundManagerStubIterator = managerStubs_.find(parentObjectPath); - assert(foundManagerStubIterator != managerStubs_.end()); - - if (std::get<0>(foundManagerStubIterator->second)->exportManagedDBusStubAdapter(dbusStubAdapter)) { + if (managerStubs_.end() == foundManagerStubIterator) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no manager stub found for ", parentObjectPath); + } else if (std::get<0>(foundManagerStubIterator->second)->exportManagedDBusStubAdapter(dbusStubAdapter)) { // TODO Check if other handling is necessary? return true; } @@ -180,8 +199,12 @@ bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) { const char* objectPath = dbusMessage.getObjectPath(); const char* interfaceName = dbusMessage.getInterface(); - assert(objectPath); - assert(interfaceName); + if (NULL == objectPath) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " objectPath == NULL"); + } + if (NULL == interfaceName) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " interfaceName == NULL"); + } DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName); @@ -191,8 +214,10 @@ bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) { bool dbusMessageHandled = false; if (foundDBusInterfaceHandler) { - std::shared_ptr<DBusInterfaceHandler> dbusStubAdapterBase = handlerIterator->second; + std::shared_ptr<DBusInterfaceHandler> dbusStubAdapterBase = handlerIterator->second.front(); + objectPathLock_.unlock(); dbusMessageHandled = dbusStubAdapterBase->onInterfaceDBusMessage(dbusMessage); + return dbusMessageHandled; } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.Introspectable")) { dbusMessageHandled = onIntrospectableInterfaceDBusMessage(dbusMessage); } @@ -207,18 +232,20 @@ bool DBusObjectManager::addDBusInterfaceHandler(const DBusInterfaceHandlerPath& const bool isDBusInterfaceHandlerAlreadyAdded = (dbusRegisteredObjectsTableIter != dbusRegisteredObjectsTable_.end()); if (isDBusInterfaceHandlerAlreadyAdded) { - //If another ObjectManager or a freedesktop properties stub is to be registered, - //you can go on and just use the first one. - if (dbusInterfaceHandlerPath.second == "org.freedesktop.DBus.ObjectManager" || - dbusInterfaceHandlerPath.second == "org.freedesktop.DBus.Properties") { - return true; + + auto handler = find(dbusRegisteredObjectsTableIter->second.begin(), dbusRegisteredObjectsTableIter->second.end(), dbusInterfaceHandler); + if (handler != dbusRegisteredObjectsTableIter->second.end()) { + //If another ObjectManager or a freedesktop properties stub is to be registered, + //you can go on and just use the first one. + if (dbusInterfaceHandlerPath.second == "org.freedesktop.DBus.ObjectManager" || + dbusInterfaceHandlerPath.second == "org.freedesktop.DBus.Properties") { + return true; + } + return false; } - return false; } - auto insertResult = dbusRegisteredObjectsTable_.insert({ dbusInterfaceHandlerPath, dbusInterfaceHandler }); - const bool insertSuccess = insertResult.second; - + auto insertSuccess = addToRegisteredObjectsTable(dbusInterfaceHandlerPath, dbusInterfaceHandler); return insertSuccess; } @@ -228,10 +255,15 @@ bool DBusObjectManager::removeDBusInterfaceHandler(const DBusInterfaceHandlerPat const bool isDBusInterfaceHandlerAdded = (dbusRegisteredObjectsTableIter != dbusRegisteredObjectsTable_.end()); if (isDBusInterfaceHandlerAdded) { - auto registeredDBusStubAdapter = dbusRegisteredObjectsTableIter->second; - assert(registeredDBusStubAdapter == dbusInterfaceHandler); - (void)dbusInterfaceHandler; - dbusRegisteredObjectsTable_.erase(dbusRegisteredObjectsTableIter); + auto registeredDBusStubAdapter = find(dbusRegisteredObjectsTableIter->second.begin(), dbusRegisteredObjectsTableIter->second.end(), dbusInterfaceHandler); + if (dbusRegisteredObjectsTableIter->second.end() == registeredDBusStubAdapter) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no stub adapter registered for ", dbusInterfaceHandlerPath.first, " ", dbusInterfaceHandlerPath.second); + } else { + dbusRegisteredObjectsTableIter->second.erase(registeredDBusStubAdapter); + if (dbusRegisteredObjectsTableIter->second.empty()) { + dbusRegisteredObjectsTable_.erase(dbusRegisteredObjectsTableIter); + } + } } return isDBusInterfaceHandlerAdded; @@ -261,7 +293,7 @@ bool DBusObjectManager::onIntrospectableInterfaceDBusMessage(const DBusMessage& const DBusInterfaceHandlerPath& handlerPath = registeredObjectsIterator.first; const std::string& dbusObjectPath = handlerPath.first; const std::string& dbusInterfaceName = handlerPath.second; - std::shared_ptr<DBusInterfaceHandler> dbusStubAdapterBase = registeredObjectsIterator.second; + std::shared_ptr<DBusInterfaceHandler> dbusStubAdapterBase = registeredObjectsIterator.second.front(); std::vector<std::string> elems = CommonAPI::split(dbusObjectPath, '/'); if (dbusMessage.hasObjectPath(dbusObjectPath)) { @@ -329,5 +361,30 @@ std::shared_ptr<DBusObjectManagerStub> DBusObjectManager::getRootDBusObjectManag return rootDBusObjectManagerStub_; } +bool DBusObjectManager::addToRegisteredObjectsTable(DBusInterfaceHandlerPath ifpath, std::shared_ptr<DBusInterfaceHandler> handler) { + auto handlerRecord = dbusRegisteredObjectsTable_.find(ifpath); + if (handlerRecord == dbusRegisteredObjectsTable_.end()) { + // not found, create and add entry + dbusRegisteredObjectsTable_.insert({ + ifpath, + std::vector<std::shared_ptr<DBusInterfaceHandler>>({handler}) + }); + } + else { + // found. search through vector to find the handler + std::vector<std::shared_ptr<DBusInterfaceHandler>> handlerList = handlerRecord->second; + auto adapter = find(handlerList.begin(), handlerList.end(), handler); + if (adapter != handlerList.end()) { + // found; don't add + return false; + } + else { + handlerList.push_back(handler); + handlerRecord->second = handlerList; + } + } + return true; +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusObjectManagerStub.cpp b/src/CommonAPI/DBus/DBusObjectManagerStub.cpp index 7516994..20bbf1d 100644 --- a/src/CommonAPI/DBus/DBusObjectManagerStub.cpp +++ b/src/CommonAPI/DBus/DBusObjectManagerStub.cpp @@ -3,9 +3,8 @@ // 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 <cassert> #include <vector> - +#include <algorithm> #include <CommonAPI/DBus/DBusObjectManagerStub.hpp> #include <CommonAPI/DBus/DBusOutputStream.hpp> #include <CommonAPI/DBus/DBusStubAdapter.hpp> @@ -18,9 +17,15 @@ DBusObjectManagerStub::DBusObjectManagerStub(const std::string& dbusObjectPath, const std::shared_ptr<DBusProxyConnection>& dbusConnection) : dbusObjectPath_(dbusObjectPath), dbusConnection_(dbusConnection) { - assert(!dbusObjectPath.empty()); - assert(dbusObjectPath[0] == '/'); - assert(dbusConnection); + if (dbusObjectPath.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty _path"); + } + if ('/' != dbusObjectPath[0]) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid _path ", dbusObjectPath); + } + if (!dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid _connection"); + } } DBusObjectManagerStub::~DBusObjectManagerStub() { @@ -29,21 +34,33 @@ DBusObjectManagerStub::~DBusObjectManagerStub() { for (auto& dbusInterfaceIterator : registeredDBusInterfacesMap) { auto managedDBusStubAdapter = dbusInterfaceIterator.second; - auto managedDBusStubAdapterServiceAddress = managedDBusStubAdapter->getDBusAddress(); #ifdef COMMONAPI_TODO - const bool isServiceUnregistered = DBusServicePublisher::getInstance()->unregisterManagedService( - managedDBusStubAdapterServiceAddress); - assert(isServiceUnregistered); + for (auto& adapterIterator : dbusInterfaceIterator.second) { + auto managedDBusStubAdapterServiceAddress = adapterIterator->getDBusAddress(); + + const bool isServiceUnregistered = DBusServicePublisher::getInstance()->unregisterManagedService( + managedDBusStubAdapterServiceAddress); + if (!isServiceUnregistered) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " service still registered ", managedDBusStubAdapterServiceAddress.getService()); + } #endif } } } bool DBusObjectManagerStub::exportManagedDBusStubAdapter(std::shared_ptr<DBusStubAdapter> managedDBusStubAdapter) { - assert(managedDBusStubAdapter); + if (!managedDBusStubAdapter) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "managedDBusStubAdapter == nullptr"); + return false; + } - std::lock_guard<std::mutex> dbusObjectManagerStubLock(dbusObjectManagerStubLock_); + // if already registered, return true. + const bool alreadyExported = isDBusStubAdapterExported(managedDBusStubAdapter); + if (alreadyExported) { + return true; + } + std::lock_guard<std::mutex> dbusObjectManagerStubLock(dbusObjectManagerStubLock_); const bool isRegistrationSuccessful = registerDBusStubAdapter(managedDBusStubAdapter); if (!isRegistrationSuccessful) { return false; @@ -63,7 +80,10 @@ bool DBusObjectManagerStub::exportManagedDBusStubAdapter(std::shared_ptr<DBusStu } bool DBusObjectManagerStub::unexportManagedDBusStubAdapter(std::shared_ptr<DBusStubAdapter> managedDBusStubAdapter) { - assert(managedDBusStubAdapter); + if (!managedDBusStubAdapter) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "managedDBusStubAdapter == nullptr"); + return false; + } std::lock_guard<std::mutex> dbusObjectManagerStubLock(dbusObjectManagerStubLock_); @@ -86,7 +106,10 @@ bool DBusObjectManagerStub::unexportManagedDBusStubAdapter(std::shared_ptr<DBusS } bool DBusObjectManagerStub::isDBusStubAdapterExported(std::shared_ptr<DBusStubAdapter> dbusStubAdapter) { - assert(dbusStubAdapter); + if (!dbusStubAdapter) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "dbusStubAdapter == nullptr"); + return false; + } const auto& dbusObjectPath = dbusStubAdapter->getDBusAddress().getObjectPath(); const auto& dbusInterfaceName = dbusStubAdapter->getDBusAddress().getInterface(); @@ -103,13 +126,15 @@ bool DBusObjectManagerStub::isDBusStubAdapterExported(std::shared_ptr<DBusStubAd auto& registeredDBusInterfacesMap = registeredDBusObjectPathIterator->second; const auto& registeredDBusInterfaceIterator = registeredDBusInterfacesMap.find(dbusInterfaceName); const bool isRegisteredDBusInterfaceName = (registeredDBusInterfaceIterator != registeredDBusInterfacesMap.end()); - - if (isRegisteredDBusInterfaceName) { - auto registeredDBusStubAdapter = registeredDBusInterfaceIterator->second; - assert(registeredDBusStubAdapter == dbusStubAdapter); + if (!isRegisteredDBusInterfaceName) { + return false; } - return isRegisteredDBusInterfaceName; + const auto& registeredDBusStubAdapterList = registeredDBusInterfaceIterator->second; + auto registeredDBusStubAdapter = find(registeredDBusStubAdapterList.begin(), registeredDBusStubAdapterList.end(), dbusStubAdapter); + + return registeredDBusStubAdapter != registeredDBusStubAdapterList.end(); + } bool DBusObjectManagerStub::registerDBusStubAdapter(std::shared_ptr<DBusStubAdapter> dbusStubAdapter) { @@ -125,12 +150,27 @@ bool DBusObjectManagerStub::registerDBusStubAdapter(std::shared_ptr<DBusStubAdap const bool isDBusInterfaceAlreadyRegistered = (registeredDBusInterfaceIterator != registeredDBusInterfacesMap.end()); if (!isDBusInterfaceAlreadyRegistered) { - const auto& insertResult = registeredDBusInterfacesMap.insert({ dbusInterfaceName, dbusStubAdapter }); + const auto& insertResult = registeredDBusInterfacesMap.insert( + { dbusInterfaceName, + std::vector<std::shared_ptr<DBusStubAdapter>>({dbusStubAdapter})}); isRegisterationSuccessful = insertResult.second; } + else { + // add to existing interface + auto adapterList = registeredDBusInterfaceIterator->second; + if (find(adapterList.begin(), adapterList.end(), dbusStubAdapter) == adapterList.end()) { + adapterList.push_back(dbusStubAdapter); + registeredDBusInterfaceIterator->second = adapterList; + isRegisterationSuccessful = true; + } + else { + // already registered + isRegisterationSuccessful = false; + } + } } else { const auto& insertResult = registeredDBusObjectPathsMap_.insert({ - dbusObjectPath, DBusInterfacesMap({{ dbusInterfaceName, dbusStubAdapter }}) + dbusObjectPath, DBusInterfacesMap({{ dbusInterfaceName, std::vector<std::shared_ptr<DBusStubAdapter>>({dbusStubAdapter}) }}) }); isRegisterationSuccessful = insertResult.second; } @@ -156,23 +196,37 @@ bool DBusObjectManagerStub::unregisterDBusStubAdapter(std::shared_ptr<DBusStubAd return false; } - auto registeredDBusStubAdapter = registeredDBusInterfaceIterator->second; - assert(registeredDBusStubAdapter == dbusStubAdapter); - - registeredDBusInterfacesMap.erase(registeredDBusInterfaceIterator); + auto& registeredAdapterList = registeredDBusInterfaceIterator->second; + auto adapter = find (registeredAdapterList.begin(), registeredAdapterList.end(), dbusStubAdapter); - if (registeredDBusInterfacesMap.empty()) { - registeredDBusObjectPathsMap_.erase(registeredDBusObjectPathIterator); + if (registeredAdapterList.end() == adapter) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " stub adapter not registered ", dbusObjectPath, " interface: ", dbusInterfaceName); + return false; } + registeredAdapterList.erase(adapter); + + if (registeredAdapterList.empty()) { + registeredDBusInterfacesMap.erase(registeredDBusInterfaceIterator); + + if (registeredDBusInterfacesMap.empty()) { + registeredDBusObjectPathsMap_.erase(registeredDBusObjectPathIterator); + } + } return true; } bool DBusObjectManagerStub::emitInterfacesAddedSignal(std::shared_ptr<DBusStubAdapter> dbusStubAdapter, const std::shared_ptr<DBusProxyConnection>& dbusConnection) const { - assert(dbusConnection); - assert(dbusConnection->isConnected()); + if (!dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusConnection == nullptr"); + return false; + } + if (!dbusConnection->isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " not connected"); + return false; + } const auto& dbusStubObjectPath = dbusStubAdapter->getDBusAddress().getObjectPath(); const auto& dbusStubInterfaceName = dbusStubAdapter->getDBusAddress().getInterface(); @@ -200,8 +254,14 @@ bool DBusObjectManagerStub::emitInterfacesAddedSignal(std::shared_ptr<DBusStubAd bool DBusObjectManagerStub::emitInterfacesRemovedSignal(std::shared_ptr<DBusStubAdapter> dbusStubAdapter, const std::shared_ptr<DBusProxyConnection>& dbusConnection) const { - assert(dbusConnection); - assert(dbusConnection->isConnected()); + if (!dbusConnection) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusConnection == nullptr"); + return false; + } + if (!dbusConnection->isConnected()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " not connected"); + return false; + } const auto& dbusStubObjectPath = dbusStubAdapter->getDBusAddress().getObjectPath(); const auto& dbusStubInterfaceName = dbusStubAdapter->getDBusAddress().getInterface(); @@ -254,23 +314,30 @@ bool DBusObjectManagerStub::onInterfaceDBusMessage(const DBusMessage& dbusMessag const auto& registeredDBusInterfacesMap = registeredDBusObjectPathIterator.second; DBusInterfacesAndPropertiesDict dbusInterfacesAndPropertiesDict; - assert(registeredDBusObjectPath.length() > 0); - assert(registeredDBusInterfacesMap.size() > 0); - - for (const auto& registeredDBusInterfaceIterator : registeredDBusInterfacesMap) { - const std::string& registeredDBusInterfaceName = registeredDBusInterfaceIterator.first; - const auto& registeredDBusStubAdapter = registeredDBusInterfaceIterator.second; + if (0 == registeredDBusObjectPath.length()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty object path"); + } else { + if (0 == registeredDBusInterfacesMap.size()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty interfaces map for ", registeredDBusObjectPath); + } - assert(registeredDBusInterfaceName.length() > 0); + for (const auto& registeredDBusInterfaceIterator : registeredDBusInterfacesMap) { + const std::string& registeredDBusInterfaceName = registeredDBusInterfaceIterator.first; + const auto& registeredDBusStubAdapter = registeredDBusInterfaceIterator.second.begin(); - dbusInterfacesAndPropertiesDict.insert({ registeredDBusInterfaceName, DBusPropertiesChangedDict() }); + if (0 == registeredDBusInterfaceName.length()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty interface name for ", registeredDBusObjectPath); + } else { + dbusInterfacesAndPropertiesDict.insert({ registeredDBusInterfaceName, DBusPropertiesChangedDict() }); + } - if (registeredDBusStubAdapter->isManaging()) { - dbusInterfacesAndPropertiesDict.insert({ getInterfaceName(), DBusPropertiesChangedDict() }); + if ((*registeredDBusStubAdapter)->isManaging()) { + dbusInterfacesAndPropertiesDict.insert({ getInterfaceName(), DBusPropertiesChangedDict() }); + } } - } - dbusObjectPathAndInterfacesDict.insert({ registeredDBusObjectPath, std::move(dbusInterfacesAndPropertiesDict) }); + dbusObjectPathAndInterfacesDict.insert({ registeredDBusObjectPath, std::move(dbusInterfacesAndPropertiesDict) }); + } } DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("a{oa{sa{sv}}}"); diff --git a/src/CommonAPI/DBus/DBusOutputStream.cpp b/src/CommonAPI/DBus/DBusOutputStream.cpp index 728c017..6fd5d0a 100644 --- a/src/CommonAPI/DBus/DBusOutputStream.cpp +++ b/src/CommonAPI/DBus/DBusOutputStream.cpp @@ -63,17 +63,32 @@ void DBusOutputStream::setError() { * @param numOfBytes The number of bytes that should be reserved for writing. */ void DBusOutputStream::reserveMemory(size_t numOfBytes) { - assert(numOfBytes > 0); + if (0 == numOfBytes) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " reserving 0 bytes"); + } payload_.reserve(numOfBytes); } DBusOutputStream& DBusOutputStream::writeString(const char *_value, const uint32_t &_length) { - assert(_value != NULL); - assert(_value[_length] == '\0'); - - _writeValue(_length); - _writeRaw(_value, _length + 1); + if (NULL == _value) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " _value == NULL"); + } else if (_value[_length] != '\0') { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " _value is not zero-terminated") + } else { + _writeValue(_length); + _writeRaw(_value, _length + 1); + } + return (*this); +} +DBusOutputStream& DBusOutputStream::writeByteBuffer(const uint8_t *_value, + const uint32_t &_length) { + if (NULL == _value) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " _value == NULL"); + } else { + _writeValue(_length); + _writeRaw(reinterpret_cast<const char*>(_value), _length); + } return (*this); } @@ -81,8 +96,9 @@ DBusOutputStream& DBusOutputStream::writeString(const char *_value, const uint32 static const char eightByteZeroString[] = "\0\0\0\0\0\0\0"; void DBusOutputStream::align(const size_t _boundary) { - assert(_boundary > 0 && _boundary <= 8 && - (_boundary % 2 == 0 || _boundary == 1)); + if ( _boundary == 0 || _boundary > 8 || ( 0 != _boundary % 2 && 1 != _boundary) ) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid boundary ", _boundary); + } size_t mask = _boundary - 1; size_t necessary = ((mask - (payload_.size() & mask)) + 1) & mask; @@ -100,7 +116,9 @@ void DBusOutputStream::_writeRawAt(const char *_data, const size_t _size, size_t void DBusOutputStream::writeSignature(const std::string& signature) { const auto& signatureLength = signature.length(); - assert(signatureLength > 0 && signatureLength < 256); + if (0 == signatureLength || 255 < signatureLength) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " invalid signatureLength ", signatureLength); + } const uint8_t wireLength = (uint8_t) signatureLength; (*this) << wireLength; diff --git a/src/CommonAPI/DBus/DBusProxy.cpp b/src/CommonAPI/DBus/DBusProxy.cpp index e92d90c..95c3d59 100644 --- a/src/CommonAPI/DBus/DBusProxy.cpp +++ b/src/CommonAPI/DBus/DBusProxy.cpp @@ -3,7 +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 <cassert> #include <sstream> #include <CommonAPI/Utils.hpp> @@ -25,15 +24,153 @@ void DBusProxyStatusEvent::onListenerAdded(const Listener &_listener, const Subs _listener(AvailabilityStatus::AVAILABLE); } +void DBusProxy::availabilityTimeoutThreadHandler() const { + std::unique_lock<std::mutex> threadLock(availabilityTimeoutThreadMutex_); + + bool cancel = false; + bool firstIteration = true; + + // the callbacks that have to be done are stored with + // their required data in a list of tuples. + typedef std::tuple< + isAvailableAsyncCallback, + std::promise<AvailabilityStatus>, + AvailabilityStatus, + std::chrono::time_point<std::chrono::high_resolution_clock> + > CallbackData_t; + std::list<CallbackData_t> callbacks; + + while(!cancel) { + + //get min timeout + timeoutsMutex_.lock(); + + int timeout = std::numeric_limits<int>::max(); + std::chrono::time_point<std::chrono::high_resolution_clock> minTimeout; + if (timeouts_.size() > 0) { + auto minTimeoutElement = std::min_element(timeouts_.begin(), timeouts_.end(), + [] (const AvailabilityTimeout_t& lhs, const AvailabilityTimeout_t& rhs) { + return std::get<0>(lhs) < std::get<0>(rhs); + }); + minTimeout = std::get<0>(*minTimeoutElement); + std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); + timeout = (int)std::chrono::duration_cast<std::chrono::milliseconds>(minTimeout - now).count(); + } + timeoutsMutex_.unlock(); + + //wait for timeout or notification + if (!firstIteration && std::cv_status::timeout == + availabilityTimeoutCondition_.wait_for(threadLock, std::chrono::milliseconds(timeout))) { + timeoutsMutex_.lock(); + + //iterate through timeouts + auto it = timeouts_.begin(); + while (it != timeouts_.end()) { + std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); + + isAvailableAsyncCallback callback = std::get<1>(*it); + + if (now > std::get<0>(*it)) { + //timeout + availabilityMutex_.lock(); + if(isAvailable()) + callbacks.push_back(std::make_tuple(callback, std::move(std::get<2>(*it)), + AvailabilityStatus::AVAILABLE, + std::chrono::time_point<std::chrono::high_resolution_clock>())); + else + callbacks.push_back(std::make_tuple(callback, std::move(std::get<2>(*it)), + AvailabilityStatus::NOT_AVAILABLE, + std::chrono::time_point<std::chrono::high_resolution_clock>())); + it = timeouts_.erase(it); + availabilityMutex_.unlock(); + } else { + //timeout not expired + availabilityMutex_.lock(); + if(isAvailable()) { + callbacks.push_back(std::make_tuple(callback, std::move(std::get<2>(*it)), + AvailabilityStatus::AVAILABLE, + minTimeout)); + it = timeouts_.erase(it); + } else { + ++it; + } + availabilityMutex_.unlock(); + } + } + + timeoutsMutex_.unlock(); + } else { + + if(firstIteration) { + firstIteration = false; + continue; + } + + //timeout not expired + timeoutsMutex_.lock(); + auto it = timeouts_.begin(); + while (it != timeouts_.end()) { + isAvailableAsyncCallback callback = std::get<1>(*it); + + availabilityMutex_.lock(); + if(isAvailable()) { + callbacks.push_back(std::make_tuple(callback, std::move(std::get<2>(*it)), + AvailabilityStatus::AVAILABLE, + minTimeout)); + it = timeouts_.erase(it); + } else { + ++it; + } + availabilityMutex_.unlock(); + } + + timeoutsMutex_.unlock(); + } + + //do callbacks + isAvailableAsyncCallback callback; + AvailabilityStatus avStatus; + int remainingTimeout; + std::chrono::high_resolution_clock::time_point now; + + auto it = callbacks.begin(); + while(it != callbacks.end()) { + callback = std::get<0>(*it); + avStatus = std::get<2>(*it); + + // compute remaining timeout + now = std::chrono::high_resolution_clock::now(); + remainingTimeout = (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::get<3>(*it) - now).count(); + if(remainingTimeout < 0) + remainingTimeout = 0; + + threadLock.unlock(); + + std::get<1>(*it).set_value(avStatus); + callback(avStatus, remainingTimeout); + + threadLock.lock(); + + it = callbacks.erase(it); + } + + //cancel thread + timeoutsMutex_.lock(); + if(timeouts_.size() == 0 && callbacks.size() == 0) + cancel = true; + timeoutsMutex_.unlock(); + } +} + DBusProxy::DBusProxy(const DBusAddress &_dbusAddress, const std::shared_ptr<DBusProxyConnection> &_connection): DBusProxyBase(_dbusAddress, _connection), dbusProxyStatusEvent_(this), availabilityStatus_(AvailabilityStatus::UNKNOWN), interfaceVersionAttribute_(*this, "uu", "getInterfaceVersion"), - dbusServiceRegistry_(DBusServiceRegistry::get(_connection)), - signalMemberHandlerInfo_(3000) + dbusServiceRegistry_(DBusServiceRegistry::get(_connection)) { + Factory::get()->incrementConnection(connection_); } void DBusProxy::init() { @@ -43,9 +180,14 @@ void DBusProxy::init() { } DBusProxy::~DBusProxy() { + if(availabilityTimeoutThread_) { + if(availabilityTimeoutThread_->joinable()) + availabilityTimeoutThread_->join(); + } dbusServiceRegistry_->unsubscribeAvailabilityListener( getAddress().getAddress(), dbusServiceRegistrySubscription_); + Factory::get()->decrementConnection(connection_); } bool DBusProxy::isAvailable() const { @@ -66,6 +208,56 @@ bool DBusProxy::isAvailableBlocking() const { return true; } +std::future<AvailabilityStatus> DBusProxy::isAvailableAsync( + isAvailableAsyncCallback _callback, + const CommonAPI::CallInfo *_info) const { + + std::promise<AvailabilityStatus> promise; + std::future<AvailabilityStatus> future = promise.get_future(); + + //set timeout point + auto timeoutPoint = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(_info->timeout_); + + timeoutsMutex_.lock(); + if(timeouts_.size() == 0) { + //no timeouts + + bool isAvailabilityTimeoutThread = false; + + //join running availability thread + if(availabilityTimeoutThread_) { + + //check if current thread is availability timeout thread + isAvailabilityTimeoutThread = (std::this_thread::get_id() == + availabilityTimeoutThread_.get()->get_id()); + + if(availabilityTimeoutThread_->joinable() && !isAvailabilityTimeoutThread) { + timeoutsMutex_.unlock(); + availabilityTimeoutThread_->join(); + timeoutsMutex_.lock(); + } + } + //add new timeout + timeouts_.push_back(std::make_tuple(timeoutPoint, _callback, std::move(promise))); + + //start availability thread + if(!isAvailabilityTimeoutThread) + availabilityTimeoutThread_ = std::make_shared<std::thread>( + std::bind(&DBusProxy::availabilityTimeoutThreadHandler, this)); + } else { + //add timeout + timeouts_.push_back(std::make_tuple(timeoutPoint, _callback, std::move(promise))); + } + timeoutsMutex_.unlock(); + + availabilityTimeoutThreadMutex_.lock(); + //notify availability thread that new timeout was added + availabilityTimeoutCondition_.notify_all(); + availabilityTimeoutThreadMutex_.unlock(); + + return future; +} + ProxyStatusEvent& DBusProxy::getProxyStatusEvent() { return dbusProxyStatusEvent_; } @@ -87,15 +279,23 @@ void DBusProxy::signalInitialValueCallback(const CallStatus _status, const DBusMessage &_message, DBusProxyConnection::DBusSignalHandler *_handler, const uint32_t _tag) { - (void)_status; - _handler->onInitialValueSignalDBusMessage(_message, _tag); + if (_status != CallStatus::SUCCESS) { + COMMONAPI_ERROR("Error when receiving initial value of an attribute"); + } else { + _handler->onInitialValueSignalDBusMessage(_message, _tag); + } } void DBusProxy::onDBusServiceInstanceStatus(const AvailabilityStatus& availabilityStatus) { if (availabilityStatus != availabilityStatus_) { - availabilityStatusMutex_.lock(); + availabilityMutex_.lock(); availabilityStatus_ = availabilityStatus; - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); + + availabilityTimeoutThreadMutex_.lock(); + //notify availability thread that proxy status has changed + availabilityTimeoutCondition_.notify_all(); + availabilityTimeoutThreadMutex_.unlock(); dbusProxyStatusEvent_.notifyListeners(availabilityStatus); @@ -118,27 +318,26 @@ void DBusProxy::onDBusServiceInstanceStatus(const AvailabilityStatus& availabili DBusMessage message = createMethodCall(std::get<4>(*signalMemberHandlerIterator), ""); - DBusProxyAsyncSignalMemberCallbackHandler::FunctionType myFunc = std::bind( + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate::FunctionType myFunc = std::bind( &DBusProxy::signalMemberCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate delegate(shared_from_this(), myFunc); connection_->sendDBusMessageWithReplyAsync( message, - DBusProxyAsyncSignalMemberCallbackHandler::create(myFunc, std::get<5>(*signalMemberHandlerIterator), 0), - &signalMemberHandlerInfo_); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::create(delegate, std::get<5>(*signalMemberHandlerIterator), 0), + &defaultCallInfo); } } { std::lock_guard < std::mutex > queueLock(selectiveBroadcastHandlersMutex_); for (auto selectiveBroadcasts : selectiveBroadcastHandlers) { std::string methodName = "subscribeFor" + selectiveBroadcasts.first + "Selective"; - bool subscriptionAccepted = connection_->sendPendingSelectiveSubscription(this, methodName); - if (!subscriptionAccepted) { - selectiveBroadcasts.second->onError(CommonAPI::CallStatus::SUBSCRIPTION_REFUSED); - } + connection_->sendPendingSelectiveSubscription(this, methodName, selectiveBroadcasts.second.first, + selectiveBroadcasts.second.second); } } } else { @@ -160,38 +359,33 @@ void DBusProxy::onDBusServiceInstanceStatus(const AvailabilityStatus& availabili } } } - availabilityStatusMutex_.lock(); + availabilityMutex_.lock(); availabilityCondition_.notify_one(); - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); } -DBusProxyConnection::DBusSignalHandlerToken DBusProxy::subscribeForSelectiveBroadcastOnConnection( - bool& subscriptionAccepted, +void DBusProxy::insertSelectiveSubscription(const std::string& interfaceMemberName, + DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, uint32_t tag) { + std::lock_guard < std::mutex > queueLock(selectiveBroadcastHandlersMutex_); + selectiveBroadcastHandlers[interfaceMemberName] = std::make_pair(dbusSignalHandler, tag); +} + +void DBusProxy::subscribeForSelectiveBroadcastOnConnection( const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, const std::string& interfaceMemberSignature, - DBusProxyConnection::DBusSignalHandler* dbusSignalHandler) { - - DBusProxyConnection::DBusSignalHandlerToken token = - getDBusConnection()->subscribeForSelectiveBroadcast( - subscriptionAccepted, - objectPath, - interfaceName, - interfaceMemberName, - interfaceMemberSignature, - dbusSignalHandler, - this); - - if (!isAvailable()) { - subscriptionAccepted = true; - } - if (subscriptionAccepted) { - std::lock_guard < std::mutex > queueLock(selectiveBroadcastHandlersMutex_); - selectiveBroadcastHandlers[interfaceMemberName] = dbusSignalHandler; - } - - return token; + DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, + uint32_t tag) { + + getDBusConnection()->subscribeForSelectiveBroadcast( + objectPath, + interfaceName, + interfaceMemberName, + interfaceMemberSignature, + dbusSignalHandler, + this, + tag); } void DBusProxy::unsubscribeFromSelectiveBroadcast(const std::string& eventName, @@ -204,7 +398,7 @@ void DBusProxy::unsubscribeFromSelectiveBroadcast(const std::string& eventName, std::string interfaceMemberName = std::get<2>(subscription); auto its_handler = selectiveBroadcastHandlers.find(interfaceMemberName); if (its_handler != selectiveBroadcastHandlers.end()) { - selectiveBroadcastHandlers.erase(its_handler); + selectiveBroadcastHandlers.erase(interfaceMemberName); } } @@ -251,9 +445,9 @@ DBusProxyConnection::DBusSignalHandlerToken DBusProxy::addSignalMemberHandler( justAddFilter, false); - availabilityStatusMutex_.lock(); + availabilityMutex_.lock(); if (availabilityStatus_ == AvailabilityStatus::AVAILABLE) { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); signalHandlerToken = connection_->addSignalMemberHandler( objectPath, interfaceName, @@ -263,7 +457,7 @@ DBusProxyConnection::DBusSignalHandlerToken DBusProxy::addSignalMemberHandler( justAddFilter); std::get<7>(signalMemberHandler) = true; } else { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); } addSignalMemberHandlerToQueue(signalMemberHandler); } else { @@ -333,24 +527,25 @@ void DBusProxy::getCurrentValueForSignalListener( DBusProxyConnection::DBusSignalHandler *dbusSignalHandler, const uint32_t subscription) { - availabilityStatusMutex_.lock(); + availabilityMutex_.lock(); if (availabilityStatus_ == AvailabilityStatus::AVAILABLE) { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); DBusMessage message = createMethodCall(getMethodName, ""); - DBusProxyAsyncSignalMemberCallbackHandler::FunctionType myFunc = std::bind(&DBusProxy::signalInitialValueCallback, + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate::FunctionType myFunc = std::bind(&DBusProxy::signalInitialValueCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate delegate(shared_from_this(), myFunc); connection_->sendDBusMessageWithReplyAsync( message, - DBusProxyAsyncSignalMemberCallbackHandler::create(myFunc, dbusSignalHandler, subscription), - &signalMemberHandlerInfo_); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::create(delegate, dbusSignalHandler, subscription), + &defaultCallInfo); } else { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); } } @@ -360,9 +555,9 @@ void DBusProxy::freeDesktopGetCurrentValueForSignalListener( const std::string &interfaceName, const std::string &propertyName) { - availabilityStatusMutex_.lock(); + availabilityMutex_.lock(); if (availabilityStatus_ == AvailabilityStatus::AVAILABLE) { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); DBusAddress itsAddress(getDBusAddress()); itsAddress.setInterface("org.freedesktop.DBus.Properties"); @@ -372,20 +567,21 @@ void DBusProxy::freeDesktopGetCurrentValueForSignalListener( ::serialize(output, interfaceName, propertyName); if (success) { output.flush(); - DBusProxyAsyncSignalMemberCallbackHandler::FunctionType myFunc = std::bind(&DBusProxy::signalInitialValueCallback, + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate::FunctionType myFunc = std::bind(&DBusProxy::signalInitialValueCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::Delegate delegate(shared_from_this(), myFunc); connection_->sendDBusMessageWithReplyAsync( _message, - DBusProxyAsyncSignalMemberCallbackHandler::create(myFunc, dbusSignalHandler, subscription), - &signalMemberHandlerInfo_); + DBusProxyAsyncSignalMemberCallbackHandler<DBusProxy>::create(delegate, dbusSignalHandler, subscription), + &defaultCallInfo); } } else { - availabilityStatusMutex_.unlock(); + availabilityMutex_.unlock(); } } diff --git a/src/CommonAPI/DBus/DBusProxyManager.cpp b/src/CommonAPI/DBus/DBusProxyManager.cpp index 8ea30e3..e36f6e1 100644 --- a/src/CommonAPI/DBus/DBusProxyManager.cpp +++ b/src/CommonAPI/DBus/DBusProxyManager.cpp @@ -54,6 +54,7 @@ void DBusProxyManager::getAvailableInstances( CommonAPI::CallStatus &_status, std::vector<std::string> &_availableInstances) { + _availableInstances.clear(); DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dict; DBusProxyHelper< @@ -161,6 +162,10 @@ DBusProxyManager::translateCommonApiAddresses( CommonAPI::Address itsAddress; DBusAddress itsDBusAddress; + // get service information from proxy + const std::string &_service = proxy_.getDBusAddress().getService(); + itsDBusAddress.setService(_service); + for (const auto &objectPathIter : _dict) { itsDBusAddress.setObjectPath(objectPathIter.first); diff --git a/src/CommonAPI/DBus/DBusServiceRegistry.cpp b/src/CommonAPI/DBus/DBusServiceRegistry.cpp index 0ee7705..65290fc 100644 --- a/src/CommonAPI/DBus/DBusServiceRegistry.cpp +++ b/src/CommonAPI/DBus/DBusServiceRegistry.cpp @@ -37,6 +37,12 @@ DBusServiceRegistry::get(std::shared_ptr<DBusProxyConnection> _connection) { return registry; } +void +DBusServiceRegistry::remove(std::shared_ptr<DBusProxyConnection> _connection) { + std::lock_guard<std::mutex> itsGuard(registriesMutex_); + registries_.erase(_connection); +} + DBusServiceRegistry::DBusServiceRegistry(std::shared_ptr<DBusProxyConnection> dbusProxyConnection) : dbusDaemonProxy_(std::make_shared<CommonAPI::DBus::DBusDaemonProxy>(dbusProxyConnection)), initialized_(false), @@ -70,8 +76,9 @@ DBusServiceRegistry::~DBusServiceRegistry() { const bool isSubscriptionCancelled = dbusProxyConnection->removeObjectManagerSignalMemberHandler( dbusServiceUniqueName, this); - assert(isSubscriptionCancelled); - (void)isSubscriptionCancelled; + if (!isSubscriptionCancelled) { + COMMONAPI_ERROR(std::string(__FUNCTION__), ": still subscribed too ", std::string(dbusServiceUniqueName)); + } } } @@ -105,12 +112,13 @@ DBusServiceRegistry::subscribeAvailabilityListener( COMMONAPI_ERROR( "You must not build proxies in callbacks of ProxyStatusEvent.", " Please refer to the documentation for suggestions how to avoid this."); - assert(false); } - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); auto& dbusServiceListenersRecord = dbusServiceListenersMap[dbusAddress.getService()]; - assert(dbusServiceListenersRecord.uniqueBusNameState != DBusRecordState::AVAILABLE); + if (dbusServiceListenersRecord.uniqueBusNameState == DBusRecordState::AVAILABLE) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " uniqueBusName ", dbusServiceListenersRecord.uniqueBusName, " already AVAILABLE"); + } auto& dbusInterfaceNameListenersMap = dbusServiceListenersRecord.dbusObjectPathListenersMap[dbusAddress.getObjectPath()]; auto& dbusInterfaceNameListenersRecord = dbusInterfaceNameListenersMap[dbusAddress.getInterface()]; @@ -166,6 +174,8 @@ DBusServiceRegistry::subscribeAvailabilityListener( dbusInterfaceNameListenersRecord.listenerList.push_front(std::move(serviceListener)); + dbusServicesMutex_.unlock(); + return dbusInterfaceNameListenersRecord.listenerList.begin(); } @@ -175,11 +185,12 @@ DBusServiceRegistry::unsubscribeAvailabilityListener( DBusAddress dbusAddress; translator_->translate(_address, dbusAddress); - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); auto dbusServiceListenersIterator = dbusServiceListenersMap.find(dbusAddress.getService()); const bool isDBusServiceListenersRecordFound = (dbusServiceListenersIterator != dbusServiceListenersMap.end()); if (!isDBusServiceListenersRecordFound) { + dbusServicesMutex_.unlock(); return; // already unsubscribed } @@ -190,6 +201,7 @@ DBusServiceRegistry::unsubscribeAvailabilityListener( (dbusObjectPathListenersIterator != dbusServiceListenersRecord.dbusObjectPathListenersMap.end()); if (!isDBusObjectPathListenersRecordFound) { + dbusServicesMutex_.unlock(); return; // already unsubscribed } @@ -199,6 +211,7 @@ DBusServiceRegistry::unsubscribeAvailabilityListener( (dbusInterfaceNameListenersIterator != dbusInterfaceNameListenersMap.end()); if (!isDBusInterfaceNameListenersRecordFound) { + dbusServicesMutex_.unlock(); return; // already unsubscribed } @@ -213,6 +226,8 @@ DBusServiceRegistry::unsubscribeAvailabilityListener( dbusServiceListenersRecord.dbusObjectPathListenersMap.erase(dbusObjectPathListenersIterator); } } + + dbusServicesMutex_.unlock(); } // d-feet mode until service is found @@ -283,7 +298,10 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac dbusServicesMutex_.unlock(); - assert(dbusUniqueNameRecord != NULL); + if (NULL == dbusUniqueNameRecord) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no unique name record found for IF: ", dbusInterfaceName, + " service: ", dbusServiceName, "object path: ", dbusObjectPath); + } auto& dbusObjectPathsCache = dbusUniqueNameRecord->dbusObjectPathsCache; auto dbusObjectPathCacheIterator = dbusObjectPathsCache.find(dbusObjectPath); @@ -319,14 +337,17 @@ bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& dbusInterfac dbusObjectPathCache = &(dbusObjectPathCacheIterator->second); - std::future<DBusRecordState> futureObjectPathResolved = dbusObjectPathCache->promiseOnResolve.get_future(); + newDbusObjectPathCache.futureOnResolve = dbusObjectPathCache->promiseOnResolve.get_future(); dbusServicesMutex_.unlock(); introspectDBusObjectPath(uniqueName, dbusObjectPath); - futureObjectPathResolved.wait_for(timeout); + newDbusObjectPathCache.futureOnResolve.wait_for(timeout); } - assert(dbusObjectPathCache != NULL); + if (NULL == dbusObjectPathCache) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no object path cache entry found for IF: ", dbusInterfaceName, + " service: ", dbusServiceName, "object path: ", dbusObjectPath); + } dbusServicesMutex_.lock(); if(dbusObjectPathCache->state != DBusRecordState::RESOLVED) { @@ -471,9 +492,15 @@ void DBusServiceRegistry::getAvailableServiceInstancesAsync(CommonAPI::Factory:: void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { const std::string& dbusServiceUniqueName = _dbusMessage.getSender(); - assert(_dbusMessage.isSignalType()); - assert(_dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")); - assert(_dbusMessage.hasMemberName("InterfacesAdded") || _dbusMessage.hasMemberName("InterfacesRemoved")); + if (!_dbusMessage.isSignalType()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signal message expected, got ", _dbusMessage.getMember(), " type: ", int(_dbusMessage.getType())); + } + if (!_dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unexpected interface ", _dbusMessage.getInterface()); + } + if (!_dbusMessage.hasMemberName("InterfacesAdded") && !_dbusMessage.hasMemberName("InterfacesAdded")) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unexpected member ", _dbusMessage.getMember()); + } DBusInputStream dbusInputStream(_dbusMessage); std::string dbusObjectPath; @@ -491,7 +518,9 @@ void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { dbusInputStream.align(8); dbusInputStream >> dbusInterfaceName; dbusInputStream.skipMap(); - assert(!dbusInputStream.hasError()); + if (dbusInputStream.hasError()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " input stream error"); + } dbusInterfaceNames.insert(dbusInterfaceName); } dbusInputStream.endReadMapOfSerializableStructs(); @@ -515,7 +544,7 @@ void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { return; } - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); auto dbusServiceUniqueNameIterator = dbusUniqueNamesMap_.find(dbusServiceUniqueName); const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); @@ -523,6 +552,7 @@ void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { if (!isDBusServiceUniqueNameFound) { // LB TODO: unsubscribe here! // Needs to be reworked in order to store the subscription identifier! + dbusServicesMutex_.unlock(); return; } @@ -530,12 +560,15 @@ void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { DBusObjectPathCache *dbusObjectPathRecord; auto dbusObjectPathCacheIterator = dbusUniqueNameRecord.dbusObjectPathsCache.find(dbusObjectPath); - if(dbusObjectPathCacheIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()) + if(dbusObjectPathCacheIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()) { dbusObjectPathRecord = &(dbusObjectPathCacheIterator->second); - else + } else { + dbusServicesMutex_.unlock(); return; + } if (dbusObjectPathRecord->state != DBusRecordState::RESOLVED) { + dbusServicesMutex_.unlock(); return; } @@ -548,6 +581,8 @@ void DBusServiceRegistry::onSignalDBusMessage(const DBusMessage &_dbusMessage) { } notifyDBusServiceListeners(dbusUniqueNameRecord, dbusObjectPath, dbusInterfaceNames, dbusInterfaceNameState); + + dbusServicesMutex_.unlock(); } void DBusServiceRegistry::setDBusServicePredefined(const std::string& _serviceName) { @@ -556,22 +591,30 @@ void DBusServiceRegistry::setDBusServicePredefined(const std::string& _serviceNa void DBusServiceRegistry::resolveDBusServiceName(const std::string& dbusServiceName, DBusServiceListenersRecord& dbusServiceListenersRecord) { - assert(dbusServiceListenersRecord.uniqueBusNameState != DBusRecordState::RESOLVED); - assert(dbusServiceListenersRecord.uniqueBusName.empty()); + if (dbusServiceListenersRecord.uniqueBusNameState == DBusRecordState::RESOLVED) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " already resolved ", dbusServiceName); + } + if (!dbusServiceListenersRecord.uniqueBusName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unique name not empty ", dbusServiceListenersRecord.uniqueBusName); + } mutexServiceResolveCount.lock(); servicesToResolve++; mutexServiceResolveCount.unlock(); if (dbusDaemonProxy_->isAvailable()) { - dbusDaemonProxy_->getNameOwnerAsync( - dbusServiceName, - std::bind( - &DBusServiceRegistry::onGetNameOwnerCallback, - this->shared_from_this(), - std::placeholders::_1, - std::placeholders::_2, - dbusServiceName)); + + auto func = std::bind( + &DBusServiceRegistry::onGetNameOwnerCallback, + this->shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + dbusServiceName); + + DBusProxyAsyncCallbackHandler<DBusServiceRegistry, + std::string>::Delegate delegate(shared_from_this(), func); + + dbusDaemonProxy_->getNameOwnerAsync<DBusServiceRegistry>(dbusServiceName, delegate); dbusServiceListenersRecord.uniqueBusNameState = DBusRecordState::RESOLVING; } @@ -580,7 +623,7 @@ void DBusServiceRegistry::resolveDBusServiceName(const std::string& dbusServiceN void DBusServiceRegistry::onGetNameOwnerCallback(const CallStatus& status, std::string dbusServiceUniqueName, const std::string& dbusServiceName) { - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); auto dbusServiceListenerIterator = dbusServiceListenersMap.find(dbusServiceName); const bool isDBusServiceListenerRecordFound = (dbusServiceListenerIterator != dbusServiceListenersMap.end()); @@ -609,16 +652,25 @@ void DBusServiceRegistry::onGetNameOwnerCallback(const CallStatus& status, servicesToResolve--; mutexServiceResolveCount.unlock(); monitorResolveAllServices_.notify_all(); + + dbusServicesMutex_.unlock(); } DBusServiceRegistry::DBusRecordState DBusServiceRegistry::resolveDBusInterfaceNameState( const DBusAddress &_dbusAddress, DBusServiceListenersRecord &dbusServiceListenersRecord) { - assert(dbusServiceListenersRecord.uniqueBusNameState == DBusRecordState::RESOLVED); - assert(!dbusServiceListenersRecord.uniqueBusName.empty()); + + if (dbusServiceListenersRecord.uniqueBusNameState != DBusRecordState::RESOLVED) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unresolved ", dbusServiceListenersRecord.uniqueBusName); + } + if (dbusServiceListenersRecord.uniqueBusName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unique bus name is empty"); + } auto& dbusServiceUniqueNameRecord = dbusUniqueNamesMap_[dbusServiceListenersRecord.uniqueBusName]; - assert(!dbusServiceUniqueNameRecord.ownedBusNames.empty()); + if (dbusServiceListenersRecord.uniqueBusName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " empty ownedBusNames"); + } auto& dbusObjectPathRecord = getDBusObjectPathCacheReference( _dbusAddress.getObjectPath(), @@ -661,8 +713,9 @@ DBusServiceRegistry::getDBusObjectPathCacheReference( const bool isSubscriptionSuccessful = dbusProxyConnection->addObjectManagerSignalMemberHandler( dbusServiceUniqueName, this); - assert(isSubscriptionSuccessful); - (void)isSubscriptionSuccessful; + if (!isSubscriptionSuccessful) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " cannot subscribe too ", dbusServiceUniqueName); + } } if (dbusObjectPathCacheIterator->second.state == DBusRecordState::UNKNOWN @@ -683,19 +736,28 @@ void DBusServiceRegistry::releaseDBusObjectPathCacheReference(const std::string& return; } - assert(!dbusServiceListenersRecord.uniqueBusName.empty()); + if (dbusServiceListenersRecord.uniqueBusName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unique bus name is empty"); + } auto& dbusUniqueNameRecord = dbusUniqueNamesMap_[dbusServiceListenersRecord.uniqueBusName]; - assert(!dbusUniqueNameRecord.ownedBusNames.empty()); - assert(!dbusUniqueNameRecord.dbusObjectPathsCache.empty()); + 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()); - assert(isDBusObjectPathCacheFound); - (void)isDBusObjectPathCacheFound; + if (!isDBusObjectPathCacheFound) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " no object path cache entry found for ", dbusObjectPath); + } auto& dbusObjectPathCache = dbusObjectPathCacheIterator->second; - assert(dbusObjectPathCache.referenceCount > 0); + if (0 == dbusObjectPathCache.referenceCount) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " reference count is 0"); + } dbusObjectPathCache.referenceCount--; @@ -704,12 +766,15 @@ void DBusServiceRegistry::releaseDBusObjectPathCacheReference(const std::string& const bool isLastDBusObjectPathCache = dbusUniqueNameRecord.dbusObjectPathsCache.empty(); if (isLastDBusObjectPathCache) { + dbusServicesMutex_.unlock(); auto dbusProxyConnection = dbusDaemonProxy_->getDBusConnection(); const bool isSubscriptionCancelled = dbusProxyConnection->removeObjectManagerSignalMemberHandler( dbusServiceListenersRecord.uniqueBusName, this); - assert(isSubscriptionCancelled); - (void)isSubscriptionCancelled; + if (!isSubscriptionCancelled) { + COMMONAPI_ERROR(std::string(__FUNCTION__), ": still subscribed too ", dbusServiceListenersRecord.uniqueBusName); + } + dbusServicesMutex_.lock(); } } } @@ -732,7 +797,9 @@ bool DBusServiceRegistry::getManagedObjects(const std::string& dbusServiceUnique bool isSendingInProgress = false; auto dbusConnection = dbusDaemonProxy_->getDBusConnection(); - assert(!dbusServiceUniqueName.empty()); + if (dbusServiceUniqueName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusServiceUniqueName empty"); + } if(dbusConnection->isConnected()) { @@ -754,11 +821,17 @@ bool DBusServiceRegistry::getManagedObjects(const std::string& dbusServiceUnique dbusServiceUniqueName, dbusObjectPath); + DBusProxyAsyncCallbackHandler< + DBusServiceRegistry, + DBusObjectManagerStub::DBusObjectPathAndInterfacesDict + >::Delegate delegate(shared_from_this(), getManagedObjectsCallback); + dbusConnection->sendDBusMessageWithReplyAsync( dbusMessageCall, DBusProxyAsyncCallbackHandler< + DBusServiceRegistry, DBusObjectManagerStub::DBusObjectPathAndInterfacesDict - >::create(getManagedObjectsCallback, std::tuple<DBusObjectManagerStub::DBusObjectPathAndInterfacesDict>()), + >::create(delegate, std::tuple<DBusObjectManagerStub::DBusObjectPathAndInterfacesDict>()), &serviceRegistryInfo); isSendingInProgress = true; @@ -852,12 +925,13 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolveFurther(const CallSt // No further managed objects } - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); auto dbusServiceUniqueNameIterator = dbusUniqueNamesMap_.find(dbusServiceUniqueName); const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); if (!isDBusServiceUniqueNameFound) { + dbusServicesMutex_.unlock(); return; } @@ -866,13 +940,16 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolveFurther(const CallSt const bool isDBusObjectPathFound = (dbusObjectPathIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); if (!isDBusObjectPathFound) { + dbusServicesMutex_.unlock(); return; } DBusObjectPathCache& dbusObjectPathRecord = dbusObjectPathIterator->second; dbusObjectPathRecord.state = DBusRecordState::RESOLVED; - dbusObjectPathRecord.promiseOnResolve.set_value(dbusObjectPathRecord.state); + if(dbusObjectPathRecord.futureOnResolve.valid()) { + dbusObjectPathRecord.promiseOnResolve.set_value(dbusObjectPathRecord.state); + } mutexObjectPathsResolveCount.lock(); objectPathsToResolve--; mutexObjectPathsResolveCount.unlock(); @@ -885,6 +962,8 @@ void DBusServiceRegistry::onGetManagedObjectsCallbackResolveFurther(const CallSt dbusObjectPath, dbusObjectPathRecord.dbusInterfaceNamesCache, DBusRecordState::RESOLVED); + + dbusServicesMutex_.unlock(); } void DBusServiceRegistry::processManagedObject(const std::string& dbusObjectPath, @@ -905,7 +984,9 @@ bool DBusServiceRegistry::introspectDBusObjectPath(const std::string& dbusServic bool isResolvingInProgress = false; auto dbusConnection = dbusDaemonProxy_->getDBusConnection(); - assert(!dbusServiceUniqueName.empty()); + if (dbusServiceUniqueName.empty()) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " dbusServiceUniqueName empty"); + } if (dbusConnection->isConnected()) { mutexObjectPathsResolveCount.lock(); @@ -924,11 +1005,17 @@ bool DBusServiceRegistry::introspectDBusObjectPath(const std::string& dbusServic dbusServiceUniqueName, dbusObjectPath); + DBusProxyAsyncCallbackHandler< + DBusServiceRegistry, + std::string + >::Delegate delegate(shared_from_this(), instrospectAsyncCallback); + dbusConnection->sendDBusMessageWithReplyAsync( dbusMessageCall, DBusProxyAsyncCallbackHandler< + DBusServiceRegistry, std::string - >::create(instrospectAsyncCallback, std::tuple<std::string>()), + >::create(delegate, std::tuple<std::string>()), &serviceRegistryInfo); isResolvingInProgress = true; @@ -956,7 +1043,7 @@ void DBusServiceRegistry::onIntrospectCallback(const CallStatus& callStatus, parseIntrospectionData(xmlData, dbusObjectPath, dbusServiceUniqueName); } - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); // Error CallStatus will result in empty parsedDBusInterfaceNameSet (and not available notification) @@ -964,6 +1051,7 @@ void DBusServiceRegistry::onIntrospectCallback(const CallStatus& callStatus, const bool isDBusServiceUniqueNameFound = (dbusServiceUniqueNameIterator != dbusUniqueNamesMap_.end()); if (!isDBusServiceUniqueNameFound) { + dbusServicesMutex_.unlock(); return; } @@ -972,6 +1060,7 @@ void DBusServiceRegistry::onIntrospectCallback(const CallStatus& callStatus, const bool isDBusObjectPathFound = (dbusObjectPathIterator != dbusUniqueNameRecord.dbusObjectPathsCache.end()); if (!isDBusObjectPathFound) { + dbusServicesMutex_.unlock(); return; } @@ -991,6 +1080,8 @@ void DBusServiceRegistry::onIntrospectCallback(const CallStatus& callStatus, dbusObjectPath, dbusObjectPathRecord.dbusInterfaceNamesCache, DBusRecordState::RESOLVED); + + dbusServicesMutex_.unlock(); } void DBusServiceRegistry::parseIntrospectionNode(const pugi::xml_node& node, const std::string& rootObjectPath, const std::string& fullObjectPath, const std::string& dbusServiceUniqueName) { @@ -1069,9 +1160,11 @@ void DBusServiceRegistry::parseIntrospectionData(const std::string& xmlData, void DBusServiceRegistry::onDBusDaemonProxyStatusEvent(const AvailabilityStatus& availabilityStatus) { - assert(availabilityStatus != AvailabilityStatus::UNKNOWN); + if (availabilityStatus == AvailabilityStatus::UNKNOWN) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unexpected availability status ", int(availabilityStatus)); + } - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); for (auto& dbusServiceListenersIterator : dbusServiceListenersMap) { const auto& dbusServiceName = dbusServiceListenersIterator.first; @@ -1083,6 +1176,8 @@ void DBusServiceRegistry::onDBusDaemonProxyStatusEvent(const AvailabilityStatus& onDBusServiceNotAvailable(dbusServiceListenersRecord, dbusServiceName); } } + + dbusServicesMutex_.unlock(); } void DBusServiceRegistry::checkDBusServiceWasAvailable(const std::string& dbusServiceName, @@ -1105,7 +1200,7 @@ void DBusServiceRegistry::onDBusDaemonProxyNameOwnerChangedEvent(const std::stri const bool isDBusServiceNameLost = newOwner.empty(); const std::string& dbusServiceUniqueName = (isDBusServiceNameLost ? oldOwner : newOwner); - std::lock_guard<std::mutex> dbusServicesLock(dbusServicesMutex_); + dbusServicesMutex_.lock(); if (isDBusServiceNameLost) { checkDBusServiceWasAvailable(affectedName, dbusServiceUniqueName); @@ -1113,6 +1208,8 @@ void DBusServiceRegistry::onDBusDaemonProxyNameOwnerChangedEvent(const std::stri onDBusServiceAvailable(affectedName, dbusServiceUniqueName); } + dbusServicesMutex_.unlock(); + return; } @@ -1175,7 +1272,7 @@ void DBusServiceRegistry::onDBusServiceAvailable(const std::string& dbusServiceN } void DBusServiceRegistry::onDBusServiceNotAvailable(DBusServiceListenersRecord& dbusServiceListenersRecord, const std::string &_serviceName) { - const std::unordered_set<std::string> dbusInterfaceNamesCache; + const std::unordered_set<std::string> dbusInterfaceNamesCache {}; const DBusUniqueNamesMapIterator dbusUniqueNameRecordIterator = dbusUniqueNamesMap_.find(dbusServiceListenersRecord.uniqueBusName); @@ -1268,9 +1365,9 @@ void DBusServiceRegistry::notifyDBusObjectPathChanged(DBusInterfaceNameListeners const DBusRecordState& dbusInterfaceNamesState) { const bool isDBusInterfaceNameAvailable = (dbusInterfaceNamesState == DBusRecordState::AVAILABLE); - assert( - dbusInterfaceNamesState == DBusRecordState::AVAILABLE - || dbusInterfaceNamesState == DBusRecordState::NOT_AVAILABLE); + if ((dbusInterfaceNamesState != DBusRecordState::AVAILABLE) && (dbusInterfaceNamesState != DBusRecordState::NOT_AVAILABLE)) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " unexpected state ", int(dbusInterfaceNamesState)); + } for (const auto& dbusInterfaceName : dbusInterfaceNames) { auto dbusInterfaceNameListenersIterator = dbusInterfaceNameListenersMap.find(dbusInterfaceName); @@ -1305,12 +1402,6 @@ void DBusServiceRegistry::notifyDBusInterfaceNameListeners(DBusInterfaceNameList } void DBusServiceRegistry::removeUniqueName(const DBusUniqueNamesMapIterator& dbusUniqueNamesIterator, const std::string &_serviceName) { - const bool isSubscriptionCancelled = dbusDaemonProxy_->getDBusConnection()->removeObjectManagerSignalMemberHandler( - dbusUniqueNamesIterator->first, - this); - assert(isSubscriptionCancelled); - (void)isSubscriptionCancelled; - if ("" != _serviceName) { auto findServiceName = dbusUniqueNamesIterator->second.ownedBusNames.find(_serviceName); if (findServiceName != dbusUniqueNamesIterator->second.ownedBusNames.end()) @@ -1320,7 +1411,16 @@ void DBusServiceRegistry::removeUniqueName(const DBusUniqueNamesMapIterator& dbu } if (dbusUniqueNamesIterator->second.ownedBusNames.size() == 0) { + std::string dbusUniqueName = dbusUniqueNamesIterator->first; dbusUniqueNamesMap_.erase(dbusUniqueNamesIterator); + dbusServicesMutex_.unlock(); + const bool isSubscriptionCancelled = dbusDaemonProxy_->getDBusConnection()->removeObjectManagerSignalMemberHandler( + dbusUniqueName, + this); + if (!isSubscriptionCancelled) { + COMMONAPI_ERROR(std::string(__FUNCTION__), ": still subscribed too ", dbusUniqueName); + } + dbusServicesMutex_.lock(); } else { //delete object path cache entry of service auto& dbusObjectPathsCache = dbusUniqueNamesIterator->second.dbusObjectPathsCache; diff --git a/src/CommonAPI/DBus/DBusStubAdapter.cpp b/src/CommonAPI/DBus/DBusStubAdapter.cpp index 6a3a8cf..422a419 100644 --- a/src/CommonAPI/DBus/DBusStubAdapter.cpp +++ b/src/CommonAPI/DBus/DBusStubAdapter.cpp @@ -5,6 +5,7 @@ #include <CommonAPI/DBus/DBusAddressTranslator.hpp> #include <CommonAPI/DBus/DBusStubAdapter.hpp> +#include <CommonAPI/DBus/DBusFactory.hpp> namespace CommonAPI { namespace DBus { @@ -15,10 +16,12 @@ DBusStubAdapter::DBusStubAdapter(const DBusAddress &_dbusAddress, : dbusAddress_(_dbusAddress), connection_(_connection), isManaging_(_isManaging) { + Factory::get()->incrementConnection(connection_); } DBusStubAdapter::~DBusStubAdapter() { deinit(); + Factory::get()->decrementConnection(connection_); } void DBusStubAdapter::init(std::shared_ptr<DBusStubAdapter> _instance) { |