Coverage Report

Created: 2026-03-31 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qt/qtbase/src/dbus/qdbusconnectioninterface.cpp
Line
Count
Source
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
5
#include "qdbusconnectioninterface.h"
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
20
QT_BEGIN_NAMESPACE
21
22
using 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
*/
122
const char *QDBusConnectionInterface::staticInterfaceName()
123
0
{ return "org.freedesktop.DBus"; }
124
125
/*!
126
    \internal
127
*/
128
QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
129
                                                   QObject *parent)
130
0
    : QDBusAbstractInterface(QDBusUtil::dbusService(),
131
0
                             QDBusUtil::dbusPath(),
132
0
                             DBUS_INTERFACE_DBUS, connection, parent)
133
0
{
134
0
    connect(this, &QDBusConnectionInterface::NameAcquired, this, emit &QDBusConnectionInterface::serviceRegistered);
135
0
    connect(this, &QDBusConnectionInterface::NameLost, this, emit &QDBusConnectionInterface::serviceUnregistered);
136
0
    connect(this, &QDBusConnectionInterface::NameOwnerChanged,
137
0
            this, emit &QDBusConnectionInterface::serviceOwnerChanged);
138
0
}
139
140
/*!
141
    \internal
142
*/
143
QDBusConnectionInterface::~QDBusConnectionInterface()
144
0
{
145
0
}
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
*/
152
QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
153
0
{
154
0
    return internalConstCall(QDBus::AutoDetect, "GetNameOwner"_L1, QList<QVariant>() << name);
155
0
}
156
157
/*!
158
  \property QDBusConnectionInterface::registeredServiceNames
159
  \brief holds the registered service names
160
161
  Lists all names currently registered on the bus.
162
*/
163
QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
164
0
{
165
0
    return internalConstCall(QDBus::AutoDetect, "ListNames"_L1);
166
0
}
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
*/
175
QDBusReply<QStringList> QDBusConnectionInterface::activatableServiceNames() const
176
0
{
177
0
    return internalConstCall(QDBus::AutoDetect, "ListActivatableNames"_L1);
178
0
}
179
180
/*!
181
    Returns \c true if the service name \a serviceName has is currently
182
    registered.
183
*/
184
QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
185
0
{
186
0
    return internalConstCall(QDBus::AutoDetect, "NameHasOwner"_L1,
187
0
                             QList<QVariant>() << serviceName);
188
0
}
189
190
/*!
191
    Returns the Unix Process ID (PID) for the process currently
192
    holding the bus service \a serviceName.
193
*/
194
QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
195
0
{
196
0
    return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixProcessID"_L1,
197
0
                             QList<QVariant>() << serviceName);
198
0
}
199
200
/*!
201
    Returns the Unix User ID (UID) for the process currently holding
202
    the bus service \a serviceName.
203
*/
204
QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
205
0
{
206
0
    return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixUser"_L1,
207
0
                             QList<QVariant>() << serviceName);
208
0
}
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
*/
219
QDBusReply<QVariantMap> QDBusConnectionInterface::serviceCredentials(const QString &serviceName) const
220
0
{
221
0
    return internalConstCall(QDBus::AutoDetect, "GetConnectionCredentials"_L1,
222
0
                             QList<QVariant>() << serviceName);
223
0
}
224
225
/*!
226
    Requests that the bus start the service given by the name \a name.
227
*/
228
QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
229
0
{
230
0
    return call("StartServiceByName"_L1, name, uint(0));
231
0
}
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
*/
248
QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
249
QDBusConnectionInterface::registerService(const QString &serviceName,
250
                                          ServiceQueueOptions qoption,
251
                                          ServiceReplacementOptions roption)
252
0
{
253
    // reconstruct the low-level flags
254
0
    uint flags = 0;
255
0
    switch (qoption) {
256
0
    case DontQueueService:
257
0
        flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
258
0
        break;
259
0
    case QueueService:
260
0
        flags = 0;
261
0
        break;
262
0
    case ReplaceExistingService:
263
0
        flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
264
0
        break;
265
0
    }
266
267
0
    switch (roption) {
268
0
    case DontAllowReplacement:
269
0
        break;
270
0
    case AllowReplacement:
271
0
        flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
272
0
        break;
273
0
    }
274
275
0
    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
0
    if (reply.type() == QDBusMessage::ReplyMessage) {
280
0
        uint code = 0;
281
282
0
        switch (reply.arguments().at(0).toUInt()) {
283
0
        case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
284
0
        case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
285
0
            code = uint(ServiceRegistered);
286
0
            break;
287
288
0
        case DBUS_REQUEST_NAME_REPLY_EXISTS:
289
0
            code = uint(ServiceNotRegistered);
290
0
            break;
291
292
0
        case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
293
0
            code = uint(ServiceQueued);
294
0
            break;
295
0
        }
296
297
0
        reply.setArguments(QVariantList() << code);
298
0
    }
299
300
0
    return reply;
301
0
}
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
*/
310
QDBusReply<bool>
311
QDBusConnectionInterface::unregisterService(const QString &serviceName)
312
0
{
313
0
    QDBusMessage reply = call("ReleaseName"_L1, serviceName);
314
0
    if (reply.type() == QDBusMessage::ReplyMessage) {
315
0
        bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
316
0
        reply.setArguments(QVariantList() << success);
317
0
    }
318
0
    return reply;
319
0
}
320
321
/*!
322
    \internal
323
*/
324
void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
325
0
{
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
0
    static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
329
0
    static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
330
0
    static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
331
0
    static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
332
0
    static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
333
0
    static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
334
0
    if (signal == serviceRegisteredSignal)
335
0
        QDBusAbstractInterface::connectNotify(NameAcquiredSignal);
336
337
0
    else if (signal == serviceUnregisteredSignal)
338
0
        QDBusAbstractInterface::connectNotify(NameLostSignal);
339
340
0
    else if (signal == serviceOwnerChangedSignal) {
341
0
        static bool warningPrinted = false;
342
0
        if (!warningPrinted) {
343
0
            qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
344
0
            warningPrinted = true;
345
0
        }
346
0
        QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
347
0
    }
348
0
}
349
350
/*!
351
    \internal
352
*/
353
void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
354
0
{
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
0
    static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
358
0
    static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
359
0
    static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
360
0
    static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
361
0
    static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
362
0
    static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
363
0
    if (signal == serviceRegisteredSignal)
364
0
        QDBusAbstractInterface::disconnectNotify(NameAcquiredSignal);
365
366
0
    else if (signal == serviceUnregisteredSignal)
367
0
        QDBusAbstractInterface::disconnectNotify(NameLostSignal);
368
369
0
    else if (signal == serviceOwnerChangedSignal)
370
0
        QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
371
0
}
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
425
QT_END_NAMESPACE
426
427
#include "moc_qdbusconnectioninterface.cpp"
428
429
#endif // QT_NO_DBUS