diff options
Diffstat (limited to 'src/pingu_host.c')
-rw-r--r-- | src/pingu_host.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/pingu_host.c b/src/pingu_host.c new file mode 100644 index 0000000..f7695c4 --- /dev/null +++ b/src/pingu_host.c @@ -0,0 +1,165 @@ + +#include <arpa/inet.h> +#include <linux/rtnetlink.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ev.h> + +#include "list.h" +#include "log.h" +#include "pingu_burst.h" +#include "pingu_host.h" +#include "pingu_iface.h" +#include "pingu_ping.h" +#include "xlib.h" + +static struct list_head host_list = LIST_INITIALIZER(host_list); + +void execute_action(const char *action) +{ + pid_t pid; + const char *shell; + + if (action == NULL) + return; + + shell = getenv("SHELL"); + if (shell == NULL) + shell = "/bin/sh"; + + log_debug("executing '%s'", action); + pid = fork(); + if (pid < 0) { + log_perror("fork"); + return; + } + if (pid == 0) { + execl(shell, shell, "-c", action, NULL); + log_perror(action); + exit(1); + } +} + +int pingu_host_set_status(struct pingu_host *host, int status) +{ + const char *action, *statusstr = ""; + int adjustment; + host->burst.active = 0; + if (host->status == status) { + log_debug("%s: status is still %i", host->label, status); + return status; + } + host->status = status; + switch (host->status) { + case PINGU_HOST_STATUS_OFFLINE: + action = host->down_action; + adjustment = -1; + statusstr = "OFFLINE"; + break; + case PINGU_HOST_STATUS_ONLINE: + action = host->up_action; + adjustment = 1; + statusstr = "ONLINE"; + break; + } + log_info("%s: went %s", host->label, statusstr); + + execute_action(action); + pingu_iface_adjust_hosts_online(host->iface, adjustment); + return status; +} + +int pingu_host_verify_status(struct ev_loop *loop, struct pingu_host *host) +{ + if (host->burst.pings_replied >= host->required_replies) { + pingu_host_set_status(host, PINGU_HOST_STATUS_ONLINE); + } else if (host->burst.pings_sent >= host->max_retries) { + pingu_host_set_status(host, PINGU_HOST_STATUS_OFFLINE); + } else + pingu_ping_send(loop, host, PINGU_PING_SET_STATUS_ON_ERROR); + return 0; +} + +struct pingu_host *pingu_host_new(char *hoststr, float burst_interval, + int max_retries, int required_replies, + float timeout, + const char *up_action, + const char *down_action) +{ + struct pingu_host *host = calloc(1, sizeof(struct pingu_host)); + + if (host == NULL) { + log_perror(hoststr); + return NULL; + } + + host->host = hoststr; + host->status = PINGU_HOST_DEFAULT_STATUS; + host->burst_interval = burst_interval; + host->max_retries = max_retries; + host->required_replies = required_replies; + host->timeout = timeout; + host->up_action = up_action; + host->down_action = down_action; + + list_add(&host->host_list_entry, &host_list); + return host; +} + +void pingu_host_dump_status(int fd, char *filter) +{ + struct pingu_host *host; + char buf[512]; + list_for_each_entry(host, &host_list, host_list_entry) { + if (filter != NULL && strcmp(filter, host->label) != 0) + continue; + snprintf(buf, sizeof(buf), "%s: %i\n", host->label, host->status); + write(fd, buf, strlen(buf)); + } + write(fd, "\n", 1); +} + +int pingu_host_init(struct ev_loop *loop) +{ + struct pingu_host *host; + list_for_each_entry(host, &host_list, host_list_entry) { + if (host->label == NULL) + host->label = host->host; + ev_timer_init(&host->burst_timeout_watcher, + pingu_burst_timeout_cb, 1.0, host->burst_interval); + ev_timer_start(loop, &host->burst_timeout_watcher); + + if (host->iface->required_hosts_online == 0) + host->iface->required_hosts_online = 1; + host->iface->hosts_online += PINGU_HOST_DEFAULT_STATUS; + } + return 0; +} + +void pingu_host_iface_deleted(struct pingu_iface *iface) +{ + struct pingu_host *host; + list_for_each_entry(host, &host_list, host_list_entry) + if (host->iface == iface) + pingu_host_set_status(host, 0); +} + +void pingu_host_cleanup(void) +{ + struct pingu_host *host, *n; + list_for_each_entry_safe(host, n, &host_list, host_list_entry) { + if (host->host != NULL) + free(host->host); + if (host->label != NULL) + free(host->label); + if (host->up_action != NULL) + free((void *)host->up_action); + if (host->down_action != NULL) + free((void *)host->down_action); + list_del(&host->host_list_entry); + free(host); + } +} |