1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "objectendpoint_dbus_p.h"
35#include "instancemanager_p.h"
36#include "proxyobject_p.h"
37#include "qsignalintercepter_p.h"
38#include <private/qmetaobjectbuilder_p.h>
39#include <QTimer>
40#include <QEventLoop>
41#include <QVarLengthArray>
42
43QT_BEGIN_NAMESPACE
44
45class Response
46{
47public:
48 Response() : isFinished(false), result(0)
49 { }
50
51 bool isFinished;
52 void* result;
53};
54
55typedef QHash<QUuid, Response*> Replies;
56Q_GLOBAL_STATIC(Replies, openRequests);
57
58class ServiceSignalIntercepter : public QSignalIntercepter
59{
60 //Do not put Q_OBJECT here
61public:
62 ServiceSignalIntercepter(QObject* sender, const QByteArray& signal,
63 ObjectEndPoint* parent)
64 : QSignalIntercepter(sender, signal, parent), endPoint(parent)
65 {
66
67 }
68
69 void setMetaIndex(int index)
70 {
71 metaIndex = index;
72 }
73
74protected:
75 void activated( const QList<QVariant>& args )
76 {
77 endPoint->invokeRemote(metaIndex, args, returnType: QMetaType::Void);
78 }
79private:
80 ObjectEndPoint* endPoint;
81 int metaIndex;
82};
83
84struct ClientInstance {
85 QString clientId;
86 QRemoteServiceRegister::Entry entry;
87 QUuid instanceId;
88 int ref;
89};
90
91class ObjectEndPointPrivate
92{
93public:
94 ObjectEndPointPrivate()
95 {
96 }
97
98 ~ObjectEndPointPrivate()
99 {
100 }
101
102 // Used on client and service side
103 ObjectEndPoint::Type endPointType;
104 ObjectEndPoint* parent;
105
106 // Used to calculate the registered paths on DBus
107 QRemoteServiceRegister::Entry entry;
108 QUuid serviceInstanceId;
109
110 // Service side local client ownership list
111 QList<ClientInstance> clientList;
112};
113
114/*!
115 Client to service communication only used for establishing an object request since the returned
116 proxy is an interface to that object registered on QtDBus. Client communicates directly to QtDBus
117 for method and property access. Signals are automatically relayed from QtDBus to the proxy object.
118*/
119ObjectEndPoint::ObjectEndPoint(Type type, QServiceIpcEndPoint* comm, QObject* parent)
120 : QObject(parent), dispatch(comm), service(0), iface(0)
121{
122 Q_ASSERT(dispatch);
123 d = new ObjectEndPointPrivate;
124 d->parent = this;
125 d->endPointType = type;
126
127 dispatch->setParent(this);
128 connect(sender: dispatch, SIGNAL(readyRead()), receiver: this, SLOT(newPackageReady()));
129 if (type == Client) {
130 // client waiting for construct proxy and registers DBus custom type
131 qDBusRegisterMetaType<QServiceUserTypeDBus>();
132 qRegisterMetaType<QServiceUserTypeDBus>();
133 return;
134 } else {
135 connect(sender: InstanceManager::instance(),
136 SIGNAL(instanceClosed(QRemoteServiceRegister::Entry,QUuid)),
137 receiver: this, SLOT(unregisterObjectDBus(QRemoteServiceRegister::Entry,QUuid)));
138
139 if (dispatch->packageAvailable())
140 QTimer::singleShot(msec: 0, receiver: this, SLOT(newPackageReady()));
141 }
142}
143
144ObjectEndPoint::~ObjectEndPoint()
145{
146 if (iface)
147 delete iface;
148 delete d;
149}
150
151/*!
152 Removes all instances of the client from the instance manager
153*/
154void ObjectEndPoint::disconnected(const QString& clientId, const QString& instanceId)
155{
156 // Service Side
157 Q_ASSERT(d->endPointType != ObjectEndPoint::Client);
158
159 for (int i=d->clientList.size()-1; i>=0; i--) {
160 // Find right client process
161 if (d->clientList[i].clientId == clientId) {
162 if (d->clientList[i].ref-- == 1) {
163 QRemoteServiceRegister::Entry entry = d->clientList[i].entry;
164 QUuid instance = d->clientList[i].instanceId;
165
166 if (instance.toString() == instanceId) {
167 // Remove an instance from the InstanceManager and local list
168 InstanceManager::instance()->removeObjectInstance(entry, instanceId: instance);
169 d->clientList.removeAt(i);
170 }
171 }
172 }
173 }
174}
175
176/*!
177 Unregisters the DBus object
178*/
179void ObjectEndPoint::unregisterObjectDBus(const QRemoteServiceRegister::Entry& entry, const QUuid& id)
180{
181 uint hash = qHash(key: id.toString());
182 QString objPath = QLatin1Char('/') + entry.interfaceName() + QLatin1Char('/') + entry.version() +
183 QLatin1Char('/') + QString::number(hash);
184 objPath.replace(before: QLatin1Char('.'), after: QLatin1Char('/'));
185 QDBusConnection::sessionBus().unregisterObject(path: objPath, mode: QDBusConnection::UnregisterTree);
186}
187
188/*!
189 Client requests proxy object. The proxy is owned by calling
190 code and this object must clean itself up upon destruction of
191 proxy.
192*/
193QObject* ObjectEndPoint::constructProxy(const QRemoteServiceRegister::Entry& entry)
194{
195 // Client side
196 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
197
198 // Request a serialized meta object
199 QServicePackage p;
200 p.d = new QServicePackagePrivate();
201 p.d->messageId = QUuid::createUuid();
202 p.d->entry = entry;
203
204 Response* response = new Response();
205 openRequests()->insert(key: p.d->messageId, value: response);
206
207 dispatch->writePackage(newPackage: p);
208 waitForResponse(requestId: p.d->messageId);
209
210 // Get the proxy based on the meta object
211 if (response->isFinished) {
212 if (response->result == 0)
213 qWarning() << "Request for remote service failed";
214 else
215 service = reinterpret_cast<QServiceProxy* >(response->result);
216 } else {
217 qDebug() << "response passed but not finished";
218 }
219
220 openRequests()->take(key: p.d->messageId);
221 delete response;
222
223 if (!service)
224 return 0;
225
226 // Connect all DBus interface signals to the proxy slots
227 const QMetaObject *mo = service->metaObject();
228 while (mo && strcmp(s1: mo->className(), s2: "QObject")) {
229 for (int i = mo->methodOffset(); i < mo->methodCount(); i++) {
230 const QMetaMethod mm = mo->method(index: i);
231 if (mm.methodType() == QMetaMethod::Signal) {
232 QByteArray sig(mm.methodSignature());
233
234 bool customType = false;
235
236 QList<QByteArray> params = mm.parameterTypes();
237 for (int arg = 0; arg < params.size(); arg++) {
238 const QByteArray& type = params[arg];
239 int variantType = QMetaType::type(typeName: type);
240 if (variantType >= QMetaType::User || variantType == QMetaType::QVariant) {
241 sig.replace(before: QByteArray(type), after: QByteArray("QDBusVariant"));
242 customType = true;
243 }
244 }
245
246 int serviceIndex = iface->metaObject()->indexOfSignal(signal: sig);
247 QByteArray signal = QByteArray("2").append(a: sig);
248
249 if (serviceIndex > 0) {
250 if (customType) {
251 QObject::connect(sender: iface, signal: signal.constData(), receiver: signalsObject, member: signal.constData());
252
253 ServiceSignalIntercepter *intercept =
254 new ServiceSignalIntercepter((QObject*)signalsObject, signal, this);
255 intercept->setMetaIndex(localToRemote[i]);
256 } else {
257 QObject::connect(sender: iface, signal: signal.constData(), receiver: service, member: signal.constData());
258 }
259 }
260 }
261 }
262 mo = mo->superClass();
263 }
264
265 return service;
266}
267
268/*!
269 Received a new package from the DBus client-server controller.
270 Once an object request is handled there is only direct communication to the DBus object so
271 no other package types should be received on this layer.
272*/
273void ObjectEndPoint::newPackageReady()
274{
275 // Client and service side
276 while (dispatch->packageAvailable())
277 {
278 // must call get getSecurityCredentials everytime you call nextPackage
279 QServiceClientCredentials creds;
280 dispatch->getSecurityCredentials(creds);
281 QServicePackage p = dispatch->nextPackage();
282 if (!p.isValid())
283 continue;
284
285 if (p.d->packageType == QServicePackage::ObjectCreation) {
286 objectRequest(p, creds);
287 } else {
288 qWarning() << "Unknown package type received.";
289 }
290 }
291}
292
293void ObjectEndPoint::setLookupTable(int *local, int *remote)
294{
295 localToRemote = local;
296 remoteToLocal = remote;
297}
298
299/*!
300 Service finds existing objects or spawns new object instances and registers them on DBus using a
301 hash of the unique instance ID. This registered object has a special metaobject representation
302 of the service that is compatible with the QDBus type system.
303
304 Client receives a package containing the information to connect an interface to the registered
305 DBus object.
306*/
307void ObjectEndPoint::objectRequest(const QServicePackage& p, QServiceClientCredentials& creds)
308{
309 if (p.d->responseType != QServicePackage::NotAResponse ) {
310 // Client side
311 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
312
313 d->serviceInstanceId = p.d->instanceId;
314 d->entry = p.d->entry;
315
316 Response* response = openRequests()->value(key: p.d->messageId);
317 if (p.d->responseType == QServicePackage::Failed) {
318 response->result = 0;
319 response->isFinished = true;
320 QTimer::singleShot(msec: 0, receiver: this, SIGNAL(pendingRequestFinished()));
321 qWarning() << "Service instantiation failed";
322 return;
323 }
324
325 // Deserialize meta object and create proxy object
326 QServiceProxy* proxy = new QServiceProxy(p.d->payload.toByteArray(), this);
327 response->result = reinterpret_cast<void *>(proxy);
328 response->isFinished = true;
329
330 // Create DBUS interface by using a hash of the service instance ID
331 QString serviceName = QStringLiteral("com.nokia.qtmobility.sfw.") + p.d->entry.serviceName();
332 uint hash = qHash(key: d->serviceInstanceId.toString());
333 QString objPath = QLatin1Char('/') + p.d->entry.interfaceName() + QLatin1Char('/') + p.d->entry.version() + QLatin1Char('/') + QString::number(hash);
334 objPath.replace(before: QLatin1Char('.'), after: QLatin1Char('/'));
335
336#ifdef DEBUG
337 qDebug() << "Client Interface ObjectPath:" << objPath;
338#endif
339 // Instantiate our DBus interface and its corresponding signals object
340 if (!iface)
341 iface = new QDBusInterface(serviceName, objPath, QString(), QDBusConnection::sessionBus(), this);
342 signalsObject = new QServiceMetaObjectDBus(iface, true);
343
344 // Wake up waiting proxy construction code
345 QTimer::singleShot(msec: 0, receiver: this, SIGNAL(pendingRequestFinished()));
346
347 } else {
348 // Service side
349 Q_ASSERT(d->endPointType == ObjectEndPoint::Service);
350
351 QServicePackage response = p.createResponse();
352 InstanceManager* iManager = InstanceManager::instance();
353
354 if (!creds.isValid()) {
355 qWarning() << "SFW Unable to get socket credentials client asking for" << p.d->entry.interfaceName() << p.d->entry.serviceName() << "this may fail in the future";
356 }
357
358 // Instantiate service object from type register
359 service = iManager->createObjectInstance(entry: p.d->entry, instanceId&: d->serviceInstanceId, creds);
360 if (!service) {
361 qWarning() << "Cannot instantiate service object";
362 dispatch->writePackage(newPackage: response);
363 return;
364 }
365
366 if (!creds.isClientAccepted()) {
367 qWarning() << "SFW Security failure by" <<
368 creds.getProcessIdentifier() <<
369 creds.getUserIdentifier() <<
370 creds.getGroupIdentifier() <<
371 "requesting" << p.d->entry.interfaceName() << p.d->entry.serviceName();
372 iManager->removeObjectInstance(entry: p.d->entry, instanceId: d->serviceInstanceId);
373 dispatch->writePackage(newPackage: response);
374 return;
375 }
376
377 // Start DBus connection and register proxy service
378 if (!QDBusConnection::sessionBus().isConnected()) {
379 qWarning() << "Cannot connect to DBus";
380 }
381
382 // DBus registration path uses a hash of the service instance ID
383 QString serviceName = QStringLiteral("com.nokia.qtmobility.sfw.") + p.d->entry.serviceName();
384 uint hash = qHash(key: d->serviceInstanceId.toString());
385 QString objPath = QLatin1Char('/') + p.d->entry.interfaceName() + QLatin1Char('/') + p.d->entry.version() + QLatin1Char('/') + QString::number(hash);
386 objPath.replace(before: QLatin1Char('.'), after: QLatin1Char('/'));
387
388 QServiceMetaObjectDBus *serviceDBus = new QServiceMetaObjectDBus(service);
389 QDBusConnection::sessionBus().registerObject(path: objPath, object: serviceDBus, options: QDBusConnection::ExportAllContents);
390
391 QString clientId = p.d->payload.toString();
392
393 int exists = 0;
394 for (int i=d->clientList.size()-1; i>=0; i--) {
395 // Find right client process
396 if (d->clientList[i].clientId == clientId) {
397 d->clientList[i].ref++;
398 exists = 1;
399 break;
400 }
401 }
402
403 if (!exists) {
404 // Add new instance to client ownership list
405 ClientInstance c;
406 c.clientId = clientId;
407 c.entry = p.d->entry;
408 c.instanceId = d->serviceInstanceId;
409 c.ref = 1;
410 d->clientList << c;
411 }
412
413
414
415#ifdef DEBUG
416 qDebug() << "Service Interface ObjectPath:" << objPath;
417
418 const QMetaObject *s_meta = service->metaObject();
419 qDebug() << "+++++++++++++++++++++SERVICE+++++++++++++++++++++++";
420 qDebug() << s_meta->className();
421 qDebug() << "METHOD COUNT: " << s_meta->methodCount();
422 for (int i=0; i<s_meta->methodCount(); i++) {
423 QMetaMethod mm = s_meta->method(i);
424
425 QString type;
426 switch (mm.methodType()) {
427 case QMetaMethod::Method:
428 type = "Q_INVOKABLE";
429 break;
430 case QMetaMethod::Signal:
431 type = "SIGNAL";
432 break;
433 case QMetaMethod::Slot:
434 type = "SLOT";
435 break;
436 default:
437 break;
438 }
439
440 QString returnType = mm.typeName();
441 if (returnType == "") returnType = "void";
442
443 qDebug() << "METHOD" << type << ":" << returnType << mm.methodSignature();
444 }
445 qDebug() << "++++++++++++++++++++++++++++++++++++++++++++++++++++";
446 if (!iface)
447 iface = new QDBusInterface(serviceName, objPath, "", QDBusConnection::sessionBus(), this);
448 const QMetaObject *i_meta = iface->metaObject();
449 qDebug() << "++++++++++++++++++++DBUS SERVICE++++++++++++++++++++";
450 qDebug() << i_meta->className();
451 qDebug() << "METHOD COUNT: " << i_meta->methodCount();
452 for (int i=0; i<i_meta->methodCount(); i++) {
453 QMetaMethod mm = i_meta->method(i);
454
455 QString type;
456 switch (mm.methodType()) {
457 case QMetaMethod::Method:
458 type = "Q_INVOKABLE";
459 break;
460 case QMetaMethod::Signal:
461 type = "SIGNAL";
462 break;
463 case QMetaMethod::Slot:
464 type = "SLOT";
465 break;
466 default:
467 break;
468 }
469
470 QString returnType = mm.typeName();
471 if (returnType == "") returnType = "void";
472
473 qDebug() << "METHOD" << type << ":" << returnType << mm.methodSignature();
474 }
475 qDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++";
476#endif
477
478 // Get meta object from type register
479 const QMetaObject* meta = iManager->metaObject(ident: p.d->entry);
480 if (!meta) {
481 qDebug() << "Unknown type" << p.d->entry;
482 dispatch->writePackage(newPackage: response);
483 return;
484 }
485
486 // Serialize meta object
487 QByteArray data;
488 QDataStream stream( &data, QIODevice::WriteOnly | QIODevice::Append );
489 QMetaObjectBuilder builder(meta);
490 builder.serialize(stream);
491
492 // Send meta object and instance ID to the client for processing
493 d->entry = p.d->entry;
494 response.d->instanceId = d->serviceInstanceId;
495 response.d->entry = p.d->entry;
496 response.d->responseType = QServicePackage::Success;
497 response.d->payload = QVariant(data);
498 dispatch->writePackage(newPackage: response);
499 }
500}
501
502/*!
503 Returns the created service instance Id
504*/
505QString ObjectEndPoint::getInstanceId() const
506{
507 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
508
509 return d->serviceInstanceId.toString();
510}
511
512/*!
513 Client side property call that directly accesses properties through the DBus interface.
514 Read and reset have special hardcoded DBus methods due to the nature of QtDBus properties
515 without an adaptor class incorrectly forwarding the metacall type
516*/
517QVariant ObjectEndPoint::invokeRemoteProperty(int metaIndex, const QVariant& arg, int /*returnType*/, QMetaObject::Call c )
518{
519 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
520
521 const QMetaObject *imeta = service->metaObject();
522 QMetaProperty property = imeta->property(index: metaIndex);
523
524 if (c == QMetaObject::WriteProperty) {
525 // Writing property, direct property DBus call
526 if (!iface->setProperty(name: property.name(), value: arg)) {
527 qWarning() << "Service property write call failed";
528 }
529
530 } else if (c == QMetaObject::ResetProperty) {
531 // Resetting property, direct special method DBus call
532 QVariantList args;
533 args << QVariant(QLatin1String(property.name()));
534 QDBusMessage msg = iface->callWithArgumentList(mode: QDBus::Block, method: QLatin1String("propertyReset"), args);
535 if (msg.type() == QDBusMessage::InvalidMessage) {
536 qWarning() << "Service property reset call failed";
537 }
538
539 } else if (c == QMetaObject::ReadProperty) {
540 // Reading property, direct special method DBus call
541 QVariantList args;
542 args << QVariant(QLatin1String(property.name()));
543 QDBusMessage msg = iface->callWithArgumentList(mode: QDBus::Block, method: QLatin1String("propertyRead"), args);
544 if (msg.type() == QDBusMessage::ReplyMessage) {
545 QVariantList retList = msg.arguments();
546 return retList[0];
547 } else {
548 qWarning() << "Service property read call failed" << msg.errorMessage();
549 }
550 } else {
551 qWarning() << "Invalid property call";
552 }
553
554 return QVariant();
555}
556
557/*!
558 Client side method call that converts an argument of type to its corresponding value as a
559 valid type supported by the QtDBus type system.
560
561 Supports conversion from a QVariant, QList, QMap, QHash, and custom user-defined types.
562*/
563QVariant ObjectEndPoint::toDBusVariant(const QByteArray& typeName, const QVariant& arg)
564{
565 QVariant dbusVariant = arg;
566
567 int type = QMetaType::type(typeName);
568 if (type == QMetaType::QVariant) {
569 // Wrap QVariants in a QDBusVariant
570 QDBusVariant replacement(arg);
571 dbusVariant = QVariant::fromValue(value: replacement);
572 } else if (type >= QMetaType::User) {
573 // Wrap custom types in a QDBusVariant of the type name and
574 // a buffer of its variant-wrapped data
575 QByteArray buffer;
576 QDataStream stream(&buffer, QIODevice::ReadWrite | QIODevice::Append);
577 stream << arg;
578
579 QServiceUserTypeDBus customType;
580 customType.typeName = typeName;
581 customType.variantBuffer = buffer;
582
583 QDBusVariant replacement(QVariant::fromValue(value: customType));
584 dbusVariant = QVariant::fromValue(value: replacement);
585 }
586
587 return dbusVariant;
588}
589
590/*!
591 Client side method call that directly accesses the object through the DBus interface.
592 All arguments and return types are processed and converted accordingly so that all functions
593 satisfy the QtDBus type system.
594*/
595QVariant ObjectEndPoint::invokeRemote(int metaIndex, const QVariantList& args, int returnType)
596{
597 QMetaMethod method = service->metaObject()->method(index: remoteToLocal[metaIndex]);
598
599 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
600
601 // Check is this is a signal relay
602 if (method.methodType() == QMetaMethod::Signal) {
603 // Convert custom arguments
604 QVariantList convertedList;
605 QList<QByteArray> params = method.parameterTypes();
606 for (int i = 0; i < params.size(); i++) {
607 const QByteArray& type = params[i];
608 int variantType = QMetaType::type(typeName: type);
609 if (variantType >= QMetaType::User || variantType == QMetaType::QVariant) {
610 QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(v: args[i]);
611 QVariant variant = dbusVariant.variant();
612
613 if (variantType == QMetaType::QVariant) {
614 convertedList << variant;
615 } else {
616 QByteArray buffer = variant.toByteArray();
617 QDataStream stream(&buffer, QIODevice::ReadWrite);
618 QVariant *customType = new QVariant(variantType, (const void*)0);
619 QMetaType::load(stream, type: QMetaType::QVariant, data: customType);
620 convertedList << *customType;
621 }
622 } else {
623 convertedList << args[i];
624 }
625 }
626
627 // Signal relay
628 const int numArgs = convertedList.size();
629 QVarLengthArray<void *, 32> a( numArgs+1 );
630 a[0] = 0;
631
632 const QList<QByteArray> pTypes = method.parameterTypes();
633 for ( int arg = 0; arg < numArgs; ++arg ) {
634 if (pTypes.at(i: arg) == "QVariant") {
635 a[arg+1] = (void *)&( convertedList[arg] );
636 } else {
637 a[arg+1] = (void *)( convertedList[arg].data() );
638 }
639 }
640
641 // Activate the service proxy signal call
642 QMetaObject::activate(sender: service, signal_index: remoteToLocal[metaIndex], argv: a.data());
643 return QVariant();
644 }
645
646 // Method call so process arguments and convert if not a supported DBus type
647 QVariantList convertedList;
648 QList<QByteArray> params = method.parameterTypes();
649 for (int i = 0; i < params.size(); i++) {
650 QVariant converted = toDBusVariant(typeName: params[i], arg: args[i]);
651 convertedList << converted;
652 }
653
654 bool validDBus = false;
655 QDBusMessage msg;
656
657 // Find the method name and try a direct DBus call
658 QString methodName(QLatin1String(method.methodSignature().constData()));
659 methodName.truncate(pos: methodName.indexOf(s: QLatin1String("(")));
660
661 if (method.methodType() == QMetaMethod::Slot || method.methodType() == QMetaMethod::Method) {
662 // Slot or Invokable method
663 msg = iface->callWithArgumentList(mode: QDBus::Block, method: methodName, args: convertedList);
664 if (msg.type() == QDBusMessage::ReplyMessage) {
665 validDBus = true;
666 }
667 }
668
669 // DBus call should only fail for methods with invalid type definitions
670 if (validDBus) {
671 if (returnType == QMetaType::Void) {
672 // Void method call
673 return QVariant();
674 }
675 else {
676 // Use DBus message return value
677 QVariantList retList = msg.arguments();
678
679 // Process return
680 const QByteArray& retType = QByteArray(method.typeName());
681 int variantType = QMetaType::type(typeName: retType);
682 if (variantType == QMetaType::QVariant) {
683 // QVariant return from QDBusVariant wrapper
684 QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(v: retList[0]);
685 return dbusVariant.variant();
686 } else if (variantType >= QMetaType::User) {
687 // Custom return type
688 QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(v: retList[0]);
689 QVariant convert = dbusVariant.variant();
690
691 QServiceUserTypeDBus customType = qdbus_cast<QServiceUserTypeDBus>(v: convert);
692 QByteArray buffer = customType.variantBuffer;
693 QDataStream stream(&buffer, QIODevice::ReadWrite);
694
695 // Load our buffered variant-wrapped custom return
696 QVariant *customReturn = new QVariant(variantType, (const void*)0);
697 QMetaType::load(stream, type: QMetaType::QVariant, data: customReturn);
698
699 return QVariant(variantType, customReturn->data());
700 } else {
701 // Standard return type
702 return retList[0];
703 }
704 }
705 } else {
706 qWarning( msg: "%s::%s cannot be called.", service->metaObject()->className(), method.methodSignature().constData());
707 }
708
709 return QVariant();
710}
711
712/*!
713 Client side waits for service side requested
714*/
715void ObjectEndPoint::waitForResponse(const QUuid& requestId)
716{
717 Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
718
719 if (openRequests()->contains(key: requestId) ) {
720 Response* response = openRequests()->value(key: requestId);
721 QEventLoop* loop = new QEventLoop( this );
722 connect(sender: this, SIGNAL(pendingRequestFinished()), receiver: loop, SLOT(quit()));
723
724 while (!response->isFinished) {
725 loop->exec();
726 }
727
728 delete loop;
729 }
730}
731
732#include "moc_objectendpoint_dbus_p.cpp"
733
734QT_END_NAMESPACE
735

source code of qtsystems/src/serviceframework/ipc/objectendpoint_dbus.cpp