fix: keep systemd's socket file when the daemon exits idle
This commit is contained in:
1 parent
08a18ce736
commit
2ff27160e3
2 files changed
+48
-16
No files matched your search
+46
-16
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user