From 488ff96ce63115ccbfbe1174c50cd0f3a18125ec Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Thu, 26 Jul 2018 22:32:53 +0200 Subject: [PATCH] Add DBus P2P support to XSwiftBus ref T291 --- .../simulation/settings/xswiftbussettings.h | 4 +- .../simulator/xplane/simulatorxplane.cpp | 96 +++++++++++++++---- .../simulator/xplane/simulatorxplane.h | 20 +++- src/plugins/simulator/xplane/xplane.pro | 5 + src/xswiftbus/dbusconnection.cpp | 6 ++ src/xswiftbus/dbusconnection.h | 5 +- src/xswiftbus/dbusserver.cpp | 86 +++++++++++++++++ src/xswiftbus/dbusserver.h | 84 ++++++++++++++++ src/xswiftbus/plugin.cpp | 54 +++++++---- src/xswiftbus/plugin.h | 4 + 10 files changed, 324 insertions(+), 40 deletions(-) create mode 100644 src/xswiftbus/dbusserver.cpp create mode 100644 src/xswiftbus/dbusserver.h diff --git a/src/blackmisc/simulation/settings/xswiftbussettings.h b/src/blackmisc/simulation/settings/xswiftbussettings.h index f93427d1a..aae3e52a8 100644 --- a/src/blackmisc/simulation/settings/xswiftbussettings.h +++ b/src/blackmisc/simulation/settings/xswiftbussettings.h @@ -34,10 +34,10 @@ namespace BlackMisc static const QString &humanReadable() { static const QString name("XSwiftBus"); return name; } //! \copydoc BlackMisc::TSettingTrait::defaultValue - static QString defaultValue() { return BlackMisc::CDBusServer::sessionBusAddress(); } + static QString defaultValue() { return "tcp:host=127.0.0.1,port=45001"; } //! \copydoc BlackMisc::TSettingTrait::defaultValue - static bool isValid(const QString &dBusAddress) { return BlackMisc::CDBusServer::isSessionOrSystemAddress(dBusAddress); } + static bool isValid(const QString &dBusAddress) { return BlackMisc::CDBusServer::isSessionOrSystemAddress(dBusAddress) || BlackMisc::CDBusServer::isQtDBusAddress(dBusAddress); } }; } // ns } // ns diff --git a/src/plugins/simulator/xplane/simulatorxplane.cpp b/src/plugins/simulator/xplane/simulatorxplane.cpp index 0a9d160a2..77079415c 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.cpp +++ b/src/plugins/simulator/xplane/simulatorxplane.cpp @@ -54,6 +54,8 @@ #include "blackmisc/logmessage.h" #include "blackconfig/buildconfig.h" +#include "dbus/dbus.h" + #include #include #include @@ -289,12 +291,29 @@ namespace BlackSimPlugin bool CSimulatorXPlane::connectTo() { if (isConnected()) { return true; } - m_dBusConnection = QDBusConnection::sessionBus(); // TODO make this configurable + QString dbusAddress = m_xswiftbusServerSetting.getThreadLocal(); + + if (BlackMisc::CDBusServer::isSessionOrSystemAddress(dbusAddress)) + { + m_dBusConnection = connectionFromString(dbusAddress); + m_dbusMode = Session; + } + else if (BlackMisc::CDBusServer::isQtDBusAddress(dbusAddress)) + { + m_dBusConnection = QDBusConnection::connectToPeer(dbusAddress, "xswiftbus"); + if (! m_dBusConnection.isConnected()) { return false; } + m_dbusMode = P2P; + } + m_serviceProxy = new CXSwiftBusServiceProxy(m_dBusConnection, this); m_trafficProxy = new CXSwiftBusTrafficProxy(m_dBusConnection, this); m_weatherProxy = new CXSwiftBusWeatherProxy(m_dBusConnection, this); bool ok = false; + bool s = m_dBusConnection.connect(QString(), DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, + "Disconnected", this, SLOT(serviceUnregistered())); + Q_ASSERT(s); + if (m_serviceProxy->isValid() && m_trafficProxy->isValid() && m_weatherProxy->isValid() && m_trafficProxy->initialize()) { emitOwnAircraftModelChanged(m_serviceProxy->getAircraftModelPath(), m_serviceProxy->getAircraftModelFilename(), m_serviceProxy->getAircraftLivery(), @@ -337,6 +356,7 @@ namespace BlackSimPlugin void CSimulatorXPlane::serviceUnregistered() { + if (m_dbusMode == P2P) { m_dBusConnection.disconnectFromPeer(m_dBusConnection.name()); } m_dBusConnection = QDBusConnection { "default" }; if (m_watcher) { m_watcher->setConnection(m_dBusConnection); } delete m_serviceProxy; @@ -428,7 +448,6 @@ namespace BlackSimPlugin { if (str == CDBusServer::sessionBusAddress()) { return QDBusConnection::sessionBus(); } if (str == CDBusServer::systemBusAddress()) { return QDBusConnection::systemBus(); } - Q_UNREACHABLE(); return QDBusConnection("NO CONNECTION"); } @@ -897,9 +916,8 @@ namespace BlackSimPlugin { if (m_trafficProxy) { m_trafficProxy->cleanup(); } - // works for session/system bus - // see CCoreFacade::initDBusConnection for P2P - QDBusConnection::disconnectFromBus(m_dBusConnection.name()); + if (m_dbusMode == P2P) { QDBusConnection::disconnectFromPeer(m_dBusConnection.name()); } + else { QDBusConnection::disconnectFromBus(m_dBusConnection.name()); } } m_dBusConnection = QDBusConnection { "default" }; } @@ -1067,21 +1085,29 @@ namespace BlackSimPlugin } CSimulatorXPlaneListener::CSimulatorXPlaneListener(const CSimulatorPluginInfo &info): ISimulatorListener(info) - { } + { + constexpr int QueryInterval = 5 * 1000; // 5 seconds + m_timer.setInterval(QueryInterval); + m_timer.setObjectName(this->objectName().append(":m_timer")); + connect(&m_timer, &QTimer::timeout, this, &CSimulatorXPlaneListener::checkConnectionViaPeer); + } void CSimulatorXPlaneListener::startImpl() { - if (m_watcher) { return; } // already started - if (isXSwiftBusRunning()) + QString dbusAddress = m_xswiftbusServerSetting.getThreadLocal(); + + if (BlackMisc::CDBusServer::isSessionOrSystemAddress(dbusAddress)) { - emit simulatorStarted(getPluginInfo()); + checkConnectionViaBus(dbusAddress); + } + else if (BlackMisc::CDBusServer::isQtDBusAddress(dbusAddress)) + { + m_timer.start(); } else { - CLogMessage(this).debug() << "Watching XSwiftBus on" << m_xswiftbusServerSetting.getThreadLocal(); - m_conn = CSimulatorXPlane::connectionFromString(m_xswiftbusServerSetting.getThreadLocal()); - m_watcher = new QDBusServiceWatcher(xswiftbusServiceName(), m_conn, QDBusServiceWatcher::WatchForRegistration, this); - connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &CSimulatorXPlaneListener::serviceRegistered); + CLogMessage(this).warning("Invalid DBus address. Not listening for X-Plane connections!"); + return; } } @@ -1092,20 +1118,53 @@ namespace BlackSimPlugin delete m_watcher; m_watcher = nullptr; } + m_timer.stop(); } - bool CSimulatorXPlaneListener::isXSwiftBusRunning() const + void CSimulatorXPlaneListener::checkConnectionViaBus(const QString &address) { - QDBusConnection conn = CSimulatorXPlane::connectionFromString(m_xswiftbusServerSetting.getThreadLocal()); - CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(conn); - CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(conn); + if (m_watcher) { return; } + m_conn = CSimulatorXPlane::connectionFromString(address); + CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(m_conn); + CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(m_conn); bool result = service->isValid() && traffic->isValid(); service->deleteLater(); traffic->deleteLater(); - return result; + if (result) + { + emit simulatorStarted(getPluginInfo()); + m_conn.disconnectFromBus(m_conn.name()); + } + else + { + m_watcher = new QDBusServiceWatcher(xswiftbusServiceName(), m_conn, QDBusServiceWatcher::WatchForRegistration, this); + connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &CSimulatorXPlaneListener::serviceRegistered); + } + } + + void CSimulatorXPlaneListener::checkConnectionViaPeer() + { + m_conn = QDBusConnection::connectToPeer(m_xswiftbusServerSetting.getThreadLocal(), "xswiftbus"); + if (! m_conn.isConnected()) + { + // This is required to cleanup the connection in QtDBus + m_conn.disconnectFromPeer(m_conn.name()); + return; + } + + CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(m_conn); + CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(m_conn); + + bool result = service->isValid() && traffic->isValid(); + + service->deleteLater(); + traffic->deleteLater(); + + if (result) { emit simulatorStarted(getPluginInfo()); } + m_conn.disconnectFromPeer(m_conn.name()); } void CSimulatorXPlaneListener::serviceRegistered(const QString &serviceName) @@ -1114,6 +1173,7 @@ namespace BlackSimPlugin { emit simulatorStarted(getPluginInfo()); } + m_conn.disconnectFromBus(m_conn.name()); } void CSimulatorXPlaneListener::xSwiftBusServerSettingChanged() diff --git a/src/plugins/simulator/xplane/simulatorxplane.h b/src/plugins/simulator/xplane/simulatorxplane.h index afda85279..cbeeb12aa 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.h +++ b/src/plugins/simulator/xplane/simulatorxplane.h @@ -162,10 +162,18 @@ namespace BlackSimPlugin } //! @} + private slots: + void serviceUnregistered(); + private: + enum DBusMode + { + Session, + P2P + }; + using QDoubleList = QList; - void serviceUnregistered(); void setAirportsInRange(const QStringList &icaoCodes, const QStringList &names, const BlackMisc::CSequence &lats, const BlackMisc::CSequence &lons, const BlackMisc::CSequence &alts); void emitOwnAircraftModelChanged(const QString &path, const QString &filename, const QString &livery, const QString &icao, const QString &modelString, const QString &name, const QString &description); @@ -215,6 +223,8 @@ namespace BlackSimPlugin //! Dsiconnect from DBus void disconnectFromDBus(); + DBusMode m_dbusMode; + BlackMisc::CSettingReadOnly m_xswiftbusServerSetting { this }; static constexpr qint64 TimeoutAdding = 10000; QDBusConnection m_dBusConnection { "default" }; QDBusServiceWatcher *m_watcher { nullptr }; @@ -264,12 +274,16 @@ namespace BlackSimPlugin virtual void stopImpl() override; private: - //! Check if XSwiftBus service is already registered - bool isXSwiftBusRunning() const; + //! Check if XSwiftBus service is already registered on the bus + void checkConnectionViaBus(const QString &address); + + //! Check if XSwiftBus service is available via P2P address + void checkConnectionViaPeer(); void serviceRegistered(const QString &serviceName); void xSwiftBusServerSettingChanged(); + QTimer m_timer { this }; QDBusConnection m_conn { "default" }; QDBusServiceWatcher *m_watcher { nullptr }; BlackMisc::CSettingReadOnly m_xswiftbusServerSetting { this, &CSimulatorXPlaneListener::xSwiftBusServerSettingChanged }; diff --git a/src/plugins/simulator/xplane/xplane.pro b/src/plugins/simulator/xplane/xplane.pro index 90a5d466e..1865e635f 100644 --- a/src/plugins/simulator/xplane/xplane.pro +++ b/src/plugins/simulator/xplane/xplane.pro @@ -11,6 +11,11 @@ CONFIG += blackmisc blackcore blackgui blackconfig DEPENDPATH += . $$SourceRoot/src INCLUDEPATH += . $$SourceRoot/src +unix:!macx { + INCLUDEPATH *= /usr/include/dbus-1.0 + INCLUDEPATH *= /usr/lib/x86_64-linux-gnu/dbus-1.0/include +} + SOURCES += *.cpp HEADERS += *.h DISTFILES += simulatorxplane.json diff --git a/src/xswiftbus/dbusconnection.cpp b/src/xswiftbus/dbusconnection.cpp index e199116fa..69419f0bd 100644 --- a/src/xswiftbus/dbusconnection.cpp +++ b/src/xswiftbus/dbusconnection.cpp @@ -24,6 +24,12 @@ namespace XSwiftBus dbus_threads_init_default(); } + CDBusConnection::CDBusConnection(DBusConnection *connection) + { + dbus_connection_ref(connection); + // Don't exit application, if the connection is disconnected + dbus_connection_set_exit_on_disconnect(connection, false); + m_connection.reset(connection); } CDBusConnection::~CDBusConnection() diff --git a/src/xswiftbus/dbusconnection.h b/src/xswiftbus/dbusconnection.h index 1ad1017b0..3d1f78e17 100644 --- a/src/xswiftbus/dbusconnection.h +++ b/src/xswiftbus/dbusconnection.h @@ -34,9 +34,12 @@ namespace XSwiftBus //! Bus type enum BusType { SessionBus }; - //! Constructor + //! Default constructor CDBusConnection(); + //! Constructor + CDBusConnection(DBusConnection *connection); + //! Destructor ~CDBusConnection(); diff --git a/src/xswiftbus/dbusserver.cpp b/src/xswiftbus/dbusserver.cpp new file mode 100644 index 000000000..84f1430b9 --- /dev/null +++ b/src/xswiftbus/dbusserver.cpp @@ -0,0 +1,86 @@ +#include + +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "dbusserver.h" +#include "dbusobject.h" +#include "utils.h" + +#include +#include +#include + +namespace XSwiftBus +{ + + CDBusServer::CDBusServer() + { + dbus_threads_init_default(); + } + + CDBusServer::~CDBusServer() + { + close(); + } + + bool CDBusServer::listen(const std::string &address) + { + DBusError error; + dbus_error_init(&error); + m_server.reset(dbus_server_listen(address.c_str(), &error)); + dbus_server_set_new_connection_function(m_server.get(), onNewConnection, this, nullptr); + return true; + } + + bool CDBusServer::isConnected() const + { + return dbus_server_get_is_connected(m_server.get()); + } + + void CDBusServer::close() + { + dbus_server_disconnect(m_server.get()); + } + + void CDBusServer::setDispatcher(CDBusDispatcher *dispatcher) + { + assert(dispatcher); + + m_dispatcher = dispatcher; + + dbus_server_set_watch_functions( + m_server.get(), + dispatcher->m_watchCallbacks.add, + dispatcher->m_watchCallbacks.remove, + dispatcher->m_watchCallbacks.toggled, + &dispatcher->m_watchCallbacks, nullptr); + + dbus_server_set_timeout_functions( + m_server.get(), + dispatcher->m_timeoutCallbacks.add, + dispatcher->m_timeoutCallbacks.remove, + dispatcher->m_timeoutCallbacks.toggled, + &dispatcher->m_timeoutCallbacks, nullptr); + } + + void CDBusServer::onNewConnection(DBusServer *, DBusConnection *conn) + { + INFO_LOG("onNewConnection"); + auto dbusConnection = std::make_shared(conn); + m_newConnectionFunc(dbusConnection); + } + + void CDBusServer::onNewConnection(DBusServer *server, DBusConnection *conn, void *data) + { + auto *obj = static_cast(data); + return obj->onNewConnection(server, conn); + } + +} diff --git a/src/xswiftbus/dbusserver.h b/src/xswiftbus/dbusserver.h new file mode 100644 index 000000000..a7211008f --- /dev/null +++ b/src/xswiftbus/dbusserver.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKSIM_XSWIFTBUS_DBUSSERVER_H +#define BLACKSIM_XSWIFTBUS_DBUSSERVER_H + +#include "dbusmessage.h" +#include "dbuserror.h" +#include "dbuscallbacks.h" +#include "dbusdispatcher.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace XSwiftBus +{ + + class CDBusObject; + + //! DBus connection + class CDBusServer : public IDispatchable + { + public: + //! New connection handler function + using NewConnectionFunc = std::function)>; + + //! Constructor + CDBusServer(); + + //! Destructor + ~CDBusServer(); + + //! Set the dispatcher + void setDispatcher(CDBusDispatcher *dispatcher); + + //! Connect to bus + bool listen(const std::string &address); + + //! Is connected? + bool isConnected() const; + + void dispatch() {} + + //! Close connection + void close(); + + //! Get the last error + CDBusError lastError() const { return m_lastError; } + + //! Set the function to be used for handling new connections. + void setNewConnectionFunc(const NewConnectionFunc &func) + { + m_newConnectionFunc = func; + } + + private: + void onNewConnection(DBusServer *server, DBusConnection *conn); + static void onNewConnection(DBusServer *server, DBusConnection *conn, void *data); + + struct DBusServerDeleter + { + void operator()(DBusServer *obj) const { dbus_server_unref(obj); } + }; + + std::unique_ptr m_server; + CDBusError m_lastError; + CDBusDispatcher *m_dispatcher; + NewConnectionFunc m_newConnectionFunc; + }; + +} + +#endif // guard diff --git a/src/xswiftbus/plugin.cpp b/src/xswiftbus/plugin.cpp index c6bf1617e..f8c9fc504 100644 --- a/src/xswiftbus/plugin.cpp +++ b/src/xswiftbus/plugin.cpp @@ -36,13 +36,13 @@ namespace XSwiftBus m_planeViewSubMenu = m_menu.subMenu("Follow Plane View"); planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item("Own Aircraft", [this] { switchToOwnAircraftView(); }); - m_dbusThread = std::thread([this]() + /*m_dbusThread = std::thread([this]() { while(!m_shouldStop) { m_dbusConnection->runBlockingEventLoop(); } - }); + });*/ XPLMRegisterFlightLoopCallback(flightLoopCallback, -1, this); } @@ -67,25 +67,47 @@ namespace XSwiftBus m_traffic->setPlaneViewMenu(m_planeViewSubMenu); - // Todo: retry if it fails - bool success = m_dbusConnection->connect(CDBusConnection::SessionBus); - - if (!success) + if (m_useDBusP2P) { - // Print error - return; + m_dbusP2PServer = std::make_unique(); + + // FIXME: make listen address configurable + m_dbusP2PServer->listen("tcp:host=127.0.0.1,port=45000"); + m_dbusP2PServer->setDispatcher(&m_dbusDispatcher); + + m_dbusP2PServer->setNewConnectionFunc([this](const std::shared_ptr &conn) + { + m_dbusConnection = conn; + m_dbusConnection->setDispatcher(&m_dbusDispatcher); + m_service->setDBusConnection(m_dbusConnection); + m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath()); + m_traffic->setDBusConnection(m_dbusConnection); + m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath()); + m_weather->setDBusConnection(m_dbusConnection); + m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath()); + }); } + else + { + // Todo: retry if it fails + bool success = m_dbusConnection->connect(CDBusConnection::SessionBus); - m_dbusConnection->setDispatcher(&m_dbusDispatcher); - m_dbusConnection->requestName(xswiftbusServiceName()); + if (!success) + { + // Print error + return; + } - m_service->setDBusConnection(m_dbusConnection); - m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath()); - m_traffic->setDBusConnection(m_dbusConnection); - m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath()); - m_weather->setDBusConnection(m_dbusConnection); - m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath()); + m_dbusConnection->setDispatcher(&m_dbusDispatcher); + m_dbusConnection->requestName(xswiftbusServiceName()); + m_service->setDBusConnection(m_dbusConnection); + m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath()); + m_traffic->setDBusConnection(m_dbusConnection); + m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath()); + m_weather->setDBusConnection(m_dbusConnection); + m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath()); + } INFO_LOG("XSwiftBus started."); } diff --git a/src/xswiftbus/plugin.h b/src/xswiftbus/plugin.h index c747c5489..9913a45a7 100644 --- a/src/xswiftbus/plugin.h +++ b/src/xswiftbus/plugin.h @@ -23,6 +23,7 @@ #include "dbusconnection.h" #include "dbusdispatcher.h" +#include "dbusserver.h" #include "datarefs.h" #include "XPLM/XPLMCamera.h" #include "menus.h" @@ -55,6 +56,7 @@ namespace XSwiftBus private: CDBusDispatcher m_dbusDispatcher; + std::unique_ptr m_dbusP2PServer; std::shared_ptr m_dbusConnection; std::unique_ptr m_service; std::unique_ptr m_traffic; @@ -72,6 +74,8 @@ namespace XSwiftBus std::thread m_dbusThread; bool m_shouldStop = false; + bool m_useDBusP2P = true; + void startServer(CDBusConnection::BusType bus); void switchToOwnAircraftView();