summaryrefslogtreecommitdiff
path: root/tacplus-daemon/global.c
diff options
context:
space:
mode:
Diffstat (limited to 'tacplus-daemon/global.c')
-rw-r--r--tacplus-daemon/global.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/tacplus-daemon/global.c b/tacplus-daemon/global.c
new file mode 100644
index 0000000..1de9aeb
--- /dev/null
+++ b/tacplus-daemon/global.c
@@ -0,0 +1,106 @@
+/*
+ TACACS+ D-Bus Daemon code
+
+ Copyright (c) 2019, AT&T Intellectual Property
+
+ SPDX-License-Identifier: GPL-2.0-only
+*/
+
+#include <syslog.h>
+
+#include "dbus_service.h"
+#include "global.h"
+#include "utils.h"
+
+static void offline_timer_expiry_cb(__attribute__((unused)) union sigval val)
+{
+ int id = val.sival_int;
+
+ syslog(LOG_DEBUG, "Offline timer %d expired", id);
+
+ pthread_mutex_lock(&connControl->state.lock);
+
+ /*
+ * Every time we attempt to start an offline timer we increment the
+ * offline_timer_id. The incremented value is stored ready to be passed
+ * into the callback (ie. us) at timer expiry.
+ *
+ * This allows us to detect a race condition where we (attempted to)
+ * cancel a timer just after it expired and ignore the callback.
+ */
+ if (id != connControl->state.offline_timer_id) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ syslog(LOG_DEBUG, "Stale timer - ignoring");
+ return;
+ }
+
+ if (! connControl->state.offline) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ syslog(LOG_DEBUG, "Already online");
+ return;
+ }
+
+ connControl->state.offline = false;
+ connControl->state.offline_timer_id = 0;
+ signal_offline_state_change();
+
+ pthread_mutex_unlock(&connControl->state.lock);
+
+ syslog(LOG_NOTICE, "TACACS+ component back online");
+}
+
+bool tacplusd_go_online() {
+ pthread_mutex_lock(&connControl->state.lock);
+
+ if (! connControl->state.offline) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ return true;
+ }
+
+ /* Expire the running timer to trigger an online state change */
+ int ret = expire_timer(connControl->state.offline_timer);
+
+ pthread_mutex_unlock(&connControl->state.lock);
+ return ret == 0;
+}
+
+bool tacplusd_go_offline(const struct timespec *time) {
+ struct itimerspec it = { .it_value = *time };
+
+ pthread_mutex_lock(&connControl->state.lock);
+
+ /* If we are already offline then cancel an existing timer */
+ if (connControl->state.offline)
+ timer_delete(connControl->state.offline_timer);
+
+ /* Start the offline timer */
+ union sigval sv = { .sival_int = ++connControl->state.offline_timer_id };
+ if (new_cb_timer(&connControl->state.offline_timer,
+ offline_timer_expiry_cb, &sv) < 0) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ return false;
+ }
+
+ if (set_timer(connControl->state.offline_timer, &it) < 0) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ return false;
+ }
+
+ if (connControl->state.offline) {
+ pthread_mutex_unlock(&connControl->state.lock);
+ return true;
+ }
+
+ /* If we were previously online then signal a state change */
+ connControl->state.offline = true;
+ signal_offline_state_change();
+
+ pthread_mutex_unlock(&connControl->state.lock);
+
+ syslog(LOG_WARNING, "TACACS+ component has gone offline");
+ return true;
+}
+
+bool tacplusd_online() {
+ return !connControl->state.offline;
+}