From c6b3980fe063e5022882a31a132dec6952f8c6a7 Mon Sep 17 00:00:00 2001 From: Alexander von Renteln Date: Tue, 15 Apr 2008 16:48:44 +0000 Subject: [PATCH 1/1] BR#132: implemented an anti-flood protection (details in the BG) --- src/core/networkconnection.cpp | 28 ++++++++++++++++++++++++++++ src/core/networkconnection.h | 11 +++++++++++ version.inc | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/core/networkconnection.cpp b/src/core/networkconnection.cpp index be2787aa..15b081cc 100644 --- a/src/core/networkconnection.cpp +++ b/src/core/networkconnection.cpp @@ -61,6 +61,14 @@ NetworkConnection::NetworkConnection(Network *network, CoreSession *session) : Q _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000); _autoWhoCycleTimer.setSingleShot(false); + // TokenBucket to avaid sending too much at once + _messagesPerSecond = 1; + _burstSize = 5; + _tokenBucket = 5; // init with a full bucket + + _tokenBucketTimer.start(_messagesPerSecond * 1000); + _tokenBucketTimer.setSingleShot(false); + QHash channels = coreSession()->persistentChannels(networkId()); foreach(QString chan, channels.keys()) { _channelKeys[chan.toLower()] = channels[chan]; @@ -69,6 +77,7 @@ NetworkConnection::NetworkConnection(Network *network, CoreSession *session) : Q connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect())); connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho())); connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle())); + connect(&_tokenBucketTimer, SIGNAL(timeout()), this, SLOT(fillBucketAndProcessQueue())); connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(networkInitialized(const QString &))); connect(network, SIGNAL(useAutoReconnectSet(bool)), this, SLOT(autoReconnectSettingsChanged())); @@ -380,8 +389,27 @@ void NetworkConnection::userInput(BufferInfo buf, QString msg) { } void NetworkConnection::putRawLine(QByteArray s) { + if(_tokenBucket > 0) { + writeToSocket(s); + } else { + _msgQueue.append(s); + } +} + +void NetworkConnection::writeToSocket(QByteArray s) { s += "\r\n"; socket.write(s); + _tokenBucket--; +} + +void NetworkConnection::fillBucketAndProcessQueue() { + if(_tokenBucket < _burstSize) { + _tokenBucket++; + } + + while(_msgQueue.size() > 0 && _tokenBucket > 0) { + writeToSocket(_msgQueue.takeFirst()); + } } void NetworkConnection::putCmd(const QString &cmd, const QVariantList ¶ms, const QByteArray &prefix) { diff --git a/src/core/networkconnection.h b/src/core/networkconnection.h index 5f593137..959eb740 100644 --- a/src/core/networkconnection.h +++ b/src/core/networkconnection.h @@ -147,6 +147,8 @@ private slots: void sslErrors(const QList &errors); #endif + void fillBucketAndProcessQueue(); + private: #ifndef QT_NO_OPENSSL QSslSocket socket; @@ -180,6 +182,15 @@ private: int _autoWhoDelay; QTimer _autoWhoTimer, _autoWhoCycleTimer; + QTimer _tokenBucketTimer; + int _messagesPerSecond; // token refill speed + int _burstSize; // size of the token bucket + int _tokenBucket; // the virtual bucket that holds the tokens + QList _msgQueue; + + void writeToSocket(QByteArray s); + + class ParseError : public Exception { public: diff --git a/version.inc b/version.inc index 96693bd1..be268c69 100644 --- a/version.inc +++ b/version.inc @@ -5,7 +5,7 @@ quasselVersion = "0.2.0-beta1-pre"; quasselDate = "2008-04-15"; - quasselBuild = 750; + quasselBuild = 755; //! Minimum client build number the core needs clientBuildNeeded = 731; -- 2.20.1