From: Manuel Nickschas Date: Sun, 10 Nov 2013 22:25:07 +0000 (+0100) Subject: Allow peer-specific sending and receiving of remote signals X-Git-Tag: 0.10-beta1~70 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=f44459818f34b556df8ff2f400098c50b78501eb Allow peer-specific sending and receiving of remote signals For file transfers and possibly other use cases, it is important to know which peer has received a specific signal, and to allow sending remote signals only through a particular peer rather than multicasting to all connected clients. For this reason, we now treat attached signals/slots specially if their first argument is a PeerPtr (a typedef for Peer *): * An attached slot will have a pointer to the peer which received the signal in its first argument * An attached signal on the core side will be relayed only through the peer that is given as the first argument (and the receiving slot will have a pointer to the client-side peer in this argument) * The peer argument for an attached signal on the client side will be ignored, as clients only have one peer anyway --- diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 418fdec8..e65f09ff 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -34,6 +34,7 @@ #include "protocol.h" #include "syncableobject.h" #include "util.h" +#include "types.h" using namespace Protocol; @@ -147,7 +148,11 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** params << QVariant(argTypes[i], _a[i+1]); } - proxy()->dispatch(RpcCall(signal.signature, params)); + if (argTypes.size() >= 1 && argTypes[0] == qMetaTypeId() && proxy()->proxyMode() == SignalProxy::Server) { + Peer *peer = params[0].value(); + proxy()->dispatch(peer, RpcCall(signal.signature, params)); + } else + proxy()->dispatch(RpcCall(signal.signature, params)); } _id -= _slots.count(); } @@ -502,6 +507,15 @@ void SignalProxy::dispatch(const T &protoMessage) } +void SignalProxy::dispatch(Peer *peer, const RpcCall &rpcCall) +{ + if (peer && peer->isOpen()) + peer->dispatch(rpcCall); + else + QCoreApplication::postEvent(this, new ::RemovePeerEvent(peer)); +} + + void SignalProxy::handle(Peer *peer, const SyncMessage &syncMessage) { if (!_syncSlave.contains(syncMessage.className) || !_syncSlave[syncMessage.className].contains(syncMessage.objectName)) { @@ -586,15 +600,13 @@ void SignalProxy::handle(Peer *peer, const InitData &initData) void SignalProxy::handle(Peer *peer, const RpcCall &rpcCall) { - Q_UNUSED(peer) - QObject *receiver; int methodId; SlotHash::const_iterator slot = _attachedSlots.constFind(rpcCall.slotName); while (slot != _attachedSlots.constEnd() && slot.key() == rpcCall.slotName) { receiver = (*slot).first; methodId = (*slot).second; - if (!invokeSlot(receiver, methodId, rpcCall.params)) { + if (!invokeSlot(receiver, methodId, rpcCall.params, peer)) { ExtendedMetaObject *eMeta = extendedMetaObject(receiver); qWarning("SignalProxy::handleSignal(): invokeMethod for \"%s\" failed ", eMeta->methodName(methodId).constData()); } @@ -603,7 +615,7 @@ void SignalProxy::handle(Peer *peer, const RpcCall &rpcCall) } -bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue) +bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue, Peer *peer) { ExtendedMetaObject *eMeta = extendedMetaObject(receiver); const QList args = eMeta->argTypes(methodId); @@ -631,7 +643,12 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList qWarning() << "SignalProxy::invokeSlot(): incompatible param types to invoke" << eMeta->methodName(methodId); return false; } - _a[i+1] = const_cast(params[i].constData()); + // if first arg is a PeerPtr, replace it by the address of the peer originally receiving the RpcCall + if (peer && i == 0 && args[0] == qMetaTypeId()) { + QVariant v = QVariant::fromValue(peer); + _a[1] = const_cast(v.constData()); + } else + _a[i+1] = const_cast(params[i].constData()); } if (returnValue.type() != QVariant::Invalid) @@ -652,10 +669,10 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList } -bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms) +bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, Peer *peer) { QVariant ret; - return invokeSlot(receiver, methodId, params, ret); + return invokeSlot(receiver, methodId, params, ret, peer); } diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index a8fe30dc..410d48cc 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -118,6 +118,7 @@ private: template void dispatch(const T &protoMessage); + void dispatch(Peer *peer, const Protocol::RpcCall &rpcCall); void handle(Peer *peer, const Protocol::SyncMessage &syncMessage); void handle(Peer *peer, const Protocol::RpcCall &rpcCall); @@ -127,8 +128,8 @@ private: template void handle(Peer *, T) { Q_ASSERT(0); } - bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue); - bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms = QVariantList()); + bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue, Peer *peer = 0); + bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms = QVariantList(), Peer *peer = 0); void requestInit(SyncableObject *obj); QVariantMap initData(SyncableObject *obj) const; diff --git a/src/common/types.h b/src/common/types.h index 4139aa4c..d683879a 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -28,6 +28,11 @@ #include #include +// We need to special-case Peer* in attached signals/slots, so typedef it for the meta type system +class Peer; +typedef Peer * PeerPtr; +Q_DECLARE_METATYPE(PeerPtr) + class SignedId { protected: