fix: keep systemd's socket file when the daemon exits idle

This commit is contained in:
Felitendo committed 2026-09-22 20:35:31 +02:00
1 parent 08a18ce736
commit 2ff27160e3
2 files changed
+48 -16

No files matched your search

+46 -16
View File
@@ -52,6 +52,11 @@
#include <QFileInfo> #include <QFileInfo>
#include <QJsonArray> #include <QJsonArray>
#include <QLocalSocket> #include <QLocalSocket>
#include <QSocketNotifier>
#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
namespace namespace
{ {
@@ -99,20 +104,25 @@ bool Server::start(QString *error)
QDir().mkpath(m_options.stateDir); QDir().mkpath(m_options.stateDir);
QFile::setPermissions(m_options.stateDir, QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); QFile::setPermissions(m_options.stateDir, QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
bool ok;
if (m_options.systemdFd >= 0) { 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 { } else {
QDir().mkpath(QFileInfo(m_options.socketPath).absolutePath()); QDir().mkpath(QFileInfo(m_options.socketPath).absolutePath());
QLocalServer::removeServer(m_options.socketPath); QLocalServer::removeServer(m_options.socketPath);
m_server.setSocketOptions(QLocalServer::WorldAccessOption); 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. // Loaded up front: whoever started the daemon is about to ask for a scan.
QString visionError; QString visionError;
@@ -140,18 +150,38 @@ Settings Server::settings() const
void Server::onConnection() void Server::onConnection()
{ {
while (QLocalSocket *socket = m_server.nextPendingConnection()) { while (QLocalSocket *socket = m_server.nextPendingConnection()) {
auto *client = new Client(socket, this); addClient(socket);
if (!client->credentialsKnown()) {
client->deleteLater();
continue;
}
connect(client, &Client::request, this, &Server::onRequest);
connect(client, &Client::disconnected, this, &Server::onDisconnected);
m_clients.append(client);
} }
updateIdle(); 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) void Server::onDisconnected(Client *client)
{ {
// Whoever asked for a scan has given up on it (the PAM module timed out, // Whoever asked for a scan has given up on it (the PAM module timed out,
+2
View File
@@ -45,6 +45,8 @@ public:
private: private:
void onConnection(); void onConnection();
void onSystemdConnection();
void addClient(QLocalSocket *socket);
void onRequest(Client *client, const QJsonObject &request); void onRequest(Client *client, const QJsonObject &request);
void onDisconnected(Client *client); void onDisconnected(Client *client);