summaryrefslogtreecommitdiffstats
path: root/src/dbus/qdbusconnection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbus/qdbusconnection.cpp')
-rw-r--r--src/dbus/qdbusconnection.cpp380
1 files changed, 57 insertions, 323 deletions
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index c4f5e2a0fa..f6918b70b0 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -1,62 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtDBus module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusconnection.h"
#include "qdbusconnection_p.h"
#include <qdebug.h>
-#include <qcoreapplication.h>
#include <qstringlist.h>
-#include <qtimer.h>
-#include <qthread.h>
-#include <QtCore/private/qlocking_p.h>
#include "qdbusconnectioninterface.h"
#include "qdbuserror.h"
#include "qdbusmessage.h"
-#include "qdbusmessage_p.h"
-#include "qdbusinterface_p.h"
#include "qdbusutil_p.h"
#include "qdbusconnectionmanager_p.h"
#include "qdbuspendingcall_p.h"
-
#include "qdbusthreaddebug_p.h"
#include <algorithm>
@@ -69,219 +26,6 @@
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_WIN
-static void preventDllUnload();
-#endif
-
-Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
-
-QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
-{
- static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
- Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
-
- if (!qdbus_loadLibDBus())
- return nullptr;
-
- // we'll start in suspended delivery mode if we're in the main thread
- // (the event loop will resume delivery)
- bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
-
- const auto locker = qt_scoped_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, suspendedDelivery);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
-{
- return connectionHash.value(name, nullptr);
-}
-
-void QDBusConnectionManager::removeConnection(const QString &name)
-{
- QDBusConnectionPrivate *d = nullptr;
- d = connectionHash.take(name);
- if (d && !d->ref.deref())
- d->deleteLater();
-
- // Static objects may be keeping the connection open.
- // However, it is harmless to have outstanding references to a connection that is
- // closing as long as those references will be soon dropped without being used.
-
- // ### 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
-
-#ifdef Q_OS_WIN
- // prevent the library from being unloaded on Windows. See comments in the function.
- preventDllUnload();
-#endif
- defaultBuses[0] = defaultBuses[1] = nullptr;
- start();
-}
-
-QDBusConnectionManager::~QDBusConnectionManager()
-{
- quit();
- wait();
-}
-
-QDBusConnectionManager* QDBusConnectionManager::instance()
-{
- return _q_manager();
-}
-
-Q_DBUS_EXPORT void qDBusBindToApplication();
-void qDBusBindToApplication()
-{
-}
-
-void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
-{
- connectionHash[name] = c;
- c->name = name;
-}
-
-void QDBusConnectionManager::run()
-{
- exec();
-
- // cleanup:
- const auto locker = qt_scoped_lock(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(nullptr); // allow it to be deleted in another thread
- }
- }
- connectionHash.clear();
-
- // allow deletion from any thread without warning
- moveToThread(nullptr);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
- bool suspendedDelivery)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToStandardBus;
- data.busType = type;
- data.name = &name;
- data.suspendedDelivery = suspendedDelivery;
-
- emit connectionRequested(&data);
- if (suspendedDelivery && data.result->connection) {
- data.result->ref.ref();
- QDBusConnectionDispatchEnabler *o = new QDBusConnectionDispatchEnabler(data.result);
- QTimer::singleShot(0, o, SLOT(execute()));
- o->moveToThread(qApp->thread()); // qApp was checked in the caller
- }
- return data.result;
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToBusByAddress;
- data.busAddress = &address;
- data.name = &name;
- data.suspendedDelivery = false;
-
- 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;
- data.suspendedDelivery = false;
-
- emit connectionRequested(&data);
- return data.result;
-}
-
-void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
-{
- const auto locker = qt_scoped_lock(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 = nullptr;
- 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 = nullptr;
- }
- }
- 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();
- if (c && data->suspendedDelivery)
- d->setDispatchEnabled(false);
- }
-}
-
-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
@@ -406,13 +150,17 @@ void QDBusConnectionManager::createServer(const QString &address, void *server)
*/
QDBusConnection::QDBusConnection(const QString &name)
{
- if (name.isEmpty() || _q_manager.isDestroyed()) {
+ if (name.isEmpty()) {
+ d = nullptr;
+ return;
+ }
+
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager) {
d = nullptr;
} else {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- d = _q_manager()->connection(name);
- if (d)
- d->ref.ref();
+ d = manager->existingConnection(name);
}
}
@@ -465,17 +213,19 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
}
/*!
- Opens a connection of type \a type to one of the known busses and
+ Opens a connection of type \a type to one of the known buses and
associate with it the connection name \a name. Returns a
QDBusConnection object associated with that connection.
*/
QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(type, name, false));
+ return QDBusConnection(manager->connectToBus(type, name, false));
}
/*!
@@ -485,11 +235,13 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
QDBusConnection QDBusConnection::connectToBus(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(address, name));
+ return QDBusConnection(manager->connectToBus(address, name));
}
/*!
\since 4.8
@@ -500,11 +252,13 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address,
QDBusConnection QDBusConnection::connectToPeer(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToPeer(address, name));
+ return QDBusConnection(manager->connectToPeer(address, name));
}
/*!
@@ -517,13 +271,11 @@ QDBusConnection QDBusConnection::connectToPeer(const QString &address,
*/
void QDBusConnection::disconnectFromBus(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
- if (d && d->mode != QDBusConnectionPrivate::ClientMode)
- return;
- _q_manager()->removeConnection(name);
- }
+ auto *manager = QDBusConnectionManager::instance();
+ if (!manager)
+ return;
+
+ manager->disconnectFrom(name, QDBusConnectionPrivate::ClientMode);
}
/*!
@@ -538,13 +290,11 @@ void QDBusConnection::disconnectFromBus(const QString &name)
*/
void QDBusConnection::disconnectFromPeer(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
- if (d && d->mode != QDBusConnectionPrivate::PeerMode)
- return;
- _q_manager()->removeConnection(name);
- }
+ auto *manager = QDBusConnectionManager::instance();
+ if (!manager)
+ return;
+
+ manager->disconnectFrom(name, QDBusConnectionPrivate::PeerMode);
}
/*!
@@ -681,6 +431,9 @@ QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode
See the QDBusInterface::asyncCall() function for a more friendly way
of placing calls.
+
+ \note Method calls to objects registered by the application itself are never
+ asynchronous due to implementation limitations.
*/
QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const
{
@@ -889,16 +642,16 @@ bool QDBusConnection::registerObject(const QString &path, const QString &interfa
if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
return false;
- auto pathComponents = QStringView{path}.split(QLatin1Char('/'));
+ auto pathComponents = QStringView{path}.split(u'/');
if (pathComponents.constLast().isEmpty())
pathComponents.removeLast();
QDBusWriteLocker locker(RegisterObjectAction, d);
// lower-bound search for where this object should enter in the tree
- QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator node = &d->rootNode;
+ QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
int i = 1;
while (node) {
- if (pathComponents.count() == i) {
+ if (pathComponents.size() == i) {
// this node exists
// consider it free if there's no object here and the user is not trying to
// replace the object sub-tree
@@ -934,7 +687,7 @@ bool QDBusConnection::registerObject(const QString &path, const QString &interfa
std::lower_bound(node->children.begin(), node->children.end(), pathComponents.at(i));
if (it != node->children.end() && it->name == pathComponents.at(i)) {
// match: this node exists
- node = it;
+ node = &(*it);
// are we allowed to go deeper?
if (node->flags & ExportChildObjects) {
@@ -945,7 +698,8 @@ bool QDBusConnection::registerObject(const QString &path, const QString &interfa
}
} else {
// add entry
- node = node->children.insert(it, pathComponents.at(i).toString());
+ it = node->children.insert(it, pathComponents.at(i).toString());
+ node = &(*it);
}
// iterate
@@ -997,7 +751,7 @@ QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
return nullptr;
- auto pathComponents = QStringView{path}.split(QLatin1Char('/'));
+ auto pathComponents = QStringView{path}.split(u'/');
if (pathComponents.constLast().isEmpty())
pathComponents.removeLast();
@@ -1007,7 +761,7 @@ QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
int i = 1;
while (node) {
- if (pathComponents.count() == i)
+ if (pathComponents.size() == i)
return node->obj;
if ((node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath))
return node->obj;
@@ -1017,7 +771,7 @@ QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
if (it == node->children.constEnd() || it->name != pathComponents.at(i))
break; // node not found
- node = it;
+ node = &(*it);
++i;
}
return nullptr;
@@ -1163,9 +917,11 @@ bool QDBusConnection::unregisterService(const QString &serviceName)
*/
QDBusConnection QDBusConnection::sessionBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SessionBus));
+ return QDBusConnection(manager->busConnection(SessionBus));
}
/*!
@@ -1177,9 +933,11 @@ QDBusConnection QDBusConnection::sessionBus()
*/
QDBusConnection QDBusConnection::systemBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SystemBus));
+ return QDBusConnection(manager->busConnection(SystemBus));
}
/*!
@@ -1254,31 +1012,7 @@ QByteArray QDBusConnection::localMachineId()
QT_END_NAMESPACE
-#ifdef Q_OS_WIN
-# include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-static void preventDllUnload()
-{
- // Thread termination is really wacky on Windows. For some reason we don't
- // understand, exiting from the thread may try to unload the DLL. Since the
- // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
- // a deadlock: the main thread is waiting for the manager thread to exit,
- // but the manager thread is attempting to acquire a lock to unload the DLL.
- //
- // We work around the issue by preventing the unload from happening in the
- // first place.
- //
- // For this trick, see
- // https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
-
- static HMODULE self;
- GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_PIN,
- reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
- &self);
-}
-QT_END_NAMESPACE
-#endif
+#include "moc_qdbusconnection_p.cpp"
+#include "moc_qdbusconnection.cpp"
#endif // QT_NO_DBUS