aboutsummaryrefslogtreecommitdiff
path: root/src/pinger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pinger.c')
-rw-r--r--src/pinger.c329
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;
}

Return to:

Send suggestions and report system problems to the System administrator.