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

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