/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "clientsettings.h"
#include "coreaccountmodel.h"
#include "identity.h"
+#include "internalpeer.h"
#include "network.h"
#include "networkmodel.h"
#include "quassel.h"
#include "signalproxy.h"
#include "util.h"
+#include "protocols/legacy/legacypeer.h"
+
CoreConnection::CoreConnection(CoreAccountModel *model, QObject *parent)
: QObject(parent),
_model(model),
- _blockSize(0),
_state(Disconnected),
_wantReconnect(false),
_progressMinimum(0),
_progressMaximum(-1),
_progressValue(-1),
_wasReconnect(false),
- _requestedDisconnect(false)
+ _requestedDisconnect(false),
+ _resetting(false)
{
qRegisterMetaType<ConnectionState>("CoreConnection::ConnectionState");
}
void CoreConnection::reconnectTimeout()
{
- if (!_socket) {
+ if (!_peer) {
CoreConnectionSettings s;
if (_wantReconnect && s.autoReconnect()) {
#ifdef HAVE_KDE
bool CoreConnection::isEncrypted() const
{
-#ifndef HAVE_SSL
- return false;
-#else
- QSslSocket *sock = qobject_cast<QSslSocket *>(_socket);
- return isConnected() && sock && sock->isEncrypted();
-#endif
+ return _peer && _peer->isSecure();
}
return false;
if (currentAccount().isInternal())
return true;
- if (_socket->peerAddress().isInSubnet(QHostAddress::LocalHost, 0x00ffffff))
+ if (_peer->isLocal())
return true;
return false;
void CoreConnection::coreSocketError(QAbstractSocket::SocketError)
{
- qDebug() << "coreSocketError" << _socket << _socket->errorString();
disconnectFromCore(_socket->errorString(), true);
}
void CoreConnection::coreSocketDisconnected()
{
- // qDebug() << Q_FUNC_INFO;
_wasReconnect = !_requestedDisconnect;
resetConnection(true);
// FIXME handle disconnects gracefully
}
-void CoreConnection::coreHasData()
+// note: this still expects the legacy protocol
+// noteĀ²: after cleaning this up, we can probably get rid of _socket altogether
+void CoreConnection::coreHasData(const QVariant &item)
{
- QVariant item;
- while (SignalProxy::readDataFromDevice(_socket, _blockSize, item)) {
- QVariantMap msg = item.toMap();
- if (!msg.contains("MsgType")) {
- // This core is way too old and does not even speak our init protocol...
- emit connectionErrorPopup(tr("The Quassel Core you try to connect to is too old! Please consider upgrading."));
- disconnectFromCore(QString(), false);
- return;
- }
- if (msg["MsgType"] == "ClientInitAck") {
- clientInitAck(msg);
- }
- else if (msg["MsgType"] == "ClientInitReject") {
- emit connectionErrorPopup(msg["Error"].toString());
- disconnectFromCore(QString(), false);
- return;
- }
- else if (msg["MsgType"] == "CoreSetupAck") {
- emit coreSetupSuccess();
- }
- else if (msg["MsgType"] == "CoreSetupReject") {
- emit coreSetupFailed(msg["Error"].toString());
- }
- else if (msg["MsgType"] == "ClientLoginReject") {
- loginFailed(msg["Error"].toString());
- }
- else if (msg["MsgType"] == "ClientLoginAck") {
- loginSuccess();
- }
- else if (msg["MsgType"] == "SessionInit") {
- // that's it, let's hand over to the signal proxy
- // if the socket is an orphan, the signalProxy adopts it.
- // -> we don't need to care about it anymore
- _socket->setParent(0);
- Client::signalProxy()->addPeer(_socket);
-
- sessionStateReceived(msg["SessionState"].toMap());
- break; // this is definitively the last message we process here!
- }
- else {
- disconnectFromCore(tr("Invalid data received from core"), false);
- return;
- }
+ QVariantMap msg = item.toMap();
+ if (!msg.contains("MsgType")) {
+ // This core is way too old and does not even speak our init protocol...
+ emit connectionErrorPopup(tr("The Quassel Core you try to connect to is too old! Please consider upgrading."));
+ disconnectFromCore(QString(), false);
+ return;
+ }
+ if (msg["MsgType"] == "ClientInitAck") {
+ clientInitAck(msg);
+ }
+ else if (msg["MsgType"] == "ClientInitReject") {
+ emit connectionErrorPopup(msg["Error"].toString());
+ disconnectFromCore(QString(), false);
+ return;
+ }
+ else if (msg["MsgType"] == "CoreSetupAck") {
+ emit coreSetupSuccess();
+ }
+ else if (msg["MsgType"] == "CoreSetupReject") {
+ emit coreSetupFailed(msg["Error"].toString());
+ }
+ else if (msg["MsgType"] == "ClientLoginReject") {
+ loginFailed(msg["Error"].toString());
}
- if (_blockSize > 0) {
- updateProgress(_socket->bytesAvailable(), _blockSize);
+ else if (msg["MsgType"] == "ClientLoginAck") {
+ loginSuccess();
+ }
+ else if (msg["MsgType"] == "SessionInit") {
+ // that's it, let's hand over to the signal proxy
+ // if the connection is an orphan, the signalProxy adopts it.
+ // -> we don't need to care about it anymore
+
+ disconnect(_peer, 0, this, 0);
+
+ _peer->setParent(0);
+ Client::signalProxy()->addPeer(_peer);
+
+ sessionStateReceived(msg["SessionState"].toMap());
+ }
+ else {
+ disconnectFromCore(tr("Invalid data received from core"), false);
+ return;
}
}
void CoreConnection::disconnectFromCore()
{
- _requestedDisconnect = true;
- disconnectFromCore(QString(), false); // requested disconnect, so don't try to reconnect
+ if (_socket) {
+ _requestedDisconnect = true;
+ disconnectFromCore(QString(), false); // requested disconnect, so don't try to reconnect
+ }
}
_wasReconnect = wantReconnect; // store if disconnect was requested
+ resetConnection(wantReconnect);
+
if (errorString.isEmpty())
emit connectionError(tr("Disconnected"));
else
emit connectionError(errorString);
-
- Client::signalProxy()->removeAllPeers();
- resetConnection(wantReconnect);
}
void CoreConnection::resetConnection(bool wantReconnect)
{
+ if (_resetting)
+ return;
+ _resetting = true;
+
_wantReconnect = wantReconnect;
- if (_socket) {
+ if (_peer) {
+ disconnect(_socket, 0, this, 0);
+ disconnect(_peer, 0, this, 0);
+ _peer->close();
+
+ if (_peer->parent() == this)
+ _peer->deleteLater(); // if it's not us, it belongs to the sigproxy which will delete it
+ _socket = 0; // socket is owned and will be deleted by RemoteConnection
+ _peer = 0;
+ }
+ else if (_socket) {
disconnect(_socket, 0, this, 0);
_socket->deleteLater();
_socket = 0;
}
+
_requestedDisconnect = false;
- _blockSize = 0;
_coreMsgBuffer.clear();
-
_netsToSync.clear();
_numNetsToSync = 0;
if (wantReconnect && s.autoReconnect()) {
_reconnectTimer.start();
}
+
+ _resetting = false;
}
return;
}
emit startInternalCore();
- emit connectToInternalCore(Client::instance()->signalProxy());
+
+ InternalPeer *peer = new InternalPeer();
+ Client::instance()->signalProxy()->addPeer(peer); // sigproxy will take ownership
+ emit connectToInternalCore(peer);
+
return;
}
Q_ASSERT(!_socket);
#ifdef HAVE_SSL
- QSslSocket *sock = new QSslSocket(Client::instance());
+ QSslSocket *sock = new QSslSocket(this);
// make sure the warning is shown if we happen to connect without SSL support later
s.setAccountValue("ShowNoClientSslWarning", true);
#else
s.setAccountValue("ShowNoClientSslWarning", false);
}
}
- QTcpSocket *sock = new QTcpSocket(Client::instance());
+ QTcpSocket *sock = new QTcpSocket(this);
#endif
#ifndef QT_NO_NETWORKPROXY
#endif
_socket = sock;
- connect(sock, SIGNAL(readyRead()), SLOT(coreHasData()));
connect(sock, SIGNAL(connected()), SLOT(coreSocketConnected()));
connect(sock, SIGNAL(disconnected()), SLOT(coreSocketDisconnected()));
connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(coreSocketError(QAbstractSocket::SocketError)));
void CoreConnection::coreSocketConnected()
{
+ // Create the connection which will handle the incoming data
+ Q_ASSERT(!_peer);
+ _peer = new LegacyPeer(_socket, this);
+ connect(_peer, SIGNAL(dataReceived(QVariant)), SLOT(coreHasData(QVariant)));
+ connect(_peer, SIGNAL(transferProgress(int,int)), SLOT(updateProgress(int,int)));
+
// Phase One: Send client info and wait for core info
emit connectionMsg(tr("Synchronizing to core..."));
clientInit["UseCompression"] = false;
#endif
- SignalProxy::writeDataToDevice(_socket, clientInit);
+ qobject_cast<RemotePeer *>(_peer)->writeSocketData(clientInit);
}
clientLogin["MsgType"] = "ClientLogin";
clientLogin["User"] = currentAccount().user();
clientLogin["Password"] = currentAccount().password();
- SignalProxy::writeDataToDevice(_socket, clientLogin);
+ qobject_cast<RemotePeer*>(_peer)->writeSocketData(clientLogin);
}
{
updateProgress(100, 100);
- // rest of communication happens through SignalProxy...
- disconnect(_socket, SIGNAL(readyRead()), this, 0);
- disconnect(_socket, SIGNAL(connected()), this, 0);
-
syncToCore(state);
}
QVariantMap setup;
setup["MsgType"] = "CoreSetupData";
setup["SetupData"] = setupData;
- SignalProxy::writeDataToDevice(_socket, setup);
+ qobject_cast<RemotePeer *>(_peer)->writeSocketData(setup);
}