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.
if (_account.useSsl())
magic |= Protocol::Encryption;
#endif
if (_account.useSsl())
magic |= Protocol::Encryption;
#endif
- //magic |= Protocol::Compression; // not implemented yet
+ magic |= Protocol::Compression;
qDebug() << "Legacy core detected, switching to compatibility mode";
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)));
// 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)));
quint16 protoFeatures = static_cast<quint16>(reply>>8 & 0xffff);
_connectionFeatures = static_cast<quint8>(reply>>24);
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>"
if (!peer) {
qWarning() << "No valid protocol supported for this core!";
emit errorPopup(tr("<b>Incompatible Quassel Core!</b><br>"
#ifndef CLIENTAUTHHANDLER_H
#define CLIENTAUTHHANDLER_H
#ifndef CLIENTAUTHHANDLER_H
#define CLIENTAUTHHANDLER_H
#include "authhandler.h"
#include "coreaccount.h"
#include "authhandler.h"
#include "coreaccount.h"
-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:
{
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))
case Protocol::DataStreamProtocol:
if (DataStreamPeer::acceptsFeatures(features))
- return new DataStreamPeer(authHandler, socket, features, parent);
+ return new DataStreamPeer(authHandler, socket, features, level, parent);
#include "protocol.h"
class QObject;
#include "protocol.h"
class QObject;
static ProtoList supportedProtocols();
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);
using namespace Protocol;
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)
- 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"; }
Protocol::Type protocol() const { return Protocol::DataStreamProtocol; }
QString protocolName() const { return "the DataStream protocol"; }
using namespace Protocol;
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),
- 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"; }
Protocol::Type protocol() const { return Protocol::LegacyProtocol; }
QString protocolName() const { return "the legacy protocol"; }
// no magic, assume legacy protocol
qDebug() << "Legacy client detected, switching to compatibility mode";
_legacy = true;
// 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;
connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
setPeer(peer);
return;
_supportedProtos.append(PeerFactory::ProtoDescriptor(type, protoFeatures));
if (data >= 0x80000000) { // last protocol
_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)));
if (peer->protocol() == Protocol::LegacyProtocol) {
_legacy = true;
connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));