aboutsummaryrefslogtreecommitdiff
path: root/src/pinger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pinger.c')
-rw-r--r--src/pinger.c358
1 files changed, 277 insertions, 81 deletions
diff --git a/src/pinger.c b/src/pinger.c
index 2517781..6d5293b 100644
--- a/src/pinger.c
+++ b/src/pinger.c
@@ -99,70 +99,162 @@ timespec_incr(struct timespec *a, struct timespec const *b)
timespec_add(&t, b, a);
}
-static HOSTPING *hostping_head, *hostping_tail;
-static size_t hostping_count;
-static pthread_rwlock_t hostping_rwlock = PTHREAD_RWLOCK_INITIALIZER;
-static size_t conf_hostping_count;
-static int hostping_updated;
+static void
+hostping_free(HOSTPING *hp)
+{
+ free(hp->name);
+ free(hp->addr);
+ pthread_mutex_destroy(&hp->mutex);
+ free(hp);
+}
-void
-hostping_add(char const *name, struct sockaddr *addr, socklen_t addrlen)
+static HOSTPING *
+hostping_create(char const *name, struct sockaddr *addr, socklen_t addrlen)
{
- HOSTPING *hp = emalloc(sizeof(*hp));
-
- memset(hp, 0, sizeof(*hp));
- hp->name = estrdup(name);
- hp->addr = emalloc(addrlen);
- memcpy(hp->addr, addr, addrlen);
- hp->addrlen =addrlen;
- pthread_mutex_init(&hp->mutex, NULL);
-
- hp->next = NULL;
- hp->prev = hostping_tail;
- if (hostping_tail)
- hostping_tail->next = hp;
+ HOSTPING *hp = malloc(sizeof(*hp));
+
+ if (hp) {
+ memset(hp, 0, sizeof(*hp));
+ hp->name = strdup(name);
+ if (!hp)
+ goto err;
+ hp->addr = malloc(addrlen);
+ if (!hp)
+ goto err;
+ memcpy(hp->addr, addr, addrlen);
+ hp->addrlen = addrlen;
+ pthread_mutex_init(&hp->mutex, NULL);
+ }
+
+ return hp;
+err:
+ hostping_free(hp);
+ return NULL;
+}
+
+static inline void
+hostping_lock(HOSTPING *host)
+{
+ pthread_mutex_lock(&host->mutex);
+}
+
+static inline void
+hostping_unlock(HOSTPING *host)
+{
+ pthread_mutex_unlock(&host->mutex);
+}
+
+typedef struct hostlist {
+ HOSTPING *head, *tail;
+ size_t count;
+} HOSTLIST;
+
+static HOSTLIST *
+hostlist_create(void)
+{
+ HOSTLIST *hl = malloc(sizeof(*hl));
+ if (hl) {
+ hl->head = hl->tail = NULL;
+ hl->count = 0;
+ }
+ return hl;
+}
+
+static void
+hostlist_free(HOSTLIST *list)
+{
+ HOSTPING *hp = list->head;
+ while (hp) {
+ HOSTPING *next = hp->next;
+ hostping_free(hp);
+ hp = next;
+ }
+ free(list);
+}
+
+static void
+hostlist_add(HOSTLIST *list, HOSTPING *hp)
+{
+ hp->prev = list->tail;
+ if (list->tail)
+ list->tail->next = hp;
else
- hostping_head = hp;
- hostping_tail = hp;
-
- hostping_count++;
- hostping_updated = 1;
+ list->head = hp;
+ list->tail = hp;
+ list->count++;
}
-void
-hostping_delete(HOSTPING *hp)
+static void
+hostlist_remove(HOSTLIST *list, HOSTPING *hp)
{
if (hp->prev)
hp->prev->next = hp->next;
else
- hostping_head = hp->next;
+ list->head = hp->next;
if (hp->next)
hp->next->prev = hp->prev;
else
- hostping_tail = hp->prev;
- hostping_count--;
- hostping_updated = 1;
-
- free(hp->name);
- free(hp->addr);
- pthread_mutex_destroy(&hp->mutex);
- free(hp);
+ list->tail = hp->prev;
+ list->count--;
+}
+
+static void
+hostlist_concat(HOSTLIST *a, HOSTLIST *b)
+{
+ if (b->head)
+ b->head->prev = a->tail;
+ if (a->tail)
+ a->tail->next = b->head;
+ a->tail = b->head;
+ a->count += b->count;
+
+ b->head = b->tail = NULL;
+ b->count = 0;
}
-#define FOR_EACH_HOSTPING(hp) for (hp = hostping_head; hp; hp = hp->next)
+static HOSTPING *
+hostlist_locate(HOSTLIST *list, char const *name)
+{
+ HOSTPING *hp;
+ for (hp = list->head; hp; hp++) {
+ if (strcmp(hp->name, name) == 0)
+ break;
+ }
+ return hp;
+}
+
+static HOSTLIST *hostlist;
+static pthread_rwlock_t hostlist_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+static HOSTPING *conf_hostping_tail;
+static int hostlist_updated;
-static inline void
-hostping_lock(HOSTPING *host)
+void
+pinger_setup(void)
{
- pthread_mutex_lock(&host->mutex);
+ hostlist = hostlist_create();
+ if (!hostlist)
+ emalloc_die();
}
-static inline void
-hostping_unlock(HOSTPING *host)
+int
+pinger_host_add(char const *name, struct sockaddr *addr, socklen_t addrlen)
{
- pthread_mutex_unlock(&host->mutex);
+ HOSTPING *hp = hostping_create(name, addr, addrlen);
+ if (!hp)
+ return -1;
+ hostlist_add(hostlist, hp);
+ hostlist_updated = 1;
+ return 0;
}
+#define FOR_EACH_HOSTPING(hp) for (hp = hostlist->head; hp; hp = hp->next)
+#define FOR_EACH_LOCAL_HOSTPING(hp) \
+ for (hp = conf_hostping_tail \
+ ? conf_hostping_tail->next \
+ : hostlist->head; \
+ hp; \
+ hp = hp->next)
+
static void
hostping_extract_stat(HOSTPING *host, struct host_stat *st)
{
@@ -344,14 +436,14 @@ get_hostname_stat(char const *name, struct json_value **retval)
int rc = 0;
*retval = NULL;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
if (strcmp(hp->name, name) == 0) {
rc = get_hostping_stat(hp, retval);
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
return rc;
}
@@ -362,7 +454,7 @@ get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval)
int rc;
*retval = NULL;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
if (hp->addrlen == salen
&& memcmp(hp->addr, sa, salen) == 0) {
@@ -370,7 +462,7 @@ get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval)
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
return 0;
}
@@ -383,7 +475,7 @@ get_all_host_stat(struct json_value **retval)
if (!(ar = json_new_array()))
return -1;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
struct json_value *v;
if (get_hostping_stat(hp, &v)) {
@@ -396,7 +488,7 @@ get_all_host_stat(struct json_value **retval)
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
if (rc == 0)
*retval = ar;
else
@@ -413,7 +505,7 @@ get_all_hosts(struct json_value **retval)
if (!(ar = json_new_array()))
return -1;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
struct json_value *jv;
jv = json_new_string(hp->name);
@@ -427,7 +519,7 @@ get_all_hosts(struct json_value **retval)
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
if (rc == 0)
*retval = ar;
else
@@ -446,7 +538,7 @@ get_host_matches(struct addrinfo **aip, struct json_value **retval)
if (!(ar = json_new_array()))
return -1;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
struct addrinfo *prev = NULL, *p;
if (!ai)
@@ -491,7 +583,7 @@ get_host_matches(struct addrinfo **aip, struct json_value **retval)
*retval = ar;
ar = NULL;
err:
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
if (ai_tail) {
ai_tail->ai_next = ai;
*aip = ai_head;
@@ -501,38 +593,40 @@ err:
}
int
-hostping_delete_by_name(char const *name)
+pinger_host_delete_by_name(char const *name)
{
HOSTPING *hp;
int rc = -1;
- pthread_rwlock_wrlock(&hostping_rwlock);
- FOR_EACH_HOSTPING(hp) {
+ pthread_rwlock_wrlock(&hostlist_rwlock);
+ FOR_EACH_LOCAL_HOSTPING(hp) {
if (strcmp(hp->name, name) == 0) {
- hostping_delete(hp);
+ hostlist_remove(hostlist, hp);
+ hostping_free(hp);
rc = 0;
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
return rc;
}
+//FIXME: return codes
int
-hostping_add_name(char const *name)
+pinger_host_add_name(char const *name)
{
int rc = 0;
struct addrinfo hints, *res;
HOSTPING *hp;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
if (strcmp(hp->name, name) == 0) {
rc = -1;
break;
}
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
if (rc)
return rc;
@@ -544,11 +638,116 @@ hostping_add_name(char const *name)
return -2;
}
- pthread_rwlock_wrlock(&hostping_rwlock);
- hostping_add(name, res->ai_addr, res->ai_addrlen);
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_wrlock(&hostlist_rwlock);
+ rc = pinger_host_add(name, res->ai_addr, res->ai_addrlen);
+ pthread_rwlock_unlock(&hostlist_rwlock);
freeaddrinfo(res);
- return 0;
+ return rc;
+}
+
+int
+pinger_hostlist_set(struct json_value *obj, char const **err_text,
+ int *err_pos)
+{
+ int append;
+ struct json_value *ar;
+ HOSTLIST *tmp = NULL;
+ HOSTPING *hp;
+ struct addrinfo hints;
+ size_t i;
+ int ret;
+#define RETERR(status,text,pos) do {\
+ *err_text = text; \
+ *err_pos = pos; \
+ ret = status; \
+ goto err; \
+} while (0)
+
+ if (!obj)
+ RETERR(MHD_HTTP_BAD_REQUEST, "invalid object", 0);
+ if (obj->type == json_object) {
+ struct json_value *jv;
+ if (json_object_get(obj, "mode", &jv)) {
+ RETERR(MHD_HTTP_BAD_REQUEST,
+ "\"mode\" attribute missing",
+ 0);
+ }
+ if (strcmp(jv->v.s, "append") == 0)
+ append = 1;
+ else if (strcmp(jv->v.s, "replace") == 0)
+ append = 0;
+ else
+ RETERR(MHD_HTTP_BAD_REQUEST, "\"mode\": invalid value",
+ 0);
+
+ if (json_object_get(obj, "ip-list", &ar))
+ RETERR(MHD_HTTP_BAD_REQUEST,
+ "\"ip-list\" attribute missing",
+ 0);
+ } else if (obj->type == json_array) {
+ append = 0;
+ ar = obj;
+ } else {
+ RETERR(MHD_HTTP_BAD_REQUEST, "bad object type", 0);
+ }
+
+ tmp = hostlist_create();
+ if (!tmp)
+ RETERR(MHD_HTTP_INTERNAL_SERVER_ERROR,NULL,0);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ for (i = 0; i < ar->v.a->oc; i++) {
+ struct addrinfo *res;
+ int rc;
+ struct json_value *jv;
+
+ if (json_array_get(ar, i, &jv) || jv->type != json_string)
+ RETERR(MHD_HTTP_BAD_REQUEST,
+ "bad object type", i + 1);
+
+ rc = getaddrinfo(jv->v.s, NULL, &hints, &res);
+ if (rc)
+ RETERR(MHD_HTTP_BAD_REQUEST,
+ "host name does not resolve", i + 1);
+ hp = hostping_create(jv->v.s, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ if (!hp)
+ RETERR(MHD_HTTP_INTERNAL_SERVER_ERROR, NULL, i + 1);
+ hostlist_add(tmp, hp);
+ }
+
+ pthread_rwlock_wrlock(&hostlist_rwlock);
+ if (append) {
+ hostlist_concat(hostlist, tmp);
+ hostlist_free(tmp);
+ } else if (conf_hostping_tail) {
+ hp = conf_hostping_tail->next;
+ if (tmp->head)
+ tmp->head->prev = conf_hostping_tail;
+ conf_hostping_tail->next = tmp->head;
+ hostlist->count += tmp->count;
+ while (hp) {
+ HOSTPING *next = hp->next;
+ hostping_free(hp);
+ hp = next;
+ hostlist->count--;
+ }
+ free(tmp);
+ } else {
+ hostlist_free(hostlist);
+ hostlist = tmp;
+ }
+ hostlist_updated = 1;
+ pthread_rwlock_unlock(&hostlist_rwlock);
+ *err_text = NULL;
+ *err_pos = 0;
+ return MHD_HTTP_OK;
+err:
+ hostlist_free(tmp);
+ return ret;
}
static int ping_fd;
@@ -619,7 +818,7 @@ p903_init(void)
int i;
FILE *fp;
- conf_hostping_count = hostping_count;
+ conf_hostping_tail = hostlist->tail;
fp = fopen(LOCAL_IP_LIST_FILE, "r");
if (fp) {
int rc = file_read_ip_list(fp, LOCAL_IP_LIST_FILE);
@@ -632,10 +831,10 @@ p903_init(void)
exit(1);
}
- if (hostping_count == 0) {
+ if (hostlist->count == 0) {
info("no IP addresses configured, starting anyway");
}
- hostping_updated = 0;
+ hostlist_updated = 0;
proto = getprotobyname("icmp");
if (!proto) {
@@ -808,7 +1007,7 @@ p903_sender(void *p)
ping_buffer = emalloc(sizeof(struct icmp) + data_length);
- d = (double) ping_interval / hostping_count;
+ d = (double) ping_interval / hostlist->count;
delay.tv_sec = (int) d;
delay.tv_nsec = (d - delay.tv_sec) * NANOSEC_IN_SEC;
@@ -823,7 +1022,7 @@ p903_sender(void *p)
send_count = 0;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
FOR_EACH_HOSTPING(hp) {
struct timespec nts;
clock_gettime(CLOCK_MONOTONIC, &nts);
@@ -835,12 +1034,12 @@ p903_sender(void *p)
fatal("poll: %s", strerror(errno));
exit(1);
}
- if (i < hostping_count - 1)
+ if (i < hostlist->count - 1)
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME, &nts,
NULL);
}
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
send_count++;
if (send_count == ping_count)
send_p = 0;
@@ -1023,7 +1222,7 @@ save_local_ip_list(void)
HOSTPING *hp;
size_t i;
- if (!hostping_updated)
+ if (!hostlist_updated)
return;
fp = fopen(LOCAL_IP_LIST_FILE, "w");
if (!fp) {
@@ -1038,15 +1237,12 @@ save_local_ip_list(void)
return;
}
}
- i = 0;
- FOR_EACH_HOSTPING(hp) {
- if (i >= conf_hostping_count)
- fprintf(fp, "%s\n", hp->name);
- i++;
+ FOR_EACH_LOCAL_HOSTPING(hp) {
+ fprintf(fp, "%s\n", hp->name);
}
fclose(fp);
- hostping_updated = 0;
+ hostlist_updated = 0;
}
void *
@@ -1055,13 +1251,13 @@ p903_scheduler(void *p)
while (1) {
HOSTPING *hp;
- pthread_rwlock_rdlock(&hostping_rwlock);
+ pthread_rwlock_rdlock(&hostlist_rwlock);
/* Reset all statistics */
FOR_EACH_HOSTPING(hp) {
hostping_reset(hp);
}
save_local_ip_list();
- pthread_rwlock_unlock(&hostping_rwlock);
+ pthread_rwlock_unlock(&hostlist_rwlock);
start_probe();
sleep(probe_interval);

Return to:

Send suggestions and report system problems to the System administrator.