mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-02 06:35:52 +08:00
375 lines
14 KiB
C++
375 lines
14 KiB
C++
/* Copyright (C) 2014
|
|
* 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 "blackmisc/logmessage.h"
|
|
#include "blackmisc/network/networkutils.h"
|
|
#include <QProcess>
|
|
#include <QMetaClassInfo>
|
|
|
|
using namespace BlackMisc::Network;
|
|
|
|
namespace BlackMisc
|
|
{
|
|
|
|
CDBusServer::CDBusServer(const QString &service, const QString &address, QObject *parent) : QObject(parent)
|
|
{
|
|
m_serverMode = modeOfAddress(address);
|
|
switch (m_serverMode)
|
|
{
|
|
case SERVERMODE_SESSIONBUS:
|
|
{
|
|
QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, coreServiceName());
|
|
if (! connection.isConnected())
|
|
{
|
|
launchDBusDaemon();
|
|
connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, coreServiceName());
|
|
}
|
|
|
|
if (! connection.registerService(service))
|
|
{
|
|
// registration fails can either mean something wrong with DBus or service already exists
|
|
CLogMessage(this).warning("DBus registration: %1") << connection.lastError().message();
|
|
CLogMessage(this).warning("Cannot register DBus service, check server running: dbus-daemon.exe --session --address=tcp:host=192.168.0.133,port=45000");
|
|
}
|
|
}
|
|
break;
|
|
case SERVERMODE_SYSTEMBUS:
|
|
{
|
|
QDBusConnection connection = QDBusConnection::systemBus();
|
|
if (!connection.isConnected())
|
|
{
|
|
launchDBusDaemon();
|
|
connection = QDBusConnection::systemBus();
|
|
}
|
|
|
|
if (!connection.registerService(service))
|
|
{
|
|
// registration fails can either mean something wrong with DBus or service already exists
|
|
CLogMessage(this).warning("DBus registration: %1") << connection.lastError().message();
|
|
CLogMessage(this).warning("Cannot register DBus service, check server running: dbus-daemon.exe --system --address=tcp:host=192.168.0.133,port=45000");
|
|
}
|
|
}
|
|
break;
|
|
case SERVERMODE_P2P:
|
|
default:
|
|
{
|
|
QString dbusAddress = isQtDBusAddress(address) ? address : "tcp:host=127.0.0.1,port=45000";
|
|
dbusAddress = dbusAddress.toLower().trimmed().replace(' ', "");
|
|
if (! dbusAddress.contains("bind=")) { dbusAddress = dbusAddress.append(",bind=*"); } // bind to all network interfaces
|
|
|
|
m_busServer.reset(new QDBusServer(dbusAddress, parent));
|
|
m_busServer->setAnonymousAuthenticationAllowed(true);
|
|
|
|
// Note: P2P has no service name
|
|
if (m_busServer->isConnected())
|
|
{
|
|
CLogMessage(this).debug() << "Server listening on address:" << m_busServer->address();
|
|
}
|
|
else
|
|
{
|
|
CLogMessage(this).warning("DBus P2P connection failed: %1") << lastQDBusServerError().message();
|
|
}
|
|
connect(m_busServer.data(), &QDBusServer::newConnection, this, &CDBusServer::ps_registerObjectsWithP2PConnection);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
const QString &CDBusServer::coreServiceName()
|
|
{
|
|
static const QString sn = SWIFT_SERVICENAME;
|
|
return sn;
|
|
}
|
|
|
|
void CDBusServer::launchDBusDaemon()
|
|
{
|
|
const QString program = QStringLiteral("dbus-daemon");
|
|
const QStringList arguments = { QStringLiteral("--config-file=../share/dbus-1/session.conf") };
|
|
bool success = QProcess::startDetached(program, arguments);
|
|
if (!success) { CLogMessage(this).warning("Failed to launch dbus-daemon!"); }
|
|
}
|
|
|
|
bool CDBusServer::isP2PAddress(const QString &address)
|
|
{
|
|
return modeOfAddress(address) == SERVERMODE_P2P;
|
|
}
|
|
|
|
bool CDBusServer::dBusAddressToHostAndPort(QString address, QString &host, int &port)
|
|
{
|
|
address = address.trimmed().toLower().replace(' ', "");
|
|
if (address.contains("host=") || address.contains("port="))
|
|
{
|
|
// "tcp:host=foo.com,port=123"
|
|
QStringList parts(address.split(','));
|
|
for (const QString &part : parts)
|
|
{
|
|
if (part.startsWith("host="))
|
|
{
|
|
host = part.mid(part.lastIndexOf("=") + 1).trimmed();
|
|
}
|
|
else if (part.startsWith("port="))
|
|
{
|
|
bool ok;
|
|
port = part.mid(part.lastIndexOf("=") + 1).trimmed().toInt(&ok);
|
|
if (! ok) { port = -1; }
|
|
}
|
|
}
|
|
if (port < 0) { port = 45000; }
|
|
if (host.isEmpty()) { host = "127.0.0.1"; }
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
host = "";
|
|
port = -1;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CDBusServer::isQtDBusAddress(const QString &address)
|
|
{
|
|
return address.startsWith("tcp:") || address.startsWith("unix:");
|
|
}
|
|
|
|
bool CDBusServer::isSessionOrSystemAddress(const QString &address)
|
|
{
|
|
return address == sessionBusAddress() || address == systemBusAddress();
|
|
}
|
|
|
|
QString CDBusServer::getDBusInterfaceFromClassInfo(QObject *object)
|
|
{
|
|
if (! object) { return ""; }
|
|
const QMetaObject *mo = object->metaObject();
|
|
for (int i = 0; i < mo->classInfoCount(); i++)
|
|
{
|
|
QMetaClassInfo ci = mo->classInfo(i);
|
|
QString name(ci.name());
|
|
if (name == "D-Bus Interface") { return QString(ci.value()); }
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bool CDBusServer::ps_registerObjectsWithP2PConnection(QDBusConnection connection)
|
|
{
|
|
Q_ASSERT(! m_objects.isEmpty());
|
|
m_connections.insert(connection.name(), connection);
|
|
CLogMessage(this).debug() << "New Connection from:" << connection.name();
|
|
bool success = true;
|
|
for (auto i = m_objects.begin(); i != m_objects.end(); ++i)
|
|
{
|
|
CLogMessage(this).debug() << "Adding" << i.key() << getDBusInterfaceFromClassInfo(i.value()) << "to the new connection.";
|
|
bool ok = connection.registerObject(i.key(), i.value(), registerOptions());
|
|
Q_ASSERT_X(ok, "CDBusServer::newConnection", "Registration failed");
|
|
if (! ok) { success = false; }
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void CDBusServer::addObject(const QString &path, QObject *object)
|
|
{
|
|
if (! object) { return; }
|
|
m_objects.insert(path, object); // will be registered when P2P connection is established
|
|
|
|
switch (m_serverMode)
|
|
{
|
|
case SERVERMODE_SESSIONBUS:
|
|
{
|
|
QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, coreServiceName());
|
|
if (connection.registerObject(path, object, registerOptions()))
|
|
{
|
|
CLogMessage(this).debug() << "Adding" << path << getDBusInterfaceFromClassInfo(object) << "to session bus.";
|
|
}
|
|
else
|
|
{
|
|
CLogMessage(this).error("Error, no success with session bus registration");
|
|
}
|
|
}
|
|
break;
|
|
case SERVERMODE_SYSTEMBUS:
|
|
{
|
|
QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, coreServiceName());
|
|
if (connection.registerObject(path, object, registerOptions()))
|
|
{
|
|
CLogMessage(this).debug() << "Adding" << path << getDBusInterfaceFromClassInfo(object) << "to system bus.";
|
|
}
|
|
else
|
|
{
|
|
CLogMessage(this).error("Error, no success with system bus registration");
|
|
}
|
|
}
|
|
break;
|
|
case SERVERMODE_P2P:
|
|
{
|
|
for (QDBusConnection connection : m_connections)
|
|
{
|
|
if (connection.registerObject(path, object, registerOptions()))
|
|
{
|
|
CLogMessage(this).debug() << "Adding" << path << getDBusInterfaceFromClassInfo(object) << "to" << connection.name();
|
|
}
|
|
else
|
|
{
|
|
CLogMessage(this).error("Error, no success with %1 registration") << connection.name();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Q_ASSERT_X(false, "CDBusServer::addObject", "Wrong server mode");
|
|
}
|
|
}
|
|
|
|
QDBusError CDBusServer::lastQDBusServerError() const
|
|
{
|
|
if (! hasQDBusServer()) { return {}; }
|
|
return m_busServer->lastError();
|
|
}
|
|
|
|
const QDBusServer *CDBusServer::qDBusServer() const
|
|
{
|
|
return m_busServer.data();
|
|
}
|
|
|
|
bool CDBusServer::hasQDBusServer() const
|
|
{
|
|
return ! m_busServer.isNull();
|
|
}
|
|
|
|
void CDBusServer::removeAllObjects()
|
|
{
|
|
for (const QString &path : m_objects.keys())
|
|
{
|
|
switch (m_serverMode)
|
|
{
|
|
case SERVERMODE_SESSIONBUS:
|
|
QDBusConnection::sessionBus().unregisterObject(path);
|
|
break;
|
|
case SERVERMODE_SYSTEMBUS:
|
|
QDBusConnection::systemBus().unregisterObject(path);
|
|
break;
|
|
case SERVERMODE_P2P:
|
|
{
|
|
for (QDBusConnection connection : m_connections)
|
|
{
|
|
connection.unregisterObject(path);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
m_objects.clear();
|
|
}
|
|
|
|
const QDBusConnection &CDBusServer::defaultConnection()
|
|
{
|
|
static QDBusConnection defaultConnection("default");
|
|
return defaultConnection;
|
|
}
|
|
|
|
const QString &CDBusServer::sessionBusAddress()
|
|
{
|
|
static QString session = "session";
|
|
return session;
|
|
}
|
|
|
|
const QString &CDBusServer::systemBusAddress()
|
|
{
|
|
static QString system = "system";
|
|
return system;
|
|
}
|
|
|
|
QString CDBusServer::p2pAddress(const QString &host, const QString &port)
|
|
{
|
|
QString h = host.isEmpty() ? "127.0.0.1" : host.trimmed();
|
|
QString p = port;
|
|
|
|
// can handle host and port separately or combined, e.g. "myhost:1234"
|
|
if (port.isEmpty())
|
|
{
|
|
if (h.contains(":"))
|
|
{
|
|
QStringList parts = h.split(":");
|
|
// todo: Replace assert with input validation
|
|
Q_ASSERT_X(parts.length() == 2, "p2pAdress", "Wrong IP string split");
|
|
h = parts.at(0).trimmed();
|
|
p = parts.at(1).trimmed();
|
|
}
|
|
else
|
|
{
|
|
p = "45000";
|
|
}
|
|
}
|
|
|
|
// todo: Replace assert with input validation
|
|
Q_ASSERT_X(CNetworkUtils::isValidIPv4Address(p), "CDBusServer::p2pAddress", "Wrong IP in String");
|
|
return QString("tcp:host=%1,port=%2").arg(h).arg(p);
|
|
}
|
|
|
|
QString CDBusServer::normalizeAddress(const QString &address)
|
|
{
|
|
if (address.isEmpty() || address == sessionBusAddress() || address == systemBusAddress()) { return address; }
|
|
if (isQtDBusAddress(address)) { return address; }
|
|
return p2pAddress(address);
|
|
}
|
|
|
|
CDBusServer::ServerMode CDBusServer::modeOfAddress(QString address)
|
|
{
|
|
address = address.toLower();
|
|
if (address == systemBusAddress()) { return SERVERMODE_SYSTEMBUS; }
|
|
else if (address == sessionBusAddress()) { return SERVERMODE_SESSIONBUS; }
|
|
else { return SERVERMODE_P2P; }
|
|
}
|
|
|
|
bool CDBusServer::isDBusAvailable(const QString &address, int port, int timeoutMs)
|
|
{
|
|
QString unused;
|
|
return CNetworkUtils::canConnect(address, port, unused, timeoutMs);
|
|
}
|
|
|
|
bool CDBusServer::isDBusAvailable(const QString &address, int port, QString &o_message, int timeoutMs)
|
|
{
|
|
return CNetworkUtils::canConnect(address, port, o_message, timeoutMs);
|
|
}
|
|
|
|
bool CDBusServer::isDBusAvailable(const QString &dbusAddress, QString &o_message, int timeoutMs)
|
|
{
|
|
if (dbusAddress.isEmpty()) { o_message = "no address"; return false; }
|
|
if (isP2PAddress(dbusAddress))
|
|
{
|
|
QString host;
|
|
int port = -1;
|
|
if (dBusAddressToHostAndPort(dbusAddress, host, port))
|
|
{
|
|
return isDBusAvailable(host, port, o_message, timeoutMs);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QDBusConnection connection(dbusAddress == systemBusAddress() ? QDBusConnection::systemBus() : QDBusConnection::connectToBus(QDBusConnection::SessionBus, coreServiceName()));
|
|
|
|
// todo: further checks would need to go here
|
|
// failing session bus not detected yet
|
|
|
|
o_message = connection.lastError().message();
|
|
return connection.isConnected();
|
|
}
|
|
}
|
|
|
|
bool CDBusServer::isDBusAvailable(const QString &dbusAddress, int timeoutMs)
|
|
{
|
|
QString unused;
|
|
return isDBusAvailable(dbusAddress, unused, timeoutMs);
|
|
}
|
|
|
|
} // namespace
|