7 #include <QMetaClassInfo>
16 using namespace swift::misc::network;
33 static const QString desc(
"Mode: %1 Address: '%2' Service: '%3'");
39 case SERVERMODE_SESSIONBUS:
41 QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
coreServiceName());
42 connection.unregisterService(service);
43 if (!connection.isConnected() || !connection.registerService(service))
47 CLogMessage(
this).
warning(u
"Cannot register DBus service, check server running: dbus-daemon.exe "
48 u
"--session --address=tcp:host=192.168.0.133,port=45000");
52 case SERVERMODE_SYSTEMBUS:
54 QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SystemBus,
coreServiceName());
55 connection.unregisterService(service);
56 if (!connection.isConnected() || !connection.registerService(service))
60 CLogMessage(
this).
warning(u
"Cannot register DBus service, check server running: dbus-daemon.exe "
61 u
"--system --address=tcp:host=192.168.0.133,port=45000");
68 QString dbusAddress =
isQtDBusAddress(address) ? address :
"tcp:host=127.0.0.1,port=45000";
69 dbusAddress = dbusAddress.toLower().trimmed().replace(
' ',
"");
70 if (!dbusAddress.contains(
"bind="))
72 dbusAddress = dbusAddress.append(
",bind=*");
75 m_busServer.reset(
new QDBusServer(dbusAddress,
this));
76 m_busServer->setObjectName(
"QDBusServer: " + this->objectName());
77 m_busServer->setAnonymousAuthenticationAllowed(
true);
80 if (m_busServer->isConnected())
82 CLogMessage(
this).
info(u
"DBus P2P Server listening on address: '%1'") << m_busServer->address();
85 connect(m_busServer.data(), &QDBusServer::newConnection,
this,
86 &CDBusServer::registerObjectsWithP2PConnection);
106 static const QString empty;
126 const QString canonicalAddress = address.trimmed().toLower().replace(
' ',
"");
127 if (canonicalAddress.contains(
"host=") || canonicalAddress.contains(
"port="))
130 const QStringList parts(canonicalAddress.split(
','));
131 for (
const QString &part : parts)
134 if (part.contains(
"host=", Qt::CaseInsensitive))
136 const QString h = part.mid(part.lastIndexOf(
"=") + 1).trimmed();
139 else if (part.contains(
"port=", Qt::CaseInsensitive))
141 const QString p = part.mid(part.lastIndexOf(
"=") + 1).trimmed();
144 if (!ok) { port = -1; }
147 if (port < 0) { port = 45000; }
148 if (host.isEmpty()) { host =
"127.0.0.1"; }
163 o_port = QString::number(port);
169 return connection.name() == QDBusConnection::sessionBus().name() ||
170 connection.name() == QDBusConnection::systemBus().name();
175 return address.startsWith(
"tcp:") || address.startsWith(
"unix:");
183 QString CDBusServer::getDBusInterfaceFromClassInfo(QObject *
object)
185 if (!
object) {
return {}; }
186 const QMetaObject *mo =
object->metaObject();
187 for (
int i = 0; i < mo->classInfoCount(); i++)
189 const QMetaClassInfo ci = mo->classInfo(i);
190 const QString name = QString(ci.name()).toLower();
191 if (name ==
"d-bus interface") {
return QString(ci.value()); }
196 QDBusConnection::RegisterOptions CDBusServer::registerOptions()
198 return QDBusConnection::ExportAdaptors | QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllSlots;
201 bool CDBusServer::registerObjectsWithP2PConnection(QDBusConnection connection)
203 Q_ASSERT(!m_objects.isEmpty());
204 m_connections.insert(connection.name(), connection);
205 CLogMessage(
this).info(u
"New Connection from: '%1'") << connection.name();
207 for (
auto i = m_objects.cbegin(); i != m_objects.cend(); ++i)
209 const QString key(i.key());
210 const bool ok = connection.registerObject(key, i.value(), registerOptions());
213 CLogMessage(
this).info(u
"Adding '%1' to the new connection '%2'")
214 << key << this->getDBusInterfaceFromClassInfo(i.value());
218 CLogMessage(
this).info(u
"Adding '%1' failed, connection '%2', error '%3'")
219 << key << this->getDBusInterfaceFromClassInfo(i.value()) << connection.lastError().message();
228 if (!
object) {
return; }
229 m_objects.insert(path,
object);
231 QObject::connect(
object, &QObject::destroyed,
this, [
this, path] { m_objects.remove(path); });
233 switch (m_serverMode)
235 case SERVERMODE_SESSIONBUS:
237 QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
coreServiceName());
238 if (connection.registerObject(path,
object, registerOptions()))
241 << path << getDBusInterfaceFromClassInfo(
object);
246 << path << getDBusInterfaceFromClassInfo(
object) << connection.lastError().message();
250 case SERVERMODE_SYSTEMBUS:
252 QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SystemBus,
coreServiceName());
253 if (connection.registerObject(path,
object, registerOptions()))
256 << path << getDBusInterfaceFromClassInfo(
object);
261 << path << getDBusInterfaceFromClassInfo(
object) << connection.lastError().message();
267 for (QDBusConnection connection : std::as_const(m_connections))
269 if (connection.registerObject(path,
object, registerOptions()))
272 << path << getDBusInterfaceFromClassInfo(
object) << connection.name();
277 << path << getDBusInterfaceFromClassInfo(
object) << connection.name()
278 << connection.lastError().message();
283 default: Q_ASSERT_X(
false, Q_FUNC_INFO,
"Wrong server mode");
290 return m_busServer->lastError();
299 for (
const QString &path :
makeKeysRange(std::as_const(m_objects)))
301 switch (m_serverMode)
303 case SERVERMODE_SESSIONBUS: QDBusConnection::sessionBus().unregisterObject(path);
break;
304 case SERVERMODE_SYSTEMBUS: QDBusConnection::systemBus().unregisterObject(path);
break;
306 for (QDBusConnection connection : std::as_const(m_connections)) { connection.unregisterObject(path); }
321 static const QString session(
"session");
327 static const QString system(
"system");
335 if (name.isEmpty())
return QDBusConnection::sessionBus();
336 return QDBusConnection::connectToBus(QDBusConnection::SessionBus, name);
340 if (name.isEmpty())
return QDBusConnection::systemBus();
341 return QDBusConnection::connectToBus(QDBusConnection::SystemBus, name);
345 return QDBusConnection::connectToPeer(dBusAddress,
348 return QDBusConnection(
"invalid");
355 else { QDBusConnection::disconnectFromBus(connection.name()); }
360 QString h = host.trimmed().toLower().remove(
' ');
361 if (h.isEmpty()) { h =
"127.0.0.1"; }
365 QString p = port.toLower().trimmed();
378 if (h.startsWith(
"tcp:") && h.contains(
"host=") && h.contains(
"port="))
387 const QStringList parts = h.split(
":");
388 h = parts.at(0).trimmed();
389 p = parts.at(1).trimmed();
391 else { p =
"45000"; }
395 Q_ASSERT_X(CNetworkUtils::isValidIPv4Address(p),
"CDBusServer::p2pAddress",
"Wrong IP in String");
396 return QStringLiteral(
"tcp:host=%1,port=%2").arg(h, p);
401 static const QString n(
"p2pConnection");
407 const QString lc(address.toLower().trimmed());
423 address = address.toLower();
426 else {
return SERVERMODE_P2P; }
431 static const QString p2p =
"P2P";
432 static const QString session =
"session";
433 static const QString system =
"system";
437 case SERVERMODE_P2P:
return p2p;
438 case SERVERMODE_SYSTEMBUS:
return system;
439 case SERVERMODE_SESSIONBUS:
448 return CNetworkUtils::canConnect(address, port, unused, timeoutMs);
453 return CNetworkUtils::canConnect(address, port, message, timeoutMs);
458 if (dBusAddress.isEmpty())
460 message =
"No address.";
474 const bool isConnected = connection.isConnected();
475 message = connection.lastError().message();
static void disconnectFromDBus(const QDBusConnection &connection, const QString &dBusAddress)
Disconnect from Bus/Peer to peer.
static bool dBusAddressToHostAndPort(const QString &dbusAddress, QString &o_host, int &o_port)
Extract host and port from a DBus address.
static const QDBusConnection & defaultConnection()
Default connection.
void removeAllObjects()
Remove all objects added with addObject.
static const QString & systemBusAddress()
Address denoting a system bus server.
void addObject(const QString &name, QObject *object)
Add a QObject to be exposed via DBus.
static QDBusConnection connectToDBus(const QString &dbusAddress, const QString &name={})
Connect to DBus.
static bool isSessionOrSystemAddress(const QString &address)
True if address is session or system bus address.
bool hasQDBusServer() const
True if using P2P.
QDBusError lastQDBusServerError() const
Last error.
static const QString & modeToString(ServerMode mode)
Mode to string.
static ServerMode modeOfAddress(QString address)
Return the server mode of the given address.
static bool isDBusAvailable(const QString &host, int port, int timeoutMs=1500)
Is there a DBus server running at the given address?
static const QStringList & getLogCategories()
Log categories.
const QDBusServer * qDBusServer() const
DBus server (if using P2P)
static QString normalizeAddress(const QString &address)
Turn something like 127.0.0.1:45000 into "tcp:host=127.0.0.1,port=45000".
static const QString & sessionBusAddress()
Address denoting a session bus server.
static QString p2pAddress(const QString &host, const QString &port="")
Address denoting a P2P server at the given host and port.
static const QString & p2pConnectionName()
P2P connection name.
CDBusServer(const QString &address, QObject *parent=nullptr)
Construct a server for the core service.
static bool isP2PConnection(const QDBusConnection &connection)
False if address is session or system bus connection.
static bool isQtDefaultConnection(const QDBusConnection &connection)
Is the given connection one of the default connections?
static bool isP2PAddress(const QString &address)
False if address is session or system bus address.
static const QString & coreServiceName()
Default service name.
virtual ~CDBusServer()
Destructor.
static bool isQtDBusAddress(const QString &address)
True if a valid Qt DBus address, e.g. "unix:tmpdir=/tmp", "tcp:host=127.0.0.1,port=45000".
static const QString & dbus()
DBus related.
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
QString message() const
Private.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
#define SWIFT_SERVICENAME
Service name of DBus service.
Free functions in swift::misc.
auto makeKeysRange(const T &container)
Returns a const CRange for iterating over the keys of a Qt associative container.