bool DBusObjectManagerStub::emitInterfacesAddedSignal(std::shared_ptr<DBusStubAdapter> dbusStubAdapter, const std::shared_ptr<DBusProxyConnection>& dbusConnection) const { assert(dbusConnection); assert(dbusConnection->isConnected()); const auto& dbusStubObjectPath = dbusStubAdapter->getObjectPath(); const auto& dbusStubInterfaceName = dbusStubAdapter->getInterfaceName(); DBusMessage dbusSignal = DBusMessage::createSignal(dbusObjectPath_, getInterfaceName(), "InterfacesAdded", "oa{sa{sv}}"); DBusOutputStream dbusOutputStream(dbusSignal); DBusInterfacesAndPropertiesDict dbusInterfacesAndPropertiesDict({ { dbusStubInterfaceName, DBusPropertiesChangedDict() } }); if (dbusStubAdapter->isManagingInterface()) { dbusInterfacesAndPropertiesDict.insert({ getInterfaceName(), DBusPropertiesChangedDict() }); } if (dbusStubAdapter->hasFreedesktopProperties()) { dbusInterfacesAndPropertiesDict.insert({ "org.freedesktop.DBus.Properties", DBusPropertiesChangedDict() }); } dbusOutputStream << dbusStubObjectPath; dbusOutputStream << dbusInterfacesAndPropertiesDict; dbusOutputStream.flush(); const bool dbusSignalEmitted = dbusConnection->sendDBusMessage(dbusSignal); return dbusSignalEmitted; }
bool DBusObjectManagerStub::onInterfaceDBusMessage(const DBusMessage& dbusMessage) { auto dbusConnection = dbusConnection_.lock(); if (!dbusConnection || !dbusConnection->isConnected()) { return false; } if (!dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("GetManagedObjects")) { return false; } std::lock_guard<std::mutex> dbusObjectManagerStubLock(dbusObjectManagerStubLock_); DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; for (const auto& registeredDBusObjectPathIterator : registeredDBusObjectPathsMap_) { const std::string& registeredDBusObjectPath = registeredDBusObjectPathIterator.first; 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; assert(registeredDBusInterfaceName.length() > 0); dbusInterfacesAndPropertiesDict.insert({ registeredDBusInterfaceName, DBusPropertiesChangedDict() }); if (registeredDBusStubAdapter->isManagingInterface()) { dbusInterfacesAndPropertiesDict.insert({ getInterfaceName(), DBusPropertiesChangedDict() }); } } dbusObjectPathAndInterfacesDict.insert({ registeredDBusObjectPath, std::move(dbusInterfacesAndPropertiesDict) }); } DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("a{oa{sa{sv}}}"); DBusOutputStream dbusOutputStream(dbusMessageReply); dbusOutputStream << dbusObjectPathAndInterfacesDict; dbusOutputStream.flush(); const bool dbusMessageReplySent = dbusConnection->sendDBusMessage(dbusMessageReply); return dbusMessageReplySent; }
bool DBusObjectManagerStub::emitInterfacesRemovedSignal(std::shared_ptr<DBusStubAdapter> dbusStubAdapter, const std::shared_ptr<DBusProxyConnection>& dbusConnection) const { assert(dbusConnection); assert(dbusConnection->isConnected()); const auto& dbusStubObjectPath = dbusStubAdapter->getObjectPath(); const auto& dbusStubInterfaceName = dbusStubAdapter->getInterfaceName(); DBusMessage dbusSignal = DBusMessage::createSignal(dbusObjectPath_, getInterfaceName(), "InterfacesRemoved", "oas"); DBusOutputStream dbusOutputStream(dbusSignal); std::vector<std::string> removedInterfaces({ { dbusStubInterfaceName } }); if (dbusStubAdapter->isManagingInterface()) { removedInterfaces.push_back(getInterfaceName()); } dbusOutputStream << dbusStubObjectPath; dbusOutputStream << removedInterfaces; dbusOutputStream.flush(); const bool dbusSignalEmitted = dbusConnection->sendDBusMessage(dbusSignal); return dbusSignalEmitted; }
TEST_F(DBusConnectionTest, SendingAsyncDBusMessagesWorks) { const char busName[] = "commonapi.dbus.test.TestInterfaceHandler"; const char objectPath[] = "/common/api/dbus/test/TestObject"; const char interfaceName[] = "commonapi.dbus.test.TestInterface"; const char methodName[] = "TestMethod"; auto interfaceHandlerDBusConnection = CommonAPI::DBus::DBusConnection::getSessionBus(); ASSERT_TRUE(interfaceHandlerDBusConnection->connect()); ASSERT_TRUE(interfaceHandlerDBusConnection->requestServiceNameAndBlock(busName)); uint32_t serviceHandlerDBusMessageCount = 0; uint32_t clientReplyHandlerDBusMessageCount = 0; interfaceHandlerDBusConnection->setObjectPathMessageHandler( [&serviceHandlerDBusMessageCount, &interfaceHandlerDBusConnection] (CommonAPI::DBus::DBusMessage dbusMessage) -> bool { ++serviceHandlerDBusMessageCount; CommonAPI::DBus::DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(""); interfaceHandlerDBusConnection->sendDBusMessage(dbusMessageReply); return true; } ); interfaceHandlerDBusConnection->registerObjectPath(objectPath); ASSERT_TRUE(dbusConnection_->connect()); CommonAPI::DBus::DBusMessage dbusReplyMessage; for (uint32_t expectedDBusMessageCount = 1; expectedDBusMessageCount <= 10; expectedDBusMessageCount++) { CommonAPI::DBus::DBusMessage dbusMessageCall = CommonAPI::DBus::DBusMessage::createMethodCall( busName, objectPath, interfaceName, methodName, ""); CommonAPI::DBus::DBusOutputStream dbusOutputStream(dbusMessageCall); interfaceHandlerDBusConnection->sendDBusMessageWithReplyAsync( dbusMessageCall, CommonAPI::DBus::DBusProxyAsyncCallbackHandler<>::create( [&clientReplyHandlerDBusMessageCount](CommonAPI::CallStatus status) { ASSERT_EQ(CommonAPI::CallStatus::SUCCESS, status); ++clientReplyHandlerDBusMessageCount; }) ); for (int i = 0; i < 10 && serviceHandlerDBusMessageCount < expectedDBusMessageCount; i++) { interfaceHandlerDBusConnection->readWriteDispatch(100); } ASSERT_EQ(serviceHandlerDBusMessageCount, expectedDBusMessageCount); for (int i = 0; i < 10 && clientReplyHandlerDBusMessageCount < expectedDBusMessageCount; i++) { dbusConnection_->readWriteDispatch(100); } ASSERT_EQ(clientReplyHandlerDBusMessageCount, expectedDBusMessageCount); } dbusConnection_->disconnect(); interfaceHandlerDBusConnection->unregisterObjectPath(objectPath); ASSERT_TRUE(interfaceHandlerDBusConnection->releaseServiceName(busName)); interfaceHandlerDBusConnection->disconnect(); }
bool DBusObjectManager::onIntrospectableInterfaceDBusMessage(const DBusMessage& dbusMessage) { std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock(); if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("Introspect")) { return false; } bool foundRegisteredObjects = false; std::stringstream xmlData(std::ios_base::out); xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" "<node name=\"" << dbusMessage.getObjectPath() << "\">\n" "<interface name=\"org.freedesktop.DBus.Introspectable\">\n" "<method name=\"Introspect\">\n" "<arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n" "</method>\n" "</interface>\n"; std::unordered_set<std::string> nodeSet; for (auto& registeredObjectsIterator : dbusRegisteredObjectsTable_) { const DBusInterfaceHandlerPath& handlerPath = registeredObjectsIterator.first; const std::string& dbusObjectPath = handlerPath.first; const std::string& dbusInterfaceName = handlerPath.second; std::shared_ptr<DBusInterfaceHandler> dbusStubAdapterBase = registeredObjectsIterator.second; std::vector<std::string> elems = CommonAPI::split(dbusObjectPath, '/'); if (dbusMessage.hasObjectPath(dbusObjectPath)) { foundRegisteredObjects = true; xmlData << "<interface name=\"" << dbusInterfaceName << "\">\n" << dbusStubAdapterBase->getMethodsDBusIntrospectionXmlData() << "\n" "</interface>\n"; nodeSet.insert(elems.back()); } else { if (dbusMessage.hasObjectPath("/") && elems.size() > 1) { if (nodeSet.find(elems[1]) == nodeSet.end()) { if (nodeSet.size() == 0) { xmlData.str(""); xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" "<node>\n"; } xmlData << " <node name=\"" << elems[1] << "\"/>\n"; nodeSet.insert(elems[1]); foundRegisteredObjects = true; } } else { for (unsigned int i = 1; i < elems.size() - 1; i++) { std::string build; for (unsigned int j = 1; j <= i; j++) { build = build + "/" + elems[j]; if (dbusMessage.hasObjectPath(build)) { if (nodeSet.find(elems[j + 1]) == nodeSet.end()) { if (nodeSet.size() == 0) { xmlData.str(""); xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n" "<node>\n"; } xmlData << " <node name=\"" << elems[j + 1] << "\"/>\n"; nodeSet.insert(elems[j + 1]); foundRegisteredObjects = true; } break; } } } } } } if (foundRegisteredObjects) { DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("s"); DBusOutputStream dbusOutputStream(dbusMessageReply); xmlData << "</node>" ""; dbusOutputStream << xmlData.str(); dbusOutputStream.flush(); return dbusConnection->sendDBusMessage(dbusMessageReply); } return false; }