From: Alberto Leiva Popper Date: Thu, 16 Nov 2023 02:37:15 +0000 (-0600) Subject: Adjust metadata.json's namespace X-Git-Tag: 1.6.0~12 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=76f417d3acb70a64531485244e57fb9579010fe4;p=thirdparty%2FFORT-validator.git Adjust metadata.json's namespace Rename some tags: "flags" -> "direct-download", "successful-download", "is-file" "ts_success" -> "success-timestamp" "ts_attempt" -> "attempt-timestamp" "error" -> "latest-result" Only "basename" is mandatory now. Also, move JSON operations to the JSON module. --- diff --git a/src/Makefile.am b/src/Makefile.am index 42517a68..9aa7d768 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,7 @@ fort_SOURCES += daemon.h daemon.c fort_SOURCES += extension.h extension.c fort_SOURCES += file.h file.c fort_SOURCES += init.h init.c -fort_SOURCES += json_parser.c json_parser.h +fort_SOURCES += json_util.c json_util.h fort_SOURCES += line_file.h line_file.c fort_SOURCES += log.h log.c fort_SOURCES += nid.h nid.c diff --git a/src/cache/local_cache.c b/src/cache/local_cache.c index 1d6c0cac..f6116b9d 100644 --- a/src/cache/local_cache.c +++ b/src/cache/local_cache.c @@ -6,6 +6,7 @@ #include "common.h" #include "config.h" #include "file.h" +#include "json_util.h" #include "log.h" #include "rrdp.h" #include "thread_var.h" @@ -30,6 +31,15 @@ * FIXME test max recursion */ +#define TAGNAME_BN "basename" +#define TAGNAME_DIRECT "direct-download" +#define TAGNAME_ERROR "latest-result" +#define TAGNAME_TSATTEMPT "attempt-timestamp" +#define TAGNAME_SUCCESS "successful-download" +#define TAGNAME_TSSUCCESS "success-timestamp" +#define TAGNAME_FILE "is-file" +#define TAGNAME_CHILDREN "children" + /* * Have we ever attempted to download this directly? * Otherwise we actually downloaded a descendant. @@ -82,7 +92,6 @@ struct rpki_cache { time_t startup_time; /* When we started the last validation */ }; - static struct cache_node * add_child(struct cache_node *parent, char const *basename) { @@ -159,90 +168,60 @@ get_metadata_json_filename(char const *tal, char **filename) return 0; } -static int -json_tt_value(struct json_t const *json, time_t *result) -{ - char const *str; - struct tm tm; - time_t tmp; - - if (json == NULL) - return -1; - str = json_string_value(json); - if (str == NULL) - return -1; - str = strptime(str, "%FT%T%z", &tm); - if (str == NULL || *str != 0) - return -1; - tmp = mktime(&tm); - if (tmp == ((time_t) -1)) - return -1; - - *result = tmp; - return 0; -} - static struct cache_node * json2node(json_t *json, struct cache_node *parent) { struct cache_node *node, *child; char const *string; + bool boolean; json_t *jchild; size_t c; + int error; if (json == NULL) return NULL; node = pzalloc(sizeof(struct cache_node)); - string = json_string_value(json_object_get(json, "basename")); - if (string == NULL) { - pr_op_warn("Tag 'basename' of a metadata.json's download node cannot be parsed as a string; skipping."); + error = json_get_str(json, TAGNAME_BN, &string); + if (error) { + if (error > 0) + pr_op_err("Node is missing the '" TAGNAME_BN "' tag."); goto cancel; } node->basename = pstrdup(string); - jchild = json_object_get(json, "flags"); - if (!json_is_integer(jchild)) { - pr_op_warn("Tag 'flags' of metadata.json's download node '%s' cannot be parsed as an integer; skipping.", - node->basename); + if (json_get_bool(json, TAGNAME_DIRECT, &boolean) < 0) goto cancel; - } - node->flags = json_integer_value(jchild); + if (boolean) { + node->flags |= CNF_DIRECT; + if (json_get_int(json, TAGNAME_ERROR, &node->error) < 0) + goto cancel; - if (json_tt_value(json_object_get(json, "ts_success"), &node->ts_success)) { - pr_op_warn("Tag 'success' of metadata.json's download node '%s' cannot be parsed as a date; skipping.", - node->basename); - goto cancel; - } + if (json_get_ts(json, TAGNAME_TSATTEMPT, &node->ts_attempt) < 0) + goto cancel; - if (json_tt_value(json_object_get(json, "ts_attempt"), &node->ts_attempt)) { - pr_op_warn("Tag 'attempt' of metadata.json's download node '%s' cannot be parsed as a date; skipping.", - node->basename); - goto cancel; + if (json_get_bool(json, TAGNAME_SUCCESS, &boolean) < 0) + goto cancel; + if (boolean) { + node->flags |= CNF_SUCCESS; + if (json_get_ts(json, TAGNAME_TSSUCCESS, &node->ts_success) < 0) + goto cancel; + } } - jchild = json_object_get(json, "error"); - if (!json_is_integer(jchild)) { - pr_op_warn("Tag 'error' of metadata.json's download node '%s' cannot be parsed as an integer; skipping.", - node->basename); + if (json_get_bool(json, TAGNAME_FILE, &boolean) < 0) goto cancel; - } - node->error = json_integer_value(jchild); + if (boolean) + node->flags |= CNF_FILE; - jchild = json_object_get(json, "children"); - if (jchild != NULL && !json_is_array(jchild)) { - pr_op_warn("Tag 'children' of metadata.json's download node '%s' cannot be parsed as an array; skipping.", - node->basename); + if (json_get_array(json, "children", &jchild) < 0) goto cancel; - } - for (c = 0; c < json_array_size(jchild); c++) { child = json2node(json_array_get(jchild, c), node); - if (child == NULL) - goto cancel; - HASH_ADD_KEYPTR(hh, node->children, child->basename, - strlen(child->basename), child); + if (child != NULL) + HASH_ADD_KEYPTR(hh, node->children, child->basename, + strlen(child->basename), child); } node->parent = parent; @@ -308,29 +287,12 @@ end: json_decref(root); } -static int -tt2json(time_t tt, json_t **result) -{ - char str[32]; - struct tm tmbuffer, *tm; - - memset(&tmbuffer, 0, sizeof(tmbuffer)); - tm = localtime_r(&tt, &tmbuffer); - if (tm == NULL) - return errno; - if (strftime(str, sizeof(str) - 1, "%FT%T%z", tm) == 0) - return ENOSPC; - - *result = json_string(str); - return 0; -} - static json_t * node2json(struct cache_node *node) { - json_t *json, *date, *children, *jchild; + json_t *json, *children, *jchild; struct cache_node *child, *tmp; - int error; + int cnf; json = json_object(); if (json == NULL) { @@ -338,47 +300,28 @@ node2json(struct cache_node *node) return NULL; } - if (json_object_set_new(json, "basename", json_string(node->basename))) { - pr_op_err("Cannot convert string '%s' to json; unknown cause.", - node->basename); + if (json_add_str(json, TAGNAME_BN, node->basename)) goto cancel; - } - if (json_object_set_new(json, "flags", json_integer(node->flags))) { - pr_op_err("Cannot convert int '%d' to json; unknown cause.", - node->flags); - goto cancel; - } - - error = tt2json(node->ts_success, &date); - if (error) { - pr_op_err("Cannot convert %s's success timestamp to json: %s", - node->basename, strerror(error)); - goto cancel; - } - if (json_object_set_new(json, "ts_success", date)) { - pr_op_err("Cannot convert %s's success timestamp to json; unknown cause.", - node->basename); - goto cancel; - } - - error = tt2json(node->ts_attempt, &date); - if (error) { - pr_op_err("Cannot convert %s's attempt timestamp to json: %s", - node->basename, strerror(error)); - goto cancel; - } - if (json_object_set_new(json, "ts_attempt", date)) { - pr_op_err("Cannot convert %s's attempt timestamp to json; unknown cause.", - node->basename); - goto cancel; + cnf = node->flags & CNF_DIRECT; + if (cnf) { + if (json_add_bool(json, TAGNAME_DIRECT, cnf)) + goto cancel; + if (json_add_int(json, TAGNAME_ERROR, node->error)) + goto cancel; + if (json_add_date(json, TAGNAME_TSATTEMPT, node->ts_attempt)) + goto cancel; + cnf = node->flags & CNF_SUCCESS; + if (cnf) { + if (json_add_bool(json, TAGNAME_SUCCESS, cnf)) + goto cancel; + if (json_add_date(json, TAGNAME_TSSUCCESS, node->ts_success)) + goto cancel; + } } - - if (json_object_set_new(json, "error", json_integer(node->error))) { - pr_op_err("Cannot convert int '%d' to json; unknown cause.", - node->error); + cnf = node->flags & CNF_FILE; + if (cnf && json_add_bool(json, TAGNAME_FILE, cnf)) goto cancel; - } if (node->children != NULL) { children = json_array(); @@ -387,7 +330,7 @@ node2json(struct cache_node *node) return NULL; } - if (json_object_set_new(json, "children", children)) { + if (json_object_set_new(json, TAGNAME_CHILDREN, children)) { pr_op_err("Cannot push children array into json node; unknown cause."); goto cancel; } diff --git a/src/incidence/incidence.c b/src/incidence/incidence.c index e8689394..dc5e4980 100644 --- a/src/incidence/incidence.c +++ b/src/incidence/incidence.c @@ -2,7 +2,7 @@ #include #include "common.h" -#include "json_parser.h" +#include "json_util.h" #include "log.h" #include "data_structure/common.h" @@ -93,15 +93,20 @@ init_action(json_t *json) int error; id = __INID_MAX; - error = json_get_string(json, "name", &name); - if (error) + error = json_get_str(json, "name", &name); + if (error < 0) return error; + if (error > 0) + return pr_op_err("Incidence is missing the 'name' tag."); error = name2id(name, &id); if (error) return error; - error = json_get_string(json, "action", &action_str); - if (error) + error = json_get_str(json, "action", &action_str); + if (error < 0) return error; + if (error > 0) + return pr_op_err("Incidence '%s' is missing the 'action' tag.", + name); if (strcmp("ignore", action_str) == 0) action = INAC_IGNORE; diff --git a/src/json_parser.c b/src/json_parser.c deleted file mode 100644 index 9dbb21ed..00000000 --- a/src/json_parser.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "json_parser.h" - -#include -#include "log.h" - -/* - * Try to get member @name from @parent as a char const *. On success, set - * @result with the members value. - * - * Returns 0 on success, -ENOENT if the @name doesn't exists, -EINVAL if the - * member isn't a JSON integer. - */ -int -json_get_string(json_t *parent, char const *name, char const **result) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) { - *result = NULL; - return -ENOENT; - } - - if (!json_is_string(child)) { - *result = NULL; - return pr_op_err("The '%s' element is not a JSON string.", name); - } - - *result = json_string_value(child); - return 0; -} - -/* - * Try to get member @name from @parent as a json_int_t. On success, set - * @result with the members value. - * - * Returns 0 on success, -ENOENT if the @name doesn't exists, -EINVAL if the - * member isn't a JSON integer. - */ -int -json_get_int(json_t *parent, char const *name, json_int_t *result) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) - return -ENOENT; - - if (!json_is_integer(child)) - return pr_op_err("The '%s' element is not a JSON integer.", name); - - *result = json_integer_value(child); - return 0; -} - -json_t * -json_get_array(json_t *parent, char const *name) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) - return NULL; - - if (!json_is_array(child)) { - pr_op_err("The '%s' element is not a JSON array.", name); - return NULL; - } - - return child; -} - -json_t * -json_get_object(json_t *parent, char const *name) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) - return NULL; - - if (!json_is_object(child)) { - pr_op_err("The '%s' element is not a JSON object.", name); - return NULL; - } - - return child; -} - -/* - * Any unknown members should be treated as errors, RFC8416 3.1: - * "JSON members that are not defined here MUST NOT be used in SLURM - * files. An RP MUST consider any deviations from the specifications to - * be errors." - */ -bool -json_valid_members_count(json_t *object, size_t expected_size) -{ - return json_object_size(object) == expected_size; -} diff --git a/src/json_parser.h b/src/json_parser.h deleted file mode 100644 index 2c183d17..00000000 --- a/src/json_parser.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SRC_JSON_PARSER_H_ -#define SRC_JSON_PARSER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int json_get_string(json_t *, char const *, char const **); -int json_get_int(json_t *, char const *, json_int_t *); -json_t *json_get_array(json_t *, char const *); -json_t *json_get_object(json_t *, char const *); - -bool json_valid_members_count(json_t *, size_t); - -#endif /* SRC_JSON_PARSER_H_ */ diff --git a/src/json_util.c b/src/json_util.c new file mode 100644 index 00000000..a89caa72 --- /dev/null +++ b/src/json_util.c @@ -0,0 +1,251 @@ +#include "json_util.h" + +#include +#include +#include "log.h" + +int +json_get_str(json_t *parent, char const *name, char const **result) +{ + json_t *child; + + *result = NULL; + + child = json_object_get(parent, name); + if (child == NULL) + return ENOENT; + + if (!json_is_string(child)) + return pr_op_err("Tag '%s' is not a JSON string.", name); + + *result = json_string_value(child); + return 0; +} + +int +json_get_bool(json_t *parent, char const *name, bool *result) +{ + json_t *child; + + *result = false; + + child = json_object_get(parent, name); + if (child == NULL) + return ENOENT; + + if (!json_is_boolean(child)) + return pr_op_err("Tag '%s' is not a JSON boolean.", name); + + *result = json_boolean_value(child); + return 0; +} + +static int +json_get_int_t(json_t *parent, char const *name, json_int_t *result) +{ + json_t *child; + + *result = 0; + + child = json_object_get(parent, name); + if (child == NULL) + return ENOENT; + + if (!json_is_integer(child)) + return pr_op_err("Tag '%s' is not a JSON integer.", name); + + *result = json_integer_value(child); + return 0; +} + +int +json_get_int(json_t *parent, char const *name, int *result) +{ + json_int_t json_int; + int error; + + *result = 0; + + error = json_get_int_t(parent, name, &json_int); + if (error) + return error; + if (json_int < INT_MIN || INT_MAX < json_int) + return pr_op_err("Tag '%s' (%" JSON_INTEGER_FORMAT + ") is out of range [%d, %d].", + name, json_int, INT_MIN, INT_MAX); + + *result = json_int; + return 0; +} + +int +json_get_u32(json_t *parent, char const *name, uint32_t *result) +{ + json_int_t json_int; + int error; + + *result = 0; + + error = json_get_int_t(parent, name, &json_int); + if (error) + return error; + if (json_int < 0 || UINT32_MAX < json_int) + return pr_op_err("Tag '%s' (%" JSON_INTEGER_FORMAT + ") is out of range [0, %u].", + name, json_int, UINT32_MAX); + + *result = json_int; + return 0; +} + +int +json_get_ts(json_t *parent, char const *name, time_t *result) +{ + char const *str, *consumed; + struct tm tm; + time_t time; + int error; + + *result = 0; + + error = json_get_str(parent, name, &str); + if (error) + return error; + + consumed = strptime(str, "%FT%T%z", &tm); + if (consumed == NULL || (*consumed) != 0) + return pr_op_err("String '%s' does not appear to be a timestamp.", + str); + time = mktime(&tm); + if (time == ((time_t) -1)) { + error = errno; + return pr_op_err("String '%s' does not appear to be a timestamp: %s", + str, strerror(error)); + } + + *result = time; + return 0; +} + +int +json_get_array(json_t *parent, char const *name, json_t **array) +{ + json_t *child; + + *array = NULL; + + child = json_object_get(parent, name); + if (child == NULL) + return ENOENT; + + if (!json_is_array(child)) + return pr_op_err("Tag '%s' is not a JSON array.", name); + + *array = child; + return 0; +} + +int +json_get_object(json_t *parent, char const *name, json_t **obj) +{ + json_t *child; + + *obj = NULL; + + child = json_object_get(parent, name); + if (child == NULL) + return ENOENT; + + if (!json_is_object(child)) + return pr_op_err("Tag '%s' is not a JSON object.", name); + + *obj = child; + return 0; +} + +/* + * Any unknown members should be treated as errors, RFC8416 3.1: + * "JSON members that are not defined here MUST NOT be used in SLURM + * files. An RP MUST consider any deviations from the specifications to + * be errors." + */ +bool +json_valid_members_count(json_t *object, size_t expected_size) +{ + return json_object_size(object) == expected_size; +} + +int +json_add_bool(json_t *parent, char const *name, bool value) +{ + if (json_object_set_new(parent, name, json_boolean(value))) + return pr_op_err( + "Cannot convert %s '%u' to json; unknown cause.", + name, value + ); + + return 0; +} + +int +json_add_int(json_t *parent, char const *name, int value) +{ + if (json_object_set_new(parent, name, json_integer(value))) + return pr_op_err( + "Cannot convert %s '%d' to json; unknown cause.", + name, value + ); + + return 0; +} + +int +json_add_str(json_t *parent, char const *name, char const *value) +{ + if (json_object_set_new(parent, name, json_string(value))) + return pr_op_err( + "Cannot convert %s '%s' to json; unknown cause.", + name, value + ); + + return 0; +} + +static int +tt2json(time_t tt, json_t **result) +{ + char str[32]; + struct tm tmbuffer, *tm; + + memset(&tmbuffer, 0, sizeof(tmbuffer)); + tm = localtime_r(&tt, &tmbuffer); + if (tm == NULL) + return errno; + if (strftime(str, sizeof(str) - 1, "%FT%T%z", tm) == 0) + return ENOSPC; + + *result = json_string(str); + return 0; +} + +int +json_add_date(json_t *parent, char const *name, time_t value) +{ + json_t *date = NULL; + int error; + + error = tt2json(value, &date); + if (error) { + pr_op_err("Cannot convert timestamp '%s' to json: %s", + name, strerror(error)); + return error; + } + + if (json_object_set_new(parent, name, date)) + return pr_op_err( + "Cannot convert timestamp '%s' to json; unknown cause.", + name + ); + + return 0; +} diff --git a/src/json_util.h b/src/json_util.h new file mode 100644 index 00000000..ebb98fa1 --- /dev/null +++ b/src/json_util.h @@ -0,0 +1,39 @@ +#ifndef SRC_JSON_UTIL_H_ +#define SRC_JSON_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Contract of get functions: + * + * result = 0: Tag parsed successfully, out param populated. + * result > 0: Tag was nonexistent, outbound param reset (0 or NULL), not logged + * result < 0: Tag was fatally invalid, outbound param reset, logged + */ + +int json_get_bool(json_t *, char const *, bool *); +int json_get_int(json_t *, char const *, int *); +int json_get_u32(json_t *, char const *, uint32_t *); +int json_get_ts(json_t *, char const *, time_t *); +int json_get_str(json_t *, char const *, char const **); +int json_get_array(json_t *, char const *, json_t **); +int json_get_object(json_t *, char const *, json_t **); + +bool json_valid_members_count(json_t *, size_t); + +int json_add_bool(json_t *, char const *, bool); +int json_add_int(json_t *, char const *, int); +int json_add_str(json_t *, char const *, char const *); +int json_add_date(json_t *, char const *, time_t); + +#endif /* SRC_JSON_UTIL_H_ */ diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index dbedd118..01d23d3c 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -189,7 +189,7 @@ log_buffer(char const *buffer, ssize_t read, int type) if (type == 0) { pr_val_err(PRE_RSYNC "%s", cur); } else { - pr_val_info(PRE_RSYNC "%s", cur); + pr_val_debug(PRE_RSYNC "%s", cur); } cur = tmp + 1; } diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c index 3aa13c0c..ad5a7d88 100644 --- a/src/slurm/slurm_parser.c +++ b/src/slurm/slurm_parser.c @@ -6,8 +6,8 @@ #include "crypto/base64.h" #include "algorithm.h" #include "alloc.h" +#include "json_util.h" #include "log.h" -#include "json_parser.h" #include "types/address.h" #include "types/router_key.h" #include "slurm/db_slurm.h" @@ -29,9 +29,7 @@ #define ROUTER_PUBLIC_KEY "routerPublicKey" #define COMMENT "comment" -#define CHECK_REQUIRED(element, name) \ - if (element == NULL) \ - return pr_op_err("SLURM member '%s' is required", name); +#define COMPLAIN_REQUIRED(name) pr_op_err("SLURM member '" name "' is required") static int handle_json(json_t *, struct db_slurm *); @@ -64,25 +62,16 @@ static int set_asn(json_t *object, bool is_assertion, uint32_t *result, uint8_t *flag, size_t *members_loaded) { - json_int_t int_tmp; int error; - int_tmp = 0; - error = json_get_int(object, ASN, &int_tmp); - if (error == -ENOENT) { - if (is_assertion) - return pr_op_err("ASN is required"); - else - return 0; /* Optional for filters */ - } else if (error) + error = json_get_u32(object, ASN, result); + if (error < 0) return error; + if (error > 0) + /* Optional for filters */ + return is_assertion ? pr_op_err("ASN is required") : 0; - /* An underflow or overflow will be considered here */ - if (int_tmp < 0 || UINT32_MAX < int_tmp) - return pr_op_err("ASN (%lld) is out of range [0 - %u].", int_tmp, - UINT32_MAX); *flag = *flag | SLURM_COM_FLAG_ASN; - *result = (uint32_t) int_tmp; (*members_loaded)++; return 0; } @@ -91,14 +80,14 @@ set_asn(json_t *object, bool is_assertion, uint32_t *result, uint8_t *flag, static int set_comment(json_t *object, uint8_t *flag, size_t *members_loaded) { - char const *tmp; + char const *comment; int error; - error = json_get_string(object, COMMENT, &tmp); - if (error && error == -ENOENT) - return 0; /* Optional member */ - else if (error) + error = json_get_str(object, COMMENT, &comment); + if (error < 0) return error; + if (comment == NULL) + return 0; *flag = *flag | SLURM_COM_FLAG_COMMENT; (*members_loaded)++; @@ -118,14 +107,14 @@ set_prefix(json_t *object, bool is_assertion, struct slurm_prefix *result, int error; /* First part: Prefix in string format */ - error = json_get_string(object, PREFIX, &str_prefix); - if (error && error == -ENOENT) { - if (is_assertion) - return pr_op_err("SLURM assertion prefix is required"); - else - return 0; /* Optional for filters */ - } else if (error) + error = json_get_str(object, PREFIX, &str_prefix); + if (error < 0) return error; + if (str_prefix == NULL) { + return is_assertion + ? pr_op_err("SLURM assertion prefix is required") + : 0; /* Optional for filters */ + } clone = pstrdup(str_prefix); @@ -174,28 +163,31 @@ static int set_max_prefix_length(json_t *object, bool is_assertion, uint8_t addr_fam, uint8_t *result, uint8_t *flag, size_t *members_loaded) { - json_int_t int_tmp; + uint32_t u32; + unsigned int max; int error; - int_tmp = 0; - error = json_get_int(object, MAX_PREFIX_LENGTH, &int_tmp); - if (error == -ENOENT) - return 0; /* Optional for assertions, unsupported by filters */ - - if (error && is_assertion) + error = json_get_u32(object, MAX_PREFIX_LENGTH, &u32); + if (error < 0) return error; - /* Unsupported by filters */ + /* Filters */ if (!is_assertion) - return pr_op_err("Prefix filter can't have a max prefix length"); + return (error == 0) + ? pr_op_err("Prefix filter can't have a max prefix length") + : 0; - /* An underflow or overflow will be considered here */ - if (int_tmp <= 0 || (addr_fam == AF_INET ? 32 : 128) < int_tmp) - return pr_op_err("Max prefix length (%lld) is out of range [1 - %d].", - int_tmp, (addr_fam == AF_INET) ? 32 : 128); + /* Assertions */ + if (error > 0) + return 0; + + max = (addr_fam == AF_INET) ? 32 : 128; + if (max < u32) + return pr_op_err("Max prefix length (%u) is out of range [0, %u].", + u32, max); *flag = *flag | SLURM_PFX_FLAG_MAX_LENGTH; - *result = (uint8_t) int_tmp; + *result = (uint8_t) u32; (*members_loaded)++; return 0; @@ -237,14 +229,13 @@ set_ski(json_t *object, bool is_assertion, struct slurm_bgpsec *result, size_t ski_len; int error; - error = json_get_string(object, SKI, &str_encoded); - if (error && error == -ENOENT) { - if (is_assertion) - return pr_op_err("SLURM assertion %s is required", SKI); - else - return 0; /* Optional for filters */ - } else if (error) + error = json_get_str(object, SKI, &str_encoded); + if (error < 0) return error; + if (str_encoded == NULL) + return is_assertion + ? pr_op_err("SLURM assertion %s is required", SKI) + : 0; /* Optional for filters */ error = validate_base64url_encoded(str_encoded); if (error) @@ -303,21 +294,20 @@ set_router_pub_key(json_t *object, bool is_assertion, size_t spk_len; int error; - error = json_get_string(object, ROUTER_PUBLIC_KEY, &str_encoded); - if (error == -ENOENT && !is_assertion) - return 0; /* OK for filters */ - - /* Required by assertions */ - if (error && is_assertion) { - if (error == -ENOENT) - return pr_op_err("SLURM assertion %s is required", - ROUTER_PUBLIC_KEY); + error = json_get_str(object, ROUTER_PUBLIC_KEY, &str_encoded); + if (error < 0) return error; - } - /* Unsupported by filters */ + /* Filters */ if (!is_assertion) - return pr_op_err("BGPsec filter can't have a router public key"); + return (error == 0) + ? pr_op_err("BGPsec filter can't have a router public key") + : 0; + + /* Assertions */ + if (str_encoded == NULL) + return pr_op_err("SLURM assertion %s is required", + ROUTER_PUBLIC_KEY); error = validate_base64url_encoded(str_encoded); if (error) @@ -577,19 +567,18 @@ load_bgpsec_array(json_t *array, struct db_slurm *db, bool is_assertion) static int load_version(json_t *root) { - json_int_t version; + uint32_t version; int error; - version = -1; - error = json_get_int(root, SLURM_VERSION, &version); - if (error) - return (error == -ENOENT) ? - pr_op_err("SLURM member '"SLURM_VERSION"' is required.") : - error; + error = json_get_u32(root, SLURM_VERSION, &version); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(SLURM_VERSION); /* Validate data */ if (version != 1) - return pr_op_err("'%s' must be 1", SLURM_VERSION); + return pr_op_err("'" SLURM_VERSION "' must be 1"); return 0; } @@ -601,14 +590,23 @@ load_filters(json_t *root, struct db_slurm *db) size_t expected_members; int error; - filters = json_get_object(root, VALIDATION_OUTPUT_FILTERS); - CHECK_REQUIRED(filters, VALIDATION_OUTPUT_FILTERS) + error = json_get_object(root, VALIDATION_OUTPUT_FILTERS, &filters); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(VALIDATION_OUTPUT_FILTERS); - prefix = json_get_array(filters, PREFIX_FILTERS); - CHECK_REQUIRED(prefix, PREFIX_FILTERS) + error = json_get_array(filters, PREFIX_FILTERS, &prefix); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(PREFIX_FILTERS); - bgpsec = json_get_array(filters, BGPSEC_FILTERS); - CHECK_REQUIRED(bgpsec, BGPSEC_FILTERS) + error = json_get_array(filters, BGPSEC_FILTERS, &bgpsec); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(BGPSEC_FILTERS); expected_members = 2; if (!json_valid_members_count(filters, expected_members)) @@ -636,14 +634,23 @@ load_assertions(json_t *root, struct db_slurm *db) size_t expected_members; int error; - assertions = json_get_object(root, LOCALLY_ADDED_ASSERTIONS); - CHECK_REQUIRED(assertions, LOCALLY_ADDED_ASSERTIONS) + error = json_get_object(root, LOCALLY_ADDED_ASSERTIONS, &assertions); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(LOCALLY_ADDED_ASSERTIONS); - prefix = json_get_array(assertions, PREFIX_ASSERTIONS); - CHECK_REQUIRED(prefix, PREFIX_ASSERTIONS) + error = json_get_array(assertions, PREFIX_ASSERTIONS, &prefix); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(PREFIX_ASSERTIONS); - bgpsec = json_get_array(assertions, BGPSEC_ASSERTIONS); - CHECK_REQUIRED(bgpsec, BGPSEC_ASSERTIONS) + error = json_get_array(assertions, BGPSEC_ASSERTIONS, &bgpsec); + if (error < 0) + return error; + if (error > 0) + return COMPLAIN_REQUIRED(BGPSEC_ASSERTIONS); expected_members = 2; if (!json_valid_members_count(assertions, expected_members)) diff --git a/test/cache/local_cache_test.c b/test/cache/local_cache_test.c index e7199222..dfb10220 100644 --- a/test/cache/local_cache_test.c +++ b/test/cache/local_cache_test.c @@ -8,6 +8,7 @@ #include "alloc.c" #include "common.c" #include "file.c" +#include "json_util.c" #include "mock.c" #include "data_structure/path_builder.c" #include "types/uri.c" @@ -986,12 +987,12 @@ START_TEST(test_metadata_json) cache->rsync = TNODE("rsync", 0, NOW + 0, NOW + 1, 0, TNODE("a.b.c", 0, NOW + 2, NOW + 3, 0, TNODE("d", SUCCESS, NOW + 4, NOW + 5, 0), - TNODE("e", SUCCESS, NOW + 6, NOW + 7, 0)), + TNODE("e", CNF_DIRECT, NOW + 6, NOW + 7, 1)), TNODE("x.y.z", 0, NOW + 8, NOW + 9, 0, TNODE("w", SUCCESS, NOW + 0, NOW + 1, 0))); cache->https = TNODE("https", 0, NOW + 2, NOW + 3, 0, TNODE("a", 0, NOW + 4, NOW + 5, 0, - TNODE("b", HTTP_SUCCESS, NOW + 6, NOW + 7, 0), + TNODE("b", HTTP_SUCCESS, NOW + 6, NOW + 7, 1), TNODE("c", HTTP_SUCCESS, NOW + 8, NOW + 9, 0))); json = build_metadata_json(cache); @@ -1001,35 +1002,39 @@ START_TEST(test_metadata_json) /* printf("%s\n", str); */ json_decref(json); + /* TODO (test) Time zones are hardcoded to CST */ ck_assert_str_eq( - "[{\"basename\":\"rsync\",\"flags\":0,\"ts_success\":\"2023-09-05T16:23:30-0600\",\"ts_attempt\":\"2023-09-05T16:23:31-0600\",\"error\":0,\"children\":[" - "{\"basename\":\"a.b.c\",\"flags\":0,\"ts_success\":\"2023-09-05T16:23:32-0600\",\"ts_attempt\":\"2023-09-05T16:23:33-0600\",\"error\":0,\"children\":[" - "{\"basename\":\"d\",\"flags\":3,\"ts_success\":\"2023-09-05T16:23:34-0600\",\"ts_attempt\":\"2023-09-05T16:23:35-0600\",\"error\":0}," - "{\"basename\":\"e\",\"flags\":3,\"ts_success\":\"2023-09-05T16:23:36-0600\",\"ts_attempt\":\"2023-09-05T16:23:37-0600\",\"error\":0}]}," - "{\"basename\":\"x.y.z\",\"flags\":0,\"ts_success\":\"2023-09-05T16:23:38-0600\",\"ts_attempt\":\"2023-09-05T16:23:39-0600\",\"error\":0,\"children\":[" - "{\"basename\":\"w\",\"flags\":3,\"ts_success\":\"2023-09-05T16:23:30-0600\",\"ts_attempt\":\"2023-09-05T16:23:31-0600\",\"error\":0}]}]}," - "{\"basename\":\"https\",\"flags\":0,\"ts_success\":\"2023-09-05T16:23:32-0600\",\"ts_attempt\":\"2023-09-05T16:23:33-0600\",\"error\":0,\"children\":[" - "{\"basename\":\"a\",\"flags\":0,\"ts_success\":\"2023-09-05T16:23:34-0600\",\"ts_attempt\":\"2023-09-05T16:23:35-0600\",\"error\":0,\"children\":[" - "{\"basename\":\"b\",\"flags\":11,\"ts_success\":\"2023-09-05T16:23:36-0600\",\"ts_attempt\":\"2023-09-05T16:23:37-0600\",\"error\":0}," - "{\"basename\":\"c\",\"flags\":11,\"ts_success\":\"2023-09-05T16:23:38-0600\",\"ts_attempt\":\"2023-09-05T16:23:39-0600\",\"error\":0}]}]}]", + "[{\"basename\":\"rsync\",\"children\":[" + "{\"basename\":\"a.b.c\",\"children\":[" + "{\"basename\":\"d\",\"direct-download\":true,\"latest-result\":0,\"attempt-timestamp\":\"2023-09-05T16:23:35-0600\",\"successful-download\":true,\"success-timestamp\":\"2023-09-05T16:23:34-0600\"}," + "{\"basename\":\"e\",\"direct-download\":true,\"latest-result\":1,\"attempt-timestamp\":\"2023-09-05T16:23:37-0600\"}]}," + "{\"basename\":\"x.y.z\",\"children\":[" + "{\"basename\":\"w\",\"direct-download\":true,\"latest-result\":0,\"attempt-timestamp\":\"2023-09-05T16:23:31-0600\",\"successful-download\":true,\"success-timestamp\":\"2023-09-05T16:23:30-0600\"}]}]}," + "{\"basename\":\"https\",\"children\":[" + "{\"basename\":\"a\",\"children\":[" + "{\"basename\":\"b\",\"direct-download\":true,\"latest-result\":1,\"attempt-timestamp\":\"2023-09-05T16:23:37-0600\",\"successful-download\":true,\"success-timestamp\":\"2023-09-05T16:23:36-0600\",\"is-file\":true}," + "{\"basename\":\"c\",\"direct-download\":true,\"latest-result\":0,\"attempt-timestamp\":\"2023-09-05T16:23:39-0600\",\"successful-download\":true,\"success-timestamp\":\"2023-09-05T16:23:38-0600\",\"is-file\":true}]}]}]", str); free(str); cache_reset(cache); load_metadata_json(cache); + ck_assert_ptr_nonnull(cache->rsync); + ck_assert_ptr_nonnull(cache->https); + validate_trees(cache->rsync, - TNODE("rsync", 0, NOW + 0, NOW + 1, 0, - TNODE("a.b.c", 0, NOW + 2, NOW + 3, 0, + TNODE("rsync", 0, 0, 0, 0, + TNODE("a.b.c", 0, 0, 0, 0, TNODE("d", SUCCESS, NOW + 4, NOW + 5, 0), - TNODE("e", SUCCESS, NOW + 6, NOW + 7, 0)), - TNODE("x.y.z", 0, NOW + 8, NOW + 9, 0, + TNODE("e", CNF_DIRECT, NOW + 6, NOW + 7, 1)), + TNODE("x.y.z", 0, 0, 0, 0, TNODE("w", SUCCESS, NOW + 0, NOW + 1, 0))), NULL); validate_trees(cache->https, - TNODE("https", 0, NOW + 2, NOW + 3, 0, - TNODE("a", 0, NOW + 4, NOW + 5, 0, - TNODE("b", HTTP_SUCCESS, NOW + 6, NOW + 7, 0), + TNODE("https", 0, 0, 0, 0, + TNODE("a", 0, 0, 0, 0, + TNODE("b", HTTP_SUCCESS, NOW + 6, NOW + 7, 1), TNODE("c", HTTP_SUCCESS, NOW + 8, NOW + 9, 0))), NULL); diff --git a/test/rtr/db/vrps_test.c b/test/rtr/db/vrps_test.c index 97f34acb..2a4f3679 100644 --- a/test/rtr/db/vrps_test.c +++ b/test/rtr/db/vrps_test.c @@ -7,7 +7,7 @@ #include "alloc.c" #include "common.c" #include "file.c" -#include "json_parser.c" +#include "json_util.c" #include "mock.c" #include "output_printer.c" #include "types/delta.c"