Allow for clients to negotiate whether compression is used
authorMichael Marley <michael@michaelmarley.com>
Mon, 24 Feb 2014 14:12:27 +0000 (14:12 +0000)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 24 Feb 2014 23:16:44 +0000 (00:16 +0100)
Previously, streaming compression would always be used for the
datastream protocol and never for the legacy protocol, regardless
of whether the client set the compression bit during the handshake.
This patch enables negotiation of compression support and also
allows for streaming compression when using the legacy protocol
with the new handshake.

As is, this patch prevents clients with streaming compression
support but without this patch from connecting to cores with this
patch.  This problem occurs because the above-mentioned clients
never set the compression bit during the handshake, which didn't
cause a problem before because both sides unconditionally enabled
compression.  However, when connecting to a core with this patch,
such a client will request no compression and the core will
disable compression.  However, the client will still enable the
compression anyway, causing the connection to fail.

src/client/clientauthhandler.cpp
src/client/clientauthhandler.h
src/common/peerfactory.cpp
src/common/peerfactory.h
src/common/protocols/datastream/datastreampeer.cpp
src/common/protocols/datastream/datastreampeer.h
src/common/protocols/legacy/legacypeer.cpp
src/common/protocols/legacy/legacypeer.h
src/core/coreauthhandler.cpp

index 15efef3..0d24a76 100644 (file)
@@ -173,7 +173,7 @@ void ClientAuthHandler::onSocketConnected()
         if (_account.useSsl())
             magic |= Protocol::Encryption;
 #endif
-        //magic |= Protocol::Compression; // not implemented yet
+        magic |= Protocol::Compression;
 
         stream << magic;
 
@@ -195,7 +195,7 @@ void ClientAuthHandler::onSocketConnected()
 
     qDebug() << "Legacy core detected, switching to compatibility mode";
 
-    RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), this);
+    RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), Compressor::NoCompression, this);
     // Only needed for the legacy peer, as all others check the protocol version before instantiation
     connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
 
@@ -222,7 +222,13 @@ void ClientAuthHandler::onReadyRead()
     quint16 protoFeatures = static_cast<quint16>(reply>>8 & 0xffff);
     _connectionFeatures = static_cast<quint8>(reply>>24);
 
