X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fidentserver.cpp;h=18411562d9a23523da65a5d7c447e79c9d8990e9;hp=21ea5ff6f6755392e461ce19e690248d5b93ea8e;hb=900cce213a6ed000b7131a05a0dec7d04b35b023;hpb=9451580d19875b23ec52af64585496efb7268e0f diff --git a/src/core/identserver.cpp b/src/core/identserver.cpp index 21ea5ff6..18411562 100644 --- a/src/core/identserver.cpp +++ b/src/core/identserver.cpp @@ -18,20 +18,23 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include +#include #include "corenetwork.h" #include "identserver.h" +#include "logmessage.h" -IdentServer::IdentServer(bool strict, QObject *parent) : QObject(parent), _strict(strict) { - connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); - connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); +IdentServer::IdentServer(QObject *parent) + : QObject(parent) +{ + connect(&_server, &QTcpServer::newConnection, this, &IdentServer::incomingConnection); + connect(&_v6server, &QTcpServer::newConnection, this, &IdentServer::incomingConnection); } -IdentServer::~IdentServer() = default; -bool IdentServer::startListening() { - uint16_t port = 10113; +bool IdentServer::startListening() +{ + uint16_t port = Quassel::optionValue("ident-port").toUShort(); bool success = false; if (_v6server.listen(QHostAddress("::1"), port)) { @@ -45,25 +48,27 @@ bool IdentServer::startListening() { } if (_server.listen(QHostAddress("127.0.0.1"), port)) { - success = true; - quInfo() << qPrintable( tr("Listening for identd clients on IPv4 %1 port %2") .arg("127.0.0.1") .arg(_server.serverPort()) ); + + success = true; } if (!success) { - quError() << qPrintable( - tr("Identd could not open any network interfaces to listen on! No identd functionality will be available")); + quError() << qPrintable(tr("Identd could not open any network interfaces to listen on! No identd functionality will be available")); } return success; } -void IdentServer::stopListening(const QString &msg) { + +void IdentServer::stopListening(const QString &msg) +{ bool wasListening = false; + if (_server.isListening()) { wasListening = true; _server.close(); @@ -72,6 +77,7 @@ void IdentServer::stopListening(const QString &msg) { wasListening = true; _v6server.close(); } + if (wasListening) { if (msg.isEmpty()) quInfo() << "No longer listening for identd clients."; @@ -80,79 +86,164 @@ void IdentServer::stopListening(const QString &msg) { } } -void IdentServer::incomingConnection() { - auto *server = qobject_cast(sender()); + +void IdentServer::incomingConnection() +{ + auto server = qobject_cast(sender()); Q_ASSERT(server); while (server->hasPendingConnections()) { QTcpSocket *socket = server->nextPendingConnection(); - connect(socket, SIGNAL(readyRead()), this, SLOT(respond())); + connect(socket, &QIODevice::readyRead, this, &IdentServer::respond); + connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); } } -void IdentServer::respond() { + +void IdentServer::respond() +{ auto *socket = qobject_cast(sender()); Q_ASSERT(socket); - if (socket->canReadLine()) { - QByteArray s = socket->readLine(); - if (s.endsWith("\r\n")) - s.chop(2); - else if (s.endsWith("\n")) - s.chop(1); + qint64 transactionId = _socketId; - QList split = s.split(','); + if (!socket->canReadLine()) { + return; + } - bool success = false; + QByteArray query = socket->readLine(); + if (query.endsWith("\r\n")) + query.chop(2); + else if (query.endsWith("\n")) + query.chop(1); - uint16_t localPort; - if (!split.empty()) { - localPort = split[0].toUShort(&success, 10); - } + QList split = query.split(','); - QString user; - if (success) { - if (_connections.contains(localPort)) { - user = _connections[localPort]; - } else { - success = false; - } - } + bool success = false; + + quint16 localPort = 0; + if (!split.empty()) { + localPort = split[0].trimmed().toUShort(&success, 10); + } + + Request request{socket, localPort, query, transactionId, _requestId++}; + if (!success) { + request.respondError("INVALID-PORT"); + } + else if (responseAvailable(request)) { + // success + } + else if (lowestSocketId() < transactionId) { + _requestQueue.emplace_back(request); + } + else { + request.respondError("NO-USER"); + } +} + + +void Request::respondSuccess(const QString &user) +{ + if (socket) { + QString data = query + " : USERID : Quassel : " + user + "\r\n"; + socket->write(data.toUtf8()); + socket->flush(); + socket->close(); + } +} - QString data; - if (success) { - data += s + " : USERID : Quassel : " + user + "\r\n"; - } else { - data += s + " : ERROR : NO-USER\r\n"; - } +void Request::respondError(const QString &error) +{ + if (socket) { + QString data = query + " : ERROR : " + error + "\r\n"; socket->write(data.toUtf8()); socket->flush(); socket->close(); - socket->deleteLater(); } } -bool IdentServer::addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, - const QHostAddress &peerAddress, quint16 peerPort) { +bool IdentServer::responseAvailable(Request request) const +{ + if (!_connections.contains(request.localPort)) { + return false; + } + + request.respondSuccess(_connections[request.localPort]); + return true; +} + + +void IdentServer::addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, + const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId) +{ Q_UNUSED(localAddress) Q_UNUSED(peerAddress) Q_UNUSED(peerPort) const CoreNetwork *network = qobject_cast(sender()); _connections[localPort] = network->coreSession()->strictCompliantIdent(identity);; - return true; + processWaiting(socketId); } -//! not yet implemented -bool IdentServer::removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, - const QHostAddress &peerAddress, quint16 peerPort) { +void IdentServer::removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, + const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId) +{ Q_UNUSED(identity) Q_UNUSED(localAddress) Q_UNUSED(peerAddress) Q_UNUSED(peerPort) _connections.remove(localPort); - return true; + processWaiting(socketId); +} + + +qint64 IdentServer::addWaitingSocket() +{ + qint64 newSocketId = _socketId++; + _waiting.push_back(newSocketId); + return newSocketId; +} + + +qint64 IdentServer::lowestSocketId() const +{ + if (_waiting.empty()) { + return std::numeric_limits::max(); + } + + return _waiting.front(); +} + + +void IdentServer::removeWaitingSocket(qint64 socketId) +{ + _waiting.remove(socketId); +} + + +void IdentServer::processWaiting(qint64 socketId) +{ + removeWaitingSocket(socketId); + + _requestQueue.remove_if([this, socketId](Request request) { + if (socketId < request.transactionId && responseAvailable(request)) { + return true; + } + else if (lowestSocketId() < request.transactionId) { + return false; + } + else { + request.respondError("NO-USER"); + return true; + } + }); +} + + +bool operator==(const Request &a, const Request &b) +{ + return a.requestId == b.requestId; }