aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-02-23 21:44:03 +0200
committerSergey Poznyakoff <gray@gnu.org>2020-02-23 21:44:03 +0200
commitd9dfecfa5f1d8e217f1f8a05a261afa5b5f4d6cd (patch)
tree94d6a0f7690434e8b86110104613c111a26f883a
parentf33711d8d90fc069141affff9005b7b146a8f6a3 (diff)
downloadping903-d9dfecfa5f1d8e217f1f8a05a261afa5b5f4d6cd.tar.gz
ping903-d9dfecfa5f1d8e217f1f8a05a261afa5b5f4d6cd.tar.bz2
New API for adding and removing IP addresses on the fly.
* src/config.c (cf_ip_list): Support both parse and serialize calls. * src/ping903.c (/config/ip-list): New endpoint. PUT to add a host or IP to the ip-list, DELETE to remove existing one. * src/ping903.h (hostping_add_name) (hostping_add_name,get_all_hosts): New protos. * src/pinger.c: Protect each iteration over hostping list by a rwlock object. (hostping_delete,get_all_hosts) (hostping_delete_by_name) (hostping_add_name): New functions.
-rw-r--r--src/config.c24
-rw-r--r--src/ping903.c50
-rw-r--r--src/ping903.h3
-rw-r--r--src/pinger.c168
4 files changed, 218 insertions, 27 deletions
diff --git a/src/config.c b/src/config.c
index e8b2f36..f2376a5 100644
--- a/src/config.c
+++ b/src/config.c
@@ -44,7 +44,7 @@ get_num(char const *str, unsigned long *retval,
}
static int
-cf_ip_list(int mode, union cf_callback_arg *arg, void *data)
+cf_ip_list_parse(union cf_callback_arg *arg, void *data)
{
FILE *fp;
char buf[1024];
@@ -53,9 +53,6 @@ cf_ip_list(int mode, union cf_callback_arg *arg, void *data)
int ret = CF_RET_OK;
struct addrinfo hints;
- if (mode != CF_PARSE)
- return CF_RET_IGNORE;
-
fp = fopen(arg->input.val, "r");
if (!fp) {
error("%s:%d: can't open file %s: %s",
@@ -115,6 +112,25 @@ cf_ip_list(int mode, union cf_callback_arg *arg, void *data)
fclose(fp);
return ret;
}
+
+static int
+cf_ip_list_serialize(union cf_callback_arg *arg, void *data)
+{
+ if (get_all_hosts(&arg->output))
+ return CF_RET_FAIL;
+ return CF_RET_OK;
+}
+
+static int
+cf_ip_list(int mode, union cf_callback_arg *arg, void *data)
+{
+ switch (mode) {
+ case CF_PARSE:
+ return cf_ip_list_parse(arg, data);
+ case CF_SERIALIZE:
+ return cf_ip_list_serialize(arg, data);
+ }
+}
struct cf_stmt {
char const *kw;
diff --git a/src/ping903.c b/src/ping903.c
index bda2314..efc6246 100644
--- a/src/ping903.c
+++ b/src/ping903.c
@@ -298,6 +298,52 @@ ept_config(struct MHD_Connection *conn,
}
static int
+ept_ip_delete(struct MHD_Connection *conn,
+ const char *url, const char *method, const char *suffix)
+{
+ 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;
+}
+
+static int
+ept_ip_put(struct MHD_Connection *conn,
+ const char *url, const char *method, const char *suffix)
+{
+ 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))
+ //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;
+}
+
+static int
ept_host_stat(struct MHD_Connection *conn,
const char *url, const char *method, const char *suffix)
{
@@ -402,7 +448,9 @@ struct endpoint {
};
static struct endpoint endpoint[] = {
- { "/config", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_config },
+ { "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_PUT, ept_ip_put },
+ { "/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 },
{ "/ip", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_ip_stat },
{ "/match", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_ip_match },
diff --git a/src/ping903.h b/src/ping903.h
index d7ad922..2f2d7ef 100644
--- a/src/ping903.h
+++ b/src/ping903.h
@@ -59,6 +59,8 @@ 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);
char *get_remote_ip(struct MHD_Connection *conn);
@@ -125,6 +127,7 @@ extern size_t data_length;
struct json_value *config_to_json(void);
int get_hostname_stat(char const *name, struct json_value **retval);
int get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval);
+int get_all_hosts(struct json_value **);
int get_all_host_stat(struct json_value **);
struct addrinfo;
int get_host_matches(struct addrinfo **aip, struct json_value **retval);
diff --git a/src/pinger.c b/src/pinger.c
index 070cbe6..19572d5 100644
--- a/src/pinger.c
+++ b/src/pinger.c
@@ -99,6 +99,7 @@ timespec_incr(struct timespec *a, struct timespec const *b)
static HOSTPING *hostping_head, *hostping_tail;
static size_t hostping_count;
+static pthread_rwlock_t hostping_rwlock = PTHREAD_RWLOCK_INITIALIZER;
void
hostping_add(char const *name, struct sockaddr *addr, socklen_t addrlen)
@@ -123,6 +124,25 @@ hostping_add(char const *name, struct sockaddr *addr, socklen_t addrlen)
hostping_count++;
}
+void
+hostping_delete(HOSTPING *hp)
+{
+ if (hp->prev)
+ hp->prev->next = hp->next;
+ else
+ hostping_head = hp->next;
+ if (hp->next)
+ hp->next->prev = hp->prev;
+ else
+ hostping_tail = hp->prev;
+ hostping_count--;
+
+ free(hp->name);
+ free(hp->addr);
+ pthread_mutex_destroy(&hp->mutex);
+ free(hp);
+}
+
#define FOR_EACH_HOSTPING(hp) for (hp = hostping_head; hp; hp = hp->next)
static inline void
@@ -315,26 +335,36 @@ int
get_hostname_stat(char const *name, struct json_value **retval)
{
HOSTPING *hp;
-
+ int rc = 0;
+
+ *retval = NULL;
+ pthread_rwlock_rdlock(&hostping_rwlock);
FOR_EACH_HOSTPING(hp) {
- if (strcmp(hp->name, name) == 0)
- return get_hostping_stat(hp, retval);
+ if (strcmp(hp->name, name) == 0) {
+ rc = get_hostping_stat(hp, retval);
+ break;
+ }
}
- *retval = NULL;
- return 0;
+ pthread_rwlock_unlock(&hostping_rwlock);
+ return rc;
}
int
get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval)
{
HOSTPING *hp;
-
+ int rc;
+
+ *retval = NULL;
+ pthread_rwlock_rdlock(&hostping_rwlock);
FOR_EACH_HOSTPING(hp) {
if (hp->addrlen == salen
- && memcmp(hp->addr, sa, salen) == 0)
- return get_hostping_stat(hp, retval);
+ && memcmp(hp->addr, sa, salen) == 0) {
+ rc = get_hostping_stat(hp, retval);
+ break;
+ }
}
- *retval = NULL;
+ pthread_rwlock_unlock(&hostping_rwlock);
return 0;
}
@@ -343,23 +373,60 @@ get_all_host_stat(struct json_value **retval)
{
struct json_value *ar;
HOSTPING *hp;
+ int rc = 0;
if (!(ar = json_new_array()))
- goto err;
+ return -1;
+ pthread_rwlock_rdlock(&hostping_rwlock);
FOR_EACH_HOSTPING(hp) {
struct json_value *v;
- if (get_hostping_stat(hp, &v))
- goto err;
+ if (get_hostping_stat(hp, &v)) {
+ rc = -1;
+ break;
+ }
if (json_array_append(ar, v)) {
json_value_free(v);
- goto err;
+ rc = -1;
+ break;
}
}
- *retval = ar;
- return 0;
- err:
- json_value_free(ar);
- return -1;
+ pthread_rwlock_unlock(&hostping_rwlock);
+ if (rc == 0)
+ *retval = ar;
+ else
+ json_value_free(ar);
+ return rc;
+}
+
+int
+get_all_hosts(struct json_value **retval)
+{
+ struct json_value *ar;
+ HOSTPING *hp;
+ int rc = 0;
+
+ if (!(ar = json_new_array()))
+ return -1;
+ pthread_rwlock_rdlock(&hostping_rwlock);
+ FOR_EACH_HOSTPING(hp) {
+ struct json_value *jv;
+ jv = json_new_string(hp->name);
+ if (!jv) {
+ rc = -1;
+ break;
+ }
+ if (json_array_append(ar, jv)) {
+ json_value_free(jv);
+ rc = -1;
+ break;
+ }
+ }
+ pthread_rwlock_unlock(&hostping_rwlock);
+ if (rc == 0)
+ *retval = ar;
+ else
+ json_value_free(ar);
+ return rc;
}
int
@@ -372,7 +439,8 @@ get_host_matches(struct addrinfo **aip, struct json_value **retval)
int ret = -1;
if (!(ar = json_new_array()))
- goto err;
+ return -1;
+ pthread_rwlock_rdlock(&hostping_rwlock);
FOR_EACH_HOSTPING(hp) {
struct addrinfo *prev = NULL, *p;
if (!ai)
@@ -417,6 +485,7 @@ get_host_matches(struct addrinfo **aip, struct json_value **retval)
*retval = ar;
ar = NULL;
err:
+ pthread_rwlock_unlock(&hostping_rwlock);
if (ai_tail) {
ai_tail->ai_next = ai;
*aip = ai_head;
@@ -424,6 +493,57 @@ err:
json_value_free(ar);
return ret;
}
+
+int
+hostping_delete_by_name(char const *name)
+{
+ HOSTPING *hp;
+ int rc = -1;
+
+ pthread_rwlock_wrlock(&hostping_rwlock);
+ FOR_EACH_HOSTPING(hp) {
+ if (strcmp(hp->name, name) == 0) {
+ hostping_delete(hp);
+ rc = 0;
+ break;
+ }
+ }
+ pthread_rwlock_unlock(&hostping_rwlock);
+ return rc;
+}
+
+int
+hostping_add_name(char const *name)
+{
+ int rc = 0;
+ struct addrinfo hints, *res;
+ HOSTPING *hp;
+
+ pthread_rwlock_rdlock(&hostping_rwlock);
+ FOR_EACH_HOSTPING(hp) {
+ if (strcmp(hp->name, name) == 0) {
+ rc = -1;
+ break;
+ }
+ }
+ pthread_rwlock_unlock(&hostping_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;
+ }
+
+ pthread_rwlock_wrlock(&hostping_rwlock);
+ hostping_add(name, res->ai_addr, res->ai_addrlen);
+ pthread_rwlock_unlock(&hostping_rwlock);
+ freeaddrinfo(res);
+ return 0;
+}
static int ping_fd;
@@ -493,8 +613,7 @@ p903_init(void)
int i;
if (hostping_count == 0) {
- fatal("no host IPs configured, nothing to do?");
- exit(1);
+ info("no IP addresses configured, starting anyway");
}
proto = getprotobyname("icmp");
@@ -683,6 +802,7 @@ p903_sender(void *p)
send_count = 0;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
+ pthread_rwlock_rdlock(&hostping_rwlock);
FOR_EACH_HOSTPING(hp) {
struct timespec nts;
clock_gettime(CLOCK_MONOTONIC, &nts);
@@ -699,6 +819,7 @@ p903_sender(void *p)
TIMER_ABSTIME, &nts,
NULL);
}
+ pthread_rwlock_unlock(&hostping_rwlock);
send_count++;
if (send_count == ping_count)
send_p = 0;
@@ -827,11 +948,14 @@ p903_scheduler(void *p)
{
while (1) {
HOSTPING *hp;
-
+
+ pthread_rwlock_rdlock(&hostping_rwlock);
/* Reset all statistics */
FOR_EACH_HOSTPING(hp) {
hostping_reset(hp);
}
+ pthread_rwlock_unlock(&hostping_rwlock);
+
start_probe();
sleep(probe_interval);
if (verbose)

Return to:

Send suggestions and report system problems to the System administrator.