refactor: add more C++ glue for the daemon (#3815)
Get rid of C-style callbacks on void pointers and convert (well, the most of) daemon code to (somewhat more) real C++, adjust related bits.
This commit is contained in:
parent
3c8d8488ea
commit
161330ae16
|
@ -19,15 +19,8 @@
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
|
||||||
#include <libtransmission/error.h>
|
|
||||||
#include <libtransmission/utils.h>
|
|
||||||
|
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
static dtr_callbacks const* callbacks = nullptr;
|
|
||||||
static void* callback_arg = nullptr;
|
|
||||||
|
|
||||||
static void set_system_error(tr_error** error, int code, std::string_view message)
|
static void set_system_error(tr_error** error, int code, std::string_view message)
|
||||||
{
|
{
|
||||||
tr_error_set(error, code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code));
|
tr_error_set(error, code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code));
|
||||||
|
@ -35,41 +28,35 @@ static void set_system_error(tr_error** error, int code, std::string_view messag
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SIGNALFD_H
|
#ifdef HAVE_SYS_SIGNALFD_H
|
||||||
|
|
||||||
static int sigfd = -1;
|
static void handle_signals(evutil_socket_t fd, short /*what*/, void* arg)
|
||||||
|
|
||||||
static void handle_signal(int sig)
|
|
||||||
{
|
|
||||||
switch (sig)
|
|
||||||
{
|
|
||||||
case SIGHUP:
|
|
||||||
callbacks->on_reconfigure(callback_arg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SIGINT:
|
|
||||||
case SIGTERM:
|
|
||||||
callbacks->on_stop(callback_arg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert("Unexpected signal" && 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_signals(evutil_socket_t fd, short /*what*/, void* /*arg*/)
|
|
||||||
{
|
{
|
||||||
struct signalfd_siginfo fdsi;
|
struct signalfd_siginfo fdsi;
|
||||||
|
auto* const daemon = static_cast<tr_daemon*>(arg);
|
||||||
|
|
||||||
if (read(fd, &fdsi, sizeof(fdsi)) != sizeof(fdsi))
|
if (read(fd, &fdsi, sizeof(fdsi)) != sizeof(fdsi))
|
||||||
assert("Error reading signal descriptor" && 0);
|
assert("Error reading signal descriptor" && 0);
|
||||||
else
|
else
|
||||||
handle_signal(fdsi.ssi_signo);
|
{
|
||||||
|
switch (fdsi.ssi_signo)
|
||||||
|
{
|
||||||
|
case SIGHUP:
|
||||||
|
daemon->reconfigure();
|
||||||
|
break;
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
daemon->stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert("Unexpected signal" && 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool setup_signals(void* arg)
|
bool tr_daemon::setup_signals()
|
||||||
{
|
{
|
||||||
sigset_t mask = {};
|
sigset_t mask = {};
|
||||||
struct event* sigev = nullptr;
|
struct event* sigev = nullptr;
|
||||||
struct event_base* base = static_cast<struct event_base*>(arg);
|
struct event_base* base = ev_base_;
|
||||||
|
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
sigaddset(&mask, SIGINT);
|
sigaddset(&mask, SIGINT);
|
||||||
|
@ -79,21 +66,21 @@ static bool setup_signals(void* arg)
|
||||||
if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0)
|
if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sigfd = signalfd(-1, &mask, 0);
|
sigfd_ = signalfd(-1, &mask, 0);
|
||||||
if (sigfd < 0)
|
if (sigfd_ < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sigev = event_new(base, sigfd, EV_READ | EV_PERSIST, handle_signals, nullptr);
|
sigev = event_new(base, sigfd_, EV_READ | EV_PERSIST, handle_signals, this);
|
||||||
if (sigev == nullptr)
|
if (sigev == nullptr)
|
||||||
{
|
{
|
||||||
close(sigfd);
|
close(sigfd_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_add(sigev, nullptr) < 0)
|
if (event_add(sigev, nullptr) < 0)
|
||||||
{
|
{
|
||||||
event_del(sigev);
|
event_del(sigev);
|
||||||
close(sigfd);
|
close(sigfd_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,19 +89,19 @@ static bool setup_signals(void* arg)
|
||||||
|
|
||||||
#else /* no signalfd API, use evsignal */
|
#else /* no signalfd API, use evsignal */
|
||||||
|
|
||||||
static void reconfigure(evutil_socket_t /*fd*/, short /*events*/, void* /*arg*/)
|
static void reconfigureMarshall(evutil_socket_t /*fd*/, short /*events*/, void* arg)
|
||||||
{
|
{
|
||||||
callbacks->on_reconfigure(callback_arg);
|
static_cast<tr_daemon*>(arg)->reconfigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop(evutil_socket_t /*fd*/, short /*events*/, void* /*arg*/)
|
static void stopMarshall(evutil_socket_t /*fd*/, short /*events*/, void* arg)
|
||||||
{
|
{
|
||||||
callbacks->on_stop(callback_arg);
|
static_cast<tr_daemon*>(arg)->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool setup_signal(struct event_base* base, int sig, void (*callback)(evutil_socket_t, short, void*))
|
static bool setup_signal(struct event_base* base, int sig, void (*callback)(evutil_socket_t, short, void*), void* arg)
|
||||||
{
|
{
|
||||||
struct event* sigev = evsignal_new(base, sig, callback, nullptr);
|
struct event* sigev = evsignal_new(base, sig, callback, arg);
|
||||||
|
|
||||||
if (sigev == nullptr)
|
if (sigev == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
@ -128,20 +115,16 @@ static bool setup_signal(struct event_base* base, int sig, void (*callback)(evut
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool setup_signals(void* arg)
|
bool tr_daemon::setup_signals()
|
||||||
{
|
{
|
||||||
struct event_base* base = static_cast<struct event_base*>(arg);
|
return setup_signal(ev_base_, SIGHUP, reconfigureMarshall, this) && setup_signal(ev_base_, SIGINT, stopMarshall, this) &&
|
||||||
|
setup_signal(ev_base_, SIGTERM, stopMarshall, this);
|
||||||
return (setup_signal(base, SIGHUP, reconfigure) && setup_signal(base, SIGINT, stop) && setup_signal(base, SIGTERM, stop));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SYS_SIGNALFD_H */
|
#endif /* HAVE_SYS_SIGNALFD_H */
|
||||||
|
|
||||||
bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exit_code, tr_error** error)
|
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error)
|
||||||
{
|
{
|
||||||
callbacks = cb;
|
|
||||||
callback_arg = cb_arg;
|
|
||||||
|
|
||||||
*exit_code = 1;
|
*exit_code = 1;
|
||||||
|
|
||||||
if (!foreground)
|
if (!foreground)
|
||||||
|
@ -198,7 +181,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
*exit_code = cb->on_start(cb_arg, setup_signals, foreground);
|
*exit_code = start(foreground);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,14 @@
|
||||||
// License text can be found in the licenses/ folder.
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
#include <process.h> /* _beginthreadex() */
|
#include <process.h> /* _beginthreadex() */
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <algorithm> /* std::max() */
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
|
||||||
#include <libtransmission/error.h>
|
|
||||||
#include <libtransmission/log.h>
|
|
||||||
#include <libtransmission/tr-macros.h>
|
|
||||||
#include <libtransmission/utils.h>
|
|
||||||
|
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
/***
|
|
||||||
****
|
|
||||||
***/
|
|
||||||
|
|
||||||
#ifndef SERVICE_ACCEPT_PRESHUTDOWN
|
#ifndef SERVICE_ACCEPT_PRESHUTDOWN
|
||||||
#define SERVICE_ACCEPT_PRESHUTDOWN 0x00000100
|
#define SERVICE_ACCEPT_PRESHUTDOWN 0x00000100
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,20 +19,17 @@
|
||||||
#define SERVICE_CONTROL_PRESHUTDOWN 0x0000000F
|
#define SERVICE_CONTROL_PRESHUTDOWN 0x0000000F
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static dtr_callbacks const* callbacks = nullptr;
|
|
||||||
static void* callback_arg = nullptr;
|
|
||||||
|
|
||||||
static LPCWSTR const service_name = L"TransmissionDaemon";
|
static LPCWSTR const service_name = L"TransmissionDaemon";
|
||||||
|
|
||||||
|
// If we can get rid of this global variable...
|
||||||
|
static tr_daemon* daemon;
|
||||||
|
|
||||||
|
// ...these becomes a good candidates for being converted to 'class tr_daemon' members.
|
||||||
static SERVICE_STATUS_HANDLE status_handle = nullptr;
|
static SERVICE_STATUS_HANDLE status_handle = nullptr;
|
||||||
static DWORD current_state = SERVICE_STOPPED;
|
static DWORD current_state = SERVICE_STOPPED;
|
||||||
static HANDLE service_thread = nullptr;
|
static HANDLE service_thread = nullptr;
|
||||||
static HANDLE service_stop_thread = nullptr;
|
static HANDLE service_stop_thread = nullptr;
|
||||||
|
|
||||||
/***
|
|
||||||
****
|
|
||||||
***/
|
|
||||||
|
|
||||||
static void set_system_error(tr_error** error, DWORD code, char const* message)
|
static void set_system_error(tr_error** error, DWORD code, char const* message)
|
||||||
{
|
{
|
||||||
auto const system_message = tr_win32_format_message(code);
|
auto const system_message = tr_win32_format_message(code);
|
||||||
|
@ -51,12 +39,7 @@ static void set_system_error(tr_error** error, DWORD code, char const* message)
|
||||||
static void do_log_system_error(char const* file, int line, tr_log_level level, DWORD code, char const* message)
|
static void do_log_system_error(char const* file, int line, tr_log_level level, DWORD code, char const* message)
|
||||||
{
|
{
|
||||||
auto const system_message = tr_win32_format_message(code);
|
auto const system_message = tr_win32_format_message(code);
|
||||||
tr_logAddMessage(
|
tr_logAddMessage(file, line, level, "tr_daemon", fmt::format("[tr_daemon] {} ({:#x}): {}", message, code, system_message));
|
||||||
file,
|
|
||||||
line,
|
|
||||||
level,
|
|
||||||
"dtr_daemon",
|
|
||||||
fmt::format("[dtr_daemon] {} ({:#x}): {}", message, code, system_message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define log_system_error(level, code, message) \
|
#define log_system_error(level, code, message) \
|
||||||
|
@ -70,13 +53,9 @@ static void do_log_system_error(char const* file, int line, tr_log_level level,
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/***
|
|
||||||
****
|
|
||||||
***/
|
|
||||||
|
|
||||||
static BOOL WINAPI handle_console_ctrl(DWORD /*control_type*/)
|
static BOOL WINAPI handle_console_ctrl(DWORD /*control_type*/)
|
||||||
{
|
{
|
||||||
callbacks->on_stop(callback_arg);
|
daemon->stop();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +87,9 @@ static void update_service_status(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TR_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
static unsigned int __stdcall service_stop_thread_main(void* param)
|
static unsigned int __stdcall service_stop_thread_main(void* param)
|
||||||
{
|
{
|
||||||
callbacks->on_stop(callback_arg);
|
daemon->stop();
|
||||||
|
|
||||||
DWORD const sleep_time = 500;
|
DWORD const sleep_time = 500;
|
||||||
DWORD wait_time = (DWORD)(UINT_PTR)param;
|
DWORD wait_time = (DWORD)(UINT_PTR)param;
|
||||||
|
@ -120,7 +97,7 @@ static unsigned int __stdcall service_stop_thread_main(void* param)
|
||||||
for (DWORD checkpoint = 2; WaitForSingleObject(service_thread, sleep_time) == WAIT_TIMEOUT; ++checkpoint)
|
for (DWORD checkpoint = 2; WaitForSingleObject(service_thread, sleep_time) == WAIT_TIMEOUT; ++checkpoint)
|
||||||
{
|
{
|
||||||
wait_time = wait_time >= sleep_time ? wait_time - sleep_time : 0;
|
wait_time = wait_time >= sleep_time ? wait_time - sleep_time : 0;
|
||||||
update_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0, checkpoint, TR_MAX(wait_time, sleep_time * 2));
|
update_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0, checkpoint, std::max(wait_time, sleep_time * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -158,7 +135,7 @@ static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
|
|
||||||
case SERVICE_CONTROL_PARAMCHANGE:
|
case SERVICE_CONTROL_PARAMCHANGE:
|
||||||
callbacks->on_reconfigure(callback_arg);
|
daemon->reconfigure();
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
|
|
||||||
case SERVICE_CONTROL_INTERROGATE:
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
@ -171,7 +148,7 @@ static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/
|
||||||
|
|
||||||
static unsigned int __stdcall service_thread_main(void* /*context*/)
|
static unsigned int __stdcall service_thread_main(void* /*context*/)
|
||||||
{
|
{
|
||||||
return callbacks->on_start(callback_arg, nullptr, false);
|
return daemon->start(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
||||||
|
@ -219,14 +196,14 @@ static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
||||||
update_service_status(SERVICE_STOPPED, NO_ERROR, exit_code, 0, 0);
|
update_service_status(SERVICE_STOPPED, NO_ERROR, exit_code, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
bool tr_daemon::setup_signals()
|
||||||
****
|
|
||||||
***/
|
|
||||||
|
|
||||||
bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exit_code, tr_error** error)
|
|
||||||
{
|
{
|
||||||
callbacks = cb;
|
return true;
|
||||||
callback_arg = cb_arg;
|
}
|
||||||
|
|
||||||
|
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error)
|
||||||
|
{
|
||||||
|
daemon = this;
|
||||||
|
|
||||||
*exit_code = 1;
|
*exit_code = 1;
|
||||||
|
|
||||||
|
@ -238,7 +215,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*exit_code = cb->on_start(cb_arg, nullptr, true);
|
*exit_code = start(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
130
daemon/daemon.cc
130
daemon/daemon.cc
|
@ -9,8 +9,6 @@
|
||||||
#include <cstdlib> /* atoi */
|
#include <cstdlib> /* atoi */
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYSLOG
|
#ifdef HAVE_SYSLOG
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
@ -26,22 +24,15 @@
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include "daemon.h"
|
||||||
|
|
||||||
#include <libtransmission/error.h>
|
|
||||||
#include <libtransmission/file.h>
|
|
||||||
#include <libtransmission/log.h>
|
|
||||||
#include <libtransmission/timer-ev.h>
|
#include <libtransmission/timer-ev.h>
|
||||||
#include <libtransmission/tr-getopt.h>
|
#include <libtransmission/tr-getopt.h>
|
||||||
#include <libtransmission/tr-macros.h>
|
#include <libtransmission/tr-macros.h>
|
||||||
#include <libtransmission/tr-strbuf.h>
|
#include <libtransmission/tr-strbuf.h>
|
||||||
#include <libtransmission/utils.h>
|
|
||||||
#include <libtransmission/variant.h>
|
|
||||||
#include <libtransmission/version.h>
|
#include <libtransmission/version.h>
|
||||||
#include <libtransmission/watchdir.h>
|
#include <libtransmission/watchdir.h>
|
||||||
|
|
||||||
#include "daemon.h"
|
|
||||||
|
|
||||||
#ifdef USE_SYSTEMD
|
#ifdef USE_SYSTEMD
|
||||||
|
|
||||||
#include <systemd/sd-daemon.h>
|
#include <systemd/sd-daemon.h>
|
||||||
|
@ -60,47 +51,8 @@ static void sd_notifyf(int /*status*/, char const* /*fmt*/, ...)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std::literals;
|
|
||||||
using libtransmission::Watchdir;
|
using libtransmission::Watchdir;
|
||||||
|
|
||||||
class Daemon
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct event_base* ev_base_ = nullptr;
|
|
||||||
tr_sys_file_t logfile_ = TR_BAD_SYS_FILE;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool seen_hup_ = false;
|
|
||||||
bool paused_ = false;
|
|
||||||
std::string config_dir_;
|
|
||||||
char const* log_file_name_ = nullptr;
|
|
||||||
tr_session* my_session_ = nullptr;
|
|
||||||
tr_variant settings_ = {};
|
|
||||||
tr_quark key_pidfile_ = tr_quark_new("pidfile"sv);
|
|
||||||
tr_quark key_watch_dir_force_generic_ = tr_quark_new("watch-dir-force-generic"sv);
|
|
||||||
|
|
||||||
public:
|
|
||||||
Daemon() = default;
|
|
||||||
|
|
||||||
~Daemon()
|
|
||||||
{
|
|
||||||
tr_variantClear(&settings_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(int argc, char* argv[], bool* foreground, int* ret);
|
|
||||||
bool parseArgs(int argc, char const** argv, bool* dump_settings, bool* foreground, int* exit_code);
|
|
||||||
bool reopenLogFile(char const* filename);
|
|
||||||
int start(bool (*setupsigfn)(void*), bool foreground);
|
|
||||||
void periodicUpdate();
|
|
||||||
void reportStatus();
|
|
||||||
void reconfigure();
|
|
||||||
void stop();
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
****
|
|
||||||
***/
|
|
||||||
|
|
||||||
static char constexpr MyName[] = "transmission-daemon";
|
static char constexpr MyName[] = "transmission-daemon";
|
||||||
static char constexpr Usage[] = "Transmission " LONG_VERSION_STRING
|
static char constexpr Usage[] = "Transmission " LONG_VERSION_STRING
|
||||||
" https://transmissionbt.com/\n"
|
" https://transmissionbt.com/\n"
|
||||||
|
@ -201,7 +153,7 @@ static auto constexpr Options = std::array<tr_option, 45>{
|
||||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Daemon::reopenLogFile(char const* filename)
|
bool tr_daemon::reopen_log_file(char const* filename)
|
||||||
{
|
{
|
||||||
tr_error* error = nullptr;
|
tr_error* error = nullptr;
|
||||||
tr_sys_file_t const old_log_file = logfile_;
|
tr_sys_file_t const old_log_file = logfile_;
|
||||||
|
@ -426,7 +378,7 @@ static void pumpLogMessages(tr_sys_file_t file)
|
||||||
tr_logFreeQueue(list);
|
tr_logFreeQueue(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Daemon::reportStatus(void)
|
void tr_daemon::report_status(void)
|
||||||
{
|
{
|
||||||
double const up = tr_sessionGetRawSpeed_KBps(my_session_, TR_UP);
|
double const up = tr_sessionGetRawSpeed_KBps(my_session_, TR_UP);
|
||||||
double const dn = tr_sessionGetRawSpeed_KBps(my_session_, TR_DOWN);
|
double const dn = tr_sessionGetRawSpeed_KBps(my_session_, TR_DOWN);
|
||||||
|
@ -441,15 +393,15 @@ void Daemon::reportStatus(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Daemon::periodicUpdate(void)
|
void tr_daemon::periodic_update(void)
|
||||||
{
|
{
|
||||||
pumpLogMessages(logfile_);
|
pumpLogMessages(logfile_);
|
||||||
reportStatus();
|
report_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void periodicUpdate(evutil_socket_t /*fd*/, short /*what*/, void* arg)
|
static void periodic_update(evutil_socket_t /*fd*/, short /*what*/, void* arg)
|
||||||
{
|
{
|
||||||
static_cast<Daemon*>(arg)->periodicUpdate();
|
static_cast<tr_daemon*>(arg)->periodic_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
static tr_rpc_callback_status on_rpc_callback(
|
static tr_rpc_callback_status on_rpc_callback(
|
||||||
|
@ -458,17 +410,14 @@ static tr_rpc_callback_status on_rpc_callback(
|
||||||
tr_torrent* /*tor*/,
|
tr_torrent* /*tor*/,
|
||||||
void* arg)
|
void* arg)
|
||||||
{
|
{
|
||||||
Daemon* daemon = static_cast<Daemon*>(arg);
|
|
||||||
|
|
||||||
if (type == TR_RPC_SESSION_CLOSE)
|
if (type == TR_RPC_SESSION_CLOSE)
|
||||||
{
|
{
|
||||||
event_base_loopexit(daemon->ev_base_, nullptr);
|
static_cast<tr_daemon*>(arg)->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return TR_RPC_OK;
|
return TR_RPC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon::parseArgs(int argc, char const** argv, bool* dump_settings, bool* foreground, int* exit_code)
|
bool tr_daemon::parse_args(int argc, char const** argv, bool* dump_settings, bool* foreground, int* exit_code)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
char const* optstr;
|
char const* optstr;
|
||||||
|
@ -523,7 +472,7 @@ bool Daemon::parseArgs(int argc, char const** argv, bool* dump_settings, bool* f
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if (reopenLogFile(optstr))
|
if (reopen_log_file(optstr))
|
||||||
{
|
{
|
||||||
log_file_name_ = optstr;
|
log_file_name_ = optstr;
|
||||||
}
|
}
|
||||||
|
@ -687,12 +636,7 @@ bool Daemon::parseArgs(int argc, char const** argv, bool* dump_settings, bool* f
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void daemon_reconfigure(void* arg)
|
void tr_daemon::reconfigure(void)
|
||||||
{
|
|
||||||
static_cast<Daemon*>(arg)->reconfigure();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Daemon::reconfigure(void)
|
|
||||||
{
|
{
|
||||||
if (my_session_ == nullptr)
|
if (my_session_ == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -707,7 +651,7 @@ void Daemon::reconfigure(void)
|
||||||
/* reopen the logfile to allow for log rotation */
|
/* reopen the logfile to allow for log rotation */
|
||||||
if (log_file_name_ != nullptr)
|
if (log_file_name_ != nullptr)
|
||||||
{
|
{
|
||||||
reopenLogFile(log_file_name_);
|
reopen_log_file(log_file_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
configDir = tr_sessionGetConfigDir(my_session_);
|
configDir = tr_sessionGetConfigDir(my_session_);
|
||||||
|
@ -721,17 +665,12 @@ void Daemon::reconfigure(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void daemon_stop(void* arg)
|
void tr_daemon::stop(void)
|
||||||
{
|
|
||||||
static_cast<Daemon*>(arg)->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Daemon::stop(void)
|
|
||||||
{
|
{
|
||||||
event_base_loopexit(ev_base_, nullptr);
|
event_base_loopexit(ev_base_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
int tr_daemon::start([[maybe_unused]] bool foreground)
|
||||||
{
|
{
|
||||||
bool boolVal;
|
bool boolVal;
|
||||||
bool pidfile_created = false;
|
bool pidfile_created = false;
|
||||||
|
@ -748,7 +687,7 @@ int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
||||||
/* setup event state */
|
/* setup event state */
|
||||||
ev_base_ = event_base_new();
|
ev_base_ = event_base_new();
|
||||||
|
|
||||||
if (ev_base_ == nullptr || (setupsigfn ? setupsigfn(ev_base_) : true) == false)
|
if (ev_base_ == nullptr || setup_signals() == false)
|
||||||
{
|
{
|
||||||
auto const error_code = errno;
|
auto const error_code = errno;
|
||||||
auto const errmsg = fmt::format(
|
auto const errmsg = fmt::format(
|
||||||
|
@ -809,7 +748,7 @@ int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
||||||
/* If we got a SIGHUP during startup, process that now. */
|
/* If we got a SIGHUP during startup, process that now. */
|
||||||
if (seen_hup_)
|
if (seen_hup_)
|
||||||
{
|
{
|
||||||
daemon_reconfigure(this);
|
reconfigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* maybe add a watchdir */
|
/* maybe add a watchdir */
|
||||||
|
@ -860,7 +799,7 @@ int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
||||||
/* Create new timer event to report daemon status */
|
/* Create new timer event to report daemon status */
|
||||||
{
|
{
|
||||||
constexpr auto one_sec = timeval{ 1, 0 }; // 1 second
|
constexpr auto one_sec = timeval{ 1, 0 }; // 1 second
|
||||||
status_ev = event_new(ev_base_, -1, EV_PERSIST, &::periodicUpdate, this);
|
status_ev = event_new(ev_base_, -1, EV_PERSIST, &::periodic_update, this);
|
||||||
|
|
||||||
if (status_ev == nullptr)
|
if (status_ev == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -937,12 +876,7 @@ CLEANUP:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int daemon_start(void* varg, bool (*setupsigfn)(void*), bool foreground)
|
bool tr_daemon::init(int argc, char* argv[], bool* foreground, int* ret)
|
||||||
{
|
|
||||||
return static_cast<Daemon*>(varg)->start(setupsigfn, foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Daemon::init(int argc, char* argv[], bool* foreground, int* ret)
|
|
||||||
{
|
{
|
||||||
config_dir_ = getConfigDir(argc, (char const* const*)argv);
|
config_dir_ = getConfigDir(argc, (char const* const*)argv);
|
||||||
|
|
||||||
|
@ -956,7 +890,7 @@ bool Daemon::init(int argc, char* argv[], bool* foreground, int* ret)
|
||||||
*ret = 0;
|
*ret = 0;
|
||||||
|
|
||||||
/* overwrite settings from the command line */
|
/* overwrite settings from the command line */
|
||||||
if (!parseArgs(argc, (char const**)argv, &dumpSettings, foreground, ret))
|
if (!parse_args(argc, (char const**)argv, &dumpSettings, foreground, ret))
|
||||||
{
|
{
|
||||||
goto EXIT_EARLY;
|
goto EXIT_EARLY;
|
||||||
}
|
}
|
||||||
|
@ -987,29 +921,27 @@ EXIT_EARLY:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tr_daemon::handle_error(tr_error* error)
|
||||||
|
{
|
||||||
|
auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code);
|
||||||
|
printMessage(logfile_, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
|
||||||
|
tr_error_free(error);
|
||||||
|
}
|
||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
Daemon daemon;
|
|
||||||
bool foreground;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
tr_daemon daemon;
|
||||||
|
bool foreground;
|
||||||
|
tr_error* error = nullptr;
|
||||||
|
|
||||||
if (!daemon.init(argc, argv, &foreground, &ret))
|
if (!daemon.init(argc, argv, &foreground, &ret))
|
||||||
{
|
{
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if (!daemon.spawn(foreground, &ret, &error))
|
||||||
auto constexpr cb = dtr_callbacks{
|
|
||||||
&daemon_start,
|
|
||||||
&daemon_stop,
|
|
||||||
&daemon_reconfigure,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tr_error* error = nullptr; !dtr_daemon(&cb, &daemon, foreground, &ret, &error))
|
|
||||||
{
|
{
|
||||||
auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code);
|
daemon.handle_error(error);
|
||||||
printMessage(daemon.logfile_, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
|
|
||||||
tr_error_free(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,59 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct tr_error;
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
typedef struct dtr_callbacks
|
#include <libtransmission/transmission.h>
|
||||||
|
#include <libtransmission/variant.h>
|
||||||
|
#include <libtransmission/error.h>
|
||||||
|
#include <libtransmission/utils.h>
|
||||||
|
#include <libtransmission/file.h>
|
||||||
|
#include <libtransmission/log.h>
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
class tr_daemon
|
||||||
{
|
{
|
||||||
int (*on_start)(void* arg, bool (*setupsigfn)(void*), bool foreground);
|
public:
|
||||||
void (*on_stop)(void* arg);
|
tr_daemon() = default;
|
||||||
void (*on_reconfigure)(void* arg);
|
|
||||||
} dtr_callbacks;
|
|
||||||
|
|
||||||
bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exit_code, struct tr_error** error);
|
~tr_daemon()
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SYS_SIGNALFD_H
|
||||||
|
if (sigfd_ != -1)
|
||||||
|
{
|
||||||
|
close(sigfd_);
|
||||||
|
}
|
||||||
|
#endif /* signalfd API */
|
||||||
|
tr_variantClear(&settings_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spawn(bool foreground, int* exit_code, tr_error** error);
|
||||||
|
bool init(int argc, char* argv[], bool* foreground, int* ret);
|
||||||
|
void handle_error(tr_error*);
|
||||||
|
int start(bool foreground);
|
||||||
|
void periodic_update();
|
||||||
|
void reconfigure();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef HAVE_SYS_SIGNALFD_H
|
||||||
|
int sigfd_ = -1;
|
||||||
|
#endif /* signalfd API */
|
||||||
|
bool paused_ = false;
|
||||||
|
bool seen_hup_ = false;
|
||||||
|
std::string config_dir_;
|
||||||
|
tr_variant settings_ = {};
|
||||||
|
tr_session* my_session_ = nullptr;
|
||||||
|
char const* log_file_name_ = nullptr;
|
||||||
|
struct event_base* ev_base_ = nullptr;
|
||||||
|
tr_sys_file_t logfile_ = TR_BAD_SYS_FILE;
|
||||||
|
tr_quark key_pidfile_ = tr_quark_new("pidfile"sv);
|
||||||
|
tr_quark key_watch_dir_force_generic_ = tr_quark_new("watch-dir-force-generic"sv);
|
||||||
|
|
||||||
|
bool parse_args(int argc, char const** argv, bool* dump_settings, bool* foreground, int* exit_code);
|
||||||
|
bool reopen_log_file(char const* filename);
|
||||||
|
bool setup_signals();
|
||||||
|
void report_status();
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue