Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdbusconnectioninterface.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/QByteArray>
8#include <QtCore/QList>
9#include <QtCore/QMap>
10#include <QtCore/QMetaMethod>
11#include <QtCore/QString>
12#include <QtCore/QStringList>
13#include <QtCore/QVariant>
14#include <QtCore/QDebug>
15
16#include "qdbusutil_p.h" // for the DBUS_* constants
17
18#ifndef QT_NO_DBUS
19
21
22using namespace Qt::StringLiterals;
23
24/*
25 * Implementation of interface class QDBusConnectionInterface
26 */
27
28/*!
29 \class QDBusConnectionInterface
30 \inmodule QtDBus
31 \since 4.2
32
33 \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
34
35 The D-Bus bus server daemon provides one special interface \c
36 org.freedesktop.DBus that allows clients to access certain
37 properties of the bus, such as the current list of clients
38 connected. The QDBusConnectionInterface class provides access to that
39 interface.
40
41 The most common uses of this class are to register and unregister
42 service names on the bus using the registerService() and
43 unregisterService() functions, query about existing names using
44 the isServiceRegistered(), registeredServiceNames() and
45 serviceOwner() functions, and to receive notification that a
46 client has registered or de-registered through the
47 serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
48 signals.
49*/
50
51/*!
52 \enum QDBusConnectionInterface::ServiceQueueOptions
53
54 Flags for determining how a service registration should behave, in
55 case the service name is already registered.
56
57 \value DontQueueService If an application requests a name that
58 is already owned, no queueing will be
59 performed. The registeredService()
60 call will simply fail.
61 This is the default.
62
63 \value QueueService Attempts to register the requested
64 service, but do not try to replace it
65 if another application already has it
66 registered. Instead, simply put this
67 application in queue, until it is
68 given up. The serviceRegistered()
69 signal will be emitted when that
70 happens.
71
72 \value ReplaceExistingService If another application already has
73 the service name registered, attempt
74 to replace it.
75
76 \sa ServiceReplacementOptions
77*/
78
79/*!
80 \enum QDBusConnectionInterface::ServiceReplacementOptions
81
82 Flags for determining if the D-Bus server should allow another
83 application to replace a name that this application has registered
84 with the ReplaceExistingService option.
85
86 The possible values are:
87
88 \value DontAllowReplacement Do not allow another application to
89 replace us. The service must be
90 explicitly unregistered with
91 unregisterService() for another
92 application to acquire it.
93 This is the default.
94
95 \value AllowReplacement Allow other applications to replace us
96 with the ReplaceExistingService option
97 to registerService() without
98 intervention. If that happens, the
99 serviceUnregistered() signal will be
100 emitted.
101
102 \sa ServiceQueueOptions
103*/
104
105/*!
106 \enum QDBusConnectionInterface::RegisterServiceReply
107
108 The possible return values from registerService():
109
110 \value ServiceNotRegistered The call failed and the service name was not registered.
111 \value ServiceRegistered The caller is now the owner of the service name.
112 \value ServiceQueued The caller specified the QueueService flag and the
113 service was already registered, so we are in queue.
114
115 The serviceRegistered() signal will be emitted when the service is
116 acquired by this application.
117*/
118
119/*!
120 \internal
121*/
122const char *QDBusConnectionInterface::staticInterfaceName()
123{ return "org.freedesktop.DBus"; }
124
125/*!
126 \internal
127*/
128QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
129 QObject *parent)
130 : QDBusAbstractInterface(QDBusUtil::dbusService(),
131 QDBusUtil::dbusPath(),
132 DBUS_INTERFACE_DBUS, connection, parent)
133{
134 connect(this, &QDBusConnectionInterface::NameAcquired, this, emit &QDBusConnectionInterface::serviceRegistered);
135 connect(this, &QDBusConnectionInterface::NameLost, this, emit &QDBusConnectionInterface::serviceUnregistered);
136 connect(this, &QDBusConnectionInterface::NameOwnerChanged,
137 this, emit &QDBusConnectionInterface::serviceOwnerChanged);
138}
139
140/*!
141 \internal
142*/
143QDBusConnectionInterface::~QDBusConnectionInterface()
144{
145}
146
147/*!
148 Returns the unique connection name of the primary owner of the
149 name \a name. If the requested name doesn't have an owner, returns
150 a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
151*/
152QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
153{
154 return internalConstCall(QDBus::AutoDetect, "GetNameOwner"_L1, QList<QVariant>() << name);
155}
156
157/*!
158 \property QDBusConnectionInterface::registeredServiceNames
159 \brief holds the registered service names
160
161 Lists all names currently registered on the bus.
162*/
163QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
164{
165 return internalConstCall(QDBus::AutoDetect, "ListNames"_L1);
166}
167
168/*!
169 \property QDBusConnectionInterface::activatableServiceNames
170 \brief holds the activatable service names
171 \since 5.14
172
173 Lists all names that can be activated on the bus.
174*/
175QDBusReply<QStringList> QDBusConnectionInterface::activatableServiceNames() const
176{
177 return internalConstCall(QDBus::AutoDetect, "ListActivatableNames"_L1);
178}
179
180/*!
181 Returns \c true if the service name \a serviceName has is currently
182 registered.
183*/
184QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
185{
186 return internalConstCall(QDBus::AutoDetect, "NameHasOwner"_L1,
187 QList<QVariant>() << serviceName);
188}
189
190/*!
191 Returns the Unix Process ID (PID) for the process currently
192 holding the bus service \a serviceName.
193*/
194QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
195{
196 return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixProcessID"_L1,
197 QList<QVariant>() << serviceName);
198}
199
200/*!
201 Returns the Unix User ID (UID) for the process currently holding
202 the bus service \a serviceName.
203*/
204QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
205{
206 return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixUser"_L1,
207 QList<QVariant>() << serviceName);
208}
209
210/*!
211 \since 6.10
212
213 Returns the connection credentials for the process currently holding
214 the bus service \a serviceName.
215
216 See <https://dbus.freedesktop.org/doc/dbus-specification.html>
217 section: 'Method: org.freedesktop.DBus.GetConnectionCredentials' for more information.
218*/
219QDBusReply<QVariantMap> QDBusConnectionInterface::serviceCredentials(const QString &serviceName) const
220{
221 return internalConstCall(QDBus::AutoDetect, "GetConnectionCredentials"_L1,
222 QList<QVariant>() << serviceName);
223}
224
225/*!
226 Requests that the bus start the service given by the name \a name.
227*/
228QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
229{
230 return call("StartServiceByName"_L1, name, uint(0));
231}
232
233/*!
234 Requests to register the service name \a serviceName on the
235 bus. The \a qoption flag specifies how the D-Bus server should behave
236 if \a serviceName is already registered. The \a roption flag
237 specifies if the server should allow another application to
238 replace our registered name.
239
240 If the service registration succeeds, the serviceRegistered()
241 signal will be emitted. If we are placed in queue, the signal will
242 be emitted when we obtain the name. If \a roption is
243 AllowReplacement, the serviceUnregistered() signal will be emitted
244 if another application replaces this one.
245
246 \sa unregisterService()
247*/
248QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
249QDBusConnectionInterface::registerService(const QString &serviceName,
250 ServiceQueueOptions qoption,
251 ServiceReplacementOptions roption)
252{
253 // reconstruct the low-level flags
254 uint flags = 0;
255 switch (qoption) {
256 case DontQueueService:
258 break;
259 case QueueService:
260 flags = 0;
261 break;
262 case ReplaceExistingService:
264 break;
265 }
266
267 switch (roption) {
268 case DontAllowReplacement:
269 break;
270 case AllowReplacement:
272 break;
273 }
274
275 QDBusMessage reply = call("RequestName"_L1, serviceName, flags);
276// qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
277
278 // convert the low-level flags to something that we can use
279 if (reply.type() == QDBusMessage::ReplyMessage) {
280 uint code = 0;
281
282 switch (reply.arguments().at(0).toUInt()) {
285 code = uint(ServiceRegistered);
286 break;
287
289 code = uint(ServiceNotRegistered);
290 break;
291
293 code = uint(ServiceQueued);
294 break;
295 }
296
297 reply.setArguments(QVariantList() << code);
298 }
299
300 return reply;
301}
302
303/*!
304 Releases the claim on the bus service name \a serviceName, that
305 had been previously registered with registerService(). If this
306 application had ownership of the name, it will be released for
307 other applications to claim. If it only had the name queued, it
308 gives up its position in the queue.
309*/
310QDBusReply<bool>
311QDBusConnectionInterface::unregisterService(const QString &serviceName)
312{
313 QDBusMessage reply = call("ReleaseName"_L1, serviceName);
314 if (reply.type() == QDBusMessage::ReplyMessage) {
315 bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
316 reply.setArguments(QVariantList() << success);
317 }
318 return reply;
319}
320
321/*!
322 \internal
323*/
324void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
325{
326 // translate the signal names to what we really want
327 // this avoids setting hooks for signals that don't exist on the bus
328 static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
329 static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
330 static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
331 static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
332 static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
333 static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
334 if (signal == serviceRegisteredSignal)
335 QDBusAbstractInterface::connectNotify(NameAcquiredSignal);
336
337 else if (signal == serviceUnregisteredSignal)
338 QDBusAbstractInterface::connectNotify(NameLostSignal);
339
340 else if (signal == serviceOwnerChangedSignal) {
341 static bool warningPrinted = false;
342 if (!warningPrinted) {
343 qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
344 warningPrinted = true;
345 }
346 QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
347 }
348}
349
350/*!
351 \internal
352*/
353void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
354{
355 // translate the signal names to what we really want
356 // this avoids setting hooks for signals that don't exist on the bus
357 static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
358 static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
359 static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
360 static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
361 static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
362 static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
363 if (signal == serviceRegisteredSignal)
364 QDBusAbstractInterface::disconnectNotify(NameAcquiredSignal);
365
366 else if (signal == serviceUnregisteredSignal)
367 QDBusAbstractInterface::disconnectNotify(NameLostSignal);
368
369 else if (signal == serviceOwnerChangedSignal)
370 QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
371}
372
373// signals
374/*!
375 \fn QDBusConnectionInterface::serviceRegistered(const QString &service)
376
377 This signal is emitted by the D-Bus server when the bus service
378 name (unique connection name or well-known service name) given by
379 \a service is acquired by this application.
380
381 Acquisition happens after this application has requested a name using
382 registerService().
383*/
384
385/*!
386 \fn QDBusConnectionInterface::serviceUnregistered(const QString &service)
387
388 This signal is emitted by the D-Bus server when this application
389 loses ownership of the bus service name given by \a service.
390*/
391
392/*!
393 \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
394 \deprecated
395
396 Use QDBusServiceWatcher instead.
397
398 This signal is emitted by the D-Bus server whenever a service
399 ownership change happens in the bus, including apparition and
400 disparition of names.
401
402 This signal means the application \a oldOwner lost ownership of
403 bus name \a name to application \a newOwner. If \a oldOwner is an
404 empty string, it means the name \a name has just been created; if
405 \a newOwner is empty, the name \a name has no current owner and is
406 no longer available.
407
408 \note connecting to this signal will make the application listen for and
409 receive every single service ownership change on the bus. Depending on
410 how many services are running, this make the application be activated to
411 receive more signals than it needs. To avoid this problem, use the
412 QDBusServiceWatcher class, which can listen for specific changes.
413*/
414
415/*!
416 \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
417
418 This signal is emitted when there is an error during a
419 QDBusConnection::callWithCallback(). \a error specifies the error.
420 \a call is the message that couldn't be delivered.
421
422 \sa QDBusConnection::callWithCallback()
423 */
424
425QT_END_NAMESPACE
426
427#include "moc_qdbusconnectioninterface.cpp"
428
429#endif // QT_NO_DBUS
#define DBUS_NAME_FLAG_REPLACE_EXISTING
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
#define DBUS_NAME_FLAG_DO_NOT_QUEUE
#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT
#define DBUS_INTERFACE_DBUS
#define DBUS_REQUEST_NAME_REPLY_EXISTS
#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
#define DBUS_RELEASE_NAME_REPLY_RELEASED