}
if (Quassel::isOptionSet("ident-daemon")) {
- connect(this, SIGNAL(socketInitialized(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16)), Core::instance()->identServer(), SLOT(addSocket(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16)), Qt::BlockingQueuedConnection);
- connect(this, SIGNAL(socketDisconnected(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16)), Core::instance()->identServer(), SLOT(removeSocket(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16)));
+ connect(this, SIGNAL(socketInitialized(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16, qint64)), Core::instance()->identServer(), SLOT(addSocket(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16, qint64)), Qt::BlockingQueuedConnection);
+ connect(this, SIGNAL(socketDisconnected(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16, qint64)), Core::instance()->identServer(), SLOT(removeSocket(const CoreIdentity*, QHostAddress, quint16, QHostAddress, quint16, qint64)));
}
}
void CoreNetwork::connectToIrc(bool reconnecting)
{
+ if (Core::instance()->identServer()) {
+ _socketId = Core::instance()->identServer()->addWaitingSocket();
+ }
+
if (!reconnecting && useAutoReconnect() && _autoReconnectCount == 0) {
_autoReconnectTimer.setInterval(autoReconnectInterval() * 1000);
if (unlimitedReconnectRetries())
// Non-SSL connections enter here only once, always emit socketInitialized(...) in these cases
// SSL connections call socketInitialized() twice, only emit socketInitialized(...) on the first (not yet encrypted) run
if (!server.useSsl || !socket.isEncrypted()) {
- emit socketInitialized(identity, localAddress(), localPort(), peerAddress(), peerPort());
+ emit socketInitialized(identity, localAddress(), localPort(), peerAddress(), peerPort(), _socketId);
}
if (server.useSsl && !socket.isEncrypted()) {
setConnected(false);
emit disconnected(networkId());
- emit socketDisconnected(identityPtr(), localAddress(), localPort(), peerAddress(), peerPort());
+ emit socketDisconnected(identityPtr(), localAddress(), localPort(), peerAddress(), peerPort(), _socketId);
// Reset disconnect expectations
_disconnectExpected = false;
if (_quitRequested) {
void sslErrors(const QVariant &errorData);
void newEvent(Event *event);
- void socketInitialized(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort);
- void socketDisconnected(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort);
+ void socketInitialized(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId);
+ void socketDisconnected(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId);
protected:
inline virtual IrcChannel *ircChannelFactory(const QString &channelname) { return new CoreIrcChannel(channelname, this); }
#else
QTcpSocket socket;
#endif
+ qint64 _socketId;
CoreUserInputHandler *_userInputHandler;
***************************************************************************/
#include <logger.h>
+#include <set>
#include "corenetwork.h"
#include "identserver.h"
-IdentServer::IdentServer(bool strict, QObject *parent) : QObject(parent), _strict(strict) {
+IdentServer::IdentServer(bool strict, QObject *parent) : QObject(parent), _strict(strict), _socketId(0), _requestId(0) {
connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
}
}
void IdentServer::respond() {
- auto *socket = qobject_cast<QTcpSocket *>(sender());
+ QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
Q_ASSERT(socket);
+ qint64 transactionId = _socketId;
+
if (socket->canReadLine()) {
- QByteArray s = socket->readLine();
- if (s.endsWith("\r\n"))
- s.chop(2);
- else if (s.endsWith("\n"))
- s.chop(1);
+ QByteArray query = socket->readLine();
+ if (query.endsWith("\r\n"))
+ query.chop(2);
+ else if (query.endsWith("\n"))
+ query.chop(1);
- QList<QByteArray> split = s.split(',');
+ QList<QByteArray> split = query.split(',');
bool success = false;
- uint16_t localPort;
+ quint16 localPort;
if (!split.empty()) {
- localPort = split[0].toUShort(&success, 10);
+ localPort = split[0].trimmed().toUShort(&success, 10);
}
- QString user;
- if (success) {
- if (_connections.contains(localPort)) {
- user = _connections[localPort];
+ Request request{socket, localPort, query, transactionId, _requestId++};
+ if (!success) {
+ responseUnavailable(request);
+ } else if (!responseAvailable(request)) {
+ if (hasSocketsBelowId(transactionId)) {
+ _requestQueue.emplace_back(request);
} else {
- success = false;
+ responseUnavailable(request);
}
}
+ }
+}
- QString data;
- if (success) {
- data += s + " : USERID : Quassel : " + user + "\r\n";
- } else {
- data += s + " : ERROR : NO-USER\r\n";
- }
+bool IdentServer::responseAvailable(Request request) {
+ QString user;
+ bool success = true;
+ if (_connections.contains(request.localPort)) {
+ user = _connections[request.localPort];
+ } else {
+ success = false;
+ }
+
+ QString data;
+ if (success) {
+ data += request.query + " : USERID : Quassel : " + user + "\r\n";
- socket->write(data.toUtf8());
- socket->flush();
- socket->close();
- socket->deleteLater();
+ request.socket->write(data.toUtf8());
+ request.socket->flush();
+ request.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::addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort,
- const QHostAddress &peerAddress, quint16 peerPort) {
+ 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;
}
-//! not yet implemented
bool IdentServer::removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort,
- const QHostAddress &peerAddress, quint16 peerPort) {
+ const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId) {
Q_UNUSED(identity)
Q_UNUSED(localAddress)
Q_UNUSED(peerAddress)
Q_UNUSED(peerPort)
_connections.remove(localPort);
+ processWaiting(socketId);
return true;
}
+
+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;
+ });
+}
+
+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;
+ }
+ }
+ removeWaitingSocket(socketId);
+ _requestQueue.remove_if([=](Request request) {
+ if (request.transactionId < lowestSocketId) {
+ responseUnavailable(request);
+ return true;
+ } else if (request.transactionId > socketId) {
+ return responseAvailable(request);
+ } else {
+ return false;
+ }
+ });
+}
+
+bool operator==(const Request &a, const Request &b) {
+ return a.requestId == b.requestId;
+}
#include "coreidentity.h"
+struct Request {
+ QTcpSocket *socket;
+ uint16_t localPort;
+ QString query;
+ qint64 transactionId;
+ qint64 requestId;
+
+ friend bool operator==(const Request &a, const Request &b);
+};
+
class IdentServer : public QObject {
Q_OBJECT
public:
IdentServer(bool strict, QObject *parent);
- ~IdentServer();
+ ~IdentServer() override;
bool startListening();
void stopListening(const QString &msg);
+ qint64 addWaitingSocket();
public slots:
- bool addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort);
- bool removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort);
+ bool addSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId);
+ bool removeSocket(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId);
private slots:
void incomingConnection();
-
void respond();
private:
+ bool responseAvailable(Request request);
+ void responseUnavailable(Request request);
+
+ QString sysIdentForIdentity(const CoreIdentity *identity) const;
+
+ bool hasSocketsBelowId(qint64 socketId);
+
+ void processWaiting(qint64 socketId);
+
+ void removeWaitingSocket(qint64 socketId);
+
QTcpServer _server, _v6server;
bool _strict;
QHash<uint16_t, QString> _connections;
+ std::list<Request> _requestQueue;
+ std::list<qint64> _waiting;
+ qint64 _socketId;
+ qint64 _requestId;
};