/* List of threads, one per TAL file */
SLIST_HEAD(threads_list, validation_thread);
-struct tal_param {
+struct tal_thread_args {
struct db_table *db;
struct threads_list threads;
};
+struct handle_tal_args {
+ struct tal *tal;
+ struct db_table *db;
+};
+
static int
add_uri(struct uri_list *uris, char *uri)
{
/**
* Performs the whole validation walkthrough on uri @uri, which is assumed to
- * have been extracted from a TAL.
+ * have been extracted from TAL @tal.
*/
static int
handle_tal_uri(struct tal *tal, struct rpki_uri *uri, struct db_table *db)
{
- /*
- * Because of the way the foreach iterates, this function must return
- *
- * - 0 on soft errors.
- * - `> 0` on URI handled successfully.
- * - `< 0` on hard errors.
- *
- * A "soft error" is "the connection to the preferred URI fails, or the
- * retrieved CA certificate public key does not match the TAL public
- * key." (RFC 8630)
- *
- * A "hard error" is any other error.
- */
-
struct validation_handler validation_handler;
struct validation *state;
struct cert_stack *certstack;
return ENSURE_NEGATIVE(error);
if (!uri_is_certificate(uri)) {
- error = pr_op_err("TAL URI does not point to a certificate. (Expected .cer, got '%s')",
+ pr_op_err("TAL URI does not point to a certificate. (Expected .cer, got '%s')",
uri_op_get_printable(uri));
- goto fail;
+ error = EINVAL;
+ goto end;
}
/* Handle root certificate. */
if (error) {
switch (validation_pubkey_state(state)) {
case PKS_INVALID:
- error = 0; /* Try a different TAL URI. */
+ error = EINVAL;
goto end;
case PKS_VALID:
case PKS_UNTESTED:
- goto fail; /* Reject the TAL. */
+ error = ENSURE_NEGATIVE(error);
+ goto end;
}
-
pr_crit("Unknown public key state: %u",
validation_pubkey_state(state));
}
do {
error = deferstack_pop(certstack, &deferred);
if (error == -ENOENT) {
- /* No more certificates left; we're done. */
- error = 1;
+ error = 0; /* No more certificates left; we're done */
goto end;
} else if (error) /* All other errors are critical, currently */
pr_crit("deferstack_pop() returned illegal %d.", error);
rpp_refput(deferred.pp);
} while (true);
-fail: error = ENSURE_NEGATIVE(error);
end: validation_destroy(state);
pr_val_debug("}");
return error;
}
+static int
+__handle_tal_uri(struct rpki_uri *uri, void *arg)
+{
+ struct handle_tal_args *args = arg;
+ return handle_tal_uri(args->tal, uri, args->db);
+}
+
static void *
do_file_validation(void *arg)
{
struct validation_thread *thread = arg;
struct tal *tal;
- struct rpki_uri *ta_uri;
+ struct handle_tal_args handle_args;
int error;
fnstack_init();
if (error)
goto end;
- ta_uri = uris_download(&tal->uris, false);
- if (ta_uri == NULL) {
- error = pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
+ handle_args.tal = tal;
+ handle_args.db = thread->db;
+ error = uris_download(&tal->uris, false, __handle_tal_uri, &handle_args);
+ if (error)
+ pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
thread->tal_file);
- goto destroy_tal;
- }
-
- error = handle_tal_uri(tal, ta_uri, thread->db);
-destroy_tal:
tal_destroy(tal);
-end:
- fnstack_cleanup();
+end: fnstack_cleanup();
thread->exit_status = error;
return NULL;
}
static int
spawn_tal_thread(char const *tal_file, void *arg)
{
- struct tal_param *param = arg;
+ struct tal_thread_args *thread_args = arg;
struct validation_thread *thread;
int error;
thread = pmalloc(sizeof(struct validation_thread));
thread->tal_file = pstrdup(tal_file);
- thread->db = param->db;
+ thread->db = thread_args->db;
thread->exit_status = -EINTR;
- SLIST_INSERT_HEAD(¶m->threads, thread, next);
+ SLIST_INSERT_HEAD(&thread_args->threads, thread, next);
error = pthread_create(&thread->pid, NULL, do_file_validation, thread);
if (error) {
int
perform_standalone_validation(struct db_table *table)
{
- struct tal_param param;
+ struct tal_thread_args args;
struct validation_thread *thread;
int error, tmperr;
- param.db = table;
- SLIST_INIT(¶m.threads);
+ args.db = table;
+ SLIST_INIT(&args.threads);
- /* TODO (fine) Maybe don't use threads if there's only one TAL */
+ /* TODO (fine) Maybe don't spawn threads if there's only one TAL */
error = foreach_file(config_get_tal(), ".tal", true, spawn_tal_thread,
- ¶m);
+ &args);
if (error) {
- while (!SLIST_EMPTY(¶m.threads)) {
- thread = SLIST_FIRST(¶m.threads);
- SLIST_REMOVE_HEAD(¶m.threads, next);
+ while (!SLIST_EMPTY(&args.threads)) {
+ thread = SLIST_FIRST(&args.threads);
+ SLIST_REMOVE_HEAD(&args.threads, next);
thread_destroy(thread);
}
return error;
}
/* Wait for all */
- while (!SLIST_EMPTY(¶m.threads)) {
- thread = SLIST_FIRST(¶m.threads);
+ while (!SLIST_EMPTY(&args.threads)) {
+ thread = SLIST_FIRST(&args.threads);
tmperr = pthread_join(thread->pid, NULL);
if (tmperr)
pr_crit("pthread_join() threw %d (%s) on the '%s' thread.",
tmperr, strerror(tmperr), thread->tal_file);
- SLIST_REMOVE_HEAD(¶m.threads, next);
+ SLIST_REMOVE_HEAD(&args.threads, next);
if (thread->exit_status) {
error = thread->exit_status;
pr_op_warn("Validation from TAL '%s' yielded error %d (%s); discarding all validation results.",
}
static int
-download(struct rpki_uri *uri, bool use_rrdp)
+download(struct rpki_uri *uri, bool use_rrdp, uris_dl_cb cb, void *arg)
{
- return (use_rrdp && (uri_get_type(uri) == UT_HTTPS))
+ int error;
+
+ error = (use_rrdp && (uri_get_type(uri) == UT_HTTPS))
? rrdp_update(uri)
: cache_download(uri, NULL);
+ if (error)
+ return 1;
+
+ return cb(uri, arg);
}
-static struct rpki_uri *
-download_uris(struct uri_list *uris, enum uri_type type, bool use_rrdp)
+static int
+download_uris(struct uri_list *uris, enum uri_type type, bool use_rrdp,
+ uris_dl_cb cb, void *arg)
{
- struct rpki_uri **cursor, *uri;
- ARRAYLIST_FOREACH(uris, cursor) {
- uri = *cursor;
- if (uri_get_type(uri) == type && download(uri, use_rrdp) == 0)
- return uri;
+ struct rpki_uri **uri;
+ int error;
+
+ ARRAYLIST_FOREACH(uris, uri) {
+ if (uri_get_type(*uri) == type) {
+ error = download(*uri, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
+ }
}
- return NULL;
+
+ return 1;
}
/**
*
* Sequentially (in the order dictated by their priorities) attempts to update
* (in the cache) the content pointed by each URL.
- * Stops on the first success, returning the corresponding URI.
- *
- * If there's no successful update, attempts to find one that's already cached.
- * Returns the newest successfully cached URI.
+ * If a download succeeds, calls cb on it. If cb succeeds, returns without
+ * trying more URLs.
*
- * Does not grab any references.
+ * If none of the URLs download and callback properly, attempts to find one
+ * that's already cached, and callbacks it.
*/
-struct rpki_uri *
-uris_download(struct uri_list *uris, bool use_rrdp)
+int
+uris_download(struct uri_list *uris, bool use_rrdp, uris_dl_cb cb, void *arg)
{
struct rpki_uri **cursor, *uri;
+ int error;
if (config_get_http_priority() > config_get_rsync_priority()) {
- uri = download_uris(uris, UT_HTTPS, use_rrdp);
- if (uri != NULL)
- return uri;
- uri = download_uris(uris, UT_RSYNC, use_rrdp);
- if (uri != NULL)
- return uri;
+ error = download_uris(uris, UT_HTTPS, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
+ error = download_uris(uris, UT_RSYNC, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
} else if (config_get_http_priority() < config_get_rsync_priority()) {
- uri = download_uris(uris, UT_RSYNC, use_rrdp);
- if (uri != NULL)
- return uri;
- uri = download_uris(uris, UT_HTTPS, use_rrdp);
- if (uri != NULL)
- return uri;
+ error = download_uris(uris, UT_RSYNC, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
+ error = download_uris(uris, UT_HTTPS, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
} else {
ARRAYLIST_FOREACH(uris, cursor) {
- uri = *cursor;
- if (download(uri, use_rrdp) == 0)
- return uri;
+ error = download(*cursor, use_rrdp, cb, arg);
+ if (error <= 0)
+ return error;
}
}
- return cache_recover(uris, use_rrdp);
+ uri = cache_recover(uris, use_rrdp);
+ return (uri != NULL) ? cb(uri, arg) : ESRCH;
}