diff options
Diffstat (limited to 'src/pinger.c')
-rw-r--r-- | src/pinger.c | 358 |
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); |