diff options
Diffstat (limited to 'src/dbus/qdbusconnection.cpp')
-rw-r--r-- | src/dbus/qdbusconnection.cpp | 310 |
1 files changed, 179 insertions, 131 deletions
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 0adb3dd748..e9196173ad 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Intel Corporation. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtDBus module of the Qt Toolkit. @@ -58,6 +59,41 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager) +struct QDBusConnectionManager::ConnectionRequestData +{ + enum RequestType { + ConnectToStandardBus, + ConnectToBusByAddress, + ConnectToPeerByAddress + } type; + + union { + QDBusConnection::BusType busType; + const QString *busAddress; + }; + const QString *name; + + QDBusConnectionPrivate *result; +}; + +QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type) +{ + Q_STATIC_ASSERT(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1); + Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus); + + if (!qdbus_loadLibDBus()) + return 0; + + QMutexLocker lock(&defaultBusMutex); + if (defaultBuses[type]) + return defaultBuses[type]; + + QString name = QStringLiteral("qt_default_session_bus"); + if (type == QDBusConnection::SystemBus) + name = QStringLiteral("qt_default_system_bus"); + return defaultBuses[type] = connectToBus(type, name); +} + QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const { return connectionHash.value(name, 0); @@ -68,7 +104,7 @@ void QDBusConnectionManager::removeConnection(const QString &name) QDBusConnectionPrivate *d = 0; d = connectionHash.take(name); if (d && !d->ref.deref()) - d->deleteYourself(); + d->deleteLater(); // Static objects may be keeping the connection open. // However, it is harmless to have outstanding references to a connection that is @@ -77,17 +113,22 @@ void QDBusConnectionManager::removeConnection(const QString &name) // ### Output a warning if connections are being used after they have been removed. } +QDBusConnectionManager::QDBusConnectionManager() +{ + connect(this, &QDBusConnectionManager::connectionRequested, + this, &QDBusConnectionManager::executeConnectionRequest, Qt::BlockingQueuedConnection); + connect(this, &QDBusConnectionManager::serverRequested, + this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection); + moveToThread(this); // ugly, don't do this in other projects + + defaultBuses[0] = defaultBuses[1] = Q_NULLPTR; + start(); +} + QDBusConnectionManager::~QDBusConnectionManager() { - for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin(); - it != connectionHash.constEnd(); ++it) { - QDBusConnectionPrivate *d = it.value(); - if (!d->ref.deref()) - d->deleteYourself(); - else - d->closeConnection(); - } - connectionHash.clear(); + quit(); + wait(); } QDBusConnectionManager* QDBusConnectionManager::instance() @@ -106,6 +147,122 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP c->name = name; } +void QDBusConnectionManager::run() +{ + exec(); + + // cleanup: + QMutexLocker locker(&mutex); + for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin(); + it != connectionHash.constEnd(); ++it) { + QDBusConnectionPrivate *d = it.value(); + if (!d->ref.deref()) { + delete d; + } else { + d->closeConnection(); + d->moveToThread(Q_NULLPTR); // allow it to be deleted in another thread + } + } + connectionHash.clear(); + + // allow deletion from any thread without warning + moveToThread(Q_NULLPTR); +} + +QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name) +{ + ConnectionRequestData data; + data.type = ConnectionRequestData::ConnectToStandardBus; + data.busType = type; + data.name = &name; + + emit connectionRequested(&data); + return data.result; +} + +QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name) +{ + ConnectionRequestData data; + data.type = ConnectionRequestData::ConnectToBusByAddress; + data.busAddress = &address; + data.name = &name; + + emit connectionRequested(&data); + return data.result; +} + +QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name) +{ + ConnectionRequestData data; + data.type = ConnectionRequestData::ConnectToPeerByAddress; + data.busAddress = &address; + data.name = &name; + + emit connectionRequested(&data); + return data.result; +} + +void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data) +{ + QMutexLocker locker(&mutex); + const QString &name = *data->name; + QDBusConnectionPrivate *&d = data->result; + + // check if the connection exists by name + d = connection(name); + if (d || name.isEmpty()) + return; + + d = new QDBusConnectionPrivate; + DBusConnection *c = 0; + QDBusErrorInternal error; + switch (data->type) { + case ConnectionRequestData::ConnectToStandardBus: + switch (data->busType) { + case QDBusConnection::SystemBus: + c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error); + break; + case QDBusConnection::SessionBus: + c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error); + break; + case QDBusConnection::ActivationBus: + c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error); + break; + } + break; + + case ConnectionRequestData::ConnectToBusByAddress: + case ConnectionRequestData::ConnectToPeerByAddress: + c = q_dbus_connection_open_private(data->busAddress->toUtf8().constData(), error); + if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) { + // register on the bus + if (!q_dbus_bus_register(c, error)) { + q_dbus_connection_unref(c); + c = 0; + } + } + break; + } + + setConnection(name, d); + if (data->type == ConnectionRequestData::ConnectToPeerByAddress) { + d->setPeer(c, error); + } else { + // create the bus service + // will lock in QDBusConnectionPrivate::connectRelay() + d->setConnection(c, error); + d->createBusService(); + } +} + +void QDBusConnectionManager::createServer(const QString &address, void *server) +{ + QDBusErrorInternal error; + QDBusConnectionPrivate *d = new QDBusConnectionPrivate; + d->setServer(static_cast<QDBusServer *>(server), + q_dbus_server_listen(address.toUtf8().constData(), error), error); +} + /*! \class QDBusConnection \inmodule QtDBus @@ -268,7 +425,7 @@ QDBusConnection::QDBusConnection(QDBusConnectionPrivate *dd) QDBusConnection::~QDBusConnection() { if (d && !d->ref.deref()) - d->deleteYourself(); + d->deleteLater(); } /*! @@ -283,7 +440,7 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other) if (other.d) other.d->ref.ref(); if (d && !d->ref.deref()) - d->deleteYourself(); + d->deleteLater(); d = other.d; return *this; } @@ -295,44 +452,11 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other) */ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name) { -// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", -// "Cannot create connection without a Q[Core]Application instance"); if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } - - QMutexLocker locker(&_q_manager()->mutex); - - QDBusConnectionPrivate *d = _q_manager()->connection(name); - if (d || name.isEmpty()) - return QDBusConnection(d); - - d = new QDBusConnectionPrivate; - DBusConnection *c = 0; - QDBusErrorInternal error; - switch (type) { - case SystemBus: - c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error); - break; - case SessionBus: - c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error); - break; - case ActivationBus: - c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error); - break; - } - d->setConnection(c, error); //setConnection does the error handling for us - - _q_manager()->setConnection(name, d); - - QDBusConnection retval(d); - - // create the bus service - // will lock in QDBusConnectionPrivate::connectRelay() - d->setBusService(retval); - - return retval; + return QDBusConnection(_q_manager()->connectToBus(type, name)); } /*! @@ -342,39 +466,11 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name) QDBusConnection QDBusConnection::connectToBus(const QString &address, const QString &name) { -// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", -// "Cannot create connection without a Q[Core]Application instance"); if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } - - QMutexLocker locker(&_q_manager()->mutex); - - QDBusConnectionPrivate *d = _q_manager()->connection(name); - if (d || name.isEmpty()) - return QDBusConnection(d); - - d = new QDBusConnectionPrivate; - // setConnection does the error handling for us - QDBusErrorInternal error; - DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error); - if (c) { - if (!q_dbus_bus_register(c, error)) { - q_dbus_connection_unref(c); - c = 0; - } - } - d->setConnection(c, error); - _q_manager()->setConnection(name, d); - - QDBusConnection retval(d); - - // create the bus service - // will lock in QDBusConnectionPrivate::connectRelay() - d->setBusService(retval); - - return retval; + return QDBusConnection(_q_manager()->connectToBus(address, name)); } /*! \since 4.8 @@ -385,30 +481,11 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, QDBusConnection QDBusConnection::connectToPeer(const QString &address, const QString &name) { -// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", -// "Cannot create connection without a Q[Core]Application instance"); if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } - - QMutexLocker locker(&_q_manager()->mutex); - - QDBusConnectionPrivate *d = _q_manager()->connection(name); - if (d || name.isEmpty()) - return QDBusConnection(d); - - d = new QDBusConnectionPrivate; - // setPeer does the error handling for us - QDBusErrorInternal error; - DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error); - - d->setPeer(c, error); - _q_manager()->setConnection(name, d); - - QDBusConnection retval(d); - - return retval; + return QDBusConnection(_q_manager()->connectToPeer(address, name)); } /*! @@ -467,7 +544,7 @@ bool QDBusConnection::send(const QDBusMessage &message) const d->lastError = err; return false; } - return d->send(message) != 0; + return d->send(message); } /*! @@ -688,7 +765,6 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const return false; } - QDBusWriteLocker locker(ConnectAction, d); return d->connectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot); } @@ -744,7 +820,6 @@ bool QDBusConnection::disconnect(const QString &service, const QString &path, co if (interface.isEmpty() && name.isEmpty()) return false; - QDBusWriteLocker locker(DisconnectAction, d); return d->disconnectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot); } @@ -929,7 +1004,7 @@ QObject *QDBusConnection::objectRegisteredAt(const QString &path) const */ QDBusConnectionInterface *QDBusConnection::interface() const { - if (!d) + if (!d || d->mode != QDBusConnectionPrivate::ClientMode) return 0; return d->busService; } @@ -1052,35 +1127,6 @@ bool QDBusConnection::unregisterService(const QString &serviceName) return false; } -static const char _q_sessionBusName[] = "qt_default_session_bus"; -static const char _q_systemBusName[] = "qt_default_system_bus"; - -class QDBusDefaultConnection: public QDBusConnection -{ - const char *ownName; -public: - inline QDBusDefaultConnection(BusType type, const char *name) - : QDBusConnection(connectToBus(type, QString::fromLatin1(name))), ownName(name) - { - // make sure this connection is running on the main thread - QCoreApplication *instance = QCoreApplication::instance(); - if (!instance) { - qWarning("QDBusConnection: %s D-Bus connection created before QCoreApplication. Application may misbehave.", - type == SessionBus ? "session" : type == SystemBus ? "system" : "generic"); - } else if (QDBusConnectionPrivate::d(*this)) { - QDBusConnectionPrivate::d(*this)->moveToThread(instance->thread()); - } - } - - inline ~QDBusDefaultConnection() - { disconnectFromBus(QString::fromLatin1(ownName)); } -}; - -Q_GLOBAL_STATIC_WITH_ARGS(QDBusDefaultConnection, _q_sessionBus, - (QDBusConnection::SessionBus, _q_sessionBusName)) -Q_GLOBAL_STATIC_WITH_ARGS(QDBusDefaultConnection, _q_systemBus, - (QDBusConnection::SystemBus, _q_systemBusName)) - /*! \fn QDBusConnection QDBusConnection::sessionBus() @@ -1090,7 +1136,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QDBusDefaultConnection, _q_systemBus, */ QDBusConnection QDBusConnection::sessionBus() { - return *_q_sessionBus(); + return QDBusConnection(_q_manager()->busConnection(SessionBus)); } /*! @@ -1102,7 +1148,7 @@ QDBusConnection QDBusConnection::sessionBus() */ QDBusConnection QDBusConnection::systemBus() { - return *_q_systemBus(); + return QDBusConnection(_q_manager()->busConnection(SystemBus)); } #if QT_DEPRECATED_SINCE(5,5) @@ -1123,8 +1169,10 @@ QDBusConnection QDBusConnection::sender() /*! \internal */ -void QDBusConnectionPrivate::setBusService(const QDBusConnection &connection) +void QDBusConnectionPrivate::createBusService() { + Q_ASSERT(mode == ClientMode); + QDBusConnection connection(this); busService = new QDBusConnectionInterface(connection, this); ref.deref(); // busService has increased the refcounting to us // avoid cyclic refcounting |