X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsignalproxy.cpp;h=0cc79944ce35641060b36f12bcbaa616c0b8e374;hp=8499e1ada965b2e94895d41f21bd780b1b7cff35;hb=158443f71d48215eea8b47b836b61afd77654b78;hpb=2c4e055125a3e3ab7a2bd0d9c0ea33415f6ce7cc diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 8499e1ad..0cc79944 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2016 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 * @@ -18,6 +18,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include + #include #include #include @@ -59,18 +61,18 @@ public: SignalRelay(SignalProxy *parent) : QObject(parent), _proxy(parent) {} inline SignalProxy *proxy() const { return _proxy; } - int qt_metacall(QMetaObject::Call _c, int _id, void **_a); + int qt_metacall(QMetaObject::Call _c, int _id, void **_a) override; void attachSignal(QObject *sender, int signalId, const QByteArray &funcName); void detachSignal(QObject *sender, int signalId = -1); private: struct Signal { - QObject *sender; - int signalId; + QObject *sender{nullptr}; + int signalId{-1}; QByteArray signature; - Signal(QObject *sender, int sigId, const QByteArray &signature) : sender(sender), signalId(sigId), signature(signature) {} - Signal() : sender(0), signalId(-1) {} + Signal(QObject *sender, int sigId, QByteArray signature) : sender(sender), signalId(sigId), signature(std::move(signature)) {} + Signal() {} }; SignalProxy *_proxy; @@ -96,11 +98,7 @@ void SignalProxy::SignalRelay::attachSignal(QObject *sender, int signalId, const } else { fn = SIGNAL(fakeMethodSignature()); -#if QT_VERSION >= 0x050000 fn = fn.replace("fakeMethodSignature()", sender->metaObject()->method(signalId).methodSignature()); -#else - fn = fn.replace("fakeMethodSignature()", sender->metaObject()->method(signalId).signature()); -#endif } _slots[slotId] = Signal(sender, signalId, fn); @@ -145,11 +143,7 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** const QList &argTypes = eMeta->argTypes(signal.signalId); for (int i = 0; i < argTypes.size(); i++) { if (argTypes[i] == 0) { -#if QT_VERSION >= 0x050000 qWarning() << "SignalRelay::qt_metacall(): received invalid data for argument number" << i << "of signal" << QString("%1::%2").arg(caller->metaObject()->className()).arg(caller->metaObject()->method(signal.signalId).methodSignature().constData()); -#else - qWarning() << "SignalRelay::qt_metacall(): received invalid data for argument number" << i << "of signal" << QString("%1::%2").arg(caller->metaObject()->className()).arg(caller->metaObject()->method(signal.signalId).signature()); -#endif qWarning() << " - make sure all your data types are known by the Qt MetaSystem"; return _id; } @@ -173,6 +167,11 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** // ================================================== // SignalProxy // ================================================== + +namespace { +thread_local SignalProxy *_current{nullptr}; +} + SignalProxy::SignalProxy(QObject *parent) : QObject(parent) { @@ -204,12 +203,20 @@ SignalProxy::~SignalProxy() _syncSlave.clear(); removeAllPeers(); + + _current = nullptr; +} + + +SignalProxy *SignalProxy::current() +{ + return _current; } void SignalProxy::setProxyMode(ProxyMode mode) { - if (_peers.count()) { + if (!_peerMap.empty()) { qWarning() << Q_FUNC_INFO << "Cannot change proxy mode while connected"; return; } @@ -221,7 +228,6 @@ void SignalProxy::setProxyMode(ProxyMode mode) initClient(); } - void SignalProxy::init() { _heartBeatInterval = 0; @@ -230,6 +236,7 @@ void SignalProxy::init() setHeartBeatInterval(30); setMaxHeartBeatCount(2); _secure = false; + _current = this; updateSecureState(); } @@ -268,7 +275,7 @@ bool SignalProxy::addPeer(Peer *peer) if (!peer) return false; - if (_peers.contains(peer)) + if (_peerMap.values().contains(peer)) return true; if (!peer->isOpen()) { @@ -277,7 +284,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; } @@ -290,17 +297,16 @@ bool SignalProxy::addPeer(Peer *peer) if (!peer->parent()) peer->setParent(this); - if (peer->_id < 0) { - peer->_id = nextPeerId(); - peer->_connectedSince = QDateTime::currentDateTimeUtc(); + if (peer->id() < 0) { + peer->setId(nextPeerId()); + peer->setConnectedSince(QDateTime::currentDateTimeUtc()); } - _peers.insert(peer); - _peerMap[peer->_id] = peer; + _peerMap[peer->id()] = peer; peer->setSignalProxy(this); - if (_peers.count() == 1) + if (peerCount() == 1) emit connected(); updateSecureState(); @@ -310,10 +316,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); } } @@ -326,21 +332,20 @@ 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; } - disconnect(peer, 0, this, 0); - peer->setSignalProxy(0); + disconnect(peer, nullptr, this, nullptr); + peer->setSignalProxy(nullptr); - _peerMap.remove(peer->_id); - _peers.remove(peer); + _peerMap.remove(peer->id()); emit peerRemoved(peer); if (peer->parent() == this) @@ -348,7 +353,7 @@ void SignalProxy::removePeer(Peer *peer) updateSecureState(); - if (_peers.isEmpty()) + if (_peerMap.isEmpty()) emit disconnected(); } @@ -395,7 +400,7 @@ SignalProxy::ExtendedMetaObject *SignalProxy::extendedMetaObject(const QMetaObje if (_extendedMetaObjects.contains(meta)) return _extendedMetaObjects[meta]; else - return 0; + return nullptr; } @@ -472,8 +477,11 @@ void SignalProxy::synchronize(SyncableObject *obj) void SignalProxy::detachObject(QObject *obj) { - detachSignals(obj); - detachSlots(obj); + // Don't try to connect SignalProxy from itself on shutdown + if (obj != this) { + detachSignals(obj); + detachSlots(obj); + } } @@ -515,11 +523,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); } } @@ -527,10 +532,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; } @@ -573,7 +582,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 @@ -596,7 +607,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; } @@ -651,18 +664,14 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList return false; } - void *_a[] = { 0, // return type... - 0, 0, 0, 0, 0, // and 10 args - that's the max size qt can handle with signals and slots - 0, 0, 0, 0, 0 }; + void *_a[] = { nullptr, // return type... + nullptr, nullptr, nullptr, nullptr, nullptr, // and 10 args - that's the max size qt can handle with signals and slots + nullptr, nullptr, nullptr, nullptr, nullptr }; // check for argument compatibility and build params array for (int i = 0; i < numArgs; i++) { if (!params[i].isValid()) { -#if QT_VERSION >= 0x050000 qWarning() << "SignalProxy::invokeSlot(): received invalid data for argument number" << i << "of method" << QString("%1::%2()").arg(receiver->metaObject()->className()).arg(receiver->metaObject()->method(methodId).methodSignature().constData()); -#else - qWarning() << "SignalProxy::invokeSlot(): received invalid data for argument number" << i << "of method" << QString("%1::%2()").arg(receiver->metaObject()->className()).arg(receiver->metaObject()->method(methodId).signature()); -#endif qWarning() << " - make sure all your data types are known by the Qt MetaSystem"; return false; } @@ -810,8 +819,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(); } @@ -821,21 +830,28 @@ void SignalProxy::updateSecureState() QVariantList SignalProxy::peerData() { QVariantList result; - for (auto peer : _peers) { + for (auto &&peer : _peerMap.values()) { QVariantMap data; - data["id"] = peer->_id; - data["clientVersion"] = peer->_clientVersion; - data["clientVersionDate"] = peer->_buildDate; + 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["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) { - return _peerMap[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) @@ -851,6 +867,22 @@ void SignalProxy::restrictTargetPeers(QSet peers, std::function c _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 // ================================================== @@ -862,11 +894,7 @@ SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta, boo if (_meta->method(i).methodType() != QMetaMethod::Slot) continue; -#if QT_VERSION >= 0x050000 if (_meta->method(i).methodSignature().contains('*')) -#else - if (QByteArray(_meta->method(i).signature()).contains('*')) -#endif continue; // skip methods with ptr params QByteArray method = methodName(_meta->method(i)); @@ -895,11 +923,7 @@ SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta, boo } if (checkConflicts) { qWarning() << "class" << meta->className() << "contains overloaded methods which is currently not supported!"; -#if QT_VERSION >= 0x050000 qWarning() << " - " << _meta->method(i).methodSignature() << "conflicts with" << _meta->method(_methodIds[method]).methodSignature(); -#else - qWarning() << " - " << _meta->method(i).signature() << "conflicts with" << _meta->method(_methodIds[method]).signature(); -#endif } continue; } @@ -939,11 +963,7 @@ const QHash &SignalProxy::ExtendedMetaObject::receiveMap() if (QMetaType::Void == (QMetaType::Type)returnType(i)) continue; -#if QT_VERSION >= 0x050000 signature = requestSlot.methodSignature(); -#else - signature = QByteArray(requestSlot.signature()); -#endif if (!signature.startsWith("request")) continue; @@ -977,22 +997,14 @@ const QHash &SignalProxy::ExtendedMetaObject::receiveMap() QByteArray SignalProxy::ExtendedMetaObject::methodName(const QMetaMethod &method) { -#if QT_VERSION >= 0x050000 QByteArray sig(method.methodSignature()); -#else - QByteArray sig(method.signature()); -#endif return sig.left(sig.indexOf("(")); } QString SignalProxy::ExtendedMetaObject::methodBaseName(const QMetaMethod &method) { -#if QT_VERSION >= 0x050000 QString methodname = QString(method.methodSignature()).section("(", 0, 0); -#else - QString methodname = QString(method.signature()).section("(", 0, 0); -#endif // determine where we have to chop: int upperCharPos; @@ -1030,11 +1042,7 @@ SignalProxy::ExtendedMetaObject::MethodDescriptor::MethodDescriptor(const QMetaM _argTypes = argTypes; // determine minArgCount -#if QT_VERSION >= 0x050000 QString signature(method.methodSignature()); -#else - QString signature(method.signature()); -#endif _minArgCount = method.parameterTypes().count() - signature.count("="); _receiverMode = (_methodName.startsWith("request"))