]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Adjust metadata.json's namespace
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 16 Nov 2023 02:37:15 +0000 (20:37 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 16 Nov 2023 17:25:05 +0000 (11:25 -0600)
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.

src/Makefile.am
src/cache/local_cache.c
src/incidence/incidence.c
src/json_parser.c [deleted file]
src/json_parser.h [deleted file]
src/json_util.c [new file with mode: 0644]
src/json_util.h [new file with mode: 0644]
src/rsync/rsync.c
src/slurm/slurm_parser.c
test/cache/local_cache_test.c
test/rtr/db/vrps_test.c

index 42517a68b5093018e7f6916ab08b7c7cbe889dd9..9aa7d768e60742370a7ed9eef9d3929fc3c25212 100644 (file)
@@ -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
index 1d6c0cac9c6a5eae64ae119cf043d304e1b83851..f6116b9df13e4acb93d7ed14ca48851915be23eb 100644 (file)
@@ -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"
  * 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;
                }
index e8689394c35064bf9aff363b1155d834a644700c..dc5e49806283361388d3fed956f9090c448760c8 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <assert.h>
 #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 (file)
index 9dbb21e..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "json_parser.h"
-
-#include <errno.h>
-#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 (file)
index 2c183d1..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SRC_JSON_PARSER_H_
-#define SRC_JSON_PARSER_H_
-
-#include <jansson.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-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 (file)
index 0000000..a89caa7
--- /dev/null
@@ -0,0 +1,251 @@
+#include "json_util.h"
+
+#include <errno.h>
+#include <limits.h>
+#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 (file)
index 0000000..ebb98fa
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SRC_JSON_UTIL_H_
+#define SRC_JSON_UTIL_H_
+
+#include <jansson.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+/*
+ * 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_ */
index dbedd1180f10722d20d7976481b4721f952b2faa..01d23d3caeaf77a14bb38198d0f5a85c992bda26 100644 (file)
@@ -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;
        }
index 3aa13c0c9ab53c317f4eb0e951c3268812c29e14..ad5a7d88be7de5cbc9f6b16c61883331e355c91b 100644 (file)
@@ -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))
index e71992224ea7d73d1ba83677562da62755f0cf54..dfb102203bac1c280d9c745d6bc6721024f441fc 100644 (file)
@@ -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);
 
index 97f34acbb11603c171ae7940553a0cb794cb7e84..2a4f3679e27e6d4989372a3cb7e318743166430e 100644 (file)
@@ -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"