mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-13 05:32:31 +00:00
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:
@@ -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])
|
||||
|
||||
@@ -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
|
||||
])
|
||||
])
|
||||
|
||||
@@ -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(); });
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user