diff options
Diffstat (limited to 'tacplus-daemon/global.c')
-rw-r--r-- | tacplus-daemon/global.c | 106 |
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; +} |