diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-02-23 21:44:03 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-02-23 21:44:03 +0200 |
commit | d9dfecfa5f1d8e217f1f8a05a261afa5b5f4d6cd (patch) | |
tree | 94d6a0f7690434e8b86110104613c111a26f883a | |
parent | f33711d8d90fc069141affff9005b7b146a8f6a3 (diff) | |
download | ping903-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.c | 24 | ||||
-rw-r--r-- | src/ping903.c | 50 | ||||
-rw-r--r-- | src/ping903.h | 3 | ||||
-rw-r--r-- | src/pinger.c | 168 |
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) |