1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtDBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qdbusconnection.h"
42#include "qdbusconnection_p.h"
43
44#include <qdebug.h>
45#include <qcoreapplication.h>
46#include <qstringlist.h>
47#include <qvector.h>
48#include <qtimer.h>
49#include <qthread.h>
50#include <QtCore/private/qlocking_p.h>
51
52#include "qdbusconnectioninterface.h"
53#include "qdbuserror.h"
54#include "qdbusmessage.h"
55#include "qdbusmessage_p.h"
56#include "qdbusinterface_p.h"
57#include "qdbusutil_p.h"
58#include "qdbusconnectionmanager_p.h"
59#include "qdbuspendingcall_p.h"
60
61#include "qdbusthreaddebug_p.h"
62
63#include <algorithm>
64
65#ifdef interface
66#undef interface
67#endif
68
69#ifndef QT_NO_DBUS
70
71QT_BEGIN_NAMESPACE
72
73#ifdef Q_OS_WIN
74static void preventDllUnload();
75#endif
76
77Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
78
79struct QDBusConnectionManager::ConnectionRequestData
80{
81 enum RequestType {
82 ConnectToStandardBus,
83 ConnectToBusByAddress,
84 ConnectToPeerByAddress
85 } type;
86
87 union {
88 QDBusConnection::BusType busType;
89 const QString *busAddress;
90 };
91 const QString *name;
92
93 QDBusConnectionPrivate *result;
94
95 bool suspendedDelivery;
96};
97
98QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
99{
100 Q_STATIC_ASSERT(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
101 Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
102
103 if (!qdbus_loadLibDBus())
104 return nullptr;
105
106 // we'll start in suspended delivery mode if we're in the main thread
107 // (the event loop will resume delivery)
108 bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
109
110 const auto locker = qt_scoped_lock(mutex&: defaultBusMutex);
111 if (defaultBuses[type])
112 return defaultBuses[type];
113
114 QString name = QStringLiteral("qt_default_session_bus");
115 if (type == QDBusConnection::SystemBus)
116 name = QStringLiteral("qt_default_system_bus");
117 return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
118}
119
120QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
121{
122 return connectionHash.value(akey: name, adefaultValue: 0);
123}
124
125void QDBusConnectionManager::removeConnection(const QString &name)
126{
127 QDBusConnectionPrivate *d = nullptr;
128 d = connectionHash.take(akey: name);
129 if (d && !d->ref.deref())
130 d->deleteLater();
131
132 // Static objects may be keeping the connection open.
133 // However, it is harmless to have outstanding references to a connection that is
134 // closing as long as those references will be soon dropped without being used.
135
136 // ### Output a warning if connections are being used after they have been removed.
137}
138
139QDBusConnectionManager::QDBusConnectionManager()
140{
141 connect(sender: this, signal: &QDBusConnectionManager::connectionRequested,
142 receiver: this, slot: &QDBusConnectionManager::executeConnectionRequest, type: Qt::BlockingQueuedConnection);
143 connect(sender: this, signal: &QDBusConnectionManager::serverRequested,
144 receiver: this, slot: &QDBusConnectionManager::createServer, type: Qt::BlockingQueuedConnection);
145 moveToThread(thread: this); // ugly, don't do this in other projects
146
147#ifdef Q_OS_WIN
148 // prevent the library from being unloaded on Windows. See comments in the function.
149 preventDllUnload();
150#endif
151 defaultBuses[0] = defaultBuses[1] = nullptr;
152 start();
153}
154
155QDBusConnectionManager::~QDBusConnectionManager()
156{
157 quit();
158 wait();
159}
160
161QDBusConnectionManager* QDBusConnectionManager::instance()
162{
163 return _q_manager();
164}
165
166Q_DBUS_EXPORT void qDBusBindToApplication();
167void qDBusBindToApplication()
168{
169}
170
171void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
172{
173 connectionHash[name] = c;
174 c->name = name;
175}
176
177void QDBusConnectionManager::run()
178{
179 exec();
180
181 // cleanup:
182 const auto locker = qt_scoped_lock(mutex);
183 for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
184 it != connectionHash.constEnd(); ++it) {
185 QDBusConnectionPrivate *d = it.value();
186 if (!d->ref.deref()) {
187 delete d;
188 } else {
189 d->closeConnection();
190 d->moveToThread(thread: nullptr); // allow it to be deleted in another thread
191 }
192 }
193 connectionHash.clear();
194
195 // allow deletion from any thread without warning
196 moveToThread(thread: nullptr);
197}
198
199QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
200 bool suspendedDelivery)
201{
202 ConnectionRequestData data;
203 data.type = ConnectionRequestData::ConnectToStandardBus;
204 data.busType = type;
205 data.name = &name;
206 data.suspendedDelivery = suspendedDelivery;
207
208 emit connectionRequested(&data);
209 if (suspendedDelivery && data.result->connection) {
210 data.result->ref.ref();
211 QDBusConnectionDispatchEnabler *o = new QDBusConnectionDispatchEnabler(data.result);
212 QTimer::singleShot(msec: 0, receiver: o, SLOT(execute()));
213 o->moveToThread(qApp->thread()); // qApp was checked in the caller
214 }
215 return data.result;
216}
217
218QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
219{
220 ConnectionRequestData data;
221 data.type = ConnectionRequestData::ConnectToBusByAddress;
222 data.busAddress = &address;
223 data.name = &name;
224 data.suspendedDelivery = false;
225
226 emit connectionRequested(&data);
227 return data.result;
228}
229
230QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
231{
232 ConnectionRequestData data;
233 data.type = ConnectionRequestData::ConnectToPeerByAddress;
234 data.busAddress = &address;
235 data.name = &name;
236 data.suspendedDelivery = false;
237
238 emit connectionRequested(&data);
239 return data.result;
240}
241
242void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
243{
244 const auto locker = qt_scoped_lock(mutex);
245 const QString &name = *data->name;
246 QDBusConnectionPrivate *&d = data->result;
247
248 // check if the connection exists by name
249 d = connection(name);
250 if (d || name.isEmpty())
251 return;
252
253 d = new QDBusConnectionPrivate;
254 DBusConnection *c = nullptr;
255 QDBusErrorInternal error;
256 switch (data->type) {
257 case ConnectionRequestData::ConnectToStandardBus:
258 switch (data->busType) {
259 case QDBusConnection::SystemBus:
260 c = q_dbus_bus_get_private(type: DBUS_BUS_SYSTEM, error);
261 break;
262 case QDBusConnection::SessionBus:
263 c = q_dbus_bus_get_private(type: DBUS_BUS_SESSION, error);
264 break;
265 case QDBusConnection::ActivationBus:
266 c = q_dbus_bus_get_private(type: DBUS_BUS_STARTER, error);
267 break;
268 }
269 break;
270
271 case ConnectionRequestData::ConnectToBusByAddress:
272 case ConnectionRequestData::ConnectToPeerByAddress:
273 c = q_dbus_connection_open_private(address: data->busAddress->toUtf8().constData(), error);
274 if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) {
275 // register on the bus
276 if (!q_dbus_bus_register(connection: c, error)) {
277 q_dbus_connection_unref(connection: c);
278 c = nullptr;
279 }
280 }
281 break;
282 }
283
284 setConnection(name, c: d);
285 if (data->type == ConnectionRequestData::ConnectToPeerByAddress) {
286 d->setPeer(connection: c, error);
287 } else {
288 // create the bus service
289 // will lock in QDBusConnectionPrivate::connectRelay()
290 d->setConnection(connection: c, error);
291 d->createBusService();
292 if (c && data->suspendedDelivery)
293 d->setDispatchEnabled(false);
294 }
295}
296
297void QDBusConnectionManager::createServer(const QString &address, void *server)
298{
299 QDBusErrorInternal error;
300 QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
301 d->setServer(object: static_cast<QDBusServer *>(server),
302 server: q_dbus_server_listen(address: address.toUtf8().constData(), error), error);
303}
304
305/*!
306 \class QDBusConnection
307 \inmodule QtDBus
308 \since 4.2
309
310 \brief The QDBusConnection class represents a connection to the D-Bus bus daemon.
311
312 This class is the initial point in a D-Bus session. Using it, you
313 can get access to remote objects, interfaces; connect remote
314 signals to your object's slots; register objects, etc.
315
316 D-Bus connections are created using the connectToBus() function,
317 which opens a connection to the server daemon and does the initial
318 handshaking, associating that connection with a name. Further
319 attempts to connect using the same name will return the same
320 connection.
321
322 The connection is then torn down using the disconnectFromBus()
323 function.
324
325 Once disconnected, calling connectToBus() will not reestablish a
326 connection, you must create a new QDBusConnection instance.
327
328 As a convenience for the two most common connection types, the
329 sessionBus() and systemBus() functions return open connections to
330 the session server daemon and the system server daemon,
331 respectively. Those connections are opened when first used and are
332 closed when the QCoreApplication destructor is run.
333
334 D-Bus also supports peer-to-peer connections, without the need for
335 a bus server daemon. Using this facility, two applications can
336 talk to each other and exchange messages. This can be achieved by
337 passing an address to connectToBus() function, which was opened by
338 another D-Bus application using QDBusServer.
339*/
340
341/*!
342 \enum QDBusConnection::BusType
343 Specifies the type of the bus connection. The valid bus types are:
344
345 \value SessionBus the session bus, associated with the running desktop session
346 \value SystemBus the system bus, used to communicate with system-wide processes
347 \value ActivationBus the activation bus, the "alias" for the bus that started the
348 service
349
350 On the Session Bus, one can find other applications by the same user that are sharing the same
351 desktop session (hence the name). On the System Bus, however, processes shared for the whole
352 system are usually found.
353*/
354
355/*!
356 \enum QDBusConnection::RegisterOption
357 Specifies the options for registering objects with the connection. The possible values are:
358
359 \value ExportAdaptors export the contents of adaptors found in this object
360
361 \value ExportScriptableSlots export this object's scriptable slots
362 \value ExportScriptableSignals export this object's scriptable signals
363 \value ExportScriptableProperties export this object's scriptable properties
364 \value ExportScriptableInvokables export this object's scriptable invokables
365 \value ExportScriptableContents shorthand form for ExportScriptableSlots |
366 ExportScriptableSignals |
367 ExportScriptableProperties
368
369 \value ExportNonScriptableSlots export this object's non-scriptable slots
370 \value ExportNonScriptableSignals export this object's non-scriptable signals
371 \value ExportNonScriptableProperties export this object's non-scriptable properties
372 \value ExportNonScriptableInvokables export this object's non-scriptable invokables
373 \value ExportNonScriptableContents shorthand form for ExportNonScriptableSlots |
374 ExportNonScriptableSignals |
375 ExportNonScriptableProperties
376
377 \value ExportAllSlots export all of this object's slots
378 \value ExportAllSignals export all of this object's signals
379 \value ExportAllProperties export all of this object's properties
380 \value ExportAllInvokables export all of this object's invokables
381 \value ExportAllContents export all of this object's contents
382 \value ExportChildObjects export this object's child objects
383
384 \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors}
385*/
386
387/*!
388 \internal
389 \since 4.8
390 \enum QDBusConnection::VirtualObjectRegisterOption
391 Specifies the options for registering virtual objects with the connection. The possible values are:
392
393 \value SingleNode register a virtual object to handle one path only
394 \value SubPath register a virtual object so that it handles all sub paths
395
396 \sa registerVirtualObject(), QDBusVirtualObject
397*/
398
399/*!
400 \enum QDBusConnection::UnregisterMode
401 The mode for unregistering an object path:
402
403 \value UnregisterNode unregister this node only: do not unregister child objects
404 \value UnregisterTree unregister this node and all its sub-tree
405
406 Note, however, if this object was registered with the ExportChildObjects option, UnregisterNode
407 will unregister the child objects too.
408*/
409
410/*!
411 \since 4.8
412 \enum QDBusConnection::ConnectionCapability
413
414 This enum describes the available capabilities for a D-Bus connection.
415
416 \value UnixFileDescriptorPassing enables passing of Unix file descriptors to other processes
417 (see QDBusUnixFileDescriptor)
418
419 \sa connectionCapabilities()
420*/
421
422/*!
423 Creates a QDBusConnection object attached to the connection with name \a name.
424
425 This does not open the connection. You have to call connectToBus() to open it.
426*/
427QDBusConnection::QDBusConnection(const QString &name)
428{
429 if (name.isEmpty() || _q_manager.isDestroyed()) {
430 d = nullptr;
431 } else {
432 const auto locker = qt_scoped_lock(mutex&: _q_manager()->mutex);
433 d = _q_manager()->connection(name);
434 if (d)
435 d->ref.ref();
436 }
437}
438
439/*!
440 Creates a copy of the \a other connection.
441*/
442QDBusConnection::QDBusConnection(const QDBusConnection &other)
443{
444 d = other.d;
445 if (d)
446 d->ref.ref();
447}
448
449/*!
450 \internal
451 Creates a connection object with the given \a dd as private object.
452*/
453QDBusConnection::QDBusConnection(QDBusConnectionPrivate *dd)
454{
455 d = dd;
456 if (d)
457 d->ref.ref();
458}
459
460/*!
461 Disposes of this object. This does not close the connection: you
462 have to call disconnectFromBus() to do that.
463*/
464QDBusConnection::~QDBusConnection()
465{
466 if (d && !d->ref.deref())
467 d->deleteLater();
468}
469
470/*!
471 Creates a copy of the connection \a other in this object. Note
472 that the connection this object referenced before the copy, is not
473 spontaneously disconnected.
474
475 \sa disconnectFromBus()
476*/
477QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
478{
479 if (other.d)
480 other.d->ref.ref();
481 if (d && !d->ref.deref())
482 d->deleteLater();
483 d = other.d;
484 return *this;
485}
486
487/*!
488 Opens a connection of type \a type to one of the known busses and
489 associate with it the connection name \a name. Returns a
490 QDBusConnection object associated with that connection.
491*/
492QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
493{
494 if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
495 QDBusConnectionPrivate *d = nullptr;
496 return QDBusConnection(d);
497 }
498 return QDBusConnection(_q_manager()->connectToBus(type, name, suspendedDelivery: false));
499}
500
501/*!
502 Opens a connection to a private bus on address \a address and associate with it the
503 connection name \a name. Returns a QDBusConnection object associated with that connection.
504*/
505QDBusConnection QDBusConnection::connectToBus(const QString &address,
506 const QString &name)
507{
508 if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
509 QDBusConnectionPrivate *d = nullptr;
510 return QDBusConnection(d);
511 }
512 return QDBusConnection(_q_manager()->connectToBus(address, name));
513}
514/*!
515 \since 4.8
516
517 Opens a peer-to-peer connection on address \a address and associate with it the
518 connection name \a name. Returns a QDBusConnection object associated with that connection.
519*/
520QDBusConnection QDBusConnection::connectToPeer(const QString &address,
521 const QString &name)
522{
523 if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
524 QDBusConnectionPrivate *d = nullptr;
525 return QDBusConnection(d);
526 }
527 return QDBusConnection(_q_manager()->connectToPeer(address, name));
528}
529
530/*!
531 Closes the bus connection of name \a name.
532
533 Note that if there are still QDBusConnection objects associated
534 with the same connection, the connection will not be closed until
535 all references are dropped. However, no further references can be
536 created using the QDBusConnection constructor.
537*/
538void QDBusConnection::disconnectFromBus(const QString &name)
539{
540 if (_q_manager()) {
541 const auto locker = qt_scoped_lock(mutex&: _q_manager()->mutex);
542 QDBusConnectionPrivate *d = _q_manager()->connection(name);
543 if (d && d->mode != QDBusConnectionPrivate::ClientMode)
544 return;
545 _q_manager()->removeConnection(name);
546 }
547}
548
549/*!
550 \since 4.8
551
552 Closes the peer connection of name \a name.
553
554 Note that if there are still QDBusConnection objects associated
555 with the same connection, the connection will not be closed until
556 all references are dropped. However, no further references can be
557 created using the QDBusConnection constructor.
558*/
559void QDBusConnection::disconnectFromPeer(const QString &name)
560{
561 if (_q_manager()) {
562 const auto locker = qt_scoped_lock(mutex&: _q_manager()->mutex);
563 QDBusConnectionPrivate *d = _q_manager()->connection(name);
564 if (d && d->mode != QDBusConnectionPrivate::PeerMode)
565 return;
566 _q_manager()->removeConnection(name);
567 }
568}
569
570/*!
571 Sends the \a message over this connection, without waiting for a
572 reply. This is suitable for errors, signals, and return values as
573 well as calls whose return values are not necessary.
574
575 Returns \c true if the message was queued successfully, false otherwise.
576*/
577bool QDBusConnection::send(const QDBusMessage &message) const
578{
579 if (!d || !d->connection) {
580 QDBusError err = QDBusError(QDBusError::Disconnected,
581 QDBusUtil::disconnectedErrorMessage());
582 if (d)
583 d->lastError = err;
584 return false;
585 }
586 return d->send(message);
587}
588
589/*!
590 Sends the \a message over this connection and returns immediately.
591 When the reply is received, the method \a returnMethod is called in
592 the \a receiver object. If an error occurs, the method \a errorMethod
593 will be called instead.
594
595 If no reply is received within \a timeout milliseconds, an automatic
596 error will be delivered indicating the expiration of the call.
597 The default \a timeout is -1, which will be replaced with an
598 implementation-defined value that is suitable for inter-process
599 communications (generally, 25 seconds).
600
601 This function is suitable for method calls only. It is guaranteed
602 that the slot will be called exactly once with the reply, as long
603 as the parameter types match and no error occurs.
604
605 Returns \c true if the message was sent, or false if the message could
606 not be sent.
607*/
608bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
609 const char *returnMethod, const char *errorMethod,
610 int timeout) const
611{
612 if (!d || !d->connection) {
613 QDBusError err = QDBusError(QDBusError::Disconnected,
614 QDBusUtil::disconnectedErrorMessage());
615 if (d)
616 d->lastError = err;
617 return false;
618 }
619 return d->sendWithReplyAsync(message, receiver, returnMethod, errorMethod, timeout) != nullptr;
620}
621
622/*!
623 \overload
624 \deprecated
625 Sends the \a message over this connection and returns immediately.
626 When the reply is received, the method \a returnMethod is called in
627 the \a receiver object.
628
629 This function is suitable for method calls only. It is guaranteed
630 that the slot will be called exactly once with the reply, as long
631 as the parameter types match and no error occurs.
632
633 This function is dangerous because it cannot report errors, including
634 the expiration of the timeout.
635
636 Returns \c true if the message was sent, or false if the message could
637 not be sent.
638*/
639bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
640 const char *returnMethod, int timeout) const
641{
642 return callWithCallback(message, receiver, returnMethod, errorMethod: nullptr, timeout);
643}
644
645/*!
646 Sends the \a message over this connection and blocks, waiting for
647 a reply, for at most \a timeout milliseconds. This function is
648 suitable for method calls only. It returns the reply message as
649 its return value, which will be either of type
650 QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage.
651
652 If no reply is received within \a timeout milliseconds, an automatic
653 error will be delivered indicating the expiration of the call.
654 The default \a timeout is -1, which will be replaced with an
655 implementation-defined value that is suitable for inter-process
656 communications (generally, 25 seconds).
657
658 See the QDBusInterface::call() function for a more friendly way
659 of placing calls.
660
661 \warning If \a mode is QDBus::BlockWithGui, this function will
662 reenter the Qt event loop in order to wait for the
663 reply. During the wait, it may deliver signals and other
664 method calls to your application. Therefore, it must be
665 prepared to handle a reentrancy whenever a call is
666 placed with call().
667*/
668QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const
669{
670 if (!d || !d->connection) {
671 QDBusError err = QDBusError(QDBusError::Disconnected,
672 QDBusUtil::disconnectedErrorMessage());
673 if (d)
674 d->lastError = err;
675
676 return QDBusMessage::createError(err);
677 }
678
679 if (mode != QDBus::NoBlock)
680 return d->sendWithReply(message, mode, timeout);
681
682 d->send(message);
683 QDBusMessage retval;
684 retval << QVariant(); // add one argument (to avoid .at(0) problems)
685 return retval;
686}
687
688/*!
689 \since 4.5
690 Sends the \a message over this connection and returns
691 immediately. This function is suitable for method calls only. It
692 returns an object of type QDBusPendingCall which can be used to
693 track the status of the reply.
694
695 If no reply is received within \a timeout milliseconds, an automatic
696 error will be delivered indicating the expiration of the call. The
697 default \a timeout is -1, which will be replaced with an
698 implementation-defined value that is suitable for inter-process
699 communications (generally, 25 seconds). This timeout is also the
700 upper limit for waiting in QDBusPendingCall::waitForFinished().
701
702 See the QDBusInterface::asyncCall() function for a more friendly way
703 of placing calls.
704*/
705QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const
706{
707 if (!d || !d->connection) {
708 return QDBusPendingCall(nullptr); // null pointer -> disconnected
709 }
710
711 QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, receiver: nullptr, returnMethod: nullptr, errorMethod: nullptr, timeout);
712 return QDBusPendingCall(priv);
713}
714
715/*!
716 Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to
717 the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty,
718 denoting a connection to any signal of the (\a interface, \a name) pair, from any remote
719 application.
720
721 Returns \c true if the connection was successful.
722
723 \warning The signal will only be delivered to the slot if the parameters match. This verification
724 can be done only when the signal is received, not at connection time.
725*/
726bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
727 const QString &name, QObject *receiver, const char *slot)
728{
729 return connect(service, path, interface, name, argumentMatch: QStringList(), signature: QString(), receiver, slot);
730}
731
732/*!
733 \overload
734
735 Connects the signal to the slot \a slot in object \a
736 receiver. Unlike the previous connect() overload, this function
737 allows one to specify the parameter signature to be connected
738 using the \a signature variable. The function will then verify
739 that this signature can be delivered to the slot specified by \a
740 slot and return false otherwise.
741
742 Returns \c true if the connection was successful.
743
744 \note This function verifies that the signal signature matches the
745 slot's parameters, but it does not verify that the actual
746 signal exists with the given signature in the remote
747 service.
748*/
749bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
750 const QString &name, const QString &signature,
751 QObject *receiver, const char *slot)
752{
753 return connect(service, path, interface, name, argumentMatch: QStringList(), signature, receiver, slot);
754}
755
756/*!
757 \overload
758 \since 4.6
759
760 Connects the signal to the slot \a slot in object \a
761 receiver. Unlike the previous connect() overload, this function
762 allows one to specify the parameter signature to be connected
763 using the \a signature variable. The function will then verify
764 that this signature can be delivered to the slot specified by \a
765 slot and return false otherwise.
766
767 The \a argumentMatch parameter lists the string parameters to be matched,
768 in sequential order. Note that, to match an empty string, you need to
769 pass a QString that is empty but not null (i.e., QString("")). A null
770 QString skips matching at that position.
771
772 Returns \c true if the connection was successful.
773
774 \note This function verifies that the signal signature matches the
775 slot's parameters, but it does not verify that the actual
776 signal exists with the given signature in the remote
777 service.
778*/
779bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
780 const QString &name, const QStringList &argumentMatch, const QString &signature,
781 QObject *receiver, const char *slot)
782{
783
784 if (!receiver || !slot || !d || !d->connection)
785 return false;
786 if (interface.isEmpty() && name.isEmpty())
787 return false;
788 if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(ifaceName: interface)) {
789#ifndef QT_NO_DEBUG
790 qWarning(msg: "QDBusConnection::connect: interface name '%s' is not valid", interface.toLatin1().constData());
791#endif
792 return false;
793 }
794 if (!service.isEmpty() && !QDBusUtil::isValidBusName(busName: service)) {
795#ifndef QT_NO_DEBUG
796 qWarning(msg: "QDBusConnection::connect: service name '%s' is not valid", service.toLatin1().constData());
797#endif
798 return false;
799 }
800 if (!path.isEmpty() && !QDBusUtil::isValidObjectPath(path)) {
801#ifndef QT_NO_DEBUG
802 qWarning(msg: "QDBusConnection::connect: object path '%s' is not valid", path.toLatin1().constData());
803#endif
804 return false;
805 }
806
807 return d->connectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
808}
809
810/*!
811 Disconnects the signal specified by the \a service, \a path, \a interface
812 and \a name parameters from the slot \a slot in object \a receiver. The
813 arguments must be the same as passed to the connect() function.
814
815 Returns \c true if the disconnection was successful.
816*/
817bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString &interface,
818 const QString &name, QObject *receiver, const char *slot)
819{
820 return disconnect(service, path, interface, name, argumentMatch: QStringList(), signature: QString(), receiver, slot);
821}
822
823/*!
824 \overload
825
826 Disconnects the signal specified by the \a service, \a path, \a
827 interface, \a name, and \a signature parameters from the slot \a slot in
828 object \a receiver. The arguments must be the same as passed to the
829 connect() function.
830
831 Returns \c true if the disconnection was successful.
832*/
833bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
834 const QString &name, const QString &signature,
835 QObject *receiver, const char *slot)
836{
837 return disconnect(service, path, interface, name, argumentMatch: QStringList(), signature, receiver, slot);
838}
839
840/*!
841 \overload
842 \since 4.6
843
844 Disconnects the signal specified by the \a service, \a path, \a
845 interface, \a name, \a argumentMatch, and \a signature parameters from
846 the slot \a slot in object \a receiver. The arguments must be the same as
847 passed to the connect() function.
848
849 Returns \c true if the disconnection was successful.
850*/
851bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
852 const QString &name, const QStringList &argumentMatch, const QString &signature,
853 QObject *receiver, const char *slot)
854{
855 if (!receiver || !slot || !d || !d->connection)
856 return false;
857 if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(ifaceName: interface))
858 return false;
859 if (interface.isEmpty() && name.isEmpty())
860 return false;
861
862 return d->disconnectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
863}
864
865/*!
866 Registers the object \a object at path \a path and returns \c true if
867 the registration was successful. The \a options parameter
868 specifies how much of the object \a object will be exposed through
869 D-Bus.
870
871 This function does not replace existing objects: if there is already an object registered at
872 path \a path, this function will return false. Use unregisterObject() to unregister it first.
873
874 The ExportChildObjects flag exports child objects on D-Bus based on the
875 path of the registered objects and the QObject::objectName of the child.
876 Therefore, it is important for the child object to have an object name.
877
878 You cannot register an object as a child object of an object that
879 was registered with ExportChildObjects.
880*/
881bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
882{
883 return registerObject(path, interface: QString(), object, options);
884}
885
886/*!
887 \overload
888 \since 5.5
889
890 Registers the object \a object at path \a path with interface name \a interface
891 and returns \c true if the registration was successful. The \a options parameter
892 specifies how much of the object \a object will be exposed through
893 D-Bus.
894
895 This function does not replace existing objects: if there is already an object registered at
896 path \a path, this function will return false. Use unregisterObject() to unregister it first.
897
898 The ExportChildObjects flag exports child objects on D-Bus based on the
899 path of the registered objects and the QObject::objectName of the child.
900 Therefore, it is important for the child object to have an object name.
901
902 You cannot register an object as a child object of an object that
903 was registered with ExportChildObjects.
904*/
905bool QDBusConnection::registerObject(const QString &path, const QString &interface, QObject *object, RegisterOptions options)
906{
907 Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registerObject",
908 "Invalid object path given");
909 if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
910 return false;
911
912 auto pathComponents = path.splitRef(sep: QLatin1Char('/'));
913 if (pathComponents.constLast().isEmpty())
914 pathComponents.removeLast();
915 QDBusWriteLocker locker(RegisterObjectAction, d);
916
917 // lower-bound search for where this object should enter in the tree
918 QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator node = &d->rootNode;
919 int i = 1;
920 while (node) {
921 if (pathComponents.count() == i) {
922 // this node exists
923 // consider it free if there's no object here and the user is not trying to
924 // replace the object sub-tree
925 if (node->obj)
926 return false;
927
928 if (options & QDBusConnectionPrivate::VirtualObject) {
929 if (options & SubPath && !node->children.isEmpty())
930 return false;
931 } else {
932 if ((options & ExportChildObjects && !node->children.isEmpty()))
933 return false;
934 }
935 // we can add the object here
936 node->obj = object;
937 node->flags = options;
938 node->interfaceName = interface;
939
940 d->registerObject(node);
941 //qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
942 return true;
943 }
944
945 // if a virtual object occupies this path, return false
946 if (node->obj && (node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath)) {
947 //qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.",
948 // qPrintable(path));
949 return false;
950 }
951
952 // find the position where we'd insert the node
953 QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
954 std::lower_bound(first: node->children.begin(), last: node->children.end(), val: pathComponents.at(i));
955 if (it != node->children.end() && it->name == pathComponents.at(i)) {
956 // match: this node exists
957 node = it;
958
959 // are we allowed to go deeper?
960 if (node->flags & ExportChildObjects) {
961 // we're not
962 //qDebug("Cannot register object at %s because %s exports its own child objects",
963 // qPrintable(path), qPrintable(pathComponents.at(i)));
964 return false;
965 }
966 } else {
967 // add entry
968 node = node->children.insert(before: it, t: pathComponents.at(i).toString());
969 }
970
971 // iterate
972 ++i;
973 }
974
975 Q_ASSERT_X(false, "QDBusConnection::registerObject", "The impossible happened");
976 return false;
977}
978
979/*!
980 \internal
981 \since 4.8
982 Registers a QDBusTreeNode for a path. It can handle a path including all child paths, thus
983 handling multiple DBus nodes.
984
985 To unregister a QDBusTreeNode use the unregisterObject() function with its path.
986*/
987bool QDBusConnection::registerVirtualObject(const QString &path, QDBusVirtualObject *treeNode,
988 VirtualObjectRegisterOption options)
989{
990 int opts = options | QDBusConnectionPrivate::VirtualObject;
991 return registerObject(path, object: (QObject*) treeNode, options: (RegisterOptions) opts);
992}
993
994/*!
995 Unregisters an object that was registered with the registerObject() at the object path given by
996 \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too.
997
998 Note that you cannot unregister objects that were not registered with registerObject().
999*/
1000void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
1001{
1002 if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
1003 return;
1004
1005 QDBusWriteLocker locker(UnregisterObjectAction, d);
1006 d->unregisterObject(path, mode);
1007}
1008
1009/*!
1010 Return the object that was registered with the registerObject() at the object path given by
1011 \a path.
1012*/
1013QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
1014{
1015 Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registeredObject",
1016 "Invalid object path given");
1017 if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
1018 return nullptr;
1019
1020 auto pathComponents = path.splitRef(sep: QLatin1Char('/'));
1021 if (pathComponents.constLast().isEmpty())
1022 pathComponents.removeLast();
1023
1024 // lower-bound search for where this object should enter in the tree
1025 QDBusReadLocker lock(ObjectRegisteredAtAction, d);
1026 const QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
1027
1028 int i = 1;
1029 while (node) {
1030 if (pathComponents.count() == i)
1031 return node->obj;
1032 if ((node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath))
1033 return node->obj;
1034
1035 QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
1036 std::lower_bound(first: node->children.constBegin(), last: node->children.constEnd(), val: pathComponents.at(i));
1037 if (it == node->children.constEnd() || it->name != pathComponents.at(i))
1038 break; // node not found
1039
1040 node = it;
1041 ++i;
1042 }
1043 return nullptr;
1044}
1045
1046
1047
1048/*!
1049 Returns a QDBusConnectionInterface object that represents the
1050 D-Bus server interface on this connection.
1051*/
1052QDBusConnectionInterface *QDBusConnection::interface() const
1053{
1054 if (!d || d->mode != QDBusConnectionPrivate::ClientMode)
1055 return nullptr;
1056 return d->busService;
1057}
1058
1059/*!
1060 \internal
1061 \since 4.8
1062
1063 Returns the internal, implementation-defined pointer for this
1064 connection. Currently, this returns a DBusConnection* pointer,
1065 without changing the reference count. It is the responsibility of
1066 the caller to call dbus_connection_ref if it wants to store the
1067 pointer.
1068*/
1069void *QDBusConnection::internalPointer() const
1070{
1071 return d ? d->connection : nullptr;
1072}
1073
1074/*!
1075 Returns \c true if this QDBusConnection object is connected.
1076*/
1077bool QDBusConnection::isConnected() const
1078{
1079 return d && d->connection && q_dbus_connection_get_is_connected(connection: d->connection);
1080}
1081
1082/*!
1083 Returns the last error that happened in this connection.
1084
1085 This function is provided for low-level code. If you're using
1086 QDBusInterface::call(), error codes are reported by its return
1087 value.
1088
1089 \sa QDBusInterface, QDBusMessage
1090*/
1091QDBusError QDBusConnection::lastError() const
1092{
1093 return d ? d->lastError : QDBusError(QDBusError::Disconnected, QDBusUtil::disconnectedErrorMessage());
1094}
1095
1096/*!
1097 Returns the unique connection name for this connection, if this QDBusConnection object is
1098 connected, or an empty QString otherwise.
1099
1100 A Unique Connection Name is a string in the form ":x.xxx" (where x
1101 are decimal digits) that is assigned by the D-Bus server daemon
1102 upon connection. It uniquely identifies this client in the bus.
1103
1104 This function returns an empty QString for peer-to-peer connections.
1105*/
1106QString QDBusConnection::baseService() const
1107{
1108 return d ? d->baseService : QString();
1109}
1110
1111/*!
1112 \since 4.5
1113
1114 Returns the connection name for this connection, as given as the
1115 name parameter to connectToBus().
1116
1117 The connection name can be used to uniquely identify actual
1118 underlying connections to buses. Copies made from a single
1119 connection will always implicitly share the underlying connection,
1120 and hence will have the same connection name.
1121
1122 Inversely, two connections having different connection names will
1123 always either be connected to different buses, or have a different
1124 unique name (as returned by baseService()) on that bus.
1125
1126 \sa connectToBus(), disconnectFromBus()
1127*/
1128QString QDBusConnection::name() const
1129{
1130 return d ? d->name : QString();
1131}
1132
1133/*!
1134 \since 4.8
1135
1136 Returns the capabilities of this connection as negotiated with the bus
1137 server or peer. If this QDBusConnection is not connected, this function
1138 returns no capabilities.
1139*/
1140QDBusConnection::ConnectionCapabilities QDBusConnection::connectionCapabilities() const
1141{
1142 return d ? d->connectionCapabilities() : ConnectionCapabilities();
1143}
1144
1145/*!
1146 Attempts to register the \a serviceName on the D-Bus server and
1147 returns \c true if the registration succeeded. The registration will
1148 fail if the name is already registered by another application.
1149
1150 \sa unregisterService(), QDBusConnectionInterface::registerService()
1151*/
1152bool QDBusConnection::registerService(const QString &serviceName)
1153{
1154 if (interface() && interface()->registerService(serviceName)) {
1155 if (d) d->registerService(serviceName);
1156 return true;
1157 }
1158 return false;
1159}
1160
1161/*!
1162 Unregisters the service \a serviceName that was previously
1163 registered with registerService() and returns \c true if it
1164 succeeded.
1165
1166 \sa registerService(), QDBusConnectionInterface::unregisterService()
1167*/
1168bool QDBusConnection::unregisterService(const QString &serviceName)
1169{
1170 if (interface()->unregisterService(serviceName)) {
1171 if (d) d->unregisterService(serviceName);
1172 return true;
1173 }
1174 return false;
1175}
1176
1177/*!
1178 \fn QDBusConnection QDBusConnection::sessionBus()
1179
1180 Returns a QDBusConnection object opened with the session bus. The object
1181 reference returned by this function is valid until the application terminates,
1182 at which point the connection will be closed and the object deleted.
1183*/
1184QDBusConnection QDBusConnection::sessionBus()
1185{
1186 if (_q_manager.isDestroyed())
1187 return QDBusConnection(nullptr);
1188 return QDBusConnection(_q_manager()->busConnection(type: SessionBus));
1189}
1190
1191/*!
1192 \fn QDBusConnection QDBusConnection::systemBus()
1193
1194 Returns a QDBusConnection object opened with the system bus. The object reference returned
1195 by this function is valid until the QCoreApplication's destructor is run, when the
1196 connection will be closed and the object, deleted.
1197*/
1198QDBusConnection QDBusConnection::systemBus()
1199{
1200 if (_q_manager.isDestroyed())
1201 return QDBusConnection(nullptr);
1202 return QDBusConnection(_q_manager()->busConnection(type: SystemBus));
1203}
1204
1205#if QT_DEPRECATED_SINCE(5,5)
1206/*!
1207 \deprecated
1208
1209 Always returns a disconnected, invalid QDBusConnection object. For the old
1210 functionality of determining the sender connection, please use QDBusContext.
1211
1212 \sa QDBusContext
1213*/
1214QDBusConnection QDBusConnection::sender()
1215{
1216 return QDBusConnection(QString());
1217}
1218#endif
1219
1220/*!
1221 \internal
1222*/
1223void QDBusConnectionPrivate::createBusService()
1224{
1225 Q_ASSERT(mode == ClientMode);
1226 QDBusConnection connection(this);
1227 busService = new QDBusConnectionInterface(connection, this);
1228 ref.deref(); // busService has increased the refcounting to us
1229 // avoid cyclic refcounting
1230
1231 QObject::connect(sender: this, signal: &QDBusConnectionPrivate::callWithCallbackFailed,
1232 receiver: busService, emit slot: &QDBusConnectionInterface::callWithCallbackFailed,
1233 type: Qt::QueuedConnection);
1234}
1235
1236/*!
1237 \since 4.8
1238 Returns the local machine ID as known to the D-Bus system. Each
1239 node or host that runs D-Bus has a unique identifier that can be
1240 used to distinguish it from other hosts if they are sharing
1241 resources like the filesystem.
1242
1243 Note that the local machine ID is not guaranteed to be persistent
1244 across boots of the system, so this identifier should not be
1245 stored in persistent storage (like the filesystem). It is
1246 guaranteed to remain constant only during the lifetime of this
1247 boot session.
1248*/
1249QByteArray QDBusConnection::localMachineId()
1250{
1251 char *dbus_machine_id = q_dbus_get_local_machine_id();
1252 QByteArray result = dbus_machine_id;
1253 q_dbus_free(memory: dbus_machine_id);
1254 return result;
1255}
1256
1257/*!
1258 \namespace QDBus
1259 \inmodule QtDBus
1260
1261 \brief The QDBus namespace contains miscellaneous identifiers used
1262 throughout the Qt D-Bus module.
1263*/
1264
1265/*!
1266 \enum QDBus::CallMode
1267
1268 This enum describes the various ways of placing a function call. The valid modes are:
1269
1270 \value NoBlock Place the call but don't wait for the reply (the reply's contents
1271 will be discarded).
1272 \value Block Don't use an event loop to wait for a reply, but instead block on
1273 network operations while waiting. This means the
1274 user-interface may not be updated until the function returns.
1275 \value BlockWithGui Use the Qt event loop to wait for a reply. This means that the
1276 user-interface will stay responsive (processing input events),
1277 but it also means other events may happen, like signal delivery
1278 and other D-Bus method calls.
1279 \value AutoDetect Automatically detect if the called function has a reply.
1280
1281 When using BlockWithGui, applications must be prepared for reentrancy in any function.
1282*/
1283
1284/*!
1285 \fn void QDBusConnection::swap(QDBusConnection &other)
1286
1287 Swaps this QDBusConnection instance with \a other.
1288*/
1289
1290QT_END_NAMESPACE
1291
1292#ifdef Q_OS_WIN
1293# include <qt_windows.h>
1294
1295QT_BEGIN_NAMESPACE
1296static void preventDllUnload()
1297{
1298 // Thread termination is really wacky on Windows. For some reason we don't
1299 // understand, exiting from the thread may try to unload the DLL. Since the
1300 // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
1301 // a deadlock: the main thread is waiting for the manager thread to exit,
1302 // but the manager thread is attempting to acquire a lock to unload the DLL.
1303 //
1304 // We work around the issue by preventing the unload from happening in the
1305 // first place.
1306 //
1307 // For this trick, see
1308 // https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
1309
1310 static HMODULE self;
1311 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
1312 GET_MODULE_HANDLE_EX_FLAG_PIN,
1313 reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
1314 &self);
1315}
1316QT_END_NAMESPACE
1317#endif
1318
1319#endif // QT_NO_DBUS
1320

source code of qtbase/src/dbus/qdbusconnection.cpp