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
qdbusinterface.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
7
9#include <QtCore/qpointer.h>
10#include <QtCore/qstringlist.h>
11
14
15#ifndef QT_NO_DBUS
16
18
19using namespace Qt::StringLiterals;
20
21static void copyArgument(void *to, int id, const QVariant &arg)
22{
23 if (id == arg.metaType().id()) {
24 switch (id) {
25 case QMetaType::Bool:
26 *reinterpret_cast<bool *>(to) = arg.toBool();
27 return;
28
29 case QMetaType::UChar:
30 *reinterpret_cast<uchar *>(to) = qvariant_cast<uchar>(arg);
31 return;
32
33 case QMetaType::Short:
34 *reinterpret_cast<short *>(to) = qvariant_cast<short>(arg);
35 return;
36
37 case QMetaType::UShort:
38 *reinterpret_cast<ushort *>(to) = qvariant_cast<ushort>(arg);
39 return;
40
41 case QMetaType::Int:
42 *reinterpret_cast<int *>(to) = arg.toInt();
43 return;
44
45 case QMetaType::UInt:
46 *reinterpret_cast<uint *>(to) = arg.toUInt();
47 return;
48
49 case QMetaType::LongLong:
50 *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
51 return;
52
53 case QMetaType::ULongLong:
54 *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
55 return;
56
57 case QMetaType::Double:
58 *reinterpret_cast<double *>(to) = arg.toDouble();
59 return;
60
61 case QMetaType::QString:
62 *reinterpret_cast<QString *>(to) = arg.toString();
63 return;
64
65 case QMetaType::QByteArray:
66 *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
67 return;
68
69 case QMetaType::QStringList:
70 *reinterpret_cast<QStringList *>(to) = arg.toStringList();
71 return;
72 }
73
74 if (id == QDBusMetaTypeId::variant().id()) {
75 *reinterpret_cast<QDBusVariant *>(to) = qvariant_cast<QDBusVariant>(arg);
76 return;
77 } else if (id == QDBusMetaTypeId::objectpath().id()) {
78 *reinterpret_cast<QDBusObjectPath *>(to) = qvariant_cast<QDBusObjectPath>(arg);
79 return;
80 } else if (id == QDBusMetaTypeId::signature().id()) {
81 *reinterpret_cast<QDBusSignature *>(to) = qvariant_cast<QDBusSignature>(arg);
82 return;
83 }
84
85 // those above are the only types possible
86 // the demarshaller code doesn't demarshall anything else
87 qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
88 }
89
90 // if we got here, it's either an un-dermarshalled type or a mismatch
91 if (arg.metaType() != QDBusMetaTypeId::argument()) {
92 // it's a mismatch
93 //qWarning?
94 return;
95 }
96
97 // is this type registered?
98 const char *userSignature = QDBusMetaType::typeToSignature(QMetaType(id));
99 if (!userSignature || !*userSignature) {
100 // type not registered
101 //qWarning?
102 return;
103 }
104
105 // is it the same signature?
106 QDBusArgument dbarg = qvariant_cast<QDBusArgument>(arg);
107 if (dbarg.currentSignature() != QLatin1StringView(userSignature)) {
108 // not the same signature, another mismatch
109 //qWarning?
110 return;
111 }
112
113 // we can demarshall
114 QDBusMetaType::demarshall(dbarg, QMetaType(id), to);
115}
116
117QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
118 const QString &iface, const QDBusConnection &con)
119 : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(nullptr)
120{
121 // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
122 if (connection.isConnected()) {
123 metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
124
125 if (!metaObject) {
126 // creation failed, somehow
127 // most common causes are that the service doesn't exist or doesn't support introspection
128 // those are not fatal errors, so we continue working
129
130 if (!lastError.isValid())
131 lastError = QDBusError(QDBusError::InternalError, "Unknown error"_L1);
132 }
133 }
134}
135
137{
138 if (metaObject && !metaObject->cached)
139 delete metaObject;
140}
141
142
143/*!
144 \class QDBusInterface
145 \inmodule QtDBus
146 \since 4.2
147
148 \brief The QDBusInterface class is a proxy for interfaces on remote objects.
149
150 QDBusInterface is a generic accessor class that is used to place calls to remote objects,
151 connect to signals exported by remote objects and get/set the value of remote properties. This
152 class is useful for dynamic access to remote objects: that is, when you do not have a generated
153 code that represents the remote interface.
154
155 Calls are usually placed by using the call() function, which constructs the message, sends it
156 over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
157 normal QObject::connect() function. Finally, properties are accessed using the
158 QObject::property() and QObject::setProperty() functions.
159
160 The following code snippet demonstrates how to perform a
161 mathematical operation of \tt{"2 + 2"} in a remote application
162 called \c com.example.Calculator, accessed via the session bus.
163
164 \snippet code/src_qdbus_qdbusinterface.cpp 0
165
166 \sa {Qt D-Bus XML compiler (qdbusxml2cpp)}
167*/
168
169/*!
170 Creates a dynamic QDBusInterface object associated with the
171 interface \a interface on object at path \a path on service \a
172 service, using the given \a connection. If \a interface is an
173 empty string, the object created will refer to the merging of all
174 interfaces found by introspecting that object. Otherwise if
175 \a interface is not empty, the QDBusInterface object will be cached
176 to speedup further creations of the same interface.
177
178 \a parent is passed to the base class constructor.
179
180 If the remote service \a service is not present or if an error
181 occurs trying to obtain the description of the remote interface
182 \a interface, the object created will not be valid (see
183 isValid()).
184*/
185QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
186 const QDBusConnection &connection, QObject *parent)
187 : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
188 parent)
189{
190}
191
192/*!
193 Destroy the object interface and frees up any resource used.
194*/
195QDBusInterface::~QDBusInterface()
196{
197 // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
198}
199
200/*!
201 \internal
202 Overrides QObject::metaObject to return our own copy.
203*/
204const QMetaObject *QDBusInterface::metaObject() const
205{
206 return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
207}
208
209/*!
210 \internal
211 Override QObject::qt_metacast to catch the interface name too.
212*/
213void *QDBusInterface::qt_metacast(const char *_clname)
214{
215 if (!_clname) return nullptr;
216 if (!strcmp(_clname, "QDBusInterface"))
217 return static_cast<void*>(const_cast<QDBusInterface*>(this));
218 if (d_func()->interface.toLatin1() == _clname)
219 return static_cast<void*>(const_cast<QDBusInterface*>(this));
220 return QDBusAbstractInterface::qt_metacast(_clname);
221}
222
223/*!
224 \internal
225 Dispatch the call through the private.
226*/
227int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
228{
229 _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
230 if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
231 return _id;
232 return d_func()->metacall(_c, _id, _a);
233}
234
235int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
236{
237 Q_Q(QDBusInterface);
238
239 if (c == QMetaObject::InvokeMetaMethod) {
240 int offset = metaObject->methodOffset();
241 QMetaMethod mm = metaObject->method(id + offset);
242
243 if (mm.methodType() == QMetaMethod::Signal) {
244 // signal relay from D-Bus world to Qt world
245 QMetaObject::activate(q, metaObject, id, argv);
246
247 } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
248 // method call relay from Qt world to D-Bus world
249 // get D-Bus equivalent signature
250 QString methodName = QString::fromLatin1(mm.name());
251 const int *inputTypes = metaObject->inputTypesForMethod(id);
252 int inputTypesCount = *inputTypes;
253
254 // we will assume that the input arguments were passed correctly
255 QVariantList args;
256 args.reserve(inputTypesCount);
257 int i = 1;
258 for ( ; i <= inputTypesCount; ++i)
259 args << QVariant(QMetaType(inputTypes[i]), argv[i]);
260
261 // make the call
262 QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
263
264 if (reply.type() == QDBusMessage::ReplyMessage) {
265 // attempt to demarshall the return values
266 args = reply.arguments();
267 QVariantList::ConstIterator it = args.constBegin();
268 const int *outputTypes = metaObject->outputTypesForMethod(id);
269 int outputTypesCount = *outputTypes++;
270
271 if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) {
272 // this method has a return type
273 if (argv[0] && it != args.constEnd())
274 copyArgument(argv[0], *outputTypes++, *it);
275
276 // skip this argument even if we didn't copy it
277 --outputTypesCount;
278 ++it;
279 }
280
281 for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
282 copyArgument(argv[i], outputTypes[j], *it);
283 }
284 }
285
286 // done
287 lastError = QDBusError(reply);
288 return -1;
289 }
290 }
291 return id;
292}
293
294QT_END_NAMESPACE
295
296#endif // QT_NO_DBUS
\inmodule QtDBus
int metacall(QMetaObject::Call c, int id, void **argv)
QDBusInterfacePrivate(const QString &serv, const QString &p, const QString &iface, const QDBusConnection &con)
\inmodule QtDBus
\inmodule QtDBus
\inmodule QtDBus
static void copyArgument(void *to, int id, const QVariant &arg)