/*! Client side waits for service side requested */ void ObjectEndPoint::waitForResponse(const QUuid& requestId) { Q_ASSERT(d->endPointType == ObjectEndPoint::Client); if (openRequests()->contains(requestId) ) { Response* response = openRequests()->value(requestId); QEventLoop* loop = new QEventLoop( this ); connect(this, SIGNAL(pendingRequestFinished()), loop, SLOT(quit())); while (!response->isFinished) { loop->exec(); } delete loop; } }
/* Client requests proxy object. The proxy is owned by calling code and this object must clean itself up upon destruction of proxy. */ QObject* ObjectEndPoint::constructProxy(const QRemoteServiceRegister::Entry & entry) { #ifdef QT_SFW_ENDPOINT_DEBUG qDebug() << "Start ObjectEndPoint::constructProxy"; #endif //client side Q_ASSERT(d->endPointType == ObjectEndPoint::Client); //ask for serialized meta object //get proxy based on meta object //return meta object QServicePackage p; p.d = new QServicePackagePrivate(); p.d->messageId = QUuid::createUuid(); p.d->entry = entry; Response* response = new Response(); openRequests()->insert(p.d->messageId, response); dispatch->writePackage(p); waitForResponse(p.d->messageId); if (response->isFinished) { if (response->result == 0) qWarning() << "Request for remote service failed"; else service = reinterpret_cast<QServiceProxy* >(response->result); } else { qDebug() << "response passed but not finished"; return 0; } openRequests()->take(p.d->messageId); delete response; return service; }
/*! Service finds existing objects or spawns new object instances and registers them on DBus using a hash of the unique instance ID. This registered object has a special metaobject representation of the service that is compatible with the QDBus type system. Client receives a package containing the information to connect an interface to the registered DBus object. */ void ObjectEndPoint::objectRequest(const QServicePackage& p, QServiceClientCredentials& creds) { if (p.d->responseType != QServicePackage::NotAResponse ) { // Client side Q_ASSERT(d->endPointType == ObjectEndPoint::Client); d->serviceInstanceId = p.d->instanceId; d->entry = p.d->entry; Response* response = openRequests()->value(p.d->messageId); if (p.d->responseType == QServicePackage::Failed) { response->result = 0; response->isFinished = true; QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished())); qWarning() << "Service instantiation failed"; return; } // Deserialize meta object and create proxy object QServiceProxy* proxy = new QServiceProxy(p.d->payload.toByteArray(), this); response->result = reinterpret_cast<void *>(proxy); response->isFinished = true; // Create DBUS interface by using a hash of the service instance ID QString serviceName = QStringLiteral("com.nokia.qtmobility.sfw.") + p.d->entry.serviceName(); uint hash = qHash(d->serviceInstanceId.toString()); QString objPath = QLatin1Char('/') + p.d->entry.interfaceName() + QLatin1Char('/') + p.d->entry.version() + QLatin1Char('/') + QString::number(hash); objPath.replace(QLatin1Char('.'), QLatin1Char('/')); #ifdef DEBUG qDebug() << "Client Interface ObjectPath:" << objPath; #endif // Instantiate our DBus interface and its corresponding signals object if (!iface) iface = new QDBusInterface(serviceName, objPath, QString(), QDBusConnection::sessionBus(), this); signalsObject = new QServiceMetaObjectDBus(iface, true); // Wake up waiting proxy construction code QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished())); } else { // Service side Q_ASSERT(d->endPointType == ObjectEndPoint::Service); QServicePackage response = p.createResponse(); InstanceManager* iManager = InstanceManager::instance(); if (!creds.isValid()) { qWarning() << "SFW Unable to get socket credentials client asking for" << p.d->entry.interfaceName() << p.d->entry.serviceName() << "this may fail in the future"; } // Instantiate service object from type register service = iManager->createObjectInstance(p.d->entry, d->serviceInstanceId, creds); if (!service) { qWarning() << "Cannot instantiate service object"; dispatch->writePackage(response); return; } if (!creds.isClientAccepted()) { qWarning() << "SFW Security failure by" << creds.getProcessIdentifier() << creds.getUserIdentifier() << creds.getGroupIdentifier() << "requesting" << p.d->entry.interfaceName() << p.d->entry.serviceName(); iManager->removeObjectInstance(p.d->entry, d->serviceInstanceId); dispatch->writePackage(response); return; } // Start DBus connection and register proxy service if (!QDBusConnection::sessionBus().isConnected()) { qWarning() << "Cannot connect to DBus"; } // DBus registration path uses a hash of the service instance ID QString serviceName = QStringLiteral("com.nokia.qtmobility.sfw.") + p.d->entry.serviceName(); uint hash = qHash(d->serviceInstanceId.toString()); QString objPath = QLatin1Char('/') + p.d->entry.interfaceName() + QLatin1Char('/') + p.d->entry.version() + QLatin1Char('/') + QString::number(hash); objPath.replace(QLatin1Char('.'), QLatin1Char('/')); QServiceMetaObjectDBus *serviceDBus = new QServiceMetaObjectDBus(service); QDBusConnection::sessionBus().registerObject(objPath, serviceDBus, QDBusConnection::ExportAllContents); QString clientId = p.d->payload.toString(); int exists = 0; for (int i=d->clientList.size()-1; i>=0; i--) { // Find right client process if (d->clientList[i].clientId == clientId) { d->clientList[i].ref++; exists = 1; break; } } if (!exists) { // Add new instance to client ownership list ClientInstance c; c.clientId = clientId; c.entry = p.d->entry; c.instanceId = d->serviceInstanceId; c.ref = 1; d->clientList << c; } #ifdef DEBUG qDebug() << "Service Interface ObjectPath:" << objPath; const QMetaObject *s_meta = service->metaObject(); qDebug() << "+++++++++++++++++++++SERVICE+++++++++++++++++++++++"; qDebug() << s_meta->className(); qDebug() << "METHOD COUNT: " << s_meta->methodCount(); for (int i=0; i<s_meta->methodCount(); i++) { QMetaMethod mm = s_meta->method(i); QString type; switch (mm.methodType()) { case QMetaMethod::Method: type = "Q_INVOKABLE"; break; case QMetaMethod::Signal: type = "SIGNAL"; break; case QMetaMethod::Slot: type = "SLOT"; break; default: break; } QString returnType = mm.typeName(); if (returnType == "") returnType = "void"; qDebug() << "METHOD" << type << ":" << returnType << mm.methodSignature(); } qDebug() << "++++++++++++++++++++++++++++++++++++++++++++++++++++"; if (!iface) iface = new QDBusInterface(serviceName, objPath, "", QDBusConnection::sessionBus(), this); const QMetaObject *i_meta = iface->metaObject(); qDebug() << "++++++++++++++++++++DBUS SERVICE++++++++++++++++++++"; qDebug() << i_meta->className(); qDebug() << "METHOD COUNT: " << i_meta->methodCount(); for (int i=0; i<i_meta->methodCount(); i++) { QMetaMethod mm = i_meta->method(i); QString type; switch (mm.methodType()) { case QMetaMethod::Method: type = "Q_INVOKABLE"; break; case QMetaMethod::Signal: type = "SIGNAL"; break; case QMetaMethod::Slot: type = "SLOT"; break; default: break; } QString returnType = mm.typeName(); if (returnType == "") returnType = "void"; qDebug() << "METHOD" << type << ":" << returnType << mm.methodSignature(); } qDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++"; #endif // Get meta object from type register const QMetaObject* meta = iManager->metaObject(p.d->entry); if (!meta) { qDebug() << "Unknown type" << p.d->entry; dispatch->writePackage(response); return; } // Serialize meta object QByteArray data; QDataStream stream( &data, QIODevice::WriteOnly | QIODevice::Append ); QMetaObjectBuilder builder(meta); builder.serialize(stream); // Send meta object and instance ID to the client for processing d->entry = p.d->entry; response.d->instanceId = d->serviceInstanceId; response.d->entry = p.d->entry; response.d->responseType = QServicePackage::Success; response.d->payload = QVariant(data); dispatch->writePackage(response); } }
/*! Client requests proxy object. The proxy is owned by calling code and this object must clean itself up upon destruction of proxy. */ QObject* ObjectEndPoint::constructProxy(const QRemoteServiceRegister::Entry& entry) { // Client side Q_ASSERT(d->endPointType == ObjectEndPoint::Client); // Request a serialized meta object QServicePackage p; p.d = new QServicePackagePrivate(); p.d->messageId = QUuid::createUuid(); p.d->entry = entry; Response* response = new Response(); openRequests()->insert(p.d->messageId, response); dispatch->writePackage(p); waitForResponse(p.d->messageId); // Get the proxy based on the meta object if (response->isFinished) { if (response->result == 0) qWarning() << "Request for remote service failed"; else service = reinterpret_cast<QServiceProxy* >(response->result); } else { qDebug() << "response passed but not finished"; } openRequests()->take(p.d->messageId); delete response; if (!service) return 0; // Connect all DBus interface signals to the proxy slots const QMetaObject *mo = service->metaObject(); while (mo && strcmp(mo->className(), "QObject")) { for (int i = mo->methodOffset(); i < mo->methodCount(); i++) { const QMetaMethod mm = mo->method(i); if (mm.methodType() == QMetaMethod::Signal) { QByteArray sig(mm.methodSignature()); bool customType = false; QList<QByteArray> params = mm.parameterTypes(); for (int arg = 0; arg < params.size(); arg++) { const QByteArray& type = params[arg]; int variantType = QMetaType::type(type); if (variantType >= QMetaType::User || variantType == QMetaType::QVariant) { sig.replace(QByteArray(type), QByteArray("QDBusVariant")); customType = true; } } int serviceIndex = iface->metaObject()->indexOfSignal(sig); QByteArray signal = QByteArray("2").append(sig); if (serviceIndex > 0) { if (customType) { QObject::connect(iface, signal.constData(), signalsObject, signal.constData()); ServiceSignalIntercepter *intercept = new ServiceSignalIntercepter((QObject*)signalsObject, signal, this); intercept->setMetaIndex(localToRemote[i]); } else { QObject::connect(iface, signal.constData(), service, signal.constData()); } } } } mo = mo->superClass(); } return service; }