Add support for SCGI systemd socket activation

Add a new command, `network.scgi.open_systemd`, that binds to a file
descriptor passed in via systemd socket activation.
This commit is contained in:
zqmfb
2026-03-24 20:48:32 -04:00
committed by Jari Sundell
parent a82bdf22ac
commit 63ea08bde6
5 changed files with 76 additions and 0 deletions
+1
View File
@@ -56,6 +56,7 @@ AC_LANG_POP(C++)
TORRENT_WITH_LUA
TORRENT_WITH_TINYXML2
TORRENT_WITH_SYSTEMD
if test ${with_xmlrpc_c+y} && test ${with_xmlrpc_tinyxml2+y}; then
AC_MSG_ERROR([--with-xmlrpc-c and --with-xmlrpc-tinyxml2 cannot be used together. Please choose only one])
+17
View File
@@ -358,3 +358,20 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
]
)
])
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
AC_ARG_WITH(systemd,
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
[
if test "$withval" = "yes"; then
PKG_CHECK_MODULES([SYSTEMD], [libsystemd],
[
CXXFLAGS="$CXXFLAGS $SYSTEMD_CFLAGS"
LIBS="$LIBS $SYSTEMD_LIBS"
AC_DEFINE(HAVE_SYSTEMD, 1, [Support for systemd socket activation.])
],
[AC_MSG_ERROR([libsystemd not found. Install libsystemd-dev (or the equivalent for your distribution).])])
fi
])
])
+42
View File
@@ -3,6 +3,10 @@
#include <functional>
#include <cstdio>
#include <unistd.h>
#ifdef HAVE_SYSTEMD
#include <sys/socket.h>
#include <systemd/sd-daemon.h>
#endif
#include <rak/address_info.h>
#include <torrent/torrent.h>
#include <torrent/rate.h>
@@ -143,6 +147,41 @@ apply_scgi(const std::string& arg, int type) {
return torrent::Object();
}
#ifdef HAVE_SYSTEMD
torrent::Object
apply_scgi_systemd() {
if (scgi_thread::scgi() != nullptr)
throw torrent::input_error("SCGI already enabled.");
int n = sd_listen_fds(0);
if (n < 1)
throw torrent::input_error("No systemd socket(s) provided (sd_listen_fds returned " +
std::to_string(n) + ").");
// Iterate over all provided fds. Use the first listening stream socket;
// close the rest. The systemd docs say unused fds should be closed.
int selected_fd = -1;
for (int i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i;
if (selected_fd == -1 && sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1) > 0)
selected_fd = fd;
else
::close(fd);
}
if (selected_fd == -1)
throw torrent::input_error("No listening stream socket found among systemd-provided fds.");
initialize_rpc_handlers();
rpc::SCgi* scgi = new rpc::SCgi;
scgi->open_fd(selected_fd);
scgi_thread::set_scgi(scgi);
return torrent::Object();
}
#endif
torrent::Object
apply_xmlrpc_dialect(const std::string& arg) {
int value;
@@ -243,6 +282,9 @@ initialize_command_network() {
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
#ifdef HAVE_SYSTEMD
CMD2_ANY_VALUE_V ("network.scgi.open_systemd", [](auto, auto& value) { if (value != 0) apply_scgi_systemd(); });
#endif
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", [](const auto&, const auto& arg) { return apply_xmlrpc_dialect(arg); })
CMD2_ANY ("network.xmlrpc.size_limit", [](const auto&, const auto&) { return rpc::rpc.size_limit(); });
+15
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <cassert>
#include <fcntl.h>
#include <unistd.h>
#include <sys/un.h>
#include <torrent/connection_manager.h>
@@ -80,6 +81,20 @@ SCgi::open_named(const std::string& filename) {
m_path = filename;
}
void
SCgi::open_fd(int fd) {
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
int flags = ::fcntl(fd, F_GETFL, 0);
if (flags == -1 || ::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
throw torrent::resource_error("Could not set non-blocking on systemd fd: " +
std::string(std::strerror(errno)));
set_file_descriptor(fd);
// fd is already bound and listening; no bind()/listen() needed.
});
torrent::connection_manager()->inc_socket_count();
}
void
SCgi::open(sockaddr* sa, unsigned int length) {
try {
+1
View File
@@ -21,6 +21,7 @@ public:
void open_port(sockaddr* sa, unsigned int length, bool dont_route);
void open_named(const std::string& filename);
void open_fd(int fd);
void activate();