Allow configuring listen address
[quassel.git] / src / core / identserver.cpp
index e8f89bb..510430a 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   Copyright (C) 2005-2019 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 
 #include "corenetwork.h"
 #include "identserver.h"
-#include "logger.h"
+#include "logmessage.h"
 
-IdentServer::IdentServer(bool strict, QObject *parent)
+IdentServer::IdentServer(QObject *parent)
     : QObject(parent)
-    , _strict(strict)
 {
     connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
     connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
@@ -35,27 +34,65 @@ IdentServer::IdentServer(bool strict, QObject *parent)
 
 bool IdentServer::startListening()
 {
-    uint16_t port = Quassel::optionValue("ident-port").toUShort();
-
     bool success = false;
-    if (_v6server.listen(QHostAddress("::1"), port)) {
-        quInfo() << qPrintable(
-                tr("Listening for identd clients on IPv6 %1 port %2")
-                        .arg("::1")
-                        .arg(_v6server.serverPort())
-        );
-
-        success = true;
-    }
 
-    if (_server.listen(QHostAddress("127.0.0.1"), port)) {
-        quInfo() << qPrintable(
-                tr("Listening for identd clients on IPv4 %1 port %2")
-                        .arg("127.0.0.1")
-                        .arg(_server.serverPort())
-        );
+    uint16_t port = Quassel::optionValue("ident-port").toUShort();
 
-        success = true;
+    const QString listen = Quassel::optionValue("ident-listen");
+    const QStringList listen_list = listen.split(",", QString::SkipEmptyParts);
+    for (const QString &listen_term : listen_list) { // TODO: handle multiple interfaces for same TCP version gracefully
+        QHostAddress addr;
+        if (!addr.setAddress(listen_term)) {
+            qCritical() << qPrintable(
+                    tr("Invalid listen address %1")
+                            .arg(listen_term)
+            );
+        }
+        else {
+            switch (addr.protocol()) {
+                case QAbstractSocket::IPv6Protocol:
+                    if (_v6server.listen(addr, port)) {
+                        quInfo() << qPrintable(
+                                tr("Listening for identd requests on IPv6 %1 port %2")
+                                        .arg(addr.toString())
+                                        .arg(_v6server.serverPort())
+                        );
+                        success = true;
+                    }
+                    else
+                        quWarning() << qPrintable(
+                                tr("Could not open IPv6 interface %1:%2: %3")
+                                        .arg(addr.toString())
+                                        .arg(port)
+                                        .arg(_v6server.errorString()));
+                    break;
+                case QAbstractSocket::IPv4Protocol:
+                    if (_server.listen(addr, port)) {
+                        quInfo() << qPrintable(
+                                tr("Listening for identd requests on IPv4 %1 port %2")
+                                        .arg(addr.toString())
+                                        .arg(_server.serverPort())
+                        );
+                        success = true;
+                    }
+                    else {
+                        // if v6 succeeded on Any, the port will be already in use - don't display the error then
+                        if (!success || _server.serverError() != QAbstractSocket::AddressInUseError)
+                            quWarning() << qPrintable(
+                                    tr("Could not open IPv4 interface %1:%2: %3")
+                                            .arg(addr.toString())
+                                            .arg(port)
+                                            .arg(_server.errorString()));
+                    }
+                    break;
+                default:
+                    qCritical() << qPrintable(
+                            tr("Invalid listen address %1, unknown network protocol")
+                                    .arg(listen_term)
+                    );
+                    break;
+            }
+        }
     }
 
     if (!success) {
@@ -95,6 +132,7 @@ void IdentServer::incomingConnection()
     while (server->hasPendingConnections()) {
         QTcpSocket *socket = server->nextPendingConnection();
         connect(socket, SIGNAL(readyRead()), this, SLOT(respond()));
+        connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
     }
 }
 
@@ -143,21 +181,23 @@ void IdentServer::respond()
 
 void Request::respondSuccess(const QString &user)
 {
-    QString data = query + " : USERID : Quassel : " + user + "\r\n";
-
-    socket->write(data.toUtf8());
-    socket->flush();
-    socket->close();
+    if (socket) {
+        QString data = query + " : USERID : Quassel : " + user + "\r\n";
+        socket->write(data.toUtf8());
+        socket->flush();
+        socket->close();
+    }
 }
 
 
 void Request::respondError(const QString &error)
 {
-    QString data = query + " : ERROR : " + error + "\r\n";
-
-    socket->write(data.toUtf8());
-    socket->flush();
-    socket->close();
+    if (socket) {
+        QString data = query + " : ERROR : " + error + "\r\n";
+        socket->write(data.toUtf8());
+        socket->flush();
+        socket->close();
+    }
 }