-    RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(type, protoFeatures), this, socket(), this);
+    Compressor::CompressionLevel level;
+    if (_connectionFeatures & Protocol::Compression)
+        level = Compressor::BestCompression;
+    else
+        level = Compressor::NoCompression;
+
+    RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(type, protoFeatures), this, socket(), level, this);
     if (!peer) {
         qWarning() << "No valid protocol supported for this core!";
         emit errorPopup(tr("<b>Incompatible Quassel Core!</b><br>"
index 6683d1d..f6f2fc9 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef CLIENTAUTHHANDLER_H
 #define CLIENTAUTHHANDLER_H
 
+#include "compressor.h"
 #include "authhandler.h"
 #include "coreaccount.h"
 
index 0dc0140..2364b71 100644 (file)
@@ -33,23 +33,23 @@ PeerFactory::ProtoList PeerFactory::supportedProtocols()
 }
 
 
-RemotePeer *PeerFactory::createPeer(const ProtoDescriptor &protocol, AuthHandler *authHandler, QTcpSocket *socket, QObject *parent)
+RemotePeer *PeerFactory::createPeer(const ProtoDescriptor &protocol, AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent)
 {
-    return createPeer(ProtoList() << protocol, authHandler, socket, parent);
+    return createPeer(ProtoList() << protocol, authHandler, socket, level, parent);
 }
 
 
-RemotePeer *PeerFactory::createPeer(const ProtoList &protocols, AuthHandler *authHandler, QTcpSocket *socket, QObject *parent)
+RemotePeer *PeerFactory::createPeer(const ProtoList &protocols, AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent)
 {
     foreach(const ProtoDescriptor &protodesc, protocols) {
         Protocol::Type proto = protodesc.first;
         quint16 features = protodesc.second;
         switch(proto) {
             case Protocol::LegacyProtocol:
-                return new LegacyPeer(authHandler, socket, parent);
+                return new LegacyPeer(authHandler, socket, level, parent);
             case Protocol::DataStreamProtocol:
                 if (DataStreamPeer::acceptsFeatures(features))
-                    return new DataStreamPeer(authHandler, socket, features, parent);
+                    return new DataStreamPeer(authHandler, socket, features, level, parent);
                 break;
             default:
                 break;
index 79a0c35..6b1bdf3 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <QPair>
 
+#include "compressor.h"
 #include "protocol.h"
 
 class QObject;
@@ -41,8 +42,8 @@ public:
 
     static ProtoList supportedProtocols();
 
-    static RemotePeer *createPeer(const ProtoDescriptor &protocol, AuthHandler *authHandler, QTcpSocket *socket, QObject *parent = 0);
-    static RemotePeer *createPeer(const ProtoList &protocols, AuthHandler *authHandler, QTcpSocket *socket, QObject *parent = 0);
+    static RemotePeer *createPeer(const ProtoDescriptor &protocol, AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent = 0);
+    static RemotePeer *createPeer(const ProtoList &protocols, AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent = 0);
 
 };
 
index 7d9b854..b2e4443 100644 (file)
@@ -28,8 +28,8 @@
 
 using namespace Protocol;
 
-DataStreamPeer::DataStreamPeer(::AuthHandler *authHandler, QTcpSocket *socket, quint16 features, QObject *parent)
-    : RemotePeer(authHandler, socket, Compressor::BestCompression, parent)
+DataStreamPeer::DataStreamPeer(::AuthHandler *authHandler, QTcpSocket *socket, quint16 features, Compressor::CompressionLevel level, QObject *parent)
+    : RemotePeer(authHandler, socket, level, parent)
 {
     Q_UNUSED(features);
 }
index 7d04f4b..e01fb34 100644 (file)
@@ -39,7 +39,7 @@ public:
         HeartBeatReply
     };
 
-    DataStreamPeer(AuthHandler *authHandler, QTcpSocket *socket, quint16 features, QObject *parent = 0);
+    DataStreamPeer(AuthHandler *authHandler, QTcpSocket *socket, quint16 features, Compressor::CompressionLevel level, QObject *parent = 0);
 
     Protocol::Type protocol() const { return Protocol::DataStreamProtocol; }
     QString protocolName() const { return "the DataStream protocol"; }
index 49c77fd..67e5130 100644 (file)
@@ -31,8 +31,8 @@ const uint clientNeedsProtocol = protocolVersion;
 
 using namespace Protocol;
 
-LegacyPeer::LegacyPeer(::AuthHandler *authHandler, QTcpSocket *socket, QObject *parent)
-    : RemotePeer(authHandler, socket, Compressor::NoCompression, parent),
+LegacyPeer::LegacyPeer(::AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent)
+    : RemotePeer(authHandler, socket, level, parent),
     _useCompression(false)
 {
 
index a063616..ce960fa 100644 (file)
@@ -37,7 +37,7 @@ public:
         HeartBeatReply
     };
 
-    LegacyPeer(AuthHandler *authHandler, QTcpSocket *socket, QObject *parent = 0);
+    LegacyPeer(AuthHandler *authHandler, QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent = 0);
 
     Protocol::Type protocol() const { return Protocol::LegacyProtocol; }
     QString protocolName() const { return "the legacy protocol"; }
index 36eecc1..9ef67fa 100644 (file)
@@ -63,7 +63,7 @@ void CoreAuthHandler::onReadyRead()
             // no magic, assume legacy protocol
             qDebug() << "Legacy client detected, switching to compatibility mode";
             _legacy = true;
-            RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), this);
+            RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), Compressor::NoCompression, this);
             connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
             setPeer(peer);
             return;
@@ -91,7 +91,13 @@ void CoreAuthHandler::onReadyRead()
         _supportedProtos.append(PeerFactory::ProtoDescriptor(type, protoFeatures));
 
         if (data >= 0x80000000) { // last protocol
-            RemotePeer *peer = PeerFactory::createPeer(_supportedProtos, this, socket(), this);
+            Compressor::CompressionLevel level;
+            if (_connectionFeatures & Protocol::Compression)
+                level = Compressor::BestCompression;
+            else
+                level = Compressor::NoCompression;
+
+            RemotePeer *peer = PeerFactory::createPeer(_supportedProtos, this, socket(), level, this);
             if (peer->protocol() == Protocol::LegacyProtocol) {
                 _legacy = true;
                 connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));