/* 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 "blackmisc/logmessage.h" #include "blackmisc/networkutils.h" #include "dbus_server.h" #include #include using namespace BlackMisc; namespace BlackCore { /* * Constructor * Remark, without the default "unix:tmpdir=/tmp" any refereal to address crashes * see http://download.froglogic.com/public/qt5-squishcoco-report/QtBase/source_241_preprocessed.html * DBus config: http://dbus.freedesktop.org/doc/dbus-daemon.1.html */ CDBusServer::CDBusServer(const QString &service, const QString &address, QObject *parent) : QObject(parent) { ServerMode m = CDBusServer::addressToDBusMode(address); switch (m) { case SERVERMODE_SESSIONBUS: { // we use a session bus connection instead of a real P2P connection this->m_serverMode = CDBusServer::SERVERMODE_SESSIONBUS; QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, ServiceName()); 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, server started? dbus-daemon.exe --session --address=tcp:host=192.168.0.133,port=45000"); } } break; case SERVERMODE_SYSTEMBUS: { // we use a system bus connection instead of a real P2P connection this->m_serverMode = CDBusServer::SERVERMODE_SYSTEMBUS; QDBusConnection 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, server started? dbus-daemon.exe --session --address=tcp:host=192.168.0.133,port=45000"); } } break; case SERVERMODE_P2P: default: { this->m_serverMode = CDBusServer::SERVERMODE_P2P; this->m_busServer.reset( new QDBusServer( CDBusServer::isQtDBusAddress(address) ? address : "tcp:host=127.0.0.1,port=45000", // "unix:tmpdir=/tmp" parent) ); m_busServer->setAnonymousAuthenticationAllowed(true); // Note: P2P has no service name if (!m_busServer->isConnected()) { CLogMessage(this).warning("DBus P2P connection failed: %1") << this->lastQDBusServerError().message(); } else { CLogMessage(this).debug() << "Server listening on address: " << m_busServer->address(); } connect(m_busServer.data(), &QDBusServer::newConnection, this, &CDBusServer::ps_registerObjectsWithP2PConnection); } break; } // switch } /* * Name of service */ const QString &CDBusServer::ServiceName() { static const QString sn(BLACKCORE_RUNTIME_SERVICENAME); return sn; } /* * Check for P2P address */ bool CDBusServer::isP2P(const QString &address) { return CDBusServer::addressToDBusMode(address) == SERVERMODE_P2P; } /* * Is Qt DBus address */ bool CDBusServer::isQtDBusAddress(const QString &address) { return (address.startsWith("tcp:") || address.startsWith("unix:") ); } /* * Class info */ const QString CDBusServer::getClassInfo(QObject *object) { if (!object) return ""; const QMetaObject *mo = object->metaObject(); if (mo->classInfoCount() < 1) return ""; 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 ""; } /* * Connection established */ bool CDBusServer::ps_registerObjectsWithP2PConnection(const QDBusConnection &connection) { Q_ASSERT(!this->m_objects.isEmpty()); QDBusConnection newConnection(connection); // copy, because object will be registered on this connection // insert or replace connection m_DBusConnections.insert(newConnection.name(), newConnection); bool success = true; CLogMessage(this).debug() << "New Connection from: " << newConnection.name(); QMap::ConstIterator i = m_objects.begin(); while (i != m_objects.end()) { CLogMessage(this).debug() << "Adding " << i.key() << CDBusServer::getClassInfo(i.value()) << "to the new connection."; bool ok = newConnection.registerObject(i.key(), i.value(), CDBusServer::RegisterOptions()); Q_ASSERT_X(ok, "CDBusServer::newConnection", "Registration failed"); if (!ok) { success = false; } ++i; } return success; } /* * Add the objects */ void CDBusServer::addObject(const QString &path, QObject *object) { if (!object) { return; } m_objects.insert(path, object); // For P2P: registered when P2P connection is established // P2P if (this->m_serverMode == CDBusServer::SERVERMODE_P2P) { return; } bool success = false; if (this->m_serverMode == CDBusServer::SERVERMODE_SESSIONBUS) { QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, ServiceName()); success = connection.registerObject(path, object, CDBusServer::RegisterOptions()); if (success) { CLogMessage(this).debug() << "Adding " << path << CDBusServer::getClassInfo(object) << " to session bus."; } else { CLogMessage(this).error("Error, no success with session bus registration"); } } else if (this->m_serverMode == CDBusServer::SERVERMODE_SYSTEMBUS) { QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, ServiceName()); success = connection.registerObject(path, object, CDBusServer::RegisterOptions()); if (success) { CLogMessage(this).debug() << "Adding " << path << CDBusServer::getClassInfo(object) << " to system bus."; } else { CLogMessage(this).error("Error, no success with system bus registration"); } } else { Q_ASSERT_X(false, "CDBusServer::addObject", "Wrong server mode"); } } /* * Last error */ QDBusError CDBusServer::lastQDBusServerError() const { if (!hasQDBusServer()) { return QDBusError(); } return this->m_busServer->lastError(); } const QDBusServer *CDBusServer::qDBusServer() const { return this->m_busServer.data(); } /* * Real server? */ bool CDBusServer::hasQDBusServer() const { return !this->m_busServer.isNull(); } /* * Unregister all objects */ void CDBusServer::unregisterAllObjects() { if (this->m_objects.isEmpty()) return; foreach(QString path, this->m_objects.keys()) { switch (this->m_serverMode) { case CDBusServer::SERVERMODE_SESSIONBUS: QDBusConnection::sessionBus().unregisterObject(path); break; case CDBusServer::SERVERMODE_SYSTEMBUS: QDBusConnection::systemBus().unregisterObject(path); break; case CDBusServer::SERVERMODE_P2P: { foreach(QDBusConnection connection, this->m_DBusConnections) { connection.unregisterObject(path); } break; } } } // all paths } /* * p2pDBusServer */ QString CDBusServer::p2pAddress(const QString &host, const QString &port) { QString h = host.isEmpty() ? "127.0.0.1" : host.trimmed(); QString p = port; 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(BlackMisc::CNetworkUtils::isValidIPv4Address(p), "p2pAdress", "Wrong IP in String"); QString p2p = QString("tcp:host=%1,port=%2").arg(h).arg(p); return p2p; } /* * Fix address */ QString CDBusServer::fixAddressToDBusAddress(const QString &address) { if (address.isEmpty() || address == sessionDBusServer() || address == systemDBusServer()) return address; if (address.startsWith("tcp:") || address.startsWith("unix:")) return address; return p2pAddress(address); } /* * Convert address to mode */ CDBusServer::ServerMode CDBusServer::addressToDBusMode(const QString &address) { QString a = address.toLower(); if (a == CDBusServer::systemDBusServer()) { return SERVERMODE_SYSTEMBUS; } else if (a == CDBusServer::sessionDBusServer()) { return SERVERMODE_SESSIONBUS; } else { return SERVERMODE_P2P; } } } // namespace