diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-02-24 18:48:35 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-02-24 18:53:26 +0200 |
commit | 2f6ce91c30e4683e819a3a5a2d315e34b01bb1f1 (patch) | |
tree | 9e4f072992b4982dda7d782e9e69d9fce45c6d54 /src | |
parent | a8d1e087fb0c7d378b0104810ecb4b7ab97a1329 (diff) | |
download | ping903-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.
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 7 | ||||
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/ping903.c | 276 | ||||
-rw-r--r-- | src/ping903.h | 10 | ||||
-rw-r--r-- | src/pinger.c | 358 |
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; } @@ -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); |