From c996c183b2a3fc2d853cc74aed3810c48d6f6ee4 Mon Sep 17 00:00:00 2001 From: Alberto Leiva Popper Date: Fri, 24 Oct 2025 11:28:59 -0600 Subject: [PATCH] Recover better when RRDP changes session ID The update was getting rejected because the new file URIs were conflicting with the old file URIs, so Fort was fallbacking. When session ID changes, Forget the old URIs and accept the update instead. --- src/rrdp.c | 73 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/src/rrdp.c b/src/rrdp.c index 9c5dd4ac..52ca117c 100644 --- a/src/rrdp.c +++ b/src/rrdp.c @@ -167,6 +167,36 @@ state_add_file(struct rrdp_state *state, struct cache_file *file) HASH_ADD_KEYPTR(hh, state->files, url, urlen, file); } +static void +clear_delta_hashes(struct rrdp_state *state) +{ + struct rrdp_hash *hash; + + while (!STAILQ_EMPTY(&state->delta_hashes)) { + hash = STAILQ_FIRST(&state->delta_hashes); + STAILQ_REMOVE_HEAD(&state->delta_hashes, hook); + free(hash); + } +} + +static void +rrdp_state_reset(struct rrdp_state *state) +{ + struct cache_file *file, *tmp; + + HASH_ITER(hh, state->files, file, tmp) { + file_rm_f(file->map.path); + + HASH_DEL(state->files, file); + map_cleanup(&file->map); + free(file); + } + + session_cleanup(&state->session); + clear_delta_hashes(state); + /* Leave the seq alive */ +} + static struct cache_file * cache_file_add(struct rrdp_state *state, struct uri const *url, char *path) { @@ -553,7 +583,7 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) /* Parsing done */ - pr_clutter("Publish %s", logv_filename(uri_str(&tag.meta.uri))); + pr_clutter("Publish %s", uri_str(&tag.meta.uri)); file = state_find_file(args->state, &tag.meta.uri); @@ -628,7 +658,7 @@ handle_withdraw(xmlTextReaderPtr reader, struct parser_args *args) goto end; } - pr_clutter("Withdraw %s", logv_filename(uri_str(&tag.meta.uri))); + pr_clutter("Withdraw %s", uri_str(&tag.meta.uri)); file = state_find_file(args->state, &tag.meta.uri); @@ -1222,29 +1252,50 @@ rrdp_update(struct uri const *notif, char const *path, time_t mtim, if ((*state) == NULL) { pr_trc("This is a new Notification."); + error = file_mkdir(path, false); + if (error) + goto clean_notif; + old = pzalloc(sizeof(struct rrdp_state)); /* session postponed! */ cseq_init(&old->seq, pstrdup(path), 0, true); STAILQ_INIT(&old->delta_hashes); - error = file_mkdir(path, false); + error = handle_snapshot(&new, old); if (error) { rrdp_state_free(old); goto clean_notif; } + init_notif(old, &new); + *state = old; + goto end; + } + + old = *state; + + if (strcmp(old->session.session_id, new.session.session_id) != 0) { + pr_trc("The session changed. (Was %s)", old->session.session_id); + + /* + * The problem with keeping both sessions is that session_id + * does not exist outside of RRDP, which means callers don't + * know which to ask for, which means I'd have to manage + * different tiers of fallbacks, and it's too late for that now. + */ + rrdp_state_reset(old); + error = handle_snapshot(&new, old); if (error) { rrdp_state_free(old); + *state = NULL; goto clean_notif; } init_notif(old, &new); - *state = old; goto end; } - old = *state; serial_cmp = BN_cmp(old->session.serial.num, new.session.serial.num); if (serial_cmp < 0) { pr_trc("The Notification's serial changed."); @@ -1551,18 +1602,6 @@ json2dh(json_t *json, struct rrdp_hash **dh) return 0; } -static void -clear_delta_hashes(struct rrdp_state *state) -{ - struct rrdp_hash *hash; - - while (!STAILQ_EMPTY(&state->delta_hashes)) { - hash = STAILQ_FIRST(&state->delta_hashes); - STAILQ_REMOVE_HEAD(&state->delta_hashes, hook); - free(hash); - } -} - static int json2dhs(json_t *json, struct rrdp_state *state) { -- 2.47.3