* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#include <logger.h>
-#include <set>
+#include <limits>
#include "corenetwork.h"
#include "identserver.h"
+#include "logmessage.h"
-IdentServer::IdentServer(bool strict, QObject *parent) : QObject(parent), _strict(strict), _socketId(0), _requestId(0) {
+IdentServer::IdentServer(QObject *parent)
+ : QObject(parent)
+{
connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
connect(&_v6server, SIGNAL(newConnection()), this, SLOT(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)) {
}
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();
wasListening = true;
_v6server.close();
}
+
if (wasListening) {
if (msg.isEmpty())
quInfo() << "No longer listening for identd clients.";
}
}
-void IdentServer::incomingConnection() {
- auto *server = qobject_cast<QTcpServer *>(sender());
+
+void IdentServer::incomingConnection()
+{
+ auto server = qobject_cast<QTcpServer *>(sender());
Q_ASSERT(server);
while (server->hasPendingConnections()) {
QTcpSocket *socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(respond()));
+ connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
}
}
-void IdentServer::respond() {
+
+void IdentServer::respond()
+{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
Q_ASSERT(socket);
qint64 transactionId = _socketId;
- if (socket->canReadLine()) {
- QByteArray query = socket->readLine();
- if (query.endsWith("\r\n"))
- query.chop(2);
- else if (query.endsWith("\n"))
- query.chop(1);
+ if (!socket->canReadLine()) {
+ return;
+ }
- QList<QByteArray> split = query.split(',');
+ QByteArray query = socket->readLine();
+ if (query.endsWith("\r\n"))
+ query.chop(2);
+ else if (query.endsWith("\n"))
+ query.chop(1);
- bool success = false;
+ QList<QByteArray> split = query.split(',');
- quint16 localPort;
- if (!split.empty()) {
- localPort = split[0].trimmed().toUShort(&success, 10);
- }
+ bool success = false;
- Request request{socket, localPort, query, transactionId, _requestId++};
- if (!success) {
- responseUnavailable(request);
- } else if (!responseAvailable(request)) {
- if (hasSocketsBelowId(transactionId)) {
- _requestQueue.emplace_back(request);
- } else {
- responseUnavailable(request);
- }
- }
+ 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");
}
}
-bool IdentServer::responseAvailable(Request request) {
- QString user;
- bool success = true;
- if (_connections.contains(request.localPort)) {
- user = _connections[request.localPort];
- } else {
- success = false;
+
+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 += request.query + " : USERID : Quassel : " + user + "\r\n";
- request.socket->write(data.toUtf8());
- request.socket->flush();
- request.socket->close();
+void Request::respondError(const QString &error)
+{
+ if (socket) {
+ QString data = query + " : ERROR : " + error + "\r\n";
+ socket->write(data.toUtf8());
+ socket->flush();
+ socket->close();
}
- return success;
}
-void IdentServer::responseUnavailable(Request request) {
- QString data = request.query + " : ERROR : NO-USER\r\n";
- request.socket->write(data.toUtf8());
- request.socket->flush();
- request.socket->close();
+bool IdentServer::responseAvailable(Request request) const
+{
+ if (!_connections.contains(request.localPort)) {
+ return false;
+ }
+
+ request.respondSuccess(_connections[request.localPort]);
+ return true;
}
-bool IdentServer::addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort,
- const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId) {
+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<CoreNetwork *>(sender());
_connections[localPort] = network->coreSession()->strictCompliantIdent(identity);;
processWaiting(socketId);
- return true;
}
-bool IdentServer::removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort,
- const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId) {
+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)
_connections.remove(localPort);
processWaiting(socketId);
- return true;
}
-qint64 IdentServer::addWaitingSocket() {
+
+qint64 IdentServer::addWaitingSocket()
+{
qint64 newSocketId = _socketId++;
_waiting.push_back(newSocketId);
return newSocketId;
}
-bool IdentServer::hasSocketsBelowId(qint64 id) {
- return std::any_of(_waiting.begin(), _waiting.end(), [=](qint64 socketId) {
- return socketId <= id;
- });
+
+qint64 IdentServer::lowestSocketId() const
+{
+ if (_waiting.empty()) {
+ return std::numeric_limits<qint64>::max();
+ }
+
+ return _waiting.front();
}
-void IdentServer::removeWaitingSocket(qint64 socketId) {
+
+void IdentServer::removeWaitingSocket(qint64 socketId)
+{
_waiting.remove(socketId);
}
-void IdentServer::processWaiting(qint64 socketId) {
- qint64 lowestSocketId = std::numeric_limits<qint64 >::max();
- for (qint64 id : _waiting) {
- if (id < lowestSocketId) {
- lowestSocketId = id;
- }
- }
+
+void IdentServer::processWaiting(qint64 socketId)
+{
removeWaitingSocket(socketId);
- _requestQueue.remove_if([=](Request request) {
- if (request.transactionId < lowestSocketId) {
- responseUnavailable(request);
+
+ _requestQueue.remove_if([this, socketId](Request request) {
+ if (socketId < request.transactionId && responseAvailable(request)) {
return true;
- } else if (request.transactionId > socketId) {
- return responseAvailable(request);
- } else {
+ }
+ else if (lowestSocketId() < request.transactionId) {
return false;
}
+ else {
+ request.respondError("NO-USER");
+ return true;
+ }
});
}
-bool operator==(const Request &a, const Request &b) {
+
+bool operator==(const Request &a, const Request &b)
+{
return a.requestId == b.requestId;
}