aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2020-02-24 18:48:35 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2020-02-24 18:53:26 +0200
commit2f6ce91c30e4683e819a3a5a2d315e34b01bb1f1 (patch)
tree9e4f072992b4982dda7d782e9e69d9fce45c6d54
parenta8d1e087fb0c7d378b0104810ecb4b7ab97a1329 (diff)
downloadping903-2f6ce91c30e4683e819a3a5a2d315e34b01bb1f1.tar.gz
ping903-2f6ce91c30e4683e819a3a5a2d315e34b01bb1f1.tar.bz2
New API for adding/replacing multiple IP addresses.
* src/config.c: Update. * src/main.c (main): Call pinger_setup. * src/pinger.c: Major rewrite. * src/ping903.c: Major rewrite. Implement POST /config/ip-list. * src/ping903.h (pinger_setup) (pinger_host_add,pinger_host_delete_by_name) (pinger_host_add_name,pinger_hostlist_set): New protos. (hostping_add,hostping_delete_by_name) (hostping_add_name): Remove.
-rw-r--r--src/config.c7
-rw-r--r--src/main.c1
-rw-r--r--src/ping903.c276
-rw-r--r--src/ping903.h10
-rw-r--r--src/pinger.c358
5 files changed, 497 insertions, 155 deletions
diff --git a/src/config.c b/src/config.c
index 8a5028a..bff22ca 100644
--- a/src/config.c
+++ b/src/config.c
@@ -115,8 +115,13 @@ file_read_ip_list(FILE *fp, char const *fname)
ret = CF_RET_FAIL;
continue;
}
- hostping_add(p, res->ai_addr, res->ai_addrlen);
+ rc = pinger_host_add(p, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
+ if (rc) {
+ error("%s:%d: out of memory");
+ ret = CF_RET_FAIL;
+ break;
+ }
}
return ret;
}
diff --git a/src/main.c b/src/main.c
index 1866cc5..ab630c6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -284,6 +284,7 @@ main(int argc, char **argv)
}
}
+ pinger_setup();
if (readconfig(config_file))
exit(EX_CONFIG);
diff --git a/src/ping903.c b/src/ping903.c
index efc6246..47456a7 100644
--- a/src/ping903.c
+++ b/src/ping903.c
@@ -165,11 +165,10 @@ http_log(struct MHD_Connection *connection,
user_agent ? user_agent : "");
free(ipstr);
}
-
static int
-http_error(struct MHD_Connection *conn,
- char const *method, char const *url, int status)
+http_response(struct MHD_Connection *conn,
+ char const *method, char const *url, int status)
{
int ret;
struct MHD_Response *resp =
@@ -233,6 +232,7 @@ json_to_str(struct json_value *obj)
static int
httpd_json_response(struct MHD_Connection *conn,
char const *url, char const *method,
+ int status,
struct json_value *val)
{
char *reply;
@@ -242,24 +242,25 @@ httpd_json_response(struct MHD_Connection *conn,
reply = json_to_str(val);
json_value_free(val);
if (!reply)
- return http_error(conn, method, url,
+ return http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
resp = MHD_create_response_from_buffer(strlen(reply),
reply, MHD_RESPMEM_MUST_COPY);
- http_log(conn, method, url, MHD_HTTP_OK, reply);
+ http_log(conn, method, url, status, reply);
free(reply);
MHD_add_response_header(resp,
MHD_HTTP_HEADER_CONTENT_TYPE,
"application/json");
- ret = MHD_queue_response(conn, MHD_HTTP_OK, resp);
+ ret = MHD_queue_response(conn, status, resp);
MHD_destroy_response(resp);
return ret;
}
static int
ept_config(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
struct json_value *val;
@@ -268,7 +269,7 @@ ept_config(struct MHD_Connection *conn,
val = config_to_json();
if (!val)
- return http_error(conn, method, url,
+ return http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
if (*suffix) {
@@ -276,7 +277,7 @@ ept_config(struct MHD_Connection *conn,
int ret;
if (json_object_get(val, suffix, &jv)) {
- ret = http_error(conn, method, url,
+ ret = http_response(conn, method, url,
(errno == ENOENT)
? MHD_HTTP_NOT_FOUND
: MHD_HTTP_INTERNAL_SERVER_ERROR);
@@ -285,7 +286,7 @@ ept_config(struct MHD_Connection *conn,
}
if (json_value_copy(jv, &cp)) {
- ret = http_error(conn, method, url,
+ ret = http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
json_value_free(val);
return ret;
@@ -294,58 +295,86 @@ ept_config(struct MHD_Connection *conn,
val = cp;
}
- return httpd_json_response(conn, url, method, val);
+ return httpd_json_response(conn, url, method, MHD_HTTP_OK, val);
}
static int
ept_ip_delete(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
int ret;
- struct MHD_Response *resp;
-
+
while (*suffix == '/')
suffix++;
if (!*suffix)
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
- if (hostping_delete_by_name(suffix))
- return http_error(conn, method, url, MHD_HTTP_NOT_FOUND);
-
- resp = MHD_create_response_from_buffer(0,
- NULL,
- MHD_RESPMEM_PERSISTENT);
- http_log(conn, method, url, MHD_HTTP_OK, NULL);
- ret = MHD_queue_response(conn, MHD_HTTP_OK, resp);
- MHD_destroy_response(resp);
- return ret;
+ return http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
+ if (pinger_host_delete_by_name(suffix))
+ return http_response(conn, method, url, MHD_HTTP_NOT_FOUND);
+ return http_response(conn, method, url, MHD_HTTP_OK);
}
static int
ept_ip_put(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
int ret;
- struct MHD_Response *resp;
while (*suffix == '/')
suffix++;
if (!*suffix)
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
- if (hostping_add_name(suffix))
+ return http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
+ if (pinger_host_add_name(suffix))
//FIXME
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
- resp = MHD_create_response_from_buffer(0,
- NULL,
- MHD_RESPMEM_PERSISTENT);
- http_log(conn, method, url, MHD_HTTP_CREATED, NULL);
- ret = MHD_queue_response(conn, MHD_HTTP_CREATED, resp);
- MHD_destroy_response(resp);
- return ret;
+ return http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
+ return http_response(conn, method, url, MHD_HTTP_CREATED);
+}
+
+static int
+ept_ip_post(struct MHD_Connection *conn,
+ const char *url, const char *method, const char *suffix,
+ struct json_value *obj)
+{
+ char const *err_text;
+ int err_pos;
+ int status;
+
+ status = pinger_hostlist_set(obj, &err_text, &err_pos);
+ if (!err_text && !err_pos)
+ return http_response(conn, method, url, status);
+ else {
+ struct json_value *jv, *err = json_new_object();
+ char *str;
+ int rc;
+
+ if (!err)
+ goto err;
+ if ((jv = json_new_string(err_text)) == NULL)
+ goto err;
+ if (json_object_set(err, "message", jv))
+ goto err;
+ if (err_pos) {
+ if ((jv = json_new_number(err_pos)) == NULL)
+ goto err;
+ if (json_object_set(err, "index", jv))
+ goto err;
+ }
+ str = json_to_str(err);
+ rc = httpd_json_response(conn, url, method, status, err);
+ json_value_free(err);
+ return rc;
+ err:
+ json_value_free(err);
+ return http_response(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ }
}
static int
ept_host_stat(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
struct json_value *val;
int rc;
@@ -359,15 +388,16 @@ ept_host_stat(struct MHD_Connection *conn,
rc = get_hostname_stat(suffix, &val);
}
if (rc)
- return http_error(conn, method, url,
+ return http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
- return httpd_json_response(conn, url, method, val);
+ return httpd_json_response(conn, url, method, MHD_HTTP_OK, val);
}
static int
ept_ip_stat(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
struct json_value *val;
int rc;
@@ -376,7 +406,7 @@ ept_ip_stat(struct MHD_Connection *conn,
suffix++;
if (suffix[0] == 0) {
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ return http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
} else {
int ret;
struct addrinfo hints, *res;
@@ -385,16 +415,17 @@ ept_ip_stat(struct MHD_Connection *conn,
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(suffix, NULL, &hints, &res);
if (rc)
- return http_error(conn, method, url,
+ return http_response(conn, method, url,
MHD_HTTP_NOT_FOUND);
rc = get_ipaddr_stat(res->ai_addr, res->ai_addrlen, &val);
if (rc)
- ret = http_error(conn, method, url,
+ ret = http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
else if (val)
- ret = httpd_json_response(conn, url, method, val);
+ ret = httpd_json_response(conn, url, method,
+ MHD_HTTP_OK, val);
else
- ret = http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ ret = http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
freeaddrinfo(res);
return ret;
}
@@ -402,7 +433,8 @@ ept_ip_stat(struct MHD_Connection *conn,
static int
ept_ip_match(struct MHD_Connection *conn,
- const char *url, const char *method, const char *suffix)
+ const char *url, const char *method, const char *suffix,
+ struct json_value *unused)
{
struct json_value *val;
int rc;
@@ -413,27 +445,28 @@ ept_ip_match(struct MHD_Connection *conn,
suffix++;
if (suffix[0] == 0)
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ return http_response(conn, method, url, MHD_HTTP_FORBIDDEN);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(suffix, NULL, &hints, &res);
if (rc)
- return http_error(conn, method, url, MHD_HTTP_NOT_FOUND);
+ return http_response(conn, method, url, MHD_HTTP_NOT_FOUND);
rc = get_host_matches(&res, &val);
if (rc)
- ret = http_error(conn, method, url,
+ ret = http_response(conn, method, url,
MHD_HTTP_INTERNAL_SERVER_ERROR);
else
- ret = httpd_json_response(conn, url, method, val);
+ ret = httpd_json_response(conn, url, method, MHD_HTTP_OK, val);
freeaddrinfo(res);
return ret;
}
typedef int (*ENDPOINT_HANDLER)(struct MHD_Connection *,
- const char *, const char *, const char *);
+ const char *, const char *, const char *,
+ struct json_value *);
enum {
EPT_EXACT = 0x01,
@@ -449,6 +482,7 @@ struct endpoint {
static struct endpoint endpoint[] = {
{ "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_PUT, ept_ip_put },
+ { "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_POST, ept_ip_post },
{ "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_DELETE, ept_ip_delete },
{ "/config", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_config },
{ "/host", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_host_stat },
@@ -457,28 +491,67 @@ static struct endpoint endpoint[] = {
{ NULL }
};
-static ENDPOINT_HANDLER
-find_endpoint_handler(char const *url, char const *method, char const **suffix)
+static int
+find_endpoint_handler(char const *url, char const *method,
+ ENDPOINT_HANDLER *ret_handler, char const **ret_suffix)
{
struct endpoint *ept;
+ int urlmatch = 0;
for (ept = endpoint; ept->url; ept++) {
- if (strcmp(ept->method, method))
- continue;
if (ept->flags & EPT_EXACT) {
if (strcmp(ept->url, url) == 0) {
- *suffix = url + strlen(url);
- return ept->handler;
+ if (strcmp(ept->method, method)) {
+ urlmatch++;
+ continue;
+ }
+ *ret_handler = ept->handler;
+ *ret_suffix = url + strlen(url);
+ return MHD_HTTP_OK;
}
} else {
size_t len = strlen(ept->url);
if (strncmp(url, ept->url, len) == 0
&& (url[len] == '/' || url[len] == 0)) {
- *suffix = url + len;
- return ept->handler;
+ if (strcmp(ept->method, method)) {
+ urlmatch++;
+ continue;
+ }
+ *ret_handler = ept->handler;
+ *ret_suffix = url + len;
+ return MHD_HTTP_OK;
}
}
}
- return NULL;
+ return urlmatch ? MHD_HTTP_METHOD_NOT_ALLOWED : MHD_HTTP_NOT_FOUND;
+}
+
+struct postbuf {
+ char *base;
+ size_t size;
+ size_t len;
+ ENDPOINT_HANDLER handler;
+ char suffix[1];
+};
+
+static void
+postbuf_free(struct postbuf *pb)
+{
+ free(pb->base);
+ free(pb);
+}
+
+static int
+postbuf_add(struct postbuf *pb, const char *str, size_t len)
+{
+ while (pb->len + len >= pb->size) {
+ char *np = json_2nrealloc(pb->base, &pb->size, 1);
+ if (!np)
+ return -1;
+ pb->base = np;
+ }
+ memcpy(pb->base + pb->len, str, len);
+ pb->len += len;
+ return 0;
}
static int
@@ -491,15 +564,78 @@ p903_httpd_handler(void *cls,
{
ENDPOINT_HANDLER handler;
char const *suffix;
-
- handler = find_endpoint_handler(url, method, &suffix);
- if (handler)
- return handler(conn, url, method, suffix);
-
- if (strcmp(method, MHD_HTTP_METHOD_GET))
- return http_error(conn, method, url,
- MHD_HTTP_METHOD_NOT_ALLOWED);
- return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ int status;
+
+ if (strcmp(method, MHD_HTTP_METHOD_POST) == 0) {
+ struct postbuf *pb;
+
+ if (*con_cls == NULL) {
+ char const *ctype;
+
+ status = find_endpoint_handler(url, method, &handler,
+ &suffix);
+ if (status != MHD_HTTP_OK)
+ return http_response(conn, method, url, status);
+
+ ctype = MHD_lookup_connection_value(conn,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_TYPE);
+ if (!ctype || strcmp(ctype, "application/json"))
+ return http_response(conn, method, url,
+ MHD_HTTP_NOT_ACCEPTABLE);
+
+ pb = malloc(sizeof(*pb) + strlen(suffix));
+ if (!pb)
+ return http_response(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ pb->base = NULL;
+ pb->size = 0;
+ pb->len = 0;
+ pb->handler = handler;
+ strcpy(pb->suffix, suffix);
+ *con_cls = pb;
+ } else {
+ pb = *con_cls;
+ if (*upload_data_size != 0) {
+ if (postbuf_add(pb, upload_data,
+ *upload_data_size)) {
+ postbuf_free(pb);
+ return http_response(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ }
+ *upload_data_size = 0;
+ } else {
+ char *endp;
+ int rc;
+ struct json_value *jv;
+
+ if (postbuf_add(pb, "", 1)) {
+ postbuf_free(pb);
+ return http_response(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ }
+ rc = json_parse_string(pb->base, &jv, &endp);
+ if (rc != JSON_E_NOERR) {
+ error("%s: %s near #%d", url,
+ json_strerror(rc), endp - pb->base);
+ return http_response(conn, method, url,
+ MHD_HTTP_BAD_REQUEST);
+ }
+ rc = pb->handler(conn, url, method, pb->suffix,
+ jv);
+ postbuf_free(pb);
+ json_value_free(jv);
+ return rc;
+ }
+ }
+ return MHD_YES;
+ }
+
+ /* For all other methods */
+ status = find_endpoint_handler(url, method, &handler, &suffix);
+ if (status != MHD_HTTP_OK)
+ return http_response(conn, method, url, status);
+ return handler(conn, url, method, suffix, NULL);
}
void
diff --git a/src/ping903.h b/src/ping903.h
index e24e356..0b3c7b2 100644
--- a/src/ping903.h
+++ b/src/ping903.h
@@ -59,9 +59,13 @@ enum {
int readconfig(char const *file);
int cf_trusted_ip(int mode, union cf_callback_arg *arg, void *data);
int cf_syslog_facility(int mode, union cf_callback_arg *arg, void *data);
-void hostping_add(char const *name, struct sockaddr *addr, socklen_t addrlen);
-int hostping_delete_by_name(char const *name);
-int hostping_add_name(char const *name);
+
+void pinger_setup(void);
+int pinger_host_add(char const *name, struct sockaddr *addr, socklen_t addrlen);
+int pinger_host_delete_by_name(char const *name);
+int pinger_host_add_name(char const *name);
+int pinger_hostlist_set(struct json_value *obj, char const **err_text,
+ int *err_pos);
char *get_remote_ip(struct MHD_Connection *conn);
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.