Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdbusinternalfilters.cpp
Go to the documentation of this file.
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_p.h"
6
7#include "qdbus_symbols_p.h"
8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qmetaobject.h>
10#include <QtCore/qstringlist.h>
11#include <QtCore/qthread.h>
12
15#include "qdbusconnection.h"
16#include "qdbusextratypes.h"
17#include "qdbusmessage.h"
18#include "qdbusmetatype.h"
19#include "qdbusmetatype_p.h"
20#include "qdbusmessage_p.h"
21#include "qdbusutil_p.h"
22#include "qdbusvirtualobject.h"
23
24#include <algorithm>
25
26#ifndef QT_NO_DBUS
27
29
30using namespace Qt::StringLiterals;
31
32// defined in qdbusxmlgenerator.cpp
34 const QMetaObject *base, int flags);
35
36static const char introspectableInterfaceXml[] =
37 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
38 " <method name=\"Introspect\">\n"
39 " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
40 " </method>\n"
41 " </interface>\n";
42
43static const char propertiesInterfaceXml[] =
44 " <interface name=\"org.freedesktop.DBus.Properties\">\n"
45 " <method name=\"Get\">\n"
46 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
47 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
48 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
49 " </method>\n"
50 " <method name=\"Set\">\n"
51 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
52 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
53 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
54 " </method>\n"
55 " <method name=\"GetAll\">\n"
56 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
57 " <arg name=\"values\" type=\"a{sv}\" direction=\"out\"/>\n"
58 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"
59 " </method>\n"
60 " <signal name=\"PropertiesChanged\">\n"
61 " <arg name=\"interface_name\" type=\"s\" direction=\"out\"/>\n"
62 " <arg name=\"changed_properties\" type=\"a{sv}\" direction=\"out\"/>\n"
63 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out1\" value=\"QVariantMap\"/>\n"
64 " <arg name=\"invalidated_properties\" type=\"as\" direction=\"out\"/>\n"
65 " </signal>\n"
66 " </interface>\n";
67
68static const char peerInterfaceXml[] =
69 " <interface name=\"org.freedesktop.DBus.Peer\">\n"
70 " <method name=\"Ping\"/>\n"
71 " <method name=\"GetMachineId\">\n"
72 " <arg name=\"machine_uuid\" type=\"s\" direction=\"out\"/>\n"
73 " </method>\n"
74 " </interface>\n";
75
77{
78 QString retval;
79 for (const QObject *child : object->children()) {
80 QString name = child->objectName();
82 retval += " <node name=\""_L1 + name + "\"/>\n"_L1;
83 }
84 return retval;
85}
86
87// declared as extern in qdbusconnection_p.h
88
90{
91 // object may be null
92
94 xml_data += "<node>\n"_L1;
95
96 if (node.obj) {
98 "QDBusConnection: internal threading error",
99 "function called for an object that is in another thread!!");
100
103 // create XML for the object itself
104 const QMetaObject *mo = node.obj->metaObject();
105 for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
106 xml_data += qDBusGenerateMetaObjectXml(node.interfaceName, mo, mo->superClass(),
107 node.flags);
108 }
109
110 // does this object have adaptors?
111 QDBusAdaptorConnector *connector;
113 (connector = qDBusFindAdaptorConnector(node.obj))) {
114
115 // trasverse every adaptor in this object
116 for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
117 std::as_const(connector->adaptors)) {
118 // add the interface:
119 QString ifaceXml =
121 if (ifaceXml.isEmpty()) {
122 // add the interface's contents:
123 ifaceXml += qDBusGenerateMetaObjectXml(
124 QString::fromLatin1(adaptorData.interface),
125 adaptorData.adaptor->metaObject(),
126 &QDBusAbstractAdaptor::staticMetaObject,
129
131 ifaceXml);
132 }
133
134 xml_data += ifaceXml;
135 }
136 }
137
138 // is it a virtual node that handles introspection itself?
140 xml_data += node.treeNode->introspect(path);
141 }
142
144 }
145
148
150 xml_data += generateSubObjectXml(node.obj);
151 } else {
152 // generate from the object tree
153 for (const QDBusConnectionPrivate::ObjectTreeNode &node : node.children) {
154 if (node.obj || !node.children.isEmpty())
155 xml_data += " <node name=\""_L1 + node.name + "\"/>\n"_L1;
156 }
157 }
158
159 xml_data += "</node>\n"_L1;
160 return xml_data;
161}
162
163// implement the D-Bus interface org.freedesktop.DBus.Properties
164
165static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
166{
168 "Interface %1 was not found in object %2"_L1
169 .arg(interface_name, msg.path()));
170}
171
172static inline QDBusMessage
173propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
174{
176 "Property %1%2%3 was not found in object %4"_L1
177 .arg(interface_name,
178 interface_name.isEmpty() ? ""_L1 : "."_L1,
179 QLatin1StringView(property_name),
180 msg.path()));
181}
182
184 const QDBusMessage &msg)
185{
186 Q_ASSERT(msg.arguments().size() == 2);
187 Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
188 "QDBusConnection: internal threading error",
189 "function called for an object that is in another thread!!");
190
191 QString interface_name = msg.arguments().at(0).toString();
192 QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
193
194 const QDBusAdaptorConnector *connector;
196 bool interfaceFound = false;
198 (connector = qDBusFindAdaptorConnector(node.obj))) {
199
200 // find the class that implements interface_name or try until we've found the property
201 // in case of an empty interface
202 if (interface_name.isEmpty()) {
203 for (const QDBusAdaptorConnector::AdaptorData &adaptorData : connector->adaptors) {
204 const QMetaObject *mo = adaptorData.adaptor->metaObject();
205 int pidx = mo->indexOfProperty(property_name);
206 if (pidx != -1) {
207 value = mo->property(pidx).read(adaptorData.adaptor);
208 break;
209 }
210 }
211 } else {
213 it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
214 interface_name);
215 if (it != connector->adaptors.constEnd() && interface_name == QLatin1StringView(it->interface)) {
216 interfaceFound = true;
217 value = it->adaptor->property(property_name);
218 }
219 }
220 }
221
222 if (!interfaceFound && !value.isValid()
225 // try the object itself
226 if (!interface_name.isEmpty())
227 interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
228
229 if (interfaceFound) {
230 int pidx = node.obj->metaObject()->indexOfProperty(property_name);
231 if (pidx != -1) {
232 QMetaProperty mp = node.obj->metaObject()->property(pidx);
233 if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
234 (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
235 value = mp.read(node.obj);
236 }
237 }
238 }
239
240 if (!value.isValid()) {
241 // the property was not found
242 if (!interfaceFound)
243 return interfaceNotFoundError(msg, interface_name);
244 return propertyNotFoundError(msg, interface_name, property_name);
245 }
246
248}
249
257
258static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name,
259 const QByteArray &property_name, int status)
260{
261 switch (status) {
262 case PropertyNotFound:
263 return propertyNotFoundError(msg, interface_name, property_name);
266 "Invalid arguments for writing to property %1%2%3"_L1
267 .arg(interface_name,
268 interface_name.isEmpty() ? ""_L1 : "."_L1,
269 QLatin1StringView(property_name)));
270 case PropertyReadOnly:
272 "Property %1%2%3 is read-only"_L1
273 .arg(interface_name,
274 interface_name.isEmpty() ? ""_L1 : "."_L1,
275 QLatin1StringView(property_name)));
278 QString::fromLatin1("Internal error"));
279
281 return msg.createReply();
282 }
283 Q_ASSERT_X(false, "", "Should not be reached");
284 return QDBusMessage();
285}
286
287static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value,
289{
290 const QMetaObject *mo = obj->metaObject();
291 int pidx = mo->indexOfProperty(property_name);
292 if (pidx == -1) {
293 // this object has no property by that name
294 return PropertyNotFound;
295 }
296
297 QMetaProperty mp = mo->property(pidx);
298
299 // check if this property is writable
300 if (!mp.isWritable())
301 return PropertyReadOnly;
302
303 // check if this property is exported
304 bool isScriptable = mp.isScriptable();
305 if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable)
306 return PropertyNotFound;
307 if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable)
308 return PropertyNotFound;
309
310 // we found our property
311 // do we have the right type?
312 QMetaType id = mp.metaType();
313 if (!id.isValid()){
314 // type not registered or invalid / void?
315 qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'",
316 mp.typeName(), mo->className(), property_name.constData());
317 return PropertyWriteFailed;
318 }
319
320 if (id.id() != QMetaType::QVariant && value.metaType() == QDBusMetaTypeId::argument()) {
321 // we have to demarshall before writing
323 if (!QDBusMetaType::demarshall(qvariant_cast<QDBusArgument>(value), other.metaType(), other.data())) {
324 qWarning("QDBusConnection: type '%s' (%d) is not registered with QtDBus. "
325 "Use qDBusRegisterMetaType to register it",
326 mp.typeName(), id.id());
327 return PropertyWriteFailed;
328 }
329
330 value = std::move(other);
331 }
332
333 if (mp.metaType() == QMetaType::fromType<QDBusVariant>())
335
336 // the property type here should match
337 return mp.write(obj, std::move(value)) ? PropertyWriteSuccess : PropertyWriteFailed;
338}
339
341 const QDBusMessage &msg)
342{
343 Q_ASSERT(msg.arguments().size() == 3);
344 Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
345 "QDBusConnection: internal threading error",
346 "function called for an object that is in another thread!!");
347
348 QString interface_name = msg.arguments().at(0).toString();
349 QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
350 QVariant value = qvariant_cast<QDBusVariant>(msg.arguments().at(2)).variant();
351
352 QDBusAdaptorConnector *connector;
354 (connector = qDBusFindAdaptorConnector(node.obj))) {
355
356 // find the class that implements interface_name or try until we've found the property
357 // in case of an empty interface
358 if (interface_name.isEmpty()) {
359 for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
360 std::as_const(connector->adaptors)) {
361 int status = writeProperty(adaptorData.adaptor, property_name, value);
362 if (status == PropertyNotFound)
363 continue;
364 return propertyWriteReply(msg, interface_name, property_name, status);
365 }
366 } else {
368 it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
369 interface_name);
370 if (it != connector->adaptors.cend() && interface_name == QLatin1StringView(it->interface)) {
371 return propertyWriteReply(msg, interface_name, property_name,
372 writeProperty(it->adaptor, property_name, value));
373 }
374 }
375 }
376
379 // try the object itself
380 bool interfaceFound = true;
381 if (!interface_name.isEmpty())
382 interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
383
384 if (interfaceFound) {
385 return propertyWriteReply(msg, interface_name, property_name,
386 writeProperty(node.obj, property_name, value, node.flags));
387 }
388 }
389
390 // the property was not found
391 if (!interface_name.isEmpty())
392 return interfaceNotFoundError(msg, interface_name);
393 return propertyWriteReply(msg, interface_name, property_name, PropertyNotFound);
394}
395
396// unite two QVariantMaps, but don't generate duplicate keys
398{
399 for (const auto &[key, value] : rhs.asKeyValueRange())
400 lhs.insert(key, value);
401 return lhs;
402}
403
405{
407 const QMetaObject *mo = object->metaObject();
408
409 // QObject has properties, so don't start from 0
410 for (int i = QObject::staticMetaObject.propertyCount(); i < mo->propertyCount(); ++i) {
411 QMetaProperty mp = mo->property(i);
412
413 // is it readable?
414 if (!mp.isReadable())
415 continue;
416
417 // is it a registered property?
418 QMetaType type = mp.metaType();
419 if (!type.isValid())
420 continue;
421 const char *signature = QDBusMetaType::typeToSignature(type);
422 if (!signature)
423 continue;
424
425 // is this property visible from the outside?
426 if ((mp.isScriptable() && flags & QDBusConnection::ExportScriptableProperties) ||
427 (!mp.isScriptable() && flags & QDBusConnection::ExportNonScriptableProperties)) {
428 // yes, it's visible
429 QVariant value = mp.read(object);
430 if (value.isValid())
431 result.insert(QString::fromLatin1(mp.name()), value);
432 }
433 }
434
435 return result;
436}
437
439 const QDBusMessage &msg)
440{
441 Q_ASSERT(msg.arguments().size() == 1);
442 Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
443 "QDBusConnection: internal threading error",
444 "function called for an object that is in another thread!!");
445
446 QString interface_name = msg.arguments().at(0).toString();
447
448 bool interfaceFound = false;
450
451 QDBusAdaptorConnector *connector;
453 (connector = qDBusFindAdaptorConnector(node.obj))) {
454
455 if (interface_name.isEmpty()) {
456 // iterate over all interfaces
457 for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
458 std::as_const(connector->adaptors)) {
459 result += readAllProperties(adaptorData.adaptor,
461 }
462 } else {
463 // find the class that implements interface_name
465 it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
466 interface_name);
467 if (it != connector->adaptors.constEnd() && interface_name == QLatin1StringView(it->interface)) {
468 interfaceFound = true;
470 }
471 }
472 }
473
475 (!interfaceFound || interface_name.isEmpty())) {
476 // try the object itself
477 result += readAllProperties(node.obj, node.flags);
478 interfaceFound = true;
479 }
480
481 if (!interfaceFound && !interface_name.isEmpty()) {
482 // the interface was not found
483 return interfaceNotFoundError(msg, interface_name);
484 }
485
487}
488
490
491#endif // QT_NO_DBUS
\inmodule QtCore
Definition qbytearray.h:57
static void saveIntrospectionXml(QDBusAbstractAdaptor *adaptor, const QString &xml)
static QString retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
@ UnknownProperty
Definition qdbuserror.h:46
@ PropertyReadOnly
Definition qdbuserror.h:47
@ UnknownInterface
Definition qdbuserror.h:44
\inmodule QtDBus
QDBusMessage createReply(const QList< QVariant > &arguments=QList< QVariant >()) const
Constructs a new DBus message representing a reply, with the given arguments.
QList< QVariant > arguments() const
Returns the list of arguments that are going to be sent or were received from D-Bus.
QString path() const
Returns the path of the object that this message is being sent to (in the case of a method call) or b...
QDBusMessage createErrorReply(const QString &name, const QString &msg) const
Constructs a new DBus message representing an error reply message, with the given name and msg.
static bool demarshall(const QDBusArgument &, QMetaType id, void *data)
static const char * typeToSignature(QMetaType type)
\inmodule QtDBus
virtual QString introspect(const QString &path) const =0
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator ConstIterator
Definition qlist.h:250
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
auto asKeyValueRange() &
Definition qmap.h:614
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:341
friend class QVariant
Definition qmetatype.h:796
\inmodule QtCore
Definition qobject.h:103
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
const_iterator cend() const noexcept
Definition qset.h:142
const_iterator constEnd() const noexcept
Definition qset.h:143
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QByteArray toUtf8() const &
Definition qstring.h:634
static QThread * currentThread()
Definition qthread.cpp:1039
\inmodule QtCore
Definition qvariant.h:65
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
QSet< QString >::iterator it
auto mo
[7]
QMetaType argument()
bool isValidPartOfObjectPath(QStringView part)
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
QDBusAdaptorConnector * qDBusFindAdaptorConnector(QObject *obj)
bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name, int status)
static QVariantMap & operator+=(QVariantMap &lhs, const QVariantMap &rhs)
static QString generateSubObjectXml(const QObject *object)
Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base, int flags)
static QVariantMap readAllProperties(QObject *object, int flags)
@ PropertyTypeMismatch
@ PropertyWriteFailed
@ PropertyWriteSuccess
QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node, const QString &path)
static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value, int propFlags=QDBusConnection::ExportAllProperties)
QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node, const QDBusMessage &msg)
QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node, const QDBusMessage &msg)
static const char introspectableInterfaceXml[]
static const char propertiesInterfaceXml[]
static QDBusMessage propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node, const QDBusMessage &msg)
static const char peerInterfaceXml[]
static QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
GLuint64 key
GLenum type
GLbitfield flags
GLuint name
GLhandleARB obj
[2]
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
static const uint base
Definition qurlidna.cpp:20
QSharedPointer< T > other(t)
[5]
QLayoutItem * child
[0]
QDBusConnection::RegisterOptions flags
\inmodule QtCore