X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsignalproxy.cpp;h=e7c641b4952460f1f7641e8cb1c75d099197befe;hp=08cdc7dce8eba57ca4b035556d6bddf7aa88f385;hb=d9f4d3f0eabd3767b4d25438319116f77c158c52;hpb=2a00e8f57d66d9913a10c30408b89676a74010a1 diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 08cdc7dc..e7c641b4 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -120,7 +120,7 @@ void SignalProxy::SignalRelay::detachSignal(QObject *sender, int signalId) { if(slotIter->sender == sender && (signalId == -1 || slotIter->signalId == signalId)) { slotIter = _slots.erase(slotIter); if(signalId != -1) - break; + break; } else { slotIter++; } @@ -146,12 +146,12 @@ 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) { - qWarning() << "SignalRelay::qt_metacall(): received invalid data for argument number" << i << "of signal" << QString("%1::%2").arg(caller->metaObject()->className()).arg(caller->metaObject()->method(_id).signature()); - qWarning() << " - make sure all your data types are known by the Qt MetaSystem"; - return _id; - } - params << QVariant(argTypes[i], _a[i+1]); + if(argTypes[i] == 0) { + qWarning() << "SignalRelay::qt_metacall(): received invalid data for argument number" << i << "of signal" << QString("%1::%2").arg(caller->metaObject()->className()).arg(caller->metaObject()->method(_id).signature()); + qWarning() << " - make sure all your data types are known by the Qt MetaSystem"; + return _id; + } + params << QVariant(argTypes[i], _a[i+1]); } proxy()->dispatchSignal(SignalProxy::RpcCall, params); @@ -167,7 +167,7 @@ int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void ** void SignalProxy::IODevicePeer::dispatchSignal(const RequestType &requestType, const QVariantList ¶ms) { QVariantList packedFunc; packedFunc << (qint16)requestType - << params; + << params; dispatchPackedFunc(QVariant(packedFunc)); } @@ -231,6 +231,18 @@ SignalProxy::SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent) } SignalProxy::~SignalProxy() { + QHash::iterator classIter = _syncSlave.begin(); + while(classIter != _syncSlave.end()) { + ObjectId::iterator objIter = classIter->begin(); + while(objIter != classIter->end()) { + SyncableObject *obj = objIter.value(); + objIter = classIter->erase(objIter); + obj->stopSynchronize(this); + } + classIter++; + } + _syncSlave.clear(); + removeAllPeers(); } @@ -240,8 +252,8 @@ void SignalProxy::setProxyMode(ProxyMode mode) { if((*peer)->type() != AbstractPeer::IODevicePeer) { IODevicePeer *ioPeer = static_cast(*peer); if(ioPeer->isOpen()) { - qWarning() << "SignalProxy: Cannot change proxy mode while connected"; - return; + qWarning() << "SignalProxy: Cannot change proxy mode while connected"; + return; } } if((*peer)->type() != AbstractPeer::SignalProxyPeer) { @@ -261,7 +273,9 @@ void SignalProxy::setProxyMode(ProxyMode mode) { void SignalProxy::init() { _signalRelay = new SignalRelay(this); connect(&_heartBeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartBeat())); - _heartBeatTimer.start(30 * 1000); + setHeartBeatInterval(30); + setMaxHeartBeatCount(2); + _heartBeatTimer.start(); _secure = false; updateSecureState(); } @@ -312,6 +326,17 @@ bool SignalProxy::addPeer(QIODevice* iodev) { return true; } +void SignalProxy::setHeartBeatInterval(int secs) { + if(secs != _heartBeatInterval) { + _heartBeatInterval = secs; + _heartBeatTimer.setInterval(secs * 1000); + } +} + +void SignalProxy::setMaxHeartBeatCount(int max) { + _maxHeartBeatCount = max; +} + bool SignalProxy::addPeer(SignalProxy* proxy) { if(!proxy) return false; @@ -389,15 +414,14 @@ void SignalProxy::removePeerBySender() { removePeer(sender()); } -void SignalProxy::objectRenamed(const QString &newname, const QString &oldname) { - SyncableObject *syncObject = qobject_cast(sender()); - const QMetaObject *meta = syncObject->syncMetaObject(); - const QByteArray className(meta->className()); - objectRenamed(className, newname, oldname); - +void SignalProxy::renameObject(const SyncableObject *obj, const QString &newname, const QString &oldname) { if(proxyMode() == Client) return; + const QMetaObject *meta = obj->syncMetaObject(); + const QByteArray className(meta->className()); + objectRenamed(className, newname, oldname); + QVariantList params; params << "__objectRenamed__" << className << newname << oldname; dispatchSignal(RpcCall, params); @@ -424,9 +448,9 @@ SignalProxy::ExtendedMetaObject *SignalProxy::extendedMetaObject(const QMetaObje return 0; } -SignalProxy::ExtendedMetaObject *SignalProxy::createExtendedMetaObject(const QMetaObject *meta) { +SignalProxy::ExtendedMetaObject *SignalProxy::createExtendedMetaObject(const QMetaObject *meta, bool checkConflicts) { if(!_extendedMetaObjects.contains(meta)) { - _extendedMetaObjects[meta] = new ExtendedMetaObject(meta); + _extendedMetaObjects[meta] = new ExtendedMetaObject(meta, checkConflicts); } return _extendedMetaObjects[meta]; } @@ -467,16 +491,13 @@ bool SignalProxy::attachSlot(const QByteArray& sigName, QObject* recv, const cha } void SignalProxy::synchronize(SyncableObject *obj) { - createExtendedMetaObject(obj); + createExtendedMetaObject(obj, true); // attaching as slave to receive sync Calls QByteArray className(obj->syncMetaObject()->className()); _syncSlave[className][obj->objectName()] = obj; - disconnect(obj, SIGNAL(destroyed(QObject *)), this, SLOT(detachObject(QObject *))); - connect(obj, SIGNAL(destroyed(QObject *)), this, SLOT(detachObject(QObject *))); if(proxyMode() == Server) { - connect(obj, SIGNAL(objectRenamed(QString, QString)), this, SLOT(objectRenamed(QString, QString))); obj->setInitialized(); emit objectInitialized(obj); } else { @@ -490,7 +511,6 @@ void SignalProxy::synchronize(SyncableObject *obj) { } void SignalProxy::detachObject(QObject *obj) { - stopSync(obj); detachSignals(obj); detachSlots(obj); } @@ -509,7 +529,7 @@ void SignalProxy::detachSlots(QObject* receiver) { } } -void SignalProxy::stopSync(QObject *obj) { +void SignalProxy::stopSynchronize(SyncableObject *obj) { // we can't use a className here, since it might be effed up, if we receive the call as a result of a decon // gladly the objectName() is still valid. So we have only to iterate over the classes not each instance! *sigh* QHash::iterator classIter = _syncSlave.begin(); @@ -520,6 +540,7 @@ void SignalProxy::stopSync(QObject *obj) { } classIter++; } + obj->stopSynchronize(this); } void SignalProxy::dispatchSignal(const RequestType &requestType, const QVariantList ¶ms) { @@ -529,11 +550,11 @@ void SignalProxy::dispatchSignal(const RequestType &requestType, const QVariantL switch((*peer)->type()) { case AbstractPeer::IODevicePeer: { - IODevicePeer *ioPeer = static_cast(*peer); - if(ioPeer->isOpen()) - ioPeer->dispatchPackedFunc(packedFunc); - else - QCoreApplication::postEvent(this, new RemovePeerEvent(peer.key())); + IODevicePeer *ioPeer = static_cast(*peer); + if(ioPeer->isOpen()) + ioPeer->dispatchPackedFunc(packedFunc); + else + QCoreApplication::postEvent(this, new RemovePeerEvent(peer.key())); } break; case AbstractPeer::SignalProxyPeer: @@ -570,7 +591,7 @@ void SignalProxy::receivePeerSignal(AbstractPeer *sender, const RequestType &req } } - qDebug() << "SignalProxy::receivePeerSignal)" << requestType << params; + // qDebug() << "SignalProxy::receivePeerSignal)" << requestType << params; switch(requestType) { case RpcCall: if(params.empty()) @@ -626,7 +647,7 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { if(!_syncSlave.contains(className) || !_syncSlave[className].contains(objectName)) { qWarning() << QString("no registered receiver for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(slot)).arg(objectName) - << params; + << params; return; } @@ -634,7 +655,7 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { ExtendedMetaObject *eMeta = extendedMetaObject(receiver); if(!eMeta->slotMap().contains(slot)) { qWarning() << QString("no matching slot for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(slot)).arg(objectName) - << params; + << params; return; } @@ -655,8 +676,8 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { int receiverId = eMeta->receiveMap()[slotId]; QVariantList returnParams; returnParams << className - << objectName - << eMeta->methodName(receiverId); + << objectName + << eMeta->methodName(receiverId); //QByteArray(receiver->metaObject()->method(receiverId).signature()); if(eMeta->argTypes(receiverId).count() > 1) returnParams << params; @@ -671,7 +692,7 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { void SignalProxy::handleInitRequest(AbstractPeer *sender, const QVariantList ¶ms) { if(params.count() != 2) { qWarning() << "SignalProxy::handleInitRequest() received initRequest with invalid param Count:" - << params; + << params; return; } @@ -680,13 +701,13 @@ void SignalProxy::handleInitRequest(AbstractPeer *sender, const QVariantList &pa if(!_syncSlave.contains(className)) { qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Class:" - << className; + << className; return; } if(!_syncSlave[className].contains(objectName)) { qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Object:" - << className << objectName; + << className << objectName; return; } @@ -694,8 +715,8 @@ void SignalProxy::handleInitRequest(AbstractPeer *sender, const QVariantList &pa QVariantList params_; params_ << className - << objectName - << initData(obj); + << objectName + << initData(obj); sender->dispatchSignal(InitData, params_); } @@ -704,7 +725,7 @@ void SignalProxy::handleInitData(AbstractPeer *sender, const QVariantList ¶m Q_UNUSED(sender) if(params.count() != 3) { qWarning() << "SignalProxy::handleInitData() received initData with invalid param Count:" - << params; + << params; return; } @@ -714,13 +735,13 @@ void SignalProxy::handleInitData(AbstractPeer *sender, const QVariantList ¶m if(!_syncSlave.contains(className)) { qWarning() << "SignalProxy::handleInitData() received initData for unregistered Class:" - << className; + << className; return; } if(!_syncSlave[className].contains(objectName)) { qWarning() << "SignalProxy::handleInitData() received initData for unregistered Object:" - << className << objectName; + << className << objectName; return; } @@ -760,8 +781,8 @@ bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList } 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}; + 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}; // check for argument compatibility and build params array for(int i = 0; i < numArgs; i++) { @@ -876,8 +897,8 @@ bool SignalProxy::readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVarian if(nbytes <= 4) { const char *data = rawItem.constData(); if(nbytes < 4 || (data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0)) { - disconnectDevice(dev, tr("Peer sent corrupted compressed data!")); - return false; + disconnectDevice(dev, tr("Peer sent corrupted compressed data!")); + return false; } } @@ -904,7 +925,7 @@ void SignalProxy::requestInit(SyncableObject *obj) { QVariantList params; params << obj->syncMetaObject()->className() - << obj->objectName(); + << obj->objectName(); dispatchSignal(InitRequest, params); } @@ -924,23 +945,28 @@ void SignalProxy::setInitData(SyncableObject *obj, const QVariantMap &properties void SignalProxy::sendHeartBeat() { QVariantList heartBeatParams; heartBeatParams << QTime::currentTime(); + QList toClose; + PeerHash::iterator peer = _peers.begin(); while(peer != _peers.end()) { if((*peer)->type() == AbstractPeer::IODevicePeer) { IODevicePeer *ioPeer = static_cast(*peer); ioPeer->dispatchSignal(SignalProxy::HeartBeat, heartBeatParams); if(ioPeer->sentHeartBeats > 0) { - updateLag(ioPeer, ioPeer->sentHeartBeats * _heartBeatTimer.interval()); - } - if(ioPeer->sentHeartBeats > 1) { - qWarning() << "SignalProxy: Disconnecting peer:" << ioPeer->address() - << "(didn't receive a heartbeat for over" << ioPeer->sentHeartBeats * _heartBeatTimer.interval() / 1000 << "seconds)"; - ioPeer->close(); - } else { - ioPeer->sentHeartBeats++; + updateLag(ioPeer, ioPeer->sentHeartBeats * _heartBeatTimer.interval()); } + if(maxHeartBeatCount() >= 0 && ioPeer->sentHeartBeats >= maxHeartBeatCount()) + toClose.append(ioPeer); + else + ioPeer->sentHeartBeats++; } - peer++; + ++peer; + } + + foreach(IODevicePeer *ioPeer, toClose) { + qWarning() << "SignalProxy: Disconnecting peer:" << ioPeer->address() + << "(didn't receive a heartbeat for over" << ioPeer->sentHeartBeats * _heartBeatTimer.interval() / 1000 << "seconds)"; + ioPeer->close(); } } @@ -986,20 +1012,18 @@ void SignalProxy::customEvent(QEvent *event) { } } -void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) { - qDebug() << obj << modeType << "(" << _proxyMode << ")" << funcname; +void SignalProxy::sync_call__(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) { + // qDebug() << obj << modeType << "(" << _proxyMode << ")" << funcname; if(modeType != _proxyMode) return; ExtendedMetaObject *eMeta = extendedMetaObject(obj); QVariantList params; - params << eMeta->metaObject()->className() << obj->objectName() << QByteArray(funcname); - const QList &argTypes = eMeta->argTypes(eMeta->methodId(QByteArray(funcname))); for(int i = 0; i < argTypes.size(); i++) { @@ -1014,6 +1038,8 @@ void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode mod dispatchSignal(Sync, params); } + + void SignalProxy::disconnectDevice(QIODevice *dev, const QString &reason) { if(!reason.isEmpty()) qWarning() << qPrintable(reason); @@ -1065,7 +1091,7 @@ void SignalProxy::updateSecureState() { // ================================================== // ExtendedMetaObject // ================================================== -SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta) +SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta, bool checkConflicts) : _meta(meta), _updatedRemotelyId(_meta->indexOfSignal("updatedRemotely()")) { @@ -1077,6 +1103,9 @@ SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta) continue; // skip methods with ptr params QByteArray method = methodName(_meta->method(i)); + if(method.startsWith("init")) + continue; // skip initializers + if(_methodIds.contains(method)) { /* funny... moc creates for methods containing default parameters multiple metaMethod with separate methodIds. we don't care... we just need the full fledged version @@ -1096,8 +1125,10 @@ SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta) continue; } } - qWarning() << "class" << meta->className() << "contains overloaded methods which is currently not supported!"; - qWarning() << " - " << _meta->method(i).signature() << "conflicts with" << _meta->method(_methodIds[method]).signature(); + if(checkConflicts) { + qWarning() << "class" << meta->className() << "contains overloaded methods which is currently not supported!"; + qWarning() << " - " << _meta->method(i).signature() << "conflicts with" << _meta->method(_methodIds[method]).signature(); + } continue; } _methodIds[method] = i; @@ -1126,19 +1157,19 @@ const QHash &SignalProxy::ExtendedMetaObject::receiveMap() { for(int i = 0; i < methodCount; i++) { requestSlot = _meta->method(i); if(requestSlot.methodType() != QMetaMethod::Slot) - continue; + continue; returnTypeName = requestSlot.typeName(); if(QMetaType::Void == (QMetaType::Type)returnType(i)) - continue; + continue; signature = QByteArray(requestSlot.signature()); if(!signature.startsWith("request")) - continue; + continue; paramsPos = signature.indexOf('('); if(paramsPos == -1) - continue; + continue; methodName = signature.left(paramsPos); params = signature.mid(paramsPos); @@ -1150,13 +1181,12 @@ const QHash &SignalProxy::ExtendedMetaObject::receiveMap() { receiverId = _meta->indexOfSlot(signature); if(receiverId == -1) { - signature = QMetaObject::normalizedSignature(methodName + "(" + returnTypeName + ")"); - receiverId = _meta->indexOfSlot(signature); + signature = QMetaObject::normalizedSignature(methodName + "(" + returnTypeName + ")"); + receiverId = _meta->indexOfSlot(signature); } if(receiverId != -1) { - receiveMap[i] = receiverId; - qDebug() << requestSlot.signature() << _meta->method(receiverId).signature() << "---" << i << receiverId; + receiveMap[i] = receiverId; } } _receiveMap = receiveMap;