/***************************************************************************
- * 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 "core.h"
#include "coresession.h"
#include "coresettings.h"
+#include "internalpeer.h"
#include "postgresqlstorage.h"
#include "quassel.h"
-#include "signalproxy.h"
#include "sqlitestorage.h"
#include "network.h"
#include "logger.h"
#include "util.h"
+#include "protocols/legacy/legacypeer.h"
+
// migration related
#include <QFile>
#ifdef Q_OS_WIN32
class AddClientEvent : public QEvent
{
public:
- AddClientEvent(QTcpSocket *socket, UserId uid) : QEvent(QEvent::Type(Core::AddClientEventId)), socket(socket), userId(uid) {}
- QTcpSocket *socket;
+ AddClientEvent(RemotePeer *p, UserId uid) : QEvent(QEvent::Type(Core::AddClientEventId)), peer(p), userId(uid) {}
+ RemotePeer *peer;
UserId userId;
};
Core::~Core()
{
- foreach(QTcpSocket *socket, blocksizes.keys()) {
- socket->disconnectFromHost(); // disconnect non authed clients
+ foreach(RemotePeer *peer, clientInfo.keys()) {
+ peer->close(); // disconnect non authed clients
}
qDeleteAll(sessions);
qDeleteAll(_storageBackends);
Q_ASSERT(server);
while (server->hasPendingConnections()) {
QTcpSocket *socket = server->nextPendingConnection();
- connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
- connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
+ RemotePeer *peer = new LegacyPeer(socket, this);
+
+ connect(peer, SIGNAL(disconnected()), SLOT(clientDisconnected()));
+ connect(peer, SIGNAL(dataReceived(QVariant)), SLOT(processClientMessage(QVariant)));
+ connect(peer, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
- QVariantMap clientInfo;
- blocksizes.insert(socket, (quint32)0);
+ clientInfo.insert(peer, QVariantMap());
quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString());
if (!_configured) {
}
-void Core::clientHasData()
+void Core::processClientMessage(const QVariant &data)
{
- QTcpSocket *socket = dynamic_cast<QTcpSocket *>(sender());
- Q_ASSERT(socket && blocksizes.contains(socket));
- QVariant item;
- while (SignalProxy::readDataFromDevice(socket, blocksizes[socket], item)) {
- QVariantMap msg = item.toMap();
- processClientMessage(socket, msg);
- if (!blocksizes.contains(socket)) break; // this socket is no longer ours to handle!
+ RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
+ if (!peer) {
+ qWarning() << Q_FUNC_INFO << "Message not sent by RemoteConnection!";
+ return;
}
-}
-
-void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg)
-{
+ QVariantMap msg = data.toMap();
if (!msg.contains("MsgType")) {
// Client is way too old, does not even use the current init format
qWarning() << qPrintable(tr("Antique client trying to connect... refusing."));
- socket->close();
+ peer->close();
return;
}
+
// OK, so we have at least an init message format we can understand
if (msg["MsgType"] == "ClientInit") {
QVariantMap reply;
reply["Error"] = tr("<b>Your Quassel Client is too old!</b><br>"
"This core needs at least client/core protocol version %1.<br>"
"Please consider upgrading your client.").arg(Quassel::buildInfo().coreNeedsProtocol);
- SignalProxy::writeDataToDevice(socket, reply);
- qWarning() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("too old, rejecting."));
- socket->close(); return;
+ peer->writeSocketData(reply);
+ qWarning() << qPrintable(tr("Client")) << peer->description() << qPrintable(tr("too old, rejecting."));
+ peer->close();
+ return;
}
reply["ProtocolVersion"] = Quassel::buildInfo().protocolVersion;
#ifdef HAVE_SSL
SslServer *sslServer = qobject_cast<SslServer *>(&_server);
- QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
- bool supportSsl = (bool)sslServer && (bool)sslSocket && sslServer->isCertValid();
+ QSslSocket *sslSocket = qobject_cast<QSslSocket *>(peer->socket());
+ bool supportSsl = sslServer && sslSocket && sslServer->isCertValid();
#else
bool supportSsl = false;
#endif
else {
reply["Configured"] = true;
}
- clientInfo[socket] = msg; // store for future reference
+ clientInfo[peer] = msg; // store for future reference
reply["MsgType"] = "ClientInitAck";
- SignalProxy::writeDataToDevice(socket, reply);
- socket->flush(); // ensure that the write cache is flushed before we switch to ssl
+ peer->writeSocketData(reply);
+ peer->socket()->flush(); // ensure that the write cache is flushed before we switch to ssl
#ifdef HAVE_SSL
// after we told the client that we are ssl capable we switch to ssl mode
if (supportSsl && msg["UseSsl"].toBool()) {
- qDebug() << qPrintable(tr("Starting TLS for Client:")) << qPrintable(socket->peerAddress().toString());
- connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+ qDebug() << qPrintable(tr("Starting TLS for Client:")) << peer->description();
+ connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(sslErrors(const QList<QSslError> &)));
sslSocket->startServerEncryption();
}
#endif
#ifndef QT_NO_COMPRESS
if (supportsCompression && msg["UseCompression"].toBool()) {
- socket->setProperty("UseCompression", true);
- qDebug() << "Using compression for Client:" << qPrintable(socket->peerAddress().toString());
+ peer->socket()->setProperty("UseCompression", true);
+ qDebug() << "Using compression for Client:" << qPrintable(peer->socket()->peerAddress().toString());
}
#endif
}
else {
// for the rest, we need an initialized connection
- if (!clientInfo.contains(socket)) {
+ if (!clientInfo.contains(peer)) {
QVariantMap reply;
reply["MsgType"] = "ClientLoginReject";
reply["Error"] = tr("<b>Client not initialized!</b><br>You need to send an init message before trying to login.");
- SignalProxy::writeDataToDevice(socket, reply);
- qWarning() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting."));
- socket->close(); return;
+ peer->writeSocketData(reply);
+ qWarning() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting."));
+ peer->close(); return;
}
if (msg["MsgType"] == "CoreSetupData") {
QVariantMap reply;
else {
reply["MsgType"] = "CoreSetupAck";
}
- SignalProxy::writeDataToDevice(socket, reply);
+ peer->writeSocketData(reply);
}
else if (msg["MsgType"] == "ClientLogin") {
QVariantMap reply;
if (uid == 0) {
reply["MsgType"] = "ClientLoginReject";
reply["Error"] = tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.");
- SignalProxy::writeDataToDevice(socket, reply);
+ peer->writeSocketData(reply);
return;
}
reply["MsgType"] = "ClientLoginAck";
- SignalProxy::writeDataToDevice(socket, reply);
- quInfo() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("initialized and authenticated successfully as \"%1\" (UserId: %2).").arg(msg["User"].toString()).arg(uid.toInt()));
- setupClientSession(socket, uid);
+ peer->writeSocketData(reply);
+ quInfo() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("initialized and authenticated successfully as \"%1\" (UserId: %2).").arg(msg["User"].toString()).arg(uid.toInt()));
+ setupClientSession(peer, uid);
}
}
}
// Potentially called during the initialization phase (before handing the connection off to the session)
void Core::clientDisconnected()
{
- QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
- if (socket) {
- // here it's safe to call methods on socket!
- quInfo() << qPrintable(tr("Non-authed client disconnected.")) << qPrintable(socket->peerAddress().toString());
- blocksizes.remove(socket);
- clientInfo.remove(socket);
- socket->deleteLater();
- }
- else {
- // we have to crawl through the hashes and see if we find a victim to remove
- qDebug() << qPrintable(tr("Non-authed client disconnected. (socket allready destroyed)"));
+ RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
+ Q_ASSERT(peer);
- // DO NOT CALL ANY METHODS ON socket!!
- socket = static_cast<QTcpSocket *>(sender());
-
- QHash<QTcpSocket *, quint32>::iterator blockSizeIter = blocksizes.begin();
- while (blockSizeIter != blocksizes.end()) {
- if (blockSizeIter.key() == socket) {
- blockSizeIter = blocksizes.erase(blockSizeIter);
- }
- else {
- blockSizeIter++;
- }
- }
-
- QHash<QTcpSocket *, QVariantMap>::iterator clientInfoIter = clientInfo.begin();
- while (clientInfoIter != clientInfo.end()) {
- if (clientInfoIter.key() == socket) {
- clientInfoIter = clientInfo.erase(clientInfoIter);
- }
- else {
- clientInfoIter++;
- }
- }
- }
+ quInfo() << qPrintable(tr("Non-authed client disconnected.")) << qPrintable(peer->socket()->peerAddress().toString());
+ clientInfo.remove(peer);
+ peer->deleteLater();
// make server listen again if still not configured
if (!_configured) {
}
-void Core::setupClientSession(QTcpSocket *socket, UserId uid)
+void Core::setupClientSession(RemotePeer *peer, UserId uid)
{
// From now on everything is handled by the client session
- disconnect(socket, 0, this, 0);
- socket->flush();
- blocksizes.remove(socket);
- clientInfo.remove(socket);
+ disconnect(peer, 0, this, 0);
+ peer->socket()->flush();
+ clientInfo.remove(peer);
// Find or create session for validated user
SessionThread *session;
else {
session = createSession(uid);
if (!session) {
- qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(socket->peerAddress().toString());
- socket->close();
+ qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(peer->socket()->peerAddress().toString());
+ peer->close();
return;
}
}
// as we are currently handling an event triggered by incoming data on this socket
// it is unsafe to directly move the socket to the client thread.
- QCoreApplication::postEvent(this, new AddClientEvent(socket, uid));
+ QCoreApplication::postEvent(this, new AddClientEvent(peer, uid));
}
{
if (event->type() == AddClientEventId) {
AddClientEvent *addClientEvent = static_cast<AddClientEvent *>(event);
- addClientHelper(addClientEvent->socket, addClientEvent->userId);
+ addClientHelper(addClientEvent->peer, addClientEvent->userId);
return;
}
}
-void Core::addClientHelper(QTcpSocket *socket, UserId uid)
+void Core::addClientHelper(RemotePeer *peer, UserId uid)
{
// Find or create session for validated user
if (!sessions.contains(uid)) {
- qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(socket->peerAddress().toString());
- socket->close();
+ qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(peer->socket()->peerAddress().toString());
+ peer->close();
return;
}
SessionThread *session = sessions[uid];
- session->addClient(socket);
+ session->addClient(peer);
}
-void Core::setupInternalClientSession(SignalProxy *proxy)
+void Core::setupInternalClientSession(InternalPeer *clientPeer)
{
if (!_configured) {
stopListening();
return;
}
+ InternalPeer *corePeer = new InternalPeer(this);
+ corePeer->setPeer(clientPeer);
+ clientPeer->setPeer(corePeer);
+
// Find or create session for validated user
- SessionThread *sess;
+ SessionThread *sessionThread;
if (sessions.contains(uid))
- sess = sessions[uid];
+ sessionThread = sessions[uid];
else
- sess = createSession(uid);
- sess->addClient(proxy);
+ sessionThread = createSession(uid);
+
+ sessionThread->addClient(corePeer);
}
void Core::socketError(QAbstractSocket::SocketError err)
{
- QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(sender());
- if (socket && err != QAbstractSocket::RemoteHostClosedError)
- qWarning() << "Core::socketError()" << socket << err << socket->errorString();
+ RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
+ if (peer && err != QAbstractSocket::RemoteHostClosedError)
+ qWarning() << "Core::socketError()" << peer->socket() << err << peer->socket()->errorString();
}