+The new arguments are 'rsync.retry.count', 'rsync.retry.interval', 'rrdp.retry.count', and 'rrdp.retry.interval'. Utilized whenever there's an rsync or rrdp sync error, the validator will retry at most '*.retry.count' times, waiting '*.retry.interval' between each retry.
+Ensure that HTTP files download returns a negative error in case of error.
+Wrap files download function at rrdp_parser.
unsigned int priority;
/* Synchronization download strategy. */
enum rsync_strategy strategy;
+ /* Retry conf, utilized on errors */
+ struct {
+ /* Maximum number of retries on error */
+ unsigned int count;
+ /* Interval (in seconds) between each retry */
+ unsigned int interval;
+ } retry;
char *program;
struct {
struct string_array flat;
* their accessMethod extension.
*/
unsigned int priority;
+ /* Retry conf, utilized on errors */
+ struct {
+ /* Maximum number of retries on error */
+ unsigned int count;
+ /* Interval (in seconds) between each retry */
+ unsigned int interval;
+ } retry;
} rrdp;
struct {
.type = >_rsync_strategy,
.offset = offsetof(struct rpki_config, rsync.strategy),
.doc = "RSYNC download strategy",
- },{
+ }, {
.id = 3003,
+ .name = "rsync.retry.count",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, rsync.retry.count),
+ .doc = "Maximum amount of retries whenever there's an RSYNC error",
+ .min = 0,
+ .max = UINT_MAX,
+ }, {
+ .id = 3004,
+ .name = "rsync.retry.interval",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, rsync.retry.interval),
+ .doc = "Period (in seconds) to wait between retries after an RSYNC error ocurred",
+ .min = 0,
+ .max = UINT_MAX,
+ },{
+ .id = 3005,
.name = "rsync.program",
.type = >_string,
.offset = offsetof(struct rpki_config, rsync.program),
.arg_doc = "<path to program>",
.availability = AVAILABILITY_JSON,
}, {
- .id = 3004,
+ .id = 3006,
.name = "rsync.arguments-recursive",
.type = >_string_array,
.offset = offsetof(struct rpki_config, rsync.args.recursive),
.doc = "RSYNC program arguments that will trigger a recursive RSYNC",
.availability = AVAILABILITY_JSON,
}, {
- .id = 3005,
+ .id = 3007,
.name = "rsync.arguments-flat",
.type = >_string_array,
.offset = offsetof(struct rpki_config, rsync.args.flat),
.doc = "Priority of execution to fetch repositories files, a higher value means higher priority",
.min = 0,
.max = 100,
+ }, {
+ .id = 10002,
+ .name = "rrdp.retry.count",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, rrdp.retry.count),
+ .doc = "Maximum amount of retries whenever there's an error fetching RRDP files",
+ .min = 0,
+ .max = UINT_MAX,
+ }, {
+ .id = 10003,
+ .name = "rrdp.retry.interval",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, rrdp.retry.interval),
+ .doc = "Period (in seconds) to wait between retries after an error ocurred fetching RRDP files",
+ .min = 0,
+ .max = UINT_MAX,
},
/* HTTP requests parameters */
rpki_config.rsync.enabled = true;
rpki_config.rsync.priority = 50;
rpki_config.rsync.strategy = RSYNC_ROOT;
+ rpki_config.rsync.retry.count = 1;
+ rpki_config.rsync.retry.interval = 3;
rpki_config.rsync.program = strdup("rsync");
if (rpki_config.rsync.program == NULL) {
error = pr_enomem();
rpki_config.rrdp.enabled = true;
rpki_config.rrdp.priority = 50;
+ rpki_config.rrdp.retry.count = 1;
+ rpki_config.rrdp.retry.interval = 3;
rpki_config.http.user_agent = strdup(PACKAGE_NAME "/" PACKAGE_VERSION);
if (rpki_config.http.user_agent == NULL) {
return rpki_config.rsync.strategy;
}
+unsigned int
+config_get_rsync_retry_count(void)
+{
+ return rpki_config.rsync.retry.count;
+}
+
+unsigned int
+config_get_rsync_retry_interval(void)
+{
+ return rpki_config.rsync.retry.interval;
+}
+
char *
config_get_rsync_program(void)
{
return rpki_config.rrdp.priority;
}
+unsigned int
+config_get_rrdp_retry_count(void)
+{
+ return rpki_config.rrdp.retry.count;
+}
+
+unsigned int
+config_get_rrdp_retry_interval(void)
+{
+ return rpki_config.rrdp.retry.interval;
+}
+
char const *
config_get_http_user_agent(void)
{
bool config_get_rsync_enabled(void);
unsigned int config_get_rsync_priority(void);
enum rsync_strategy config_get_rsync_strategy(void);
+unsigned int config_get_rsync_retry_count(void);
+unsigned int config_get_rsync_retry_interval(void);
char *config_get_rsync_program(void);
struct string_array const *config_get_rsync_args(bool);
bool config_get_rrdp_enabled(void);
unsigned int config_get_rrdp_priority(void);
+unsigned int config_get_rrdp_retry_count(void);
+unsigned int config_get_rrdp_retry_interval(void);
char const *config_get_output_roa(void);
char const *config_get_output_bgpsec(void);
unsigned int config_get_asn1_decode_max_stack(void);
error = create_dir_recursive(uri_get_local(uri));
if (error)
- return error;
+ return ENSURE_NEGATIVE(error);
error = file_write(uri_get_local(uri), &out, &stat);
if (error)
- return error;
+ return ENSURE_NEGATIVE(error);
error = http_easy_init(&handler);
if (error)
file_close(out);
/* Error 0 it's ok */
- return error;
+ return ENSURE_NEGATIVE(error);
close_file:
file_close(out);
delete_dir_recursive_bottom_up(uri_get_local(uri));
- return error;
+ return ENSURE_NEGATIVE(error);
}
/*
return read;
}
+static int
+download_file(struct rpki_uri *uri, long last_update)
+{
+ unsigned int retries;
+ int error;
+
+ retries = 0;
+ do {
+ if (last_update > 0)
+ error = http_download_file_with_ims(uri, write_local,
+ last_update);
+ else
+ error = http_download_file(uri, write_local);
+
+ /* Remember: positive values are expected */
+ if (error >= 0)
+ return error;
+
+ if (retries == config_get_rrdp_retry_count()) {
+ pr_info("Max RRDP retries (%u) reached, won't retry again.",
+ retries);
+ return error;
+ }
+ pr_info("Retrying RRDP file download in %u seconds, %u attempts remaining.",
+ config_get_rrdp_retry_interval(),
+ config_get_rrdp_retry_count() - retries);
+ retries++;
+ sleep(config_get_rrdp_retry_interval());
+ } while (true);
+}
+
/* Trim @from, setting the result at @result pointer */
static int
trim(char *from, char **result, size_t *result_size)
if (error)
return error;
- error = http_download_file(uri, write_local);
+ error = download_file(uri, 0);
if (error)
goto release_uri;
if (error && error != -ENOENT)
return error;
- error = http_download_file_with_ims(uri, write_local, last_update);
+ error = download_file(uri, last_update);
if (error < 0)
return error;
if (error)
return error;
- error = http_download_file(uri, write_local);
+ error = download_file(uri, 0);
if (error)
goto release_uri;
/* Descriptors to pipe stderr (first element) and stdout (second) */
int fork_fds[2][2];
pid_t child_pid;
+ unsigned int retries;
int child_status;
int error;
- child_status = 0;
- error = create_dir_recursive(uri_get_local(uri));
- if (error)
- return error;
-
- error = create_pipes(fork_fds);
- if (error)
- return error;
+ retries = 0;
+ do {
+ child_status = 0;
+ error = create_dir_recursive(uri_get_local(uri));
+ if (error)
+ return error;
- /* We need to fork because execvp() magics the thread away. */
- child_pid = fork();
- if (child_pid == 0) {
- /* This code is run by the child. */
- handle_child_thread(uri, is_ta, fork_fds);
- }
+ error = create_pipes(fork_fds);
+ if (error)
+ return error;
- /* This code is run by us. */
- error = read_pipes(fork_fds);
- if (error)
- return error;
+ /* We need to fork because execvp() magics the thread away. */
+ child_pid = fork();
+ if (child_pid == 0) {
+ /* This code is run by the child. */
+ handle_child_thread(uri, is_ta, fork_fds);
+ }
- error = waitpid(child_pid, &child_status, 0);
- do {
- if (error == -1) {
- error = errno;
- pr_err("The rsync sub-process returned error %d (%s)",
- error, strerror(error));
- if (child_status > 0)
- break;
+ /* This code is run by us. */
+ error = read_pipes(fork_fds);
+ if (error)
return error;
- }
- } while (0);
- if (WIFEXITED(child_status)) {
- /* Happy path (but also sad path sometimes). */
- error = WEXITSTATUS(child_status);
- pr_debug("Child terminated with error code %d.", error);
- return error;
- }
+ error = waitpid(child_pid, &child_status, 0);
+ do {
+ if (error == -1) {
+ error = errno;
+ pr_err("The rsync sub-process returned error %d (%s)",
+ error, strerror(error));
+ if (child_status > 0)
+ break;
+ return error;
+ }
+ } while (0);
+
+ if (WIFEXITED(child_status)) {
+ /* Happy path (but also sad path sometimes). */
+ error = WEXITSTATUS(child_status);
+ pr_debug("Child terminated with error code %d.", error);
+ if (!error)
+ return 0;
+ if (retries == config_get_rsync_retry_count()) {
+ pr_info("Max RSYNC retries (%u) reached, won't retry again.",
+ retries);
+ return error;
+ }
+ pr_info("Retrying RSYNC in %u seconds, %u attempts remaining.",
+ config_get_rsync_retry_interval(),
+ config_get_rsync_retry_count() - retries);
+ retries++;
+ sleep(config_get_rsync_retry_interval());
+ continue;
+ }
+ break;
+ } while (true);
if (WIFSIGNALED(child_status)) {
switch (WTERMSIG(child_status)) {