diff options
author | Brett Stottlemyer <bstottle@ford.com> | 2019-05-13 12:18:43 -0400 |
---|---|---|
committer | Brett Stottlemyer <bstottle@ford.com> | 2019-05-21 12:31:06 +0000 |
commit | 5971d579e0069b2d244b171c6aa916f5111c84de (patch) | |
tree | 802927f341e2a985147f125c897cb5dab27dd9c7 | |
parent | a8a3088f1fcd7ff00e7748040473c27c4bea8dad (diff) |
Fix return value propagation through proxies
A slot with return values returns a PendingCall object on the replica. If
such a replica is used in a proxy, a client would get an invalid QVariant
as the reply. This was because the proxy would try to return the pending-
call, not wait for the slot return from the original source. This change
fixes that issue.
Change-Id: I1a25ed49ce51729dde4fa4593845946041493ea1
Reviewed-by: Brett Stottlemyer <bstottle@ford.com>
-rw-r--r-- | src/remoteobjects/qremoteobjectsourceio.cpp | 22 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/client/main.cpp | 7 |
2 files changed, 26 insertions, 3 deletions
diff --git a/src/remoteobjects/qremoteobjectsourceio.cpp b/src/remoteobjects/qremoteobjectsourceio.cpp index c2dc70a..bde010b 100644 --- a/src/remoteobjects/qremoteobjectsourceio.cpp +++ b/src/remoteobjects/qremoteobjectsourceio.cpp @@ -42,6 +42,7 @@ #include "qremoteobjectpacket_p.h" #include "qremoteobjectsource_p.h" #include "qremoteobjectnode_p.h" +#include "qremoteobjectpendingcall.h" #include "qtremoteobjectglobal.h" #include <QtCore/qstringlist.h> @@ -240,11 +241,28 @@ void QRemoteObjectSourceIo::onServerRead(QObject *conn) if (!QMetaType(typeId).sizeOf()) typeId = QVariant::Invalid; QVariant returnValue(typeId, nullptr); + // If a Replica is used as a Source (which node->proxy() does) we can have a PendingCall return value. + // In this case, we need to wait for the pending call and send that. + if (source->m_api->typeName(index) == QByteArrayLiteral("QRemoteObjectPendingCall")) + returnValue = QVariant::fromValue<QRemoteObjectPendingCall>(QRemoteObjectPendingCall()); source->invoke(QMetaObject::InvokeMetaMethod, index, m_rxArgs, &returnValue); // send reply if wanted if (serialId >= 0) { - serializeInvokeReplyPacket(m_packet, m_rxName, serialId, returnValue); - connection->write(m_packet.array, m_packet.size); + if (returnValue.canConvert<QRemoteObjectPendingCall>()) { + QRemoteObjectPendingCall call = returnValue.value<QRemoteObjectPendingCall>(); + // Watcher will be destroyed when connection is, or when the finished lambda is called + QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(call, connection); + QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, connection, [this, serialId, connection, watcher]() { + if (watcher->error() == QRemoteObjectPendingCall::NoError) { + serializeInvokeReplyPacket(this->m_packet, this->m_rxName, serialId, watcher->returnValue()); + connection->write(m_packet.array, m_packet.size); + } + watcher->deleteLater(); + }); + } else { + serializeInvokeReplyPacket(m_packet, m_rxName, serialId, returnValue); + connection->write(m_packet.array, m_packet.size); + } } } else { const int resolvedIndex = source->m_api->sourcePropertyIndex(index); diff --git a/tests/auto/proxy_multiprocess/client/main.cpp b/tests/auto/proxy_multiprocess/client/main.cpp index 4874fb1..f37821f 100644 --- a/tests/auto/proxy_multiprocess/client/main.cpp +++ b/tests/auto/proxy_multiprocess/client/main.cpp @@ -72,6 +72,8 @@ private Q_SLOTS: qDebug() << "Verified expected initial states, sending start."; auto reply = m_rep->start(); QVERIFY(reply.waitForFinished()); + QVERIFY(reply.error() == QRemoteObjectPendingCall::NoError); + QCOMPARE(reply.returnValue(), QVariant::fromValue(true)); QSignalSpy advanceSpy(m_rep.data(), SIGNAL(advance())); QVERIFY(advanceSpy.wait()); @@ -87,7 +89,10 @@ private Q_SLOTS: void cleanupTestCase() { auto reply = m_rep->quit(); - QVERIFY(reply.waitForFinished()); + // Don't verify the wait result, depending on the timing of the server and proxy + // closing it may return false. We just need this process to stay alive long + // enough for the packets to be sent. + reply.waitForFinished(5000); } private: |