From 2ff27160e3959bc7542c53e5c8c52f8702845972 Mon Sep 17 00:00:00 2001 From: Felitendo Date: Tue, 22 Sep 2026 20:35:31 +0200 Subject: [PATCH] fix: keep systemd's socket file when the daemon exits idle --- src/daemon/server.cpp | 62 ++++++++++++++++++++++++++++++++----------- src/daemon/server.h | 2 ++ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/daemon/server.cpp b/src/daemon/server.cpp index 8c0bffa..902d379 100644 --- a/src/daemon/server.cpp +++ b/src/daemon/server.cpp @@ -52,6 +52,11 @@ #include #include #include +#include + +#include +#include +#include namespace { @@ -99,20 +104,25 @@ bool Server::start(QString *error) QDir().mkpath(m_options.stateDir); QFile::setPermissions(m_options.stateDir, QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); - bool ok; if (m_options.systemdFd >= 0) { - ok = m_server.listen(qintptr(m_options.systemdFd)); + // Accepted here, not handed to QLocalServer: that deletes the socket + // file when it closes, and the file is systemd's. Gone, nothing could + // start the daemon again after it exits idle. + const int fd = m_options.systemdFd; + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK); + auto *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(notifier, &QSocketNotifier::activated, this, &Server::onSystemdConnection); } else { QDir().mkpath(QFileInfo(m_options.socketPath).absolutePath()); QLocalServer::removeServer(m_options.socketPath); m_server.setSocketOptions(QLocalServer::WorldAccessOption); - ok = m_server.listen(m_options.socketPath); + if (!m_server.listen(m_options.socketPath)) { + *error = m_server.errorString(); + return false; + } + connect(&m_server, &QLocalServer::newConnection, this, &Server::onConnection); } - if (!ok) { - *error = m_server.errorString(); - return false; - } - connect(&m_server, &QLocalServer::newConnection, this, &Server::onConnection); // Loaded up front: whoever started the daemon is about to ask for a scan. QString visionError; @@ -140,18 +150,38 @@ Settings Server::settings() const void Server::onConnection() { while (QLocalSocket *socket = m_server.nextPendingConnection()) { - auto *client = new Client(socket, this); - if (!client->credentialsKnown()) { - client->deleteLater(); - continue; - } - connect(client, &Client::request, this, &Server::onRequest); - connect(client, &Client::disconnected, this, &Server::onDisconnected); - m_clients.append(client); + addClient(socket); } updateIdle(); } +void Server::onSystemdConnection() +{ + int fd; + while ((fd = ::accept4(m_options.systemdFd, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK)) >= 0) { + auto *socket = new QLocalSocket; + if (!socket->setSocketDescriptor(fd)) { + ::close(fd); + delete socket; + continue; + } + addClient(socket); + } + updateIdle(); +} + +void Server::addClient(QLocalSocket *socket) +{ + auto *client = new Client(socket, this); + if (!client->credentialsKnown()) { + client->deleteLater(); + return; + } + connect(client, &Client::request, this, &Server::onRequest); + connect(client, &Client::disconnected, this, &Server::onDisconnected); + m_clients.append(client); +} + void Server::onDisconnected(Client *client) { // Whoever asked for a scan has given up on it (the PAM module timed out, diff --git a/src/daemon/server.h b/src/daemon/server.h index 31eda86..2f94fa7 100644 --- a/src/daemon/server.h +++ b/src/daemon/server.h @@ -45,6 +45,8 @@ public: private: void onConnection(); + void onSystemdConnection(); + void addClient(QLocalSocket *socket); void onRequest(Client *client, const QJsonObject &request); void onDisconnected(Client *client);