python,
'@SOURCE_ROOT@/lint.py',
])
+
+if meson_version.version_compare('>=0.53')
+ summary({
+ 'prefix': prefix,
+ 'sandbox': cdata.has('HAVE_SANDBOX'),
+ 'watchdog': cdata.has('HAVE_WATCHDOG'),
+ }, bool_yn: true, section: 'System')
+endif
io->cb = NULL;
}
-void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
+void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, const struct timeval *tv) {
timeout->cb = cb;
timeout->data = data;
timeout->node.data = timeout;
timeout_set(timeout, tv);
}
-void timeout_set(timeout_t *timeout, struct timeval *tv) {
+void timeout_set(timeout_t *timeout, const struct timeval *tv) {
if(timerisset(&timeout->tv)) {
splay_unlink_node(&timeout_tree, &timeout->node);
}
extern void io_del(io_t *io);
extern void io_set(io_t *io, int flags);
-extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
+extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, const struct timeval *tv);
extern void timeout_del(timeout_t *timeout);
-extern void timeout_set(timeout_t *timeout, struct timeval *tv);
+extern void timeout_set(timeout_t *timeout, const struct timeval *tv);
extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
extern void signal_del(signal_t *sig);
src_tincd += files('device.c')
+dep_libsystemd = dependency('libsystemd', required: opt_systemd)
+if dep_libsystemd.found()
+ src_tincd += files('watchdog.c')
+ deps_tincd += dep_libsystemd
+ cdata.set('HAVE_WATCHDOG', 1)
+endif
+
if opt_uml
src_tincd += files('uml_device.c')
cdata.set('ENABLE_UML', 1)
--- /dev/null
+#include "../system.h"
+
+#include <systemd/sd-daemon.h>
+
+#include "../event.h"
+#include "../logger.h"
+#include "../watchdog.h"
+
+static timeout_t timer;
+static struct timeval interval;
+
+static uint64_t second_to_microsecond(time_t second) {
+ return second * 1000000;
+}
+
+static time_t microsecond_to_second(uint64_t micros) {
+ return (time_t)(micros / 1000000);
+}
+
+// Ignore errors from sd_notify() since there's nothing we can do if it breaks anyway.
+// Also, there's this passage in `man sd_notify.3`:
+// In order to support both service managers that implement this scheme and those
+// which do not, it is generally recommended to ignore the return value of this call.
+void watchdog_ping(void) {
+ sd_notify(false, "WATCHDOG=1");
+}
+
+static void watchdog_handler(void *data) {
+ (void)data;
+ watchdog_ping();
+ timeout_set(&timer, &interval);
+}
+
+static bool watchdog_register(void) {
+ uint64_t timeout = 0;
+
+ if(sd_watchdog_enabled(false, &timeout) <= 0 || !timeout) {
+ return false;
+ }
+
+ if(timeout < second_to_microsecond(2)) {
+ logger(DEBUG_ALWAYS, LOG_WARNING, "Consider using a higher watchdog timeout. Spurious failures may occur.");
+ }
+
+ // Send notifications twice per timeout period
+ timeout /= 2;
+
+ interval.tv_sec = microsecond_to_second(timeout);
+
+ if(interval.tv_sec) {
+ timeout -= second_to_microsecond(interval.tv_sec);
+ }
+
+ interval.tv_usec = (suseconds_t)timeout;
+
+ timeout_add(&timer, watchdog_handler, &timer, &interval);
+ watchdog_ping();
+
+ return true;
+}
+
+void watchdog_start(void) {
+ sd_notify(false, "READY=1");
+ bool enabled = watchdog_register();
+ logger(DEBUG_ALWAYS, LOG_INFO, "Watchdog %s", enabled ? "started" : "is disabled");
+}
+
+void watchdog_stop(void) {
+ sd_notify(false, "STOPPING=1");
+ timeout_del(&timer);
+}
#include "protocol.h"
#include "subnet.h"
#include "utils.h"
+#include "watchdog.h"
int contradicting_add_edge = 0;
int contradicting_del_edge = 0;
by default
*/
if(sleep_time > 2 * udp_discovery_timeout) {
+#ifdef HAVE_WATCHDOG
+ watchdog_ping();
+#endif
logger(DEBUG_ALWAYS, LOG_ERR, "Awaking from dead after %ld seconds of sleep", sleep_time);
/*
Do not send any packets to tinc after we wake up.
#include "version.h"
#include "random.h"
#include "sandbox.h"
+#include "watchdog.h"
/* If nonzero, display usage information and exit. */
static bool show_help = false;
try_outgoing_connections();
+#ifdef HAVE_WATCHDOG
+ watchdog_start();
+#endif
+
status = main_loop();
+#ifdef HAVE_WATCHDOG
+ watchdog_stop();
+#endif
+
/* Shutdown properly. */
end:
--- /dev/null
+#ifndef TINC_WATCHDOG_H
+#define TINC_WATCHDOG_H
+
+// Start sending keepalive notifications to watchdog.
+// Called after initialization is finished before entering the event loop.
+void watchdog_start(void);
+
+// Stop sending keepalive notifications.
+// Called shortly before exiting.
+void watchdog_stop(void);
+
+// Send keepalive notification.
+void watchdog_ping(void);
+
+#endif // TINC_WATCHDOG_H
ReloadPropagatedFrom=tinc.service
[Service]
-Type=simple
+Type=notify
WorkingDirectory=@sysconfdir@/tinc/%i
ExecStart=@sbindir@/tincd -n %i -D
ExecReload=@sbindir@/tinc -n %i reload
Restart=on-failure
RestartSec=5
TimeoutStopSec=5
+WatchdogSec=10
[Install]
WantedBy=tinc.service