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 <libtransmission/transmission.h>
|
||||
#include <libtransmission/error.h>
|
||||
#include <libtransmission/utils.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)
|
||||
{
|
||||
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
|
||||
|
||||
static int sigfd = -1;
|
||||
|
||||
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*/)
|
||||
static void handle_signals(evutil_socket_t fd, short /*what*/, void* arg)
|
||||
{
|
||||
struct signalfd_siginfo fdsi;
|
||||
auto* const daemon = static_cast<tr_daemon*>(arg);
|
||||
|
||||
if (read(fd, &fdsi, sizeof(fdsi)) != sizeof(fdsi))
|
||||
assert("Error reading signal descriptor" && 0);
|
||||
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 = {};
|
||||
struct event* sigev = nullptr;
|
||||
struct event_base* base = static_cast<struct event_base*>(arg);
|
||||
struct event_base* base = ev_base_;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGINT);
|
||||
|
@ -79,21 +66,21 @@ static bool setup_signals(void* arg)
|
|||
if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0)
|
||||
return false;
|
||||
|
||||
sigfd = signalfd(-1, &mask, 0);
|
||||
if (sigfd < 0)
|
||||
sigfd_ = signalfd(-1, &mask, 0);
|
||||
if (sigfd_ < 0)
|
||||
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)
|
||||
{
|
||||
close(sigfd);
|
||||
close(sigfd_);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event_add(sigev, nullptr) < 0)
|
||||
{
|
||||
event_del(sigev);
|
||||
close(sigfd);
|
||||
close(sigfd_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,19 +89,19 @@ static bool setup_signals(void* arg)
|
|||
|
||||
#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)
|
||||
return false;
|
||||
|
@ -128,20 +115,16 @@ static bool setup_signal(struct event_base* base, int sig, void (*callback)(evut
|
|||
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(base, SIGHUP, reconfigure) && setup_signal(base, SIGINT, stop) && setup_signal(base, SIGTERM, stop));
|
||||
return setup_signal(ev_base_, SIGHUP, reconfigureMarshall, this) && setup_signal(ev_base_, SIGINT, stopMarshall, this) &&
|
||||
setup_signal(ev_base_, SIGTERM, stopMarshall, this);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
if (!foreground)
|
||||
|
@ -198,7 +181,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi
|
|||
#endif
|
||||
}
|
||||
|
||||
*exit_code = cb->on_start(cb_arg, setup_signals, foreground);
|
||||
*exit_code = start(foreground);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,23 +4,14 @@
|
|||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <process.h> /* _beginthreadex() */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <algorithm> /* std::max() */
|
||||
|
||||
#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"
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
#ifndef SERVICE_ACCEPT_PRESHUTDOWN
|
||||
#define SERVICE_ACCEPT_PRESHUTDOWN 0x00000100
|
||||
#endif
|
||||
|
@ -28,20 +19,17 @@
|
|||
#define SERVICE_CONTROL_PRESHUTDOWN 0x0000000F
|
||||
#endif
|
||||
|
||||
static dtr_callbacks const* callbacks = nullptr;
|
||||
static void* callback_arg = nullptr;
|
||||
|
||||
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 DWORD current_state = SERVICE_STOPPED;
|
||||
static HANDLE service_thread = nullptr;
|
||||
static HANDLE service_stop_thread = nullptr;
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static void set_system_error(tr_error** error, DWORD code, char const* message)
|
||||
{
|
||||
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)
|
||||
{
|
||||
auto const system_message = tr_win32_format_message(code);
|
||||
tr_logAddMessage(
|
||||
file,
|
||||
line,
|
||||
level,
|
||||
"dtr_daemon",
|
||||
fmt::format("[dtr_daemon] {} ({:#x}): {}", message, code, system_message));
|
||||
tr_logAddMessage(file, line, level, "tr_daemon", fmt::format("[tr_daemon] {} ({:#x}): {}", message, code, system_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)
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static BOOL WINAPI handle_console_ctrl(DWORD /*control_type*/)
|
||||
{
|
||||
callbacks->on_stop(callback_arg);
|
||||
daemon->stop();
|
||||
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)
|
||||
{
|
||||
callbacks->on_stop(callback_arg);
|
||||
daemon->stop();
|
||||
|
||||
DWORD const sleep_time = 500;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -158,7 +135,7 @@ static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/
|
|||
return NO_ERROR;
|
||||
|
||||
case SERVICE_CONTROL_PARAMCHANGE:
|
||||
callbacks->on_reconfigure(callback_arg);
|
||||
daemon->reconfigure();
|
||||
return NO_ERROR;
|
||||
|
||||
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*/)
|
||||
{
|
||||
return callbacks->on_start(callback_arg, nullptr, false);
|
||||
return daemon->start(false);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exit_code, tr_error** error)
|
||||
bool tr_daemon::setup_signals()
|
||||
{
|
||||
callbacks = cb;
|
||||
callback_arg = cb_arg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error)
|
||||
{
|
||||
daemon = this;
|
||||
|
||||
*exit_code = 1;
|
||||
|
||||
|
@ -238,7 +215,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi
|
|||
return false;
|
||||
}
|
||||
|
||||
*exit_code = cb->on_start(cb_arg, nullptr, true);
|
||||
*exit_code = start(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
130
daemon/daemon.cc
130
daemon/daemon.cc
|
@ -9,8 +9,6 @@
|
|||
#include <cstdlib> /* atoi */
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
#include <syslog.h>
|
||||
|
@ -26,22 +24,15 @@
|
|||
|
||||
#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/tr-getopt.h>
|
||||
#include <libtransmission/tr-macros.h>
|
||||
#include <libtransmission/tr-strbuf.h>
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/variant.h>
|
||||
#include <libtransmission/version.h>
|
||||
#include <libtransmission/watchdir.h>
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
#ifdef USE_SYSTEMD
|
||||
|
||||
#include <systemd/sd-daemon.h>
|
||||
|
@ -60,47 +51,8 @@ static void sd_notifyf(int /*status*/, char const* /*fmt*/, ...)
|
|||
|
||||
#endif
|
||||
|
||||
using namespace std::literals;
|
||||
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 Usage[] = "Transmission " LONG_VERSION_STRING
|
||||
" https://transmissionbt.com/\n"
|
||||
|
@ -201,7 +153,7 @@ static auto constexpr Options = std::array<tr_option, 45>{
|
|||
{ 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_sys_file_t const old_log_file = logfile_;
|
||||
|
@ -426,7 +378,7 @@ static void pumpLogMessages(tr_sys_file_t file)
|
|||
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 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_);
|
||||
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(
|
||||
|
@ -458,17 +410,14 @@ static tr_rpc_callback_status on_rpc_callback(
|
|||
tr_torrent* /*tor*/,
|
||||
void* arg)
|
||||
{
|
||||
Daemon* daemon = static_cast<Daemon*>(arg);
|
||||
|
||||
if (type == TR_RPC_SESSION_CLOSE)
|
||||
{
|
||||
event_base_loopexit(daemon->ev_base_, nullptr);
|
||||
static_cast<tr_daemon*>(arg)->stop();
|
||||
}
|
||||
|
||||
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;
|
||||
char const* optstr;
|
||||
|
@ -523,7 +472,7 @@ bool Daemon::parseArgs(int argc, char const** argv, bool* dump_settings, bool* f
|
|||
break;
|
||||
|
||||
case 'e':
|
||||
if (reopenLogFile(optstr))
|
||||
if (reopen_log_file(optstr))
|
||||
{
|
||||
log_file_name_ = optstr;
|
||||
}
|
||||
|
@ -687,12 +636,7 @@ bool Daemon::parseArgs(int argc, char const** argv, bool* dump_settings, bool* f
|
|||
return true;
|
||||
}
|
||||
|
||||
static void daemon_reconfigure(void* arg)
|
||||
{
|
||||
static_cast<Daemon*>(arg)->reconfigure();
|
||||
}
|
||||
|
||||
void Daemon::reconfigure(void)
|
||||
void tr_daemon::reconfigure(void)
|
||||
{
|
||||
if (my_session_ == nullptr)
|
||||
{
|
||||
|
@ -707,7 +651,7 @@ void Daemon::reconfigure(void)
|
|||
/* reopen the logfile to allow for log rotation */
|
||||
if (log_file_name_ != nullptr)
|
||||
{
|
||||
reopenLogFile(log_file_name_);
|
||||
reopen_log_file(log_file_name_);
|
||||
}
|
||||
|
||||
configDir = tr_sessionGetConfigDir(my_session_);
|
||||
|
@ -721,17 +665,12 @@ void Daemon::reconfigure(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void daemon_stop(void* arg)
|
||||
{
|
||||
static_cast<Daemon*>(arg)->stop();
|
||||
}
|
||||
|
||||
void Daemon::stop(void)
|
||||
void tr_daemon::stop(void)
|
||||
{
|
||||
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 pidfile_created = false;
|
||||
|
@ -748,7 +687,7 @@ int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
|||
/* setup event state */
|
||||
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 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 (seen_hup_)
|
||||
{
|
||||
daemon_reconfigure(this);
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
/* maybe add a watchdir */
|
||||
|
@ -860,7 +799,7 @@ int Daemon::start(bool (*setupsigfn)(void*), bool foreground)
|
|||
/* Create new timer event to report daemon status */
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -937,12 +876,7 @@ CLEANUP:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int daemon_start(void* varg, bool (*setupsigfn)(void*), bool foreground)
|
||||
{
|
||||
return static_cast<Daemon*>(varg)->start(setupsigfn, foreground);
|
||||
}
|
||||
|
||||
bool Daemon::init(int argc, char* argv[], bool* foreground, int* ret)
|
||||
bool tr_daemon::init(int argc, char* argv[], bool* foreground, int* ret)
|
||||
{
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -987,29 +921,27 @@ EXIT_EARLY:
|
|||
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[])
|
||||
{
|
||||
Daemon daemon;
|
||||
bool foreground;
|
||||
int ret;
|
||||
tr_daemon daemon;
|
||||
bool foreground;
|
||||
tr_error* error = nullptr;
|
||||
|
||||
if (!daemon.init(argc, argv, &foreground, &ret))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto constexpr cb = dtr_callbacks{
|
||||
&daemon_start,
|
||||
&daemon_stop,
|
||||
&daemon_reconfigure,
|
||||
};
|
||||
|
||||
if (tr_error* error = nullptr; !dtr_daemon(&cb, &daemon, foreground, &ret, &error))
|
||||
if (!daemon.spawn(foreground, &ret, &error))
|
||||
{
|
||||
auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code);
|
||||
printMessage(daemon.logfile_, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
|
||||
tr_error_free(error);
|
||||
daemon.handle_error(error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,59 @@
|
|||
|
||||
#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);
|
||||
void (*on_stop)(void* arg);
|
||||
void (*on_reconfigure)(void* arg);
|
||||
} dtr_callbacks;
|
||||
public:
|
||||
tr_daemon() = default;
|
||||
|
||||
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