/src/qtbase/src/dbus/qdbusinterface.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 "qdbusinterface.h" |
6 | | #include "qdbusinterface_p.h" |
7 | | |
8 | | #include "qdbus_symbols_p.h" |
9 | | #include <QtCore/qpointer.h> |
10 | | #include <QtCore/qstringlist.h> |
11 | | |
12 | | #include "qdbusmetatype_p.h" |
13 | | #include "qdbusconnection_p.h" |
14 | | |
15 | | #ifndef QT_NO_DBUS |
16 | | |
17 | | QT_BEGIN_NAMESPACE |
18 | | |
19 | | using namespace Qt::StringLiterals; |
20 | | |
21 | | static void copyArgument(void *to, int id, const QVariant &arg) |
22 | 0 | { |
23 | 0 | if (id == arg.metaType().id()) { |
24 | 0 | switch (id) { |
25 | 0 | case QMetaType::Bool: |
26 | 0 | *reinterpret_cast<bool *>(to) = arg.toBool(); |
27 | 0 | return; |
28 | | |
29 | 0 | case QMetaType::UChar: |
30 | 0 | *reinterpret_cast<uchar *>(to) = qvariant_cast<uchar>(arg); |
31 | 0 | return; |
32 | | |
33 | 0 | case QMetaType::Short: |
34 | 0 | *reinterpret_cast<short *>(to) = qvariant_cast<short>(arg); |
35 | 0 | return; |
36 | | |
37 | 0 | case QMetaType::UShort: |
38 | 0 | *reinterpret_cast<ushort *>(to) = qvariant_cast<ushort>(arg); |
39 | 0 | return; |
40 | | |
41 | 0 | case QMetaType::Int: |
42 | 0 | *reinterpret_cast<int *>(to) = arg.toInt(); |
43 | 0 | return; |
44 | | |
45 | 0 | case QMetaType::UInt: |
46 | 0 | *reinterpret_cast<uint *>(to) = arg.toUInt(); |
47 | 0 | return; |
48 | | |
49 | 0 | case QMetaType::LongLong: |
50 | 0 | *reinterpret_cast<qlonglong *>(to) = arg.toLongLong(); |
51 | 0 | return; |
52 | | |
53 | 0 | case QMetaType::ULongLong: |
54 | 0 | *reinterpret_cast<qulonglong *>(to) = arg.toULongLong(); |
55 | 0 | return; |
56 | | |
57 | 0 | case QMetaType::Double: |
58 | 0 | *reinterpret_cast<double *>(to) = arg.toDouble(); |
59 | 0 | return; |
60 | | |
61 | 0 | case QMetaType::QString: |
62 | 0 | *reinterpret_cast<QString *>(to) = arg.toString(); |
63 | 0 | return; |
64 | | |
65 | 0 | case QMetaType::QByteArray: |
66 | 0 | *reinterpret_cast<QByteArray *>(to) = arg.toByteArray(); |
67 | 0 | return; |
68 | | |
69 | 0 | case QMetaType::QStringList: |
70 | 0 | *reinterpret_cast<QStringList *>(to) = arg.toStringList(); |
71 | 0 | return; |
72 | 0 | } |
73 | | |
74 | 0 | if (id == QDBusMetaTypeId::variant().id()) { |
75 | 0 | *reinterpret_cast<QDBusVariant *>(to) = qvariant_cast<QDBusVariant>(arg); |
76 | 0 | return; |
77 | 0 | } else if (id == QDBusMetaTypeId::objectpath().id()) { |
78 | 0 | *reinterpret_cast<QDBusObjectPath *>(to) = qvariant_cast<QDBusObjectPath>(arg); |
79 | 0 | return; |
80 | 0 | } else if (id == QDBusMetaTypeId::signature().id()) { |
81 | 0 | *reinterpret_cast<QDBusSignature *>(to) = qvariant_cast<QDBusSignature>(arg); |
82 | 0 | return; |
83 | 0 | } |
84 | | |
85 | | // those above are the only types possible |
86 | | // the demarshaller code doesn't demarshall anything else |
87 | 0 | qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there"); |
88 | 0 | } |
89 | | |
90 | | // if we got here, it's either an un-dermarshalled type or a mismatch |
91 | 0 | if (arg.metaType() != QDBusMetaTypeId::argument()) { |
92 | | // it's a mismatch |
93 | | //qWarning? |
94 | 0 | return; |
95 | 0 | } |
96 | | |
97 | | // is this type registered? |
98 | 0 | const char *userSignature = QDBusMetaType::typeToSignature(QMetaType(id)); |
99 | 0 | if (!userSignature || !*userSignature) { |
100 | | // type not registered |
101 | | //qWarning? |
102 | 0 | return; |
103 | 0 | } |
104 | | |
105 | | // is it the same signature? |
106 | 0 | QDBusArgument dbarg = qvariant_cast<QDBusArgument>(arg); |
107 | 0 | if (dbarg.currentSignature() != QLatin1StringView(userSignature)) { |
108 | | // not the same signature, another mismatch |
109 | | //qWarning? |
110 | 0 | return; |
111 | 0 | } |
112 | | |
113 | | // we can demarshall |
114 | 0 | QDBusMetaType::demarshall(dbarg, QMetaType(id), to); |
115 | 0 | } |
116 | | |
117 | | QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p, |
118 | | const QString &iface, const QDBusConnection &con) |
119 | 0 | : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(nullptr) |
120 | 0 | { |
121 | | // QDBusAbstractInterfacePrivate's constructor checked the parameters for us |
122 | 0 | if (connection.isConnected()) { |
123 | 0 | metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError); |
124 | |
|
125 | 0 | 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 | 0 | if (!lastError.isValid()) |
131 | 0 | lastError = QDBusError(QDBusError::InternalError, "Unknown error"_L1); |
132 | 0 | } |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | | QDBusInterfacePrivate::~QDBusInterfacePrivate() |
137 | 0 | { |
138 | 0 | if (metaObject && !metaObject->cached) |
139 | 0 | delete metaObject; |
140 | 0 | } |
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 | | */ |
185 | | QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface, |
186 | | const QDBusConnection &connection, QObject *parent) |
187 | 0 | : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection), |
188 | 0 | parent) |
189 | 0 | { |
190 | 0 | } |
191 | | |
192 | | /*! |
193 | | Destroy the object interface and frees up any resource used. |
194 | | */ |
195 | | QDBusInterface::~QDBusInterface() |
196 | 0 | { |
197 | | // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate() |
198 | 0 | } |
199 | | |
200 | | /*! |
201 | | \internal |
202 | | Overrides QObject::metaObject to return our own copy. |
203 | | */ |
204 | | const QMetaObject *QDBusInterface::metaObject() const |
205 | 0 | { |
206 | 0 | return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject; |
207 | 0 | } |
208 | | |
209 | | /*! |
210 | | \internal |
211 | | Override QObject::qt_metacast to catch the interface name too. |
212 | | */ |
213 | | void *QDBusInterface::qt_metacast(const char *_clname) |
214 | 0 | { |
215 | 0 | if (!_clname) return nullptr; |
216 | 0 | if (!strcmp(_clname, "QDBusInterface")) |
217 | 0 | return static_cast<void*>(const_cast<QDBusInterface*>(this)); |
218 | 0 | if (d_func()->interface.toLatin1() == _clname) |
219 | 0 | return static_cast<void*>(const_cast<QDBusInterface*>(this)); |
220 | 0 | return QDBusAbstractInterface::qt_metacast(_clname); |
221 | 0 | } |
222 | | |
223 | | /*! |
224 | | \internal |
225 | | Dispatch the call through the private. |
226 | | */ |
227 | | int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a) |
228 | 0 | { |
229 | 0 | _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a); |
230 | 0 | if (_id < 0 || !d_func()->isValid || !d_func()->metaObject) |
231 | 0 | return _id; |
232 | 0 | return d_func()->metacall(_c, _id, _a); |
233 | 0 | } |
234 | | |
235 | | int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv) |
236 | 0 | { |
237 | 0 | Q_Q(QDBusInterface); |
238 | |
|
239 | 0 | if (c == QMetaObject::InvokeMetaMethod) { |
240 | 0 | int offset = metaObject->methodOffset(); |
241 | 0 | QMetaMethod mm = metaObject->method(id + offset); |
242 | |
|
243 | 0 | if (mm.methodType() == QMetaMethod::Signal) { |
244 | | // signal relay from D-Bus world to Qt world |
245 | 0 | QMetaObject::activate(q, metaObject, id, argv); |
246 | |
|
247 | 0 | } 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 | 0 | QString methodName = QString::fromLatin1(mm.name()); |
251 | 0 | const int *inputTypes = metaObject->inputTypesForMethod(id); |
252 | 0 | int inputTypesCount = *inputTypes; |
253 | | |
254 | | // we will assume that the input arguments were passed correctly |
255 | 0 | QVariantList args; |
256 | 0 | args.reserve(inputTypesCount); |
257 | 0 | int i = 1; |
258 | 0 | for ( ; i <= inputTypesCount; ++i) |
259 | 0 | args << QVariant(QMetaType(inputTypes[i]), argv[i]); |
260 | | |
261 | | // make the call |
262 | 0 | QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args); |
263 | |
|
264 | 0 | if (reply.type() == QDBusMessage::ReplyMessage) { |
265 | | // attempt to demarshall the return values |
266 | 0 | args = reply.arguments(); |
267 | 0 | QVariantList::ConstIterator it = args.constBegin(); |
268 | 0 | const int *outputTypes = metaObject->outputTypesForMethod(id); |
269 | 0 | int outputTypesCount = *outputTypes++; |
270 | |
|
271 | 0 | if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) { |
272 | | // this method has a return type |
273 | 0 | if (argv[0] && it != args.constEnd()) |
274 | 0 | copyArgument(argv[0], *outputTypes++, *it); |
275 | | |
276 | | // skip this argument even if we didn't copy it |
277 | 0 | --outputTypesCount; |
278 | 0 | ++it; |
279 | 0 | } |
280 | |
|
281 | 0 | for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) { |
282 | 0 | copyArgument(argv[i], outputTypes[j], *it); |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | // done |
287 | 0 | lastError = QDBusError(reply); |
288 | 0 | return -1; |
289 | 0 | } |
290 | 0 | } |
291 | 0 | return id; |
292 | 0 | } |
293 | | |
294 | | QT_END_NAMESPACE |
295 | | |
296 | | #endif // QT_NO_DBUS |