diff options
Diffstat (limited to 'src/pinger.c')
-rw-r--r-- | src/pinger.c | 329 |
1 files changed, 228 insertions, 101 deletions
diff --git a/src/pinger.c b/src/pinger.c index 54fe4d2..96a55ae 100644 --- a/src/pinger.c +++ b/src/pinger.c @@ -224,9 +224,19 @@ hostlist_locate(HOSTLIST *list, char const *name) } static HOSTLIST *hostlist; -static pthread_rwlock_t hostlist_rwlock = PTHREAD_RWLOCK_INITIALIZER; static HOSTPING *conf_hostping_tail; -static int hostlist_updated; +static pthread_rwlock_t hostlist_rwlock = PTHREAD_RWLOCK_INITIALIZER; + +typedef enum update_type { + UPDATE_APPEND, + UPDATE_REPLACE, + UPDATE_DELETE +} UPDATE_TYPE; + +static pthread_mutex_t update_mutex = PTHREAD_MUTEX_INITIALIZER; +static int check_host(char const *name); +static int update_add(UPDATE_TYPE t, void *data); +static void update_commit(void); void pinger_setup(void) @@ -243,7 +253,6 @@ pinger_host_add(char const *name, struct sockaddr *addr, socklen_t addrlen) if (!hp) return -1; hostlist_add(hostlist, hp); - hostlist_updated = 1; return 0; } @@ -418,7 +427,7 @@ get_hostping_stat(HOSTPING *host, struct json_value **retval) hostping_unlock(host); *retval = obj; - return 0; + return GET_OK; err: hostping_unlock(host); @@ -426,14 +435,14 @@ get_hostping_stat(HOSTPING *host, struct json_value **retval) json_value_free(v); json_value_free(obj); - return -1; + return GET_NOMEM; } int get_hostname_stat(char const *name, struct json_value **retval) { HOSTPING *hp; - int rc = 0; + int rc = GET_NOENT; *retval = NULL; pthread_rwlock_rdlock(&hostlist_rwlock); @@ -451,7 +460,7 @@ int get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval) { HOSTPING *hp; - int rc; + int rc = GET_NOENT; *retval = NULL; pthread_rwlock_rdlock(&hostlist_rwlock); @@ -463,7 +472,7 @@ get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval) } } pthread_rwlock_unlock(&hostlist_rwlock); - return 0; + return rc; } int @@ -471,25 +480,25 @@ get_all_host_stat(struct json_value **retval) { struct json_value *ar; HOSTPING *hp; - int rc = 0; + int rc = GET_OK; if (!(ar = json_new_array())) - return -1; + return GET_NOMEM; pthread_rwlock_rdlock(&hostlist_rwlock); FOR_EACH_HOSTPING(hp) { struct json_value *v; if (get_hostping_stat(hp, &v)) { - rc = -1; + rc = GET_NOMEM; break; } if (json_array_append(ar, v)) { json_value_free(v); - rc = -1; + rc = GET_NOMEM; break; } } pthread_rwlock_unlock(&hostlist_rwlock); - if (rc == 0) + if (rc == GET_OK) *retval = ar; else json_value_free(ar); @@ -501,26 +510,26 @@ get_all_hosts(struct json_value **retval) { struct json_value *ar; HOSTPING *hp; - int rc = 0; + int rc = GET_OK; if (!(ar = json_new_array())) - return -1; + return GET_NOMEM; pthread_rwlock_rdlock(&hostlist_rwlock); FOR_EACH_HOSTPING(hp) { struct json_value *jv; jv = json_new_string(hp->name); if (!jv) { - rc = -1; + rc = GET_NOMEM; break; } if (json_array_append(ar, jv)) { json_value_free(jv); - rc = -1; + rc = GET_NOMEM; break; } } pthread_rwlock_unlock(&hostlist_rwlock); - if (rc == 0) + if (rc == GET_OK) *retval = ar; else json_value_free(ar); @@ -578,11 +587,11 @@ get_host_matches(struct addrinfo **aip, struct json_value **retval) } } } - + ret = 0; *retval = ar; ar = NULL; -err: +err: pthread_rwlock_unlock(&hostlist_rwlock); if (ai_tail) { ai_tail->ai_next = ai; @@ -596,19 +605,23 @@ int pinger_host_delete_by_name(char const *name) { HOSTPING *hp; - int rc = -1; - - pthread_rwlock_wrlock(&hostlist_rwlock); - FOR_EACH_LOCAL_HOSTPING(hp) { - if (strcmp(hp->name, name) == 0) { - hostlist_remove(hostlist, hp); - hostping_free(hp); - hostlist_updated = 1; - rc = 0; - break; + int rc; + + pthread_mutex_lock(&update_mutex); + if (check_host(name)) { + char *cp = strdup(name); + if (cp) { + if (update_add(UPDATE_DELETE, cp) == 0) + rc = UPD_OK; + else { + rc = UPD_NOMEM; + free(cp); + } } + } else { + rc = UPD_EXISTS; } - pthread_rwlock_unlock(&hostlist_rwlock); + pthread_mutex_unlock(&update_mutex); return rc; } @@ -618,29 +631,34 @@ pinger_host_add_name(char const *name) int rc = 0; struct addrinfo hints, *res; HOSTPING *hp; - - pthread_rwlock_rdlock(&hostlist_rwlock); - FOR_EACH_HOSTPING(hp) { - if (strcmp(hp->name, name) == 0) { - rc = -1; - break; - } - } - pthread_rwlock_unlock(&hostlist_rwlock); - if (rc) - return rc; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_TCP; rc = getaddrinfo(name, NULL, &hints, &res); if (rc) { - return -2; + return UPD_NORESOLV; } - - pthread_rwlock_wrlock(&hostlist_rwlock); - rc = pinger_host_add(name, res->ai_addr, res->ai_addrlen); - pthread_rwlock_unlock(&hostlist_rwlock); + + pthread_mutex_lock(&update_mutex); + if (check_host(name) == 0) { + rc = UPD_NOMEM; + hp = hostping_create(name, res->ai_addr, res->ai_addrlen); + if (hp) { + HOSTLIST *hl = hostlist_create(); + if (hl) { + hostlist_add(hl, hp); + if (update_add(UPDATE_APPEND, hl) == 0) + rc = UPD_OK; + else + hostlist_free(hl); + } else + hostping_free(hp); + } + } else { + rc = UPD_EXISTS; + } + pthread_mutex_unlock(&update_mutex); freeaddrinfo(res); return rc; } @@ -649,7 +667,7 @@ int pinger_hostlist_set(struct json_value *obj, char const **err_text, int *err_pos) { - int append; + int mode = UPDATE_APPEND; struct json_value *ar; HOSTLIST *tmp = NULL; HOSTPING *hp; @@ -673,9 +691,9 @@ pinger_hostlist_set(struct json_value *obj, char const **err_text, 0); } if (strcmp(jv->v.s, "append") == 0) - append = 1; + mode = UPDATE_APPEND; else if (strcmp(jv->v.s, "replace") == 0) - append = 0; + mode = UPDATE_REPLACE; else RETERR(MHD_HTTP_BAD_REQUEST, "\"mode\": invalid value", 0); @@ -685,7 +703,7 @@ pinger_hostlist_set(struct json_value *obj, char const **err_text, "\"ip-list\" attribute missing", 0); } else if (obj->type == json_array) { - append = 0; + mode = UPDATE_APPEND; ar = obj; } else { RETERR(MHD_HTTP_BAD_REQUEST, "bad object type", 0); @@ -718,39 +736,163 @@ pinger_hostlist_set(struct json_value *obj, char const **err_text, 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->tail = tmp->tail; - hostlist->count += tmp->count; - while (hp) { - HOSTPING *next = hp->next; - hostping_free(hp); - hp = next; - hostlist->count--; - } - free(tmp); + + if (update_add(mode, tmp)) { + RETERR(MHD_HTTP_INTERNAL_SERVER_ERROR, NULL, 0); } else { - hostlist_free(hostlist); - hostlist = tmp; + *err_text = NULL; + *err_pos = 0; + return MHD_HTTP_OK; } - hostlist_updated = 1; - pthread_rwlock_unlock(&hostlist_rwlock); - *err_text = NULL; - *err_pos = 0; - return MHD_HTTP_OK; err: hostlist_free(tmp); return ret; } +typedef struct update_entry { + enum update_type type; + struct update_entry *next; + union { + void *ptr; + HOSTLIST *hlist; + char *name; + } v; +} UPDATE_ENTRY; + +static UPDATE_ENTRY *update_head, *update_tail; + +static void save_local_ip_list(void); + +static int +update_add(UPDATE_TYPE t, void *data) +{ + UPDATE_ENTRY *uent = malloc(sizeof(*uent)); + + if (!uent) + return -1; + + uent->type = t; + uent->v.ptr = data; + uent->next = NULL; + + if (uent->type == UPDATE_REPLACE) { + while (update_head) { + UPDATE_ENTRY *next = update_head->next; + switch (update_head->type) { + case UPDATE_APPEND: + case UPDATE_REPLACE: + hostlist_free(update_head->v.hlist); + break; + case UPDATE_DELETE: + free(update_head->v.name); + } + free(update_head); + update_head = next; + } + update_tail = NULL; + } + + if (update_tail) + update_tail->next = uent; + else + update_head = uent; + update_tail = uent; + return 0; +} + +static void +update_commit(void) +{ + HOSTPING *hp; + int upd; + + pthread_mutex_lock(&update_mutex); + pthread_rwlock_wrlock(&hostlist_rwlock); + upd = update_head != NULL; + while (update_head) { + UPDATE_ENTRY *next = update_head->next; + switch (update_head->type) { + case UPDATE_APPEND: + hostlist_concat(hostlist, update_head->v.hlist); + hostlist_free(update_head->v.hlist); + break; + + case UPDATE_REPLACE: + if (conf_hostping_tail) { + HOSTLIST *tmp = update_head->v.hlist; + + hp = conf_hostping_tail->next; + if (tmp->head) + tmp->head->prev = conf_hostping_tail; + conf_hostping_tail->next = tmp->head; + hostlist->tail = tmp->tail; + hostlist->count += tmp->count; + while (hp) { + HOSTPING *next = hp->next; + hostping_free(hp); + hp = next; + hostlist->count--; + } + free(tmp); + } else { + hostlist_free(hostlist); + hostlist = update_head->v.hlist; + } + break; + + case UPDATE_DELETE: + FOR_EACH_LOCAL_HOSTPING(hp) { + if (strcmp(hp->name, update_head->v.name) == 0) { + hostlist_remove(hostlist, hp); + hostping_free(hp); + break; + } + } + free(update_head->v.name); + } + + free(update_head); + update_head = next; + } + update_tail = NULL; + if (upd) + save_local_ip_list(); + pthread_rwlock_unlock(&hostlist_rwlock); + pthread_mutex_unlock(&update_mutex); +} + +static int +check_host(char const *name) +{ + HOSTPING *hp; + UPDATE_ENTRY *uent; + int found; + + FOR_EACH_HOSTPING(hp) { + if (strcmp(hp->name, name) == 0) + return 1; + } + found = 0; + for (uent = update_head; uent; uent = uent->next) { + switch (update_head->type) { + case UPDATE_APPEND: + case UPDATE_REPLACE: + for (hp = uent->v.hlist->head; hp; hp = hp->next) { + if (strcmp(hp->name, name) == 0) { + found++; + break; + } + } + break; + case UPDATE_DELETE: + if (strcmp(uent->v.name, name) == 0) + found--; + } + } + return found; +} + + static int ping_fd; static pthread_mutex_t sendq_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -835,7 +977,6 @@ p903_init(void) if (hostlist->count == 0) { info("no IP addresses configured, starting anyway"); } - hostlist_updated = 0; proto = getprotobyname("icmp"); if (!proto) { @@ -981,15 +1122,6 @@ send_echo(HOSTPING *host, unsigned char *ping_buffer) } } -static void -start_probe(void) -{ - pthread_mutex_lock(&sendq_mutex); - send_p = 1; - pthread_cond_broadcast(&sendq_cond); - pthread_mutex_unlock(&sendq_mutex); -} - static void hostping_commit(HOSTPING *host); void * @@ -1023,7 +1155,6 @@ p903_sender(void *p) send_count = 0; } clock_gettime(CLOCK_MONOTONIC, &ts); - pthread_rwlock_rdlock(&hostlist_rwlock); FOR_EACH_HOSTPING(hp) { struct timespec nts; clock_gettime(CLOCK_MONOTONIC, &nts); @@ -1040,7 +1171,6 @@ p903_sender(void *p) TIMER_ABSTIME, &nts, NULL); } - pthread_rwlock_unlock(&hostlist_rwlock); send_count++; if (send_count == ping_count) send_p = 0; @@ -1223,8 +1353,6 @@ save_local_ip_list(void) HOSTPING *hp; size_t i; - if (!hostlist_updated) - return; info("saving mutable IP address list"); fp = fopen(LOCAL_IP_LIST_FILE, "w"); if (!fp) { @@ -1243,8 +1371,6 @@ save_local_ip_list(void) fprintf(fp, "%s\n", hp->name); } fclose(fp); - - hostlist_updated = 0; } void * @@ -1252,16 +1378,19 @@ p903_scheduler(void *p) { while (1) { HOSTPING *hp; - - pthread_rwlock_rdlock(&hostlist_rwlock); + + pthread_mutex_lock(&sendq_mutex); /* Reset all statistics */ FOR_EACH_HOSTPING(hp) { hostping_reset(hp); } - save_local_ip_list(); - pthread_rwlock_unlock(&hostlist_rwlock); + /* Commit updates */ + update_commit(); - start_probe(); + send_p = 1; + pthread_cond_broadcast(&sendq_cond); + pthread_mutex_unlock(&sendq_mutex); + sleep(probe_interval); if (verbose) info("total sent=%u, received=%u", @@ -1273,9 +1402,7 @@ p903_scheduler(void *p) void * p903_saver(void *p) { - pthread_rwlock_rdlock(&hostlist_rwlock); - save_local_ip_list(); - pthread_rwlock_unlock(&hostlist_rwlock); + update_commit(); return NULL; } |