From: Alberto Leiva Popper Date: Tue, 31 Oct 2023 18:17:34 +0000 (-0600) Subject: Improve the cache fallback algorithm X-Git-Tag: 1.6.0~30 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=604f845ce6b9eb596dc9f1fdff7a7fa5752fcc87;p=thirdparty%2FFORT-validator.git Improve the cache fallback algorithm If all of a RPP's URLs fail, fall back to most sensible cached candidate. It seems this used to be only implemented for TAs, and the heuristics for choosing a suitable fallback were rudimentary. Elaborate, centralize and extend implementation to all cache content. Side maintenance tweaks: - Remove EREQFAILED, because it largely evolved from meaning "don't try again" to "try again." So now it was just a redundant EAGAIN. - Ditch redundant arguments from valid_file_or_dir(). - Merge the three URI arraylist implementations (certificate.c, tal.c and manifest.c) into one. - Move RRDP workspace URI, from a thread variable to the stack. (Code smell. It used to be awkward to follow this variable's lifespan through the tree traversal.) - Move struct publish and struct withdraw from the heap to the stack. (Eliminate pointless allocations. These are not the only RRDP structures I want to move to the stack.) - Change file_metadata.uri from `char *` to `struct rpki_uri *`. (This string was forcing the RRDP code to recompute the URI repeatedly.) --- diff --git a/src/abbreviations.txt b/src/abbreviations.txt index 4f6fe2bd..bbb5b147 100644 --- a/src/abbreviations.txt +++ b/src/abbreviations.txt @@ -21,6 +21,7 @@ len: length max: maximum min: minimum msg: message +notif: Notification pdu: Protocol Data Unit (RFC 6810) pp: Publication Point pr: print diff --git a/src/cache/local_cache.c b/src/cache/local_cache.c index e40e4d5c..2780c618 100644 --- a/src/cache/local_cache.c +++ b/src/cache/local_cache.c @@ -444,13 +444,13 @@ cache_download(struct rpki_uri *uri, bool *changed) token = strtok_r(NULL, "/", &saveptr); } while (token != NULL); goto download; + } - } else if (recursive) { + if (recursive) { if (was_recently_downloaded(child) && !child->error) { error = 0; goto end; } - } node = child; @@ -494,6 +494,144 @@ end: return error; } +static struct cache_node * +find_uri(struct rpki_uri *uri) +{ + char *luri, *token, *saveptr; + struct cache_node *parent, *node; + bool recursive; + struct cache_node *result; + + luri = uri2luri(uri); + token = strtok_r(luri, "/", &saveptr); + node = NULL; + result = NULL; + + switch (uri_get_type(uri)) { + case UT_RSYNC: + parent = rsync; + recursive = true; + break; + case UT_HTTPS: + parent = https; + recursive = false; + break; + default: + pr_crit("Unexpected URI type: %d", uri_get_type(uri)); + } + + if (parent == NULL) + goto end; + + while ((token = strtok_r(NULL, "/", &saveptr)) != NULL) { + HASH_FIND_STR(parent->children, token, node); + if (node == NULL) + goto end; + if (recursive && (node->flags & CNF_DIRECT)) + result = node; + parent = node; + } + + if ((node != NULL) && (node->flags & CNF_DIRECT)) + result = node; + +end: + free(luri); + return result; +} + +static unsigned int +get_score(struct cache_node *node) +{ + unsigned int score; + + /* + * Highest to lowest priority: + * + * 1. Recent Success: !error, CNF_SUCCESS, high ts_success. + * 2. Old Success: !error, CNF_SUCCESS, low ts_success. + * 3. Previous Recent Success: error, CNF_SUCCESS, high ts_success. + * 4. Previous Old Success: error, CNF_SUCCESS, old ts_success. + * 5. No Success: error, !CNF_SUCCESS (completely unviable) + */ + + if (node == NULL) + return 0; + + score = 0; + if (!node->error) + score |= (1 << 1); + if (node->flags & CNF_SUCCESS) + score |= (1 << 0); + return score; +} + +/* + * Returns true if @n1's success happened earlier than n2's. + */ +static bool +earlier_success(struct cache_node *n1, struct cache_node *n2) +{ + return difftime(n1->ts_success, n2->ts_success) < 0; +} + +struct rpki_uri * +cache_recover(struct uri_list *uris, bool use_rrdp) +{ + struct scr { + struct rpki_uri *uri; + struct cache_node *node; + unsigned int score; + }; + + struct rpki_uri **uri; + struct scr cursor; + struct scr best = { 0 }; + + ARRAYLIST_FOREACH(uris, uri) { + cursor.uri = *uri; + cursor.node = find_uri(cursor.uri); + cursor.score = get_score(cursor.node); + if (cursor.score == 0) + continue; + if (cursor.score > best.score) + best = cursor; + else if (cursor.score == best.score + && earlier_success(best.node, cursor.node)) + best = cursor; + } + + return best.uri; +} + +static void +__cache_print(struct cache_node *node, unsigned int tabs) +{ + unsigned int i; + struct cache_node *child, *tmp; + + if (node == NULL) + return; + + for (i = 0; i < tabs; i++) + printf("\t"); + printf("%s: %sdirect %ssuccess %sfile error:%d\n", + node->basename, + (node->flags & CNF_DIRECT) ? "" : "!", + (node->flags & CNF_SUCCESS) ? "" : "!", + (node->flags & CNF_FILE) ? "" : "!", + node->error); + HASH_ITER(hh, node->children, child, tmp) + __cache_print(child, tabs + 1); +} + +void +cache_print(void) +{ + __cache_print(rsync, 0); + __cache_print(https, 0); +} + /* * @force: ignore nonexistent files */ diff --git a/src/cache/local_cache.h b/src/cache/local_cache.h index d826ae75..cb6db6b9 100644 --- a/src/cache/local_cache.h +++ b/src/cache/local_cache.h @@ -8,6 +8,10 @@ int cache_prepare(void); /* No revert needed */ /* Downloads @uri into the cache */ int cache_download(struct rpki_uri *uri, bool *); +/* Returns the most recent successfully cached URI of the list */ +struct rpki_uri *cache_recover(struct uri_list *, bool); +/* Prints the cache in standard output. */ +void cache_print(void); /* Deletes old untraversed cached files, writes metadata into XML */ /* FIXME call this */ diff --git a/src/common.c b/src/common.c index 0aba47b5..9d3d3cbc 100644 --- a/src/common.c +++ b/src/common.c @@ -201,32 +201,24 @@ foreach_file(char const *location, char const *file_ext, bool empty_err, } bool -valid_file_or_dir(char const *location, bool check_file, bool check_dir, - int (*error_fn)(const char *format, ...)) +valid_file_or_dir(char const *location, bool check_file) { struct stat attr; bool is_file, is_dir; bool result; - if (!check_file && !check_dir) - pr_crit("Wrong usage, at least one check must be 'true'."); - if (stat(location, &attr) == -1) { - if (error_fn != NULL) { - error_fn("stat(%s) failed: %s", location, - strerror(errno)); - } + pr_op_err("stat(%s) failed: %s", location, strerror(errno)); return false; } is_file = check_file && S_ISREG(attr.st_mode); - is_dir = check_dir && S_ISDIR(attr.st_mode); + is_dir = S_ISDIR(attr.st_mode); result = is_file || is_dir; if (!result) pr_op_err("'%s' does not seem to be a %s", location, - (check_file && check_dir) ? "file or directory" : - (check_file) ? "file" : "directory"); + check_file ? "file or directory" : "directory"); return result; } diff --git a/src/common.h b/src/common.h index 15bf84ff..6ccd70f3 100644 --- a/src/common.h +++ b/src/common.h @@ -6,29 +6,15 @@ #include #include -/* "I think that this is not supposed to be implemented." */ +/* "I think this is not supposed to be implemented." */ #define ENOTSUPPORTED 3172 /* "I haven't implemented this yet." */ #define ENOTIMPLEMENTED 3173 -/* - * "URI was not RSYNC; ignore it." - * Not really an error. The RFCs usually declare URI lists; usually only one of - * them is required to be RSYNC and the others should be skipped (until we - * start supporting them.) - */ +/* "URI was not RSYNC." */ #define ENOTRSYNC 3174 -/* - * "URI was not HTTPS; ignore it." - * Not necessarily an error (just as ENOTRSYNC), since both type of URIs can - * still coexist in most scenarios. - */ +/* "URI was not HTTPS." */ #define ENOTHTTPS 3175 -/* - * A request made to a server (eg. rsync, http) has failed, even after retrying - */ -#define EREQFAILED 3176 - /* * If you're wondering why I'm not using -abs(error), it's because abs(INT_MIN) * overflows, so gcc complains sometimes. @@ -61,8 +47,7 @@ void rwlock_unlock(pthread_rwlock_t *); typedef int (*foreach_file_cb)(char const *, void *); int foreach_file(char const *, char const *, bool, foreach_file_cb, void *); -typedef int (*pr_errno_cb)(const char *, ...); -bool valid_file_or_dir(char const *, bool, bool, pr_errno_cb); +bool valid_file_or_dir(char const *, bool); int create_dir_recursive(char const *, bool); int delete_dir_recursive_bottom_up(char const *); diff --git a/src/config.c b/src/config.c index c5387092..941c238e 100644 --- a/src/config.c +++ b/src/config.c @@ -971,8 +971,7 @@ validate_config(void) return pr_op_err("The TAL(s) location (--tal) is mandatory."); /* A file location at --tal isn't valid when --init-tals is set */ - if (!valid_file_or_dir(rpki_config.tal, !rpki_config.init_tals, true, - pr_op_err)) + if (!valid_file_or_dir(rpki_config.tal, !rpki_config.init_tals)) return pr_op_err("Invalid TAL(s) location."); /* Ignore the other checks */ @@ -993,8 +992,7 @@ validate_config(void) !valid_output_file(rpki_config.output.bgpsec)) return pr_op_err("Invalid output.bgpsec file."); - if (rpki_config.slurm != NULL && - !valid_file_or_dir(rpki_config.slurm, true, true, pr_op_err)) + if (rpki_config.slurm != NULL && !valid_file_or_dir(rpki_config.slurm, true)) return pr_op_err("Invalid slurm location."); return 0; diff --git a/src/data_structure/array_list.h b/src/data_structure/array_list.h index 7aa56fa8..96948a4a 100644 --- a/src/data_structure/array_list.h +++ b/src/data_structure/array_list.h @@ -59,10 +59,6 @@ list->array[list->len - 1] = *elem; \ } -#define ARRAY_LIST(name, elem_type) \ - DEFINE_ARRAY_LIST_STRUCT(name, elem_type); \ - DEFINE_ARRAY_LIST_FUNCTIONS(name, elem_type, ) - #define STATIC_ARRAY_LIST(name, elem_type) \ DEFINE_ARRAY_LIST_STRUCT(name, elem_type); \ DEFINE_ARRAY_LIST_FUNCTIONS(name, elem_type, static) diff --git a/src/http/http.c b/src/http/http.c index f193d368..34fafdd4 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -250,9 +250,9 @@ handle_http_response_code(long http_code) { /* This is the same logic from CURL, according to its documentation. */ if (http_code == 408 || http_code == 429) - return EREQFAILED; /* Retry */ + return EAGAIN; /* Retry */ if (500 <= http_code && http_code < 600) - return EREQFAILED; /* Retry */ + return EAGAIN; /* Retry */ return -EINVAL; /* Do not retry */ } @@ -309,7 +309,7 @@ http_fetch(char const *src, char const *dst, curl_off_t ims, bool *changed) case CURLE_COULDNT_RESOLVE_HOST: case CURLE_COULDNT_RESOLVE_PROXY: case CURLE_FTP_ACCEPT_TIMEOUT: - error = EREQFAILED; /* Retry */ + error = EAGAIN; /* Retry */ goto end; default: error = handle_http_response_code(http_code); @@ -371,7 +371,7 @@ do_retries(char const *src, char const *dst, curl_off_t ims, bool *changed) pr_val_debug("Download successful."); return 0; /* Happy path */ - case EREQFAILED: + case EAGAIN: break; default: @@ -381,7 +381,7 @@ do_retries(char const *src, char const *dst, curl_off_t ims, bool *changed) if (r >= config_get_http_retry_count()) { pr_val_debug("Download failed: Retries exhausted."); - return -EREQFAILED; + return EIO; } pr_val_warn("Download failed; retrying in %u seconds.", diff --git a/src/object/certificate.c b/src/object/certificate.c index 1004c148..7687e273 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -49,10 +49,8 @@ struct ski_arguments { OCTET_STRING_t *sid; }; -STATIC_ARRAY_LIST(sia_rpp_uris, struct rpki_uri *) - struct sia_uris { - struct sia_rpp_uris rpp; + struct uri_list rpp; struct rpki_uri *mft; }; @@ -115,20 +113,14 @@ static const struct ad_metadata RPKI_MANIFEST = { static void sia_uris_init(struct sia_uris *uris) { - sia_rpp_uris_init(&uris->rpp); + uris_init(&uris->rpp); uris->mft = NULL; } -static void -cleanup_uri(struct rpki_uri **uri) -{ - uri_refput(*uri); -} - static void sia_uris_cleanup(struct sia_uris *uris) { - sia_rpp_uris_cleanup(&uris->rpp, cleanup_uri); + uris_cleanup(&uris->rpp); uri_refput(uris->mft); } @@ -1214,7 +1206,7 @@ handle_caRepository(struct rpki_uri *uri, void *arg) { struct sia_uris *uris = arg; pr_val_debug("caRepository: %s", uri_val_get_printable(uri)); - sia_rpp_uris_add(&uris->rpp, &uri); + uris_add(&uris->rpp, uri); uri_refget(uri); return 0; } @@ -1224,7 +1216,7 @@ handle_rpkiNotify(struct rpki_uri *uri, void *arg) { struct sia_uris *uris = arg; pr_val_debug("rpkiNotify: %s", uri_val_get_printable(uri)); - sia_rpp_uris_add(&uris->rpp, &uri); + uris_add(&uris->rpp, uri); uri_refget(uri); return 0; } @@ -1531,7 +1523,7 @@ uri_create_ad(struct rpki_uri **uri, ACCESS_DESCRIPTION *ad, enum uri_type type) * directory our g2l version of @asn1_string should contain. * But ask the testers to keep an eye on it anyway. */ - return __uri_create(uri, type, + return __uri_create(uri, type, NULL, ASN1_STRING_get0_data(asn1_string), ASN1_STRING_length(asn1_string)); } @@ -1927,63 +1919,15 @@ certificate_validate_aia(struct rpki_uri *caIssuers, X509 *cert) return 0; } -static bool -try_uris(struct sia_uris *uris, enum uri_type const *filter) -{ - struct rpki_uri **node, *uri; - enum uri_type type; - - ARRAYLIST_FOREACH(&uris->rpp, node) { - uri = *node; - type = uri_get_type(uri); - - if (filter != NULL && (*filter) != type) - continue; - - switch (type) { - case UT_RSYNC: - if (cache_download(uri, NULL) == 0) - return true; - break; - case UT_HTTPS: - if (rrdp_update(uri) == 0) - return true; - break; - default: - pr_crit("Unknown URI type: %u", type); - } - } - - return false; -} - -static int +static struct rpki_uri * download_rpp(struct sia_uris *uris) { - static const enum uri_type HTTP = UT_HTTPS; - static const enum uri_type RSYNC = UT_RSYNC; - - if (uris->rpp.len == 0) - return pr_val_err("SIA lacks both caRepository and rpkiNotify."); - - if (config_get_http_priority() > config_get_rsync_priority()) { - if (try_uris(uris, &HTTP)) - return 0; - if (try_uris(uris, &RSYNC)) - return 0; - - } else if (config_get_http_priority() < config_get_rsync_priority()) { - if (try_uris(uris, &RSYNC)) - return 0; - if (try_uris(uris, &HTTP)) - return 0; - - } else { - if (try_uris(uris, NULL)) - return 0; + if (uris->rpp.len == 0) { + pr_val_err("SIA lacks both caRepository and rpkiNotify."); + return NULL; } - return pr_val_err("The RPP could not be downloaded."); + return uris_download(&uris->rpp, true); } /** Boilerplate code for CA certificate validation and recursive traversal. */ @@ -1995,6 +1939,7 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) STACK_OF(X509_CRL) *rpp_parent_crl; X509 *cert; struct sia_uris sia_uris; + struct rpki_uri *downloaded; enum rpki_policy policy; enum cert_type certype; struct rpp *pp; @@ -2061,17 +2006,21 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) if (error) goto revert_uris; - error = download_rpp(&sia_uris); - if (error) + downloaded = download_rpp(&sia_uris); + if (downloaded == NULL) { + error = EINVAL; goto revert_uris; + } - error = x509stack_push(validation_certstack(state), cert_uri, - cert, policy, certype); + error = x509stack_push(validation_certstack(state), cert_uri, cert, + policy, certype); if (error) goto revert_uris; cert = NULL; /* Ownership stolen */ - error = handle_manifest(sia_uris.mft, &pp); + error = handle_manifest(sia_uris.mft, + (uri_get_type(downloaded) == UT_HTTPS) ? downloaded : NULL, + &pp); if (error) { x509stack_cancel(validation_certstack(state)); goto revert_uris; @@ -2082,7 +2031,6 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) rpp_refput(pp); revert_uris: - validation_set_notification_uri(state, NULL); sia_uris_cleanup(&sia_uris); revert_cert: if (cert != NULL) diff --git a/src/object/manifest.c b/src/object/manifest.c index 39309a5d..7c82ad2e 100644 --- a/src/object/manifest.c +++ b/src/object/manifest.c @@ -15,15 +15,15 @@ #include "object/signed_object.h" static int -cage(struct rpki_uri **uri) +cage(struct rpki_uri **uri, struct rpki_uri *notif) { - if (validation_get_notification_uri(state_retrieve()) == NULL) { + if (notif == NULL) { /* No need to cage */ uri_refget(*uri); return 0; } - return __uri_create(uri, UT_CAGED, uri_get_global(*uri), + return __uri_create(uri, UT_CAGED, notif, uri_get_global(*uri), uri_get_global_len(*uri)); } @@ -188,7 +188,8 @@ validate_manifest(struct Manifest *manifest) } static int -build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp) +build_rpp(struct Manifest *mft, struct rpki_uri *notif, + struct rpki_uri *mft_uri, struct rpp **pp) { int i; struct FileAndHash *fah; @@ -202,7 +203,7 @@ build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp) for (i = 0; i < mft->fileList.list.count; i++) { fah = mft->fileList.list.array[i]; - error = uri_create_mft(&uri, mft_uri, &fah->file); + error = uri_create_mft(&uri, notif, mft_uri, &fah->file); /* * Not handling ENOTRSYNC is fine because the manifest URL * should have been RSYNC. Something went wrong if an RSYNC URL @@ -266,7 +267,7 @@ fail: * @pp. If @rrdp_workspace is true, use the local RRDP repository. */ int -handle_manifest(struct rpki_uri *uri, struct rpp **pp) +handle_manifest(struct rpki_uri *uri, struct rpki_uri *notif, struct rpp **pp) { static OID oid = OID_MANIFEST; struct oid_arcs arcs = OID2ARCS("manifest", oid); @@ -277,7 +278,7 @@ handle_manifest(struct rpki_uri *uri, struct rpp **pp) int error; /* Prepare */ - error = cage(&uri); /* ref++ */ + error = cage(&uri, notif); /* ref++ */ if (error) return error; pr_val_debug("Manifest '%s' {", uri_val_get_printable(uri)); @@ -292,7 +293,7 @@ handle_manifest(struct rpki_uri *uri, struct rpp **pp) goto revert_sobj; /* Initialize out parameter (@pp) */ - error = build_rpp(mft, uri, pp); + error = build_rpp(mft, notif, uri, pp); if (error) goto revert_manifest; diff --git a/src/object/manifest.h b/src/object/manifest.h index 8cadf6da..fa55a6f3 100644 --- a/src/object/manifest.h +++ b/src/object/manifest.h @@ -3,6 +3,6 @@ #include "rpp.h" -int handle_manifest(struct rpki_uri *, struct rpp **); +int handle_manifest(struct rpki_uri *, struct rpki_uri *, struct rpp **); #endif /* SRC_OBJECT_MANIFEST_H_ */ diff --git a/src/object/tal.c b/src/object/tal.c index 221eac9a..b3fc82f9 100644 --- a/src/object/tal.c +++ b/src/object/tal.c @@ -20,31 +20,17 @@ typedef int (*foreach_uri_cb)(struct tal *, struct rpki_uri *, void *); -struct uris { - struct rpki_uri **array; /* This is an array of rpki URIs. */ - unsigned int count; - unsigned int size; -}; - struct tal { char const *file_name; - struct uris uris; + struct uri_list uris; unsigned char *spki; /* Decoded; not base64. */ size_t spki_len; }; struct validation_thread { pthread_t pid; - /* TAL file name */ char *tal_file; - /* - * Try to use the TA from the local cache? Only if none of the URIs - * was sync'd. - */ - bool retry_local; - /* Try to sync the current TA URI? */ - bool sync_files; struct db_table *db; int exit_status; /* This should also only be manipulated by the parent thread. */ @@ -59,50 +45,27 @@ struct tal_param { struct threads_list threads; }; -static void -uris_init(struct uris *uris) -{ - uris->count = 0; - uris->size = 4; /* Most TALs only define one. */ - uris->array = pmalloc(uris->size * sizeof(struct rpki_uri *)); -} - -static void -uris_destroy(struct uris *uris) -{ - unsigned int i; - for (i = 0; i < uris->count; i++) - uri_refput(uris->array[i]); - free(uris->array); -} - static int -uris_add(struct uris *uris, char *uri) +add_uri(struct uri_list *uris, char *uri) { struct rpki_uri *new; int error; if (str_starts_with(uri, "rsync://")) - error = uri_create(&new, UT_RSYNC, uri); + error = uri_create(&new, UT_RSYNC, NULL, uri); else if (str_starts_with(uri, "https://")) - error = uri_create(&new, UT_HTTPS, uri); + error = uri_create(&new, UT_HTTPS, NULL, uri); else error = pr_op_err("TAL has non-RSYNC/HTTPS URI: %s", uri); if (error) return error; - if (uris->count + 1 >= uris->size) { - uris->size *= 2; - uris->array = realloc(uris->array, - uris->size * sizeof(struct rpki_uri *)); - } - - uris->array[uris->count++] = new; + uris_add(uris, new); return 0; } static int -read_uris(struct line_file *lfile, struct uris *uris) +read_uris(struct line_file *lfile, struct uri_list *uris) { char *uri; int error; @@ -136,7 +99,7 @@ read_uris(struct line_file *lfile, struct uris *uris) } do { - error = uris_add(uris, uri); + error = add_uri(uris, uri); free(uri); /* Won't be needed anymore */ if (error) return error; @@ -335,7 +298,7 @@ tal_load(char const *file_name, struct tal **result) return 0; fail: - uris_destroy(&tal->uris); + uris_cleanup(&tal->uris); free(tal); lfile_close(lfile); return error; @@ -347,56 +310,11 @@ tal_destroy(struct tal *tal) if (tal == NULL) return; - uris_destroy(&tal->uris); + uris_cleanup(&tal->uris); free(tal->spki); free(tal); } -static int -foreach(enum uri_type const *filter, struct tal *tal, - foreach_uri_cb cb, void *arg) -{ - struct rpki_uri *uri; - unsigned int i; - int error; - - for (i = 0; i < tal->uris.count; i++) { - uri = tal->uris.array[i]; - if (filter == NULL || (*filter) == uri_get_type(uri)) { - error = cb(tal, uri, arg); - if (error) - return error; - } - } - - return 0; -} - -static int -foreach_uri(struct tal *tal, foreach_uri_cb cb, void *arg) -{ - static const enum uri_type HTTP = UT_HTTPS; - static const enum uri_type RSYNC = UT_RSYNC; - int error; - - if (config_get_http_priority() > config_get_rsync_priority()) { - error = foreach(&HTTP, tal, cb, arg); - if (!error) - error = foreach(&RSYNC, tal, cb, arg); - - } else if (config_get_http_priority() < config_get_rsync_priority()) { - error = foreach(&RSYNC, tal, cb, arg); - if (!error) - error = foreach(&HTTP, tal, cb, arg); - - } else { - error = foreach(NULL, tal, cb, arg); - - } - - return error; -} - char const * tal_get_file_name(struct tal *tal) { @@ -415,7 +333,7 @@ tal_get_spki(struct tal *tal, unsigned char const **buffer, size_t *len) * have been extracted from a TAL. */ static int -handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg) +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 @@ -432,46 +350,22 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg) */ struct validation_handler validation_handler; - struct validation_thread *thread; struct validation *state; struct cert_stack *certstack; struct deferred_cert deferred; int error; - thread = arg; + pr_val_debug("TAL URI '%s' {", uri_val_get_printable(uri)); validation_handler.handle_roa_v4 = handle_roa_v4; validation_handler.handle_roa_v6 = handle_roa_v6; validation_handler.handle_router_key = handle_router_key; - validation_handler.arg = thread->db; + validation_handler.arg = db; error = validation_prepare(&state, tal, &validation_handler); if (error) return ENSURE_NEGATIVE(error); - if (thread->sync_files) { - error = cache_download(uri, NULL); - /* Reminder: there's a positive error: EREQFAILED */ - if (error) { - validation_destroy(state); - return pr_val_warn( - "TAL URI '%s' could not be downloaded.", - uri_val_get_printable(uri)); - } - } else { - /* Look for local files */ - if (!valid_file_or_dir(uri_get_local(uri), true, false, - pr_val_err)) { - validation_destroy(state); - return 0; /* Error already logged */ - } - } - - /* At least one URI was sync'd */ - thread->retry_local = false; - - pr_val_debug("TAL URI '%s' {", uri_val_get_printable(uri)); - if (!uri_is_certificate(uri)) { error = pr_op_err("TAL URI does not point to a certificate. (Expected .cer, got '%s')", uri_op_get_printable(uri)); @@ -535,6 +429,7 @@ do_file_validation(void *arg) { struct validation_thread *thread = arg; struct tal *tal; + struct rpki_uri *ta_uri; int error; fnstack_init(); @@ -544,29 +439,14 @@ do_file_validation(void *arg) if (error) goto end; - error = foreach_uri(tal, handle_tal_uri, thread); - if (error > 0) { - error = 0; - goto destroy_tal; - } else if (error < 0) { - goto destroy_tal; - } - - if (!thread->retry_local) { + 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.", thread->tal_file); goto destroy_tal; } - thread->sync_files = false; - pr_val_warn("Looking for the TA certificate at the local files."); - - error = foreach_uri(tal, handle_tal_uri, thread); - if (error > 0) - error = 0; - else if (error == 0) - error = pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.", - thread->tal_file); + error = handle_tal_uri(tal, ta_uri, thread->db); destroy_tal: tal_destroy(tal); @@ -594,8 +474,6 @@ spawn_tal_thread(char const *tal_file, void *arg) thread = pmalloc(sizeof(struct validation_thread)); thread->tal_file = pstrdup(tal_file); - thread->retry_local = true; - thread->sync_files = true; thread->db = param->db; thread->exit_status = -EINTR; SLIST_INSERT_HEAD(¶m->threads, thread, next); diff --git a/src/rpp.c b/src/rpp.c index d9592cd7..e8d795f9 100644 --- a/src/rpp.c +++ b/src/rpp.c @@ -11,11 +11,9 @@ #include "object/ghostbusters.h" #include "object/roa.h" -STATIC_ARRAY_LIST(uris, struct rpki_uri *) - /** A Repository Publication Point (RFC 6481), as described by some manifest. */ struct rpp { - struct uris certs; /* Certificates */ + struct uri_list certs; /* Certificates */ /* * uri NULL implies stack NULL and error 0. @@ -39,9 +37,9 @@ struct rpp { /* The Manifest is not needed for now. */ - struct uris roas; /* Route Origin Attestations */ + struct uri_list roas; /* Route Origin Attestations */ - struct uris ghostbusters; + struct uri_list ghostbusters; /* * Note that the reference counting functions are not prepared for @@ -74,24 +72,18 @@ rpp_refget(struct rpp *pp) pp->references++; } -static void -__uri_refput(struct rpki_uri **uri) -{ - uri_refput(*uri); -} - void rpp_refput(struct rpp *pp) { pp->references--; if (pp->references == 0) { - uris_cleanup(&pp->certs, __uri_refput); + uris_cleanup(&pp->certs); if (pp->crl.uri != NULL) uri_refput(pp->crl.uri); if (pp->crl.stack != NULL) sk_X509_CRL_pop_free(pp->crl.stack, X509_CRL_free); - uris_cleanup(&pp->roas, __uri_refput); - uris_cleanup(&pp->ghostbusters, __uri_refput); + uris_cleanup(&pp->roas); + uris_cleanup(&pp->ghostbusters); free(pp); } } @@ -100,21 +92,21 @@ rpp_refput(struct rpp *pp) void rpp_add_cert(struct rpp *pp, struct rpki_uri *uri) { - uris_add(&pp->certs, &uri); + uris_add(&pp->certs, uri); } /** Steals ownership of @uri. */ void rpp_add_roa(struct rpp *pp, struct rpki_uri *uri) { - uris_add(&pp->roas, &uri); + uris_add(&pp->roas, uri); } /** Steals ownership of @uri. */ void rpp_add_ghostbusters(struct rpp *pp, struct rpki_uri *uri) { - uris_add(&pp->ghostbusters, &uri); + uris_add(&pp->ghostbusters, uri); } /** Steals ownership of @uri. */ diff --git a/src/rrdp/rrdp_loader.c b/src/rrdp/rrdp_loader.c index 449d8ed1..7b54daa6 100644 --- a/src/rrdp/rrdp_loader.c +++ b/src/rrdp/rrdp_loader.c @@ -34,7 +34,7 @@ get_metadata(struct rpki_uri *uri, struct notification_metadata *result) *result = notification.meta; memset(¬ification.meta, 0, sizeof(notification.meta)); - update_notification_destroy(¬ification); + update_notification_cleanup(¬ification); return 0; } @@ -55,16 +55,6 @@ rrdp_update(struct rpki_uri *uri) bool changed; int error; - if (uri == NULL || !uri_is_https(uri)) - pr_crit("Wrong call, trying to parse a non HTTPS URI"); - - /* - * TODO (fine) this is dirty and error prone. - * Find a better way to deliver the notification URI to the RRDP objects - * and manifest. - */ - validation_set_notification_uri(state_retrieve(), uri); - fnstack_push_uri(uri); pr_val_debug("Processing notification."); @@ -108,7 +98,7 @@ rrdp_update(struct rpki_uri *uri) pr_val_debug("The Notification changed, but the session ID and serial didn't."); revert_notification: - update_notification_destroy(&new); + update_notification_cleanup(&new); end: notification_metadata_cleanup(&old); fnstack_pop(); diff --git a/src/rrdp/rrdp_objects.c b/src/rrdp/rrdp_objects.c index e05bdd39..48789ea9 100644 --- a/src/rrdp/rrdp_objects.c +++ b/src/rrdp/rrdp_objects.c @@ -31,7 +31,7 @@ void metadata_cleanup(struct file_metadata *meta) { free(meta->hash); - free(meta->uri); + uri_refput(meta->uri); } /* Do the @cb to the delta head elements from @from_serial to @max_serial */ @@ -113,13 +113,13 @@ deltas_head_sort(struct deltas_head *deltas, unsigned long max_serial) } void -update_notification_init(struct update_notification *notification, +update_notification_init(struct update_notification *notif, struct rpki_uri *uri) { - notification_metadata_init(¬ification->meta); - metadata_init(¬ification->snapshot); - deltas_head_init(¬ification->deltas_list); - notification->uri = uri_refget(uri); + notification_metadata_init(¬if->meta); + metadata_init(¬if->snapshot); + deltas_head_init(¬if->deltas_list); + notif->uri = uri_refget(uri); } static void @@ -129,7 +129,7 @@ delta_head_destroy(struct delta_head *delta) } void -update_notification_destroy(struct update_notification *file) +update_notification_cleanup(struct update_notification *file) { metadata_cleanup(&file->snapshot); notification_metadata_cleanup(&file->meta); @@ -173,41 +173,29 @@ delta_destroy(struct delta *file) free(file); } -struct publish * -publish_create(void) +void +publish_init(struct publish *tag) { - struct publish *tmp; - - tmp = pmalloc(sizeof(struct publish)); - metadata_init(&tmp->meta); - tmp->content = NULL; - tmp->content_len = 0; - - return tmp; + metadata_init(&tag->meta); + tag->content = NULL; + tag->content_len = 0; } void -publish_destroy(struct publish *file) +publish_cleanup(struct publish *tag) { - metadata_cleanup(&file->meta); - free(file->content); - free(file); + metadata_cleanup(&tag->meta); + free(tag->content); } -struct withdraw * -withdraw_create(void) +void +withdraw_init(struct withdraw *tag) { - struct withdraw *tmp; - - tmp = pmalloc(sizeof(struct withdraw)); - metadata_init(&tmp->meta); - - return tmp; + metadata_init(&tag->meta); } void -withdraw_destroy(struct withdraw *file) +withdraw_cleanup(struct withdraw *tag) { - metadata_cleanup(&file->meta); - free(file); + metadata_cleanup(&tag->meta); } diff --git a/src/rrdp/rrdp_objects.h b/src/rrdp/rrdp_objects.h index 6f89d3ba..5ded377e 100644 --- a/src/rrdp/rrdp_objects.h +++ b/src/rrdp/rrdp_objects.h @@ -11,7 +11,7 @@ struct notification_metadata { /* Specific RRDP files data, in some cases the hash can be omitted */ struct file_metadata { - char *uri; + struct rpki_uri *uri; unsigned char *hash; size_t hash_len; }; @@ -73,7 +73,7 @@ void metadata_init(struct file_metadata *); void metadata_cleanup(struct file_metadata *); void update_notification_init(struct update_notification *, struct rpki_uri *); -void update_notification_destroy(struct update_notification *); +void update_notification_cleanup(struct update_notification *); typedef int (*delta_head_cb)(struct delta_head *, void *); int deltas_head_for_each(struct deltas_head *, unsigned long, unsigned long, @@ -86,10 +86,10 @@ void snapshot_destroy(struct snapshot *); struct delta *delta_create(void); void delta_destroy(struct delta *); -struct publish *publish_create(void); -void publish_destroy(struct publish *); +void publish_init(struct publish *); +void publish_cleanup(struct publish *); -struct withdraw *withdraw_create(void); -void withdraw_destroy(struct withdraw *); +void withdraw_init(struct withdraw *); +void withdraw_cleanup(struct withdraw *); #endif /* SRC_RRDP_RRDP_OBJECTS_H_ */ diff --git a/src/rrdp/rrdp_parser.c b/src/rrdp/rrdp_parser.c index 721b7d93..a0b3222b 100644 --- a/src/rrdp/rrdp_parser.c +++ b/src/rrdp/rrdp_parser.c @@ -35,7 +35,7 @@ struct rdr_snapshot_ctx { /* Data being parsed */ struct snapshot *snapshot; /* Parent data to validate session ID and serial */ - struct update_notification *notification; + struct update_notification *notif; }; /* Context while reading a delta */ @@ -43,7 +43,7 @@ struct rdr_delta_ctx { /* Data being parsed */ struct delta *delta; /* Parent data to validate session ID */ - struct update_notification *notification; + struct update_notification *notif; /* Current serial loaded from update notification deltas list */ unsigned long expected_serial; }; @@ -351,19 +351,26 @@ return_val: * 2. "hash" (optional, depending on @hr) */ static int -parse_doc_data(xmlTextReaderPtr reader, hash_requirement hr, - struct file_metadata *data) +parse_doc_data(xmlTextReaderPtr reader, struct rpki_uri *notif, + hash_requirement hr, struct file_metadata *data) { - char *uri; + char *uri_str; + struct rpki_uri *uri; unsigned char *hash; size_t hash_len; int error; + uri_str = NULL; uri = NULL; hash = NULL; hash_len = 0; - error = parse_string(reader, RRDP_ATTR_URI, &uri); + error = parse_string(reader, RRDP_ATTR_URI, &uri_str); + if (error) + return error; + error = uri_create(&uri, (notif != NULL) ? UT_CAGED : UT_HTTPS, notif, + uri_str); + free(uri_str); if (error) return error; @@ -383,24 +390,22 @@ end: } static int -parse_publish(xmlTextReaderPtr reader, hash_requirement hr, - struct publish **publish) +parse_publish(xmlTextReaderPtr reader, struct rpki_uri *notif, + hash_requirement hr, struct publish *tag) { - struct publish *result; - struct rpki_uri *uri; char *base64_str; int error; - result = publish_create(); + publish_init(tag); - error = parse_doc_data(reader, hr, &result->meta); + error = parse_doc_data(reader, notif, hr, &tag->meta); if (error) goto release_tmp; /* Read the text */ if (xmlTextReaderRead(reader) != 1) { error = pr_val_err("Couldn't read publish content of element '%s'", - result->meta.uri); + uri_get_global(tag->meta.uri)); goto release_tmp; } @@ -408,108 +413,85 @@ parse_publish(xmlTextReaderPtr reader, hash_requirement hr, if (error) goto release_tmp; - error = base64_read(base64_str, &result->content, &result->content_len); + error = base64_read(base64_str, &tag->content, &tag->content_len); if (error) goto release_base64; /* rfc8181#section-2.2 but considering optional hash */ - uri = NULL; - if (result->meta.hash_len > 0) { - /* Get the current file from the uri */ - error = uri_create(&uri, UT_CAGED, result->meta.uri); - if (error) - goto release_base64; + if (tag->meta.hash_len > 0) { + /* + * FIXME How come you're checking the hash of the file? + * You haven't written the file yet. + */ - error = hash_validate_file(uri, result->meta.hash, - result->meta.hash_len); - uri_refput(uri); - if (error != 0) { + /* Get the current file from the uri */ + error = hash_validate_file(tag->meta.uri, tag->meta.hash, + tag->meta.hash_len); + if (error) { pr_val_info("Hash of base64 decoded element from URI '%s' doesn't match element hash", - result->meta.uri); + uri_get_global(tag->meta.uri)); error = EINVAL; goto release_base64; } } free(base64_str); - *publish = result; return 0; release_base64: free(base64_str); release_tmp: - publish_destroy(result); + publish_cleanup(tag); return error; } static int -parse_withdraw(xmlTextReaderPtr reader, struct withdraw **withdraw) +parse_withdraw(xmlTextReaderPtr reader, struct rpki_uri *notif, + struct withdraw *tag) { - struct withdraw *tmp; - struct rpki_uri *uri; int error; - tmp = withdraw_create(); + withdraw_init(tag); - error = parse_doc_data(reader, HR_MANDATORY, &tmp->meta); + error = parse_doc_data(reader, notif, HR_MANDATORY, &tag->meta); if (error) - goto release_tmp; - - /* rfc8181#section-2.2, get the file from the uri */ - error = uri_create(&uri, UT_CAGED, tmp->meta.uri); - if (error) - goto release_tmp; + goto fail; - error = hash_validate_file(uri, tmp->meta.hash, - tmp->meta.hash_len); + error = hash_validate_file(tag->meta.uri, tag->meta.hash, + tag->meta.hash_len); if (error) - goto release_uri; + goto fail; - uri_refput(uri); - *withdraw = tmp; return 0; -release_uri: - uri_refput(uri); -release_tmp: - withdraw_destroy(tmp); + +fail: + withdraw_cleanup(tag); return error; } static int -write_from_uri(char const *location, unsigned char *content, size_t content_len) +write_from_uri(struct rpki_uri *uri, unsigned char *content, size_t content_len) { - struct rpki_uri *uri; FILE *out; size_t written; int error; - /* rfc8181#section-2.2 must be an rsync URI */ - error = uri_create(&uri, UT_CAGED, location); - if (error) - return error; - - /* pr_val_debug("Expanding %s.", uri_get_local(uri)); */ - error = create_dir_recursive(uri_get_local(uri), false); - if (error) { - uri_refput(uri); + if (error) return error; - } error = file_write(uri_get_local(uri), &out); - if (error) { - uri_refput(uri); + if (error) return error; - } written = fwrite(content, sizeof(unsigned char), content_len, out); if (written != content_len) { - uri_refput(uri); file_close(out); - return pr_val_err("Couldn't write bytes to file %s", - uri_get_local(uri)); + return pr_val_err( + "Couldn't write file '%s' (error code not available)", + uri_get_local(uri) + ); } - uri_refput(uri); file_close(out); return 0; } @@ -522,42 +504,24 @@ delete_from_uri(struct rpki_uri *uri) return delete_dir_recursive_bottom_up(uri_get_local(uri)); } -static int -__delete_from_uri(char const *location) -{ - struct rpki_uri *uri; - int error; - - /* rfc8181#section-2.2 must be an rsync URI */ - error = uri_create(&uri, UT_CAGED, location); - if (error) - return error; - - error = delete_from_uri(uri); - - /* Error 0 is ok */ - uri_refput(uri); - return error; -} - /* * This function will call 'xmlTextReaderRead' so there's no need to expect any * other type at the caller. */ static int -parse_publish_elem(xmlTextReaderPtr reader, hash_requirement hr) +parse_publish_elem(xmlTextReaderPtr reader, struct rpki_uri *notif, + hash_requirement hr) { - struct publish *tmp; + struct publish tag; int error; - tmp = NULL; - error = parse_publish(reader, hr, &tmp); + error = parse_publish(reader, notif, hr, &tag); if (error) return error; - error = write_from_uri(tmp->meta.uri, tmp->content, tmp->content_len); + error = write_from_uri(tag.meta.uri, tag.content, tag.content_len); - publish_destroy(tmp); + publish_cleanup(&tag); return error; } @@ -566,24 +530,24 @@ parse_publish_elem(xmlTextReaderPtr reader, hash_requirement hr) * other type at the caller. */ static int -parse_withdraw_elem(xmlTextReaderPtr reader) +parse_withdraw_elem(xmlTextReaderPtr reader, struct rpki_uri *notif) { - struct withdraw *tmp; + struct withdraw tag; int error; - error = parse_withdraw(reader, &tmp); + error = parse_withdraw(reader, notif, &tag); if (error) return error; - error = __delete_from_uri(tmp->meta.uri); + error = delete_from_uri(tag.meta.uri); - withdraw_destroy(tmp); + withdraw_cleanup(&tag); return error; } static int parse_notification_delta(xmlTextReaderPtr reader, - struct update_notification *notification) + struct update_notification *notif) { struct delta_head delta; int error; @@ -591,39 +555,39 @@ parse_notification_delta(xmlTextReaderPtr reader, error = parse_long(reader, RRDP_ATTR_SERIAL, &delta.serial); if (error) return error; - error = parse_doc_data(reader, HR_MANDATORY, &delta.meta); + error = parse_doc_data(reader, NULL, HR_MANDATORY, &delta.meta); if (error) return error; - deltas_head_add(¬ification->deltas_list, &delta); + deltas_head_add(¬if->deltas_list, &delta); return 0; } static int -xml_read_notification(xmlTextReaderPtr reader, void *arg) +xml_read_notif(xmlTextReaderPtr reader, void *arg) { - struct update_notification *update = arg; + struct update_notification *notif = arg; xmlChar const *name; name = xmlTextReaderConstLocalName(reader); switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA)) { - return parse_notification_delta(reader, update); + return parse_notification_delta(reader, notif); } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT)) { - return parse_doc_data(reader, HR_MANDATORY, - &update->snapshot); + return parse_doc_data(reader, NULL, HR_MANDATORY, + ¬if->snapshot); } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_NOTIFICATION)) { /* No need to validate session ID and serial */ - return parse_metadata(reader, &update->meta, NULL, 0); + return parse_metadata(reader, ¬if->meta, NULL, 0); } return pr_val_err("Unexpected '%s' element", name); case XML_READER_TYPE_END_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_NOTIFICATION)) - return deltas_head_sort(&update->deltas_list, - update->meta.serial); + return deltas_head_sort(¬if->deltas_list, + notif->meta.serial); break; } @@ -638,9 +602,9 @@ rrdp_parse_notification(struct rpki_uri *uri, update_notification_init(result, uri); - error = relax_ng_parse(uri_get_local(uri), xml_read_notification, result); + error = relax_ng_parse(uri_get_local(uri), xml_read_notif, result); if (error) - update_notification_destroy(result); + update_notification_cleanup(result); return error; } @@ -658,12 +622,13 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg) switch (type) { case XML_READER_TYPE_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH)) - error = parse_publish_elem(reader, HR_IGNORE); + error = parse_publish_elem(reader, ctx->notif->uri, + HR_IGNORE); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT)) error = parse_metadata(reader, &ctx->snapshot->meta, - ctx->notification->meta.session_id, - ctx->notification->meta.serial); + ctx->notif->meta.session_id, + ctx->notif->meta.serial); else return pr_val_err("Unexpected '%s' element", name); @@ -678,20 +643,20 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg) } static int -parse_snapshot(struct rpki_uri *uri, struct update_notification *notification) +parse_snapshot(struct rpki_uri *uri, struct update_notification *notif) { struct rdr_snapshot_ctx ctx; int error; fnstack_push_uri(uri); /* Hash validation */ - error = hash_validate_file(uri, notification->snapshot.hash, - notification->snapshot.hash_len); + error = hash_validate_file(uri, notif->snapshot.hash, + notif->snapshot.hash_len); if (error) goto pop; ctx.snapshot = snapshot_create(); - ctx.notification = notification; + ctx.notif = notif; error = relax_ng_parse(uri_get_local(uri), xml_read_snapshot, &ctx); @@ -713,13 +678,14 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg) switch (type) { case XML_READER_TYPE_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH)) - error = parse_publish_elem(reader, HR_OPTIONAL); + error = parse_publish_elem(reader, ctx->notif->uri, + HR_OPTIONAL); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_WITHDRAW)) - error = parse_withdraw_elem(reader); + error = parse_withdraw_elem(reader, ctx->notif->uri); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA)) error = parse_metadata(reader, &ctx->delta->meta, - ctx->notification->meta.session_id, + ctx->notif->meta.session_id, ctx->expected_serial); else return pr_val_err("Unexpected '%s' element", name); @@ -736,7 +702,7 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg) static int parse_delta(struct rpki_uri *uri, struct delta_head *parents_data, - struct update_notification *notification) + struct update_notification *notif) { struct rdr_delta_ctx ctx; struct file_metadata *expected_data; @@ -751,7 +717,7 @@ parse_delta(struct rpki_uri *uri, struct delta_head *parents_data, goto pop_fnstack; ctx.delta = delta_create(); - ctx.notification = notification; + ctx.notif = notif; ctx.expected_serial = parents_data->serial; error = relax_ng_parse(uri_get_local(uri), xml_read_delta, &ctx); @@ -763,66 +729,52 @@ pop_fnstack: } static int -process_delta(struct delta_head *delta_head, void *arg) +process_delta(struct delta_head *delta, void *arg) { struct rpki_uri *uri; - struct file_metadata *head_data; int error; - head_data = &delta_head->meta; - - pr_val_debug("Processing delta '%s'.", head_data->uri); - error = uri_create(&uri, UT_HTTPS, head_data->uri); - if (error) - return error; + uri = delta->meta.uri; + pr_val_debug("Processing delta '%s'.", uri_val_get_printable(uri)); fnstack_push_uri(uri); error = cache_download(uri, NULL); if (error) - goto release_uri; - - error = parse_delta(uri, delta_head, arg); - + goto end; + error = parse_delta(uri, delta, arg); delete_from_uri(uri); - /* Error 0 its ok */ -release_uri: + +end: fnstack_pop(); - uri_refput(uri); return error; } int -rrdp_parse_snapshot(struct update_notification *notification) +rrdp_parse_snapshot(struct update_notification *notif) { struct rpki_uri *uri; int error; - pr_val_debug("Processing snapshot '%s'.", notification->snapshot.uri); - error = uri_create(&uri, UT_HTTPS, notification->snapshot.uri); - if (error) - return error; + uri = notif->snapshot.uri; + pr_val_debug("Processing snapshot '%s'.", uri_val_get_printable(uri)); fnstack_push_uri(uri); error = cache_download(uri, NULL); if (error) - goto release_uri; - - error = parse_snapshot(uri, notification); - + goto end; + error = parse_snapshot(uri, notif); delete_from_uri(uri); - /* Error 0 is ok */ -release_uri: + +end: fnstack_pop(); - uri_refput(uri); return error; } int -rrdp_process_deltas(struct update_notification *notification, - unsigned long cur_serial) +rrdp_process_deltas(struct update_notification *notif, unsigned long serial) { - return deltas_head_for_each(¬ification->deltas_list, - notification->meta.serial, cur_serial, process_delta, notification); + return deltas_head_for_each(¬if->deltas_list, notif->meta.serial, + serial, process_delta, notif); } diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index e7564a6a..9c1a874e 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -353,7 +353,7 @@ rsync_download(struct rpki_uri *uri) if (retries > 0) pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.", retries, uri_get_global(uri)); - error = EREQFAILED; + error = EIO; goto release_args; } pr_val_warn("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.", diff --git a/src/state.c b/src/state.c index bb102007..e6f7e122 100644 --- a/src/state.c +++ b/src/state.c @@ -37,9 +37,6 @@ struct validation { char addr_buffer2[INET6_ADDRSTRLEN]; struct validation_handler validation_handler; - - /* URL of the Notification file currently being traversed. */ - struct rpki_uri *notification_uri; }; /* @@ -118,7 +115,6 @@ validation_prepare(struct validation **out, struct tal *tal, result->pubkey_state = PKS_UNTESTED; result->validation_handler = *validation_handler; result->x509_data.params = params; /* Ownership transfered */ - result->notification_uri = NULL; *out = result; return 0; @@ -192,19 +188,3 @@ validation_get_validation_handler(struct validation *state) { return &state->validation_handler; } - -struct rpki_uri * -validation_get_notification_uri(struct validation *state) -{ - return state->notification_uri; -} - -void -validation_set_notification_uri(struct validation *state, struct rpki_uri *uri) -{ - if (state->notification_uri != NULL) - uri_refput(state->notification_uri); - state->notification_uri = uri; - if (uri != NULL) - uri_refget(uri); -} diff --git a/src/state.h b/src/state.h index b1386ccf..8fc48b09 100644 --- a/src/state.h +++ b/src/state.h @@ -32,7 +32,4 @@ validation_get_validation_handler(struct validation *); struct db_rrdp_uri *validation_get_rrdp_uris(struct validation *); -struct rpki_uri *validation_get_notification_uri(struct validation *); -void validation_set_notification_uri(struct validation *, struct rpki_uri *); - #endif /* SRC_STATE_H_ */ diff --git a/src/types/uri.c b/src/types/uri.c index 7776b1a1..6ea1f4c7 100644 --- a/src/types/uri.c +++ b/src/types/uri.c @@ -1,5 +1,7 @@ #include "types/uri.h" +#include + #include "alloc.h" #include "common.h" #include "config.h" @@ -9,6 +11,8 @@ #include "thread_var.h" #include "config/filename_format.h" #include "data_structure/path_builder.h" +#include "cache/local_cache.h" +#include "rrdp/rrdp_loader.h" /** * Design notes: @@ -331,20 +335,15 @@ map_simple(struct rpki_uri *uri, char const *gprefix, int err) * "/rrdp//a.b.c/d/e.cer". */ static int -map_caged(struct rpki_uri *uri) +map_caged(struct rpki_uri *uri, struct rpki_uri *notif) { struct path_builder pb; - struct rpki_uri *notification; int error; - notification = validation_get_notification_uri(state_retrieve()); - if (notification == NULL) - pr_crit("Programming error: Notification not recorded."); - error = pb_init_cache(&pb, "rrdp"); if (error) return error; - error = append_guri(&pb, notification->global, "https://", ENOTHTTPS, true); + error = append_guri(&pb, notif->global, "https://", ENOTHTTPS, true); if (error) return error; error = append_guri(&pb, uri->global, "rsync://", ENOTRSYNC, true); @@ -356,7 +355,7 @@ map_caged(struct rpki_uri *uri) } static int -autocomplete_local(struct rpki_uri *uri) +autocomplete_local(struct rpki_uri *uri, struct rpki_uri *notif) { switch (uri->type) { case UT_RSYNC: @@ -364,7 +363,7 @@ autocomplete_local(struct rpki_uri *uri) case UT_HTTPS: return map_simple(uri, "https://", ENOTHTTPS); case UT_CAGED: - return map_caged(uri); + return map_caged(uri, notif); } pr_crit("Unknown URI type: %u", uri->type); @@ -375,8 +374,8 @@ autocomplete_local(struct rpki_uri *uri) * need to be NULL terminated, but I'm not sure. */ int -__uri_create(struct rpki_uri **result, enum uri_type type, void const *guri, - size_t guri_len) +__uri_create(struct rpki_uri **result, enum uri_type type, + struct rpki_uri *notif, void const *guri, size_t guri_len) { struct rpki_uri *uri; int error; @@ -391,7 +390,7 @@ __uri_create(struct rpki_uri **result, enum uri_type type, void const *guri, uri->type = type; - error = autocomplete_local(uri); + error = autocomplete_local(uri, notif); if (error) { free(uri->global); free(uri); @@ -405,9 +404,10 @@ __uri_create(struct rpki_uri **result, enum uri_type type, void const *guri, } int -uri_create(struct rpki_uri **result, enum uri_type type, char const *guri) +uri_create(struct rpki_uri **result, enum uri_type type, struct rpki_uri *notif, + char const *guri) { - return __uri_create(result, type, guri, strlen(guri)); + return __uri_create(result, type, notif, guri, strlen(guri)); } /* @@ -415,7 +415,8 @@ uri_create(struct rpki_uri **result, enum uri_type type, char const *guri) * names. This function will infer the rest of the URL. */ int -uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5) +uri_create_mft(struct rpki_uri **result, struct rpki_uri *notif, + struct rpki_uri *mft, IA5String_t *ia5) { struct rpki_uri *uri; int error; @@ -428,11 +429,9 @@ uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5) return error; } - uri->type = (validation_get_notification_uri(state_retrieve()) == NULL) - ? UT_RSYNC - : UT_CAGED; + uri->type = (notif == NULL) ? UT_RSYNC : UT_CAGED; - error = autocomplete_local(uri); + error = autocomplete_local(uri, notif); if (error) { free(uri->global); free(uri); @@ -455,6 +454,9 @@ uri_refget(struct rpki_uri *uri) void uri_refput(struct rpki_uri *uri) { + if (uri == NULL) + return; + uri->references--; if (uri->references == 0) { free(uri->global); @@ -566,3 +568,95 @@ uri_op_get_printable(struct rpki_uri *uri) format = config_get_op_log_filename_format(); return uri_get_printable(uri, format); } + +DEFINE_ARRAY_LIST_FUNCTIONS(uri_list, struct rpki_uri *, static) + +void +uris_init(struct uri_list *uris) +{ + uri_list_init(uris); +} + +static void +__uri_refput(struct rpki_uri **uri) +{ + uri_refput(*uri); +} + +void +uris_cleanup(struct uri_list *uris) +{ + uri_list_cleanup(uris, __uri_refput); +} + +/* Swallows @uri. */ +void +uris_add(struct uri_list *uris, struct rpki_uri *uri) +{ + uri_list_add(uris, &uri); +} + +static int +download(struct rpki_uri *uri, bool use_rrdp) +{ + return (use_rrdp && (uri_get_type(uri) == UT_HTTPS)) + ? rrdp_update(uri) + : cache_download(uri, NULL); +} + +static struct rpki_uri * +download_uris(struct uri_list *uris, enum uri_type type, bool use_rrdp) +{ + struct rpki_uri **cursor, *uri; + ARRAYLIST_FOREACH(uris, cursor) { + uri = *cursor; + if (uri_get_type(uri) == type && download(uri, use_rrdp) == 0) + return uri; + } + return NULL; +} + +/** + * Assumes all the URIs are URLs, and represent different ways to access the + * same content. + * + * 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. + * + * Does not grab any references. + */ +struct rpki_uri * +uris_download(struct uri_list *uris, bool use_rrdp) +{ + struct rpki_uri **cursor, *uri; + + 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; + + } 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; + + } else { + ARRAYLIST_FOREACH(uris, cursor) { + uri = *cursor; + if (download(uri, use_rrdp) == 0) + return uri; + } + } + + return cache_recover(uris, use_rrdp); +} diff --git a/src/types/uri.h b/src/types/uri.h index a0d60700..ba03a0e6 100644 --- a/src/types/uri.h +++ b/src/types/uri.h @@ -3,6 +3,7 @@ #include #include "asn1/asn1c/IA5String.h" +#include "data_structure/array_list.h" enum uri_type { /* rsync URL */ @@ -18,9 +19,12 @@ enum uri_type { struct rpki_uri; -int __uri_create(struct rpki_uri **, enum uri_type, void const *, size_t); -int uri_create(struct rpki_uri **, enum uri_type, char const *); -int uri_create_mft(struct rpki_uri **, struct rpki_uri *, IA5String_t *); +int __uri_create(struct rpki_uri **, enum uri_type, struct rpki_uri *, + void const *, size_t); +int uri_create(struct rpki_uri **, enum uri_type, struct rpki_uri *, + char const *); +int uri_create_mft(struct rpki_uri **, struct rpki_uri *, struct rpki_uri *, + IA5String_t *); struct rpki_uri *uri_refget(struct rpki_uri *); void uri_refput(struct rpki_uri *); @@ -44,4 +48,14 @@ bool uri_is_https(struct rpki_uri *); char const *uri_val_get_printable(struct rpki_uri *); char const *uri_op_get_printable(struct rpki_uri *); +/* Plural */ + +DEFINE_ARRAY_LIST_STRUCT(uri_list, struct rpki_uri *); + +void uris_init(struct uri_list *); +void uris_cleanup(struct uri_list *); + +void uris_add(struct uri_list *, struct rpki_uri *); +struct rpki_uri *uris_download(struct uri_list *, bool); + #endif /* SRC_TYPES_URI_H_ */ diff --git a/test/cache/local_cache_test.c b/test/cache/local_cache_test.c index 761dcacd..0a663475 100644 --- a/test/cache/local_cache_test.c +++ b/test/cache/local_cache_test.c @@ -63,6 +63,8 @@ http_download(struct rpki_uri *uri, bool *changed) return error; } +MOCK_ABORT_INT(rrdp_update, struct rpki_uri *uri) + /* Helpers */ static const int SUCCESS = CNF_DIRECT | CNF_SUCCESS; @@ -90,7 +92,7 @@ __download(char const *url, enum uri_type uritype, int expected_error, { struct rpki_uri *uri; - ck_assert_int_eq(0, uri_create(&uri, uritype, url)); + ck_assert_int_eq(0, uri_create(&uri, uritype, NULL, url)); dl_count = 0; ck_assert_int_eq(expected_error, cache_download(uri, NULL)); @@ -1167,6 +1169,177 @@ START_TEST(test_ctt_traversal) } END_TEST +static void +prepare_uri_list(struct uri_list *uris, ...) +{ + char const *str; + enum uri_type type; + struct rpki_uri *uri; + va_list args; + + uris_init(uris); + + va_start(args, uris); + while ((str = va_arg(args, char const *)) != NULL) { + if (str_starts_with(str, "https://")) + type = UT_HTTPS; + else if (str_starts_with(str, "rsync://")) + type = UT_RSYNC; + else + ck_abort_msg("Bad protocol: %s", str); + ck_assert_int_eq(0, uri_create(&uri, type, NULL, str)); + uris_add(uris, uri); + } + va_end(args); +} + +#define PREPARE_URI_LIST(uris, ...) prepare_uri_list(uris, ##__VA_ARGS__, NULL) + +START_TEST(test_recover) +{ + struct uri_list uris; + + ck_assert_int_eq(0, system("rm -rf tmp/")); + dl_error = false; + + /* Query on empty database */ + PREPARE_URI_LIST(&uris, "rsync://a.b.c/d", "https://a.b.c/d"); + ck_assert_ptr_null(cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* Only first URI is cached */ + ck_assert_int_eq(0, cache_prepare()); + download_rsync("rsync://a/b/c", 0, 1); + + PREPARE_URI_LIST(&uris, "rsync://a/b/c", "https://d/e", "https://f"); + ck_assert_ptr_eq(uris.array[0], cache_recover(&uris, false)); + uris_cleanup(&uris); + + cache_teardown(); + + /* Only second URI is cached */ + ck_assert_int_eq(0, cache_prepare()); + download_https("https://d/e", 0, 1); + + PREPARE_URI_LIST(&uris, "rsync://a/b/c", "https://d/e", "https://f"); + ck_assert_ptr_eq(uris.array[1], cache_recover(&uris, false)); + uris_cleanup(&uris); + + cache_teardown(); + + /* Only third URI is cached */ + ck_assert_int_eq(0, cache_prepare()); + download_https("https://f", 0, 1); + + PREPARE_URI_LIST(&uris, "rsync://a/b/c", "https://d/e", "https://f"); + ck_assert_ptr_eq(uris.array[2], cache_recover(&uris, false)); + uris_cleanup(&uris); + + cache_teardown(); + + /* None was cached */ + ck_assert_int_eq(0, cache_prepare()); + download_rsync("rsync://d/e", 0, 1); + + PREPARE_URI_LIST(&uris, "rsync://a/b/c", "https://d/e", "https://f"); + ck_assert_ptr_null(cache_recover(&uris, false)); + uris_cleanup(&uris); + + cache_teardown(); + + /* + * At present, cache_recover() can only be called after all of a + * download's URLs yielded failure. + * However, node.error can still be zero. This happens when the download + * was successful, but the RRDP code wasn't able to expand the snapshot + * or deltas. + */ + rsync = NODE("rsync", 0, 0, + NODE("a", 0, 0, + TNODE("1", CNF_DIRECT | CNF_SUCCESS, 100, 100, 0), + TNODE("2", CNF_DIRECT | CNF_SUCCESS, 100, 100, 1), + TNODE("3", CNF_DIRECT | CNF_SUCCESS, 100, 200, 0), + TNODE("4", CNF_DIRECT | CNF_SUCCESS, 100, 200, 1), + TNODE("5", CNF_DIRECT | CNF_SUCCESS, 200, 100, 0), + TNODE("6", CNF_DIRECT | CNF_SUCCESS, 200, 100, 1)), + NODE("b", 0, 0, + TNODE("1", CNF_DIRECT, 100, 100, 0), + TNODE("2", CNF_DIRECT, 100, 100, 1), + TNODE("3", CNF_DIRECT, 100, 200, 0), + TNODE("4", CNF_DIRECT, 100, 200, 1), + TNODE("5", CNF_DIRECT, 200, 100, 0), + TNODE("6", CNF_DIRECT, 200, 100, 1)), + TNODE("c", CNF_DIRECT | CNF_SUCCESS, 300, 300, 0, + TNODE("1", 0, 0, 0, 0)), + TNODE("d", CNF_DIRECT | CNF_SUCCESS, 50, 50, 0, + TNODE("1", 0, 0, 0, 0))); + + /* Multiple successful caches: Prioritize the most recent one */ + PREPARE_URI_LIST(&uris, "rsync://a/1", "rsync://a/3", "rsync://a/5"); + ck_assert_ptr_eq(uris.array[2], cache_recover(&uris, false)); + uris_cleanup(&uris); + + PREPARE_URI_LIST(&uris, "rsync://a/5", "rsync://a/1", "rsync://a/3"); + ck_assert_ptr_eq(uris.array[0], cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* No successful caches: No viable candidates */ + PREPARE_URI_LIST(&uris, "rsync://b/2", "rsync://b/4", "rsync://b/6"); + ck_assert_ptr_null(cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* Status: CNF_SUCCESS is better than 0. */ + PREPARE_URI_LIST(&uris, "rsync://b/1", "rsync://a/1"); + ck_assert_ptr_eq(uris.array[1], cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* + * If CNF_SUCCESS && error, Fort will probably run into a problem + * reading the cached directory, because it's either outdated or + * recently corrupted. + * But it should still TRY to read it, as there's a chance the + * outdatedness is not that severe. + */ + PREPARE_URI_LIST(&uris, "rsync://a/2", "rsync://b/2"); + ck_assert_ptr_eq(uris.array[0], cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* Parents of downloaded nodes */ + PREPARE_URI_LIST(&uris, "rsync://a", "rsync://b"); + ck_assert_ptr_null(cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* Children of downloaded nodes */ + PREPARE_URI_LIST(&uris, "rsync://a/5", "rsync://c/1"); + ck_assert_ptr_eq(uris.array[1], cache_recover(&uris, false)); + uris_cleanup(&uris); + + PREPARE_URI_LIST(&uris, "rsync://a/5", "rsync://c/2"); + ck_assert_ptr_eq(uris.array[1], cache_recover(&uris, false)); + uris_cleanup(&uris); + + PREPARE_URI_LIST(&uris, "rsync://a/1", "rsync://d/1"); + ck_assert_ptr_eq(uris.array[0], cache_recover(&uris, false)); + uris_cleanup(&uris); + + PREPARE_URI_LIST(&uris, "rsync://a/1", "rsync://d/2"); + ck_assert_ptr_eq(uris.array[0], cache_recover(&uris, false)); + uris_cleanup(&uris); + + /* Try them all at the same time */ + PREPARE_URI_LIST(&uris, + "rsync://a", "rsync://a/1", "rsync://a/2", "rsync://a/3", + "rsync://a/4", "rsync://a/5", "rsync://a/6", + "rsync://b", "rsync://b/1", "rsync://b/2", "rsync://b/3", + "rsync://b/4", "rsync://b/5", "rsync://b/6", + "rsync://c/2", "rsync://d/1", "rsync://e/1"); + ck_assert_ptr_eq(uris.array[14], cache_recover(&uris, false)); + uris_cleanup(&uris); + + cache_teardown(); +} +END_TEST + /* Boilerplate */ Suite *thread_pool_suite(void) @@ -1195,6 +1368,9 @@ Suite *thread_pool_suite(void) ctt = tcase_create("ctt"); tcase_add_test(ctt, test_ctt_traversal); + ctt = tcase_create("recover"); + tcase_add_test(ctt, test_recover); + suite = suite_create("local-cache"); suite_add_tcase(suite, rsync); suite_add_tcase(suite, https); diff --git a/test/mock.c b/test/mock.c index 9d63e9a4..328d580a 100644 --- a/test/mock.c +++ b/test/mock.c @@ -108,6 +108,8 @@ MOCK(config_get_tal, char const *, "tal/", void) MOCK(config_get_local_repository, char const *, "tmp", void) MOCK(config_get_mode, enum mode, STANDALONE, void) MOCK_TRUE(config_get_rsync_enabled, void) +MOCK_UINT(config_get_rsync_priority, 50, void) +MOCK_UINT(config_get_http_priority, 60, void) MOCK_NULL(config_get_output_roa, char const *, void) MOCK_NULL(config_get_output_bgpsec, char const *, void) MOCK_UINT(config_get_thread_pool_validation_max, 10, void) diff --git a/test/tal_test.c b/test/tal_test.c index 60ef0321..7d46f45e 100644 --- a/test/tal_test.c +++ b/test/tal_test.c @@ -28,6 +28,11 @@ MOCK_ABORT_VOID(fnstack_init, void) MOCK_ABORT_VOID(fnstack_cleanup, void) MOCK_ABORT_VOID(fnstack_push, char const *f) +MOCK_ABORT_INT(cache_download, struct rpki_uri *uri, bool *changed) +MOCK_ABORT_INT(rrdp_update, struct rpki_uri *uri) +MOCK_ABORT_PTR(cache_recover, rpki_uri, struct uri_list *uris, + bool use_rrdp) + /* Tests */ START_TEST(tal_load_normal) @@ -67,7 +72,7 @@ START_TEST(tal_load_normal) ck_assert_int_eq(tal_load("tal/lacnic.tal", &tal), 0); - ck_assert_uint_eq(tal->uris.count, 3); + ck_assert_uint_eq(tal->uris.len, 3); ck_assert_str_eq(tal->uris.array[0]->global, "rsync://repository.lacnic.net/rpki/lacnic/rta-lacnic-rpki.cer"); ck_assert_str_eq(tal->uris.array[1]->global, "https://potato"); diff --git a/test/types/uri_test.c b/test/types/uri_test.c index 66852180..b6764cc1 100644 --- a/test/types/uri_test.c +++ b/test/types/uri_test.c @@ -10,79 +10,86 @@ /* Mocks */ -struct rpki_uri *notification; +struct rpki_uri *notif; MOCK(state_retrieve, struct validation *, NULL, void) -MOCK(validation_get_notification_uri, struct rpki_uri *, notification, +MOCK(validation_get_notification_uri, struct rpki_uri *, notif, struct validation *state) +MOCK_ABORT_INT(cache_download, struct rpki_uri *uri, bool *changed) +MOCK_ABORT_INT(rrdp_update, struct rpki_uri *uri) +MOCK_ABORT_PTR(cache_recover, rpki_uri, struct uri_list *uris, + bool use_rrdp) + /* Tests */ +#define URI_CREATE_HTTP(uri, str) uri_create(&uri, UT_HTTPS, NULL, str) + START_TEST(test_constructor) { struct rpki_uri *uri; - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "h")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "http")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "https")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "https:")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "https:/")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "h")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "http")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "https")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "https:")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "https:/")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://")); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c")); ck_assert_str_eq("https://a.b.c", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/")); ck_assert_str_eq("https://a.b.c/", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/d")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/d")); ck_assert_str_eq("https://a.b.c/d", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c/d", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/d/e")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/d/e")); ck_assert_str_eq("https://a.b.c/d/e", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c/d/e", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/d/..")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/d/..")); ck_assert_str_eq("https://a.b.c/d/..", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/.")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/.")); ck_assert_str_eq("https://a.b.c/.", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/././d/././e/./.")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/././d/././e/./.")); ck_assert_str_eq("https://a.b.c/././d/././e/./.", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c/d/e", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(0, uri_create(&uri, UT_HTTPS, "https://a.b.c/a/b/.././..")); + ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/a/b/.././..")); ck_assert_str_eq("https://a.b.c/a/b/.././..", uri_get_global(uri)); ck_assert_str_eq("tmp/https/a.b.c", uri_get_local(uri)); uri_refput(uri); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://a.b.c/..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://a.b.c/../..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://a.b.c/d/../..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://a.b.c/d/../../..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://.")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://./.")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://../..")); - ck_assert_int_eq(-EINVAL, uri_create(&uri, UT_HTTPS, "https://../../..")); - - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "rsync://a.b.c/d")); - ck_assert_int_eq(ENOTHTTPS, uri_create(&uri, UT_HTTPS, "http://a.b.c/d")); - ck_assert_int_eq(ENOTRSYNC, uri_create(&uri, UT_RSYNC, "https://a.b.c/d")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://a.b.c/..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://a.b.c/../..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://a.b.c/d/../..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://a.b.c/d/../../..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://.")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://./.")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://../..")); + ck_assert_int_eq(-EINVAL, URI_CREATE_HTTP(uri, "https://../../..")); + + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "rsync://a.b.c/d")); + ck_assert_int_eq(ENOTHTTPS, URI_CREATE_HTTP(uri, "http://a.b.c/d")); + ck_assert_int_eq(ENOTRSYNC, uri_create(&uri, UT_RSYNC, NULL, "https://a.b.c/d")); } END_TEST @@ -142,17 +149,17 @@ START_TEST(check_caged) { struct rpki_uri *uri; - ck_assert_int_eq(0, uri_create(¬ification, UT_HTTPS, "https://a.b.c/d/e.xml")); - ck_assert_int_eq(0, uri_create(&uri, UT_CAGED, "rsync://x.y.z/v/w.cer")); + ck_assert_int_eq(0, uri_create(¬if, UT_HTTPS, NULL, "https://a.b.c/d/e.xml")); + ck_assert_int_eq(0, uri_create(&uri, UT_CAGED, notif, "rsync://x.y.z/v/w.cer")); ck_assert_str_eq("tmp/rrdp/a.b.c/d/e.xml/x.y.z/v/w.cer", uri_get_local(uri)); uri_refput(uri); - uri_refput(notification); + uri_refput(notif); - ck_assert_int_eq(0, uri_create(¬ification, UT_HTTPS, "https://a.b.c")); - ck_assert_int_eq(0, uri_create(&uri, UT_CAGED, "rsync://w")); + ck_assert_int_eq(0, uri_create(¬if, UT_HTTPS, NULL, "https://a.b.c")); + ck_assert_int_eq(0, uri_create(&uri, UT_CAGED, notif, "rsync://w")); ck_assert_str_eq("tmp/rrdp/a.b.c/w", uri_get_local(uri)); uri_refput(uri); - uri_refput(notification); + uri_refput(notif); } END_TEST