#include #include #include #include #include #include #include #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) { struct pingu_host *host; char buf[512]; list_for_each_entry(host, &host_list, host_list_entry) { 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; }