BR#132: implemented an anti-flood protection (details in the BG)
authorAlexander von Renteln <phon@quassel-irc.org>
Tue, 15 Apr 2008 16:48:44 +0000 (16:48 +0000)
committerAlexander von Renteln <phon@quassel-irc.org>
Tue, 15 Apr 2008 16:48:44 +0000 (16:48 +0000)
src/core/networkconnection.cpp
src/core/networkconnection.h
version.inc

index be2787a..15b081c 100644 (file)
@@ -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<QString, QString> 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 &params, const QByteArray &prefix) {
index 5f59313..959eb74 100644 (file)
@@ -147,6 +147,8 @@ private slots:
   void sslErrors(const QList<QSslError> &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<QByteArray> _msgQueue;
+
+  void writeToSocket(QByteArray s);
+
+
 
   class ParseError : public Exception {
   public:
index 96693bd..be268c6 100644 (file)
@@ -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;