X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsignalproxy.cpp;h=3ac73bc0bc10aaf9808374c1a114a1686d4e7b0f;hp=78ad13781e4d07dd4b182563eaae162118acd372;hb=c27d5bfbe80bfeb583a25404f4ccee4b70b010e0;hpb=ac302112a1a41d5beebd7129b29b34f9476db0ca diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 78ad1378..3ac73bc0 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -156,9 +156,11 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** params << QVariant(argTypes[i], _a[i+1]); } - if (argTypes.size() >= 1 && argTypes[0] == qMetaTypeId() && proxy()->proxyMode() == SignalProxy::Server) { - Peer *peer = params[0].value(); - proxy()->dispatch(peer, RpcCall(signal.signature, params)); + if (proxy()->_restrictMessageTarget) { + for (auto peer : proxy()->_restrictedTargets) { + if (peer != nullptr) + proxy()->dispatch(peer, RpcCall(signal.signature, params)); + } } else proxy()->dispatch(RpcCall(signal.signature, params)); } @@ -171,6 +173,9 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** // ================================================== // SignalProxy // ================================================== + +thread_local SignalProxy *SignalProxy::_current{nullptr}; + SignalProxy::SignalProxy(QObject *parent) : QObject(parent) { @@ -202,12 +207,14 @@ SignalProxy::~SignalProxy() _syncSlave.clear(); removeAllPeers(); + + _current = nullptr; } void SignalProxy::setProxyMode(ProxyMode mode) { - if (_peers.count()) { + if (!_peerMap.empty()) { qWarning() << Q_FUNC_INFO << "Cannot change proxy mode while connected"; return; } @@ -219,7 +226,6 @@ void SignalProxy::setProxyMode(ProxyMode mode) initClient(); } - void SignalProxy::init() { _heartBeatInterval = 0; @@ -228,6 +234,7 @@ void SignalProxy::init() setHeartBeatInterval(30); setMaxHeartBeatCount(2); _secure = false; + _current = this; updateSecureState(); } @@ -266,7 +273,7 @@ bool SignalProxy::addPeer(Peer *peer) if (!peer) return false; - if (_peers.contains(peer)) + if (_peerMap.values().contains(peer)) return true; if (!peer->isOpen()) { @@ -275,7 +282,7 @@ bool SignalProxy::addPeer(Peer *peer) } if (proxyMode() == Client) { - if (!_peers.isEmpty()) { + if (!_peerMap.isEmpty()) { qWarning("SignalProxy: only one peer allowed in client mode!"); return false; } @@ -288,11 +295,16 @@ bool SignalProxy::addPeer(Peer *peer) if (!peer->parent()) peer->setParent(this); - _peers.insert(peer); + if (peer->id() < 0) { + peer->setId(nextPeerId()); + peer->setConnectedSince(QDateTime::currentDateTimeUtc()); + } + + _peerMap[peer->id()] = peer; peer->setSignalProxy(this); - if (_peers.count() == 1) + if (peerCount() == 1) emit connected(); updateSecureState(); @@ -302,10 +314,10 @@ bool SignalProxy::addPeer(Peer *peer) void SignalProxy::removeAllPeers() { - Q_ASSERT(proxyMode() == Server || _peers.count() <= 1); + Q_ASSERT(proxyMode() == Server || peerCount() <= 1); // wee need to copy that list since we modify it in the loop - QSet peers = _peers; - foreach(Peer *peer, peers) { + QList peers = _peerMap.values(); + for (auto peer : peers) { removePeer(peer); } } @@ -318,12 +330,12 @@ void SignalProxy::removePeer(Peer *peer) return; } - if (_peers.isEmpty()) { + if (_peerMap.isEmpty()) { qWarning() << "SignalProxy::removePeer(): No peers in use!"; return; } - if (!_peers.contains(peer)) { + if (!_peerMap.values().contains(peer)) { qWarning() << "SignalProxy: unknown Peer" << peer; return; } @@ -331,7 +343,7 @@ void SignalProxy::removePeer(Peer *peer) disconnect(peer, 0, this, 0); peer->setSignalProxy(0); - _peers.remove(peer); + _peerMap.remove(peer->id()); emit peerRemoved(peer); if (peer->parent() == this) @@ -339,7 +351,7 @@ void SignalProxy::removePeer(Peer *peer) updateSecureState(); - if (_peers.isEmpty()) + if (_peerMap.isEmpty()) emit disconnected(); } @@ -506,11 +518,8 @@ void SignalProxy::stopSynchronize(SyncableObject *obj) template void SignalProxy::dispatch(const T &protoMessage) { - foreach (Peer *peer, _peers) { - if (peer->isOpen()) - peer->dispatch(protoMessage); - else - QCoreApplication::postEvent(this, new ::RemovePeerEvent(peer)); + for (auto&& peer : _peerMap.values()) { + dispatch(peer, protoMessage); } } @@ -518,10 +527,14 @@ void SignalProxy::dispatch(const T &protoMessage) template void SignalProxy::dispatch(Peer *peer, const T &protoMessage) { + _targetPeer = peer; + if (peer && peer->isOpen()) peer->dispatch(protoMessage); else QCoreApplication::postEvent(this, new ::RemovePeerEvent(peer)); + + _targetPeer = nullptr; } @@ -564,7 +577,9 @@ void SignalProxy::handle(Peer *peer, const SyncMessage &syncMessage) if (eMeta->argTypes(receiverId).count() > 1) returnParams << syncMessage.params; returnParams << returnValue; + _targetPeer = peer; peer->dispatch(SyncMessage(syncMessage.className, syncMessage.objectName, eMeta->methodName(receiverId), returnParams)); + _targetPeer = nullptr; } // send emit update signal @@ -587,7 +602,9 @@ void SignalProxy::handle(Peer *peer, const InitRequest &initRequest) } SyncableObject *obj = _syncSlave[initRequest.className][initRequest.objectName]; + _targetPeer = peer; peer->dispatch(InitData(initRequest.className, initRequest.objectName, initData(obj))); + _targetPeer = nullptr; } @@ -661,12 +678,8 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList qWarning() << "SignalProxy::invokeSlot(): incompatible param types to invoke" << eMeta->methodName(methodId); return false; } - // 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()); + + _a[i+1] = const_cast(params[i].constData()); } if (returnValue.type() != QVariant::Invalid) @@ -677,9 +690,11 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList : Qt::QueuedConnection; if (type == Qt::DirectConnection) { - return receiver->qt_metacall(QMetaObject::InvokeMetaMethod, methodId, _a) < 0; - } - else { + _sourcePeer = peer; + auto result = receiver->qt_metacall(QMetaObject::InvokeMetaMethod, methodId, _a) < 0; + _sourcePeer = nullptr; + return result; + } else { qWarning() << "Queued Connections are not implemented yet"; // note to self: qmetaobject.cpp:990 ff return false; @@ -758,9 +773,11 @@ void SignalProxy::sync_call__(const SyncableObject *obj, SignalProxy::ProxyMode params << QVariant(argTypes[i], va_arg(ap, void *)); } - if (argTypes.size() >= 1 && argTypes[0] == qMetaTypeId() && proxyMode() == SignalProxy::Server) { - Peer *peer = params[0].value(); - dispatch(peer, SyncMessage(eMeta->metaObject()->className(), obj->objectName(), QByteArray(funcname), params)); + if (_restrictMessageTarget) { + for (auto peer : _restrictedTargets) { + if (peer != nullptr) + dispatch(peer, SyncMessage(eMeta->metaObject()->className(), obj->objectName(), QByteArray(funcname), params)); + } } else dispatch(SyncMessage(eMeta->metaObject()->className(), obj->objectName(), QByteArray(funcname), params)); } @@ -801,8 +818,8 @@ void SignalProxy::updateSecureState() { bool wasSecure = _secure; - _secure = !_peers.isEmpty(); - foreach (const Peer *peer, _peers) { + _secure = !_peerMap.isEmpty(); + for (auto peer : _peerMap.values()) { _secure &= peer->isSecure(); } @@ -810,6 +827,60 @@ void SignalProxy::updateSecureState() emit secureStateChanged(_secure); } +QVariantList SignalProxy::peerData() { + QVariantList result; + for (auto &&peer : _peerMap.values()) { + QVariantMap data; + data["id"] = peer->id(); + data["clientVersion"] = peer->clientVersion(); + // We explicitly rename this, as, due to the Debian reproducability changes, buildDate isn’t actually the build + // date anymore, but on newer clients the date of the last git commit + data["clientVersionDate"] = peer->buildDate(); + data["remoteAddress"] = peer->address(); + data["connectedSince"] = peer->connectedSince(); + data["secure"] = peer->isSecure(); + data["features"] = static_cast(peer->features().toLegacyFeatures()); + data["featureList"] = peer->features().toStringList(); + result << data; + } + return result; +} + +Peer *SignalProxy::peerById(int peerId) { + // We use ::value() here instead of the [] operator because the latter has the side-effect + // of automatically inserting a null value with the passed key into the map. See + // https://doc.qt.io/qt-5/qhash.html#operator-5b-5d and https://doc.qt.io/qt-5/qhash.html#value. + return _peerMap.value(peerId); +} + +void SignalProxy::restrictTargetPeers(QSet peers, std::function closure) +{ + auto previousRestrictMessageTarget = _restrictMessageTarget; + auto previousRestrictedTargets = _restrictedTargets; + _restrictMessageTarget = true; + _restrictedTargets = peers; + + closure(); + + _restrictMessageTarget = previousRestrictMessageTarget; + _restrictedTargets = previousRestrictedTargets; +} + +Peer *SignalProxy::sourcePeer() { + return _sourcePeer; +} + +void SignalProxy::setSourcePeer(Peer *sourcePeer) { + _sourcePeer = sourcePeer; +} + +Peer *SignalProxy::targetPeer() { + return _targetPeer; +} + +void SignalProxy::setTargetPeer(Peer *targetPeer) { + _targetPeer = targetPeer; +} // ================================================== // ExtendedMetaObject