+ Create common function to get the current date and time.
+ Identify request errors, specifically after trying to fetch data via http/rsync without success. This helps to identify if a whole repository can't be downloaded after a considerable time (it can be configured).
+ Allow to work with local files even when there was a download error.
+ Add 'stale-repository-period' argument to set the time period that must lapse to warn about stale repositories (this will be logged to the operation log).
fort_SOURCES += notify.c notify.h
fort_SOURCES += output_printer.h output_printer.c
fort_SOURCES += random.h random.c
+fort_SOURCES += reqs_errors.h reqs_errors.c
fort_SOURCES += resource.h resource.c
fort_SOURCES += rpp.h rpp.c
fort_SOURCES += sorted_array.h sorted_array.c
free(work_loc);
return error;
}
+
+int
+get_current_time(time_t *result)
+{
+ time_t now;
+
+ now = time(NULL);
+ if (now == ((time_t) -1))
+ return pr_errno(errno, "Error getting the current time");
+
+ *result = now;
+ return 0;
+}
#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
+#include <time.h>
#include <netinet/in.h>
/* "I think that this is not supposed to be implemented." */
* still coexist in most scenarios.
*/
#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.
int create_dir_recursive(char const *);
int delete_dir_recursive_bottom_up(char const *);
+int get_current_time(time_t *);
+
#endif /* SRC_RTR_COMMON_H_ */
/* ASN1 decoder max stack size allowed */
unsigned int asn1_decode_max_stack;
+
+ /* Time period that must lapse to warn about a stale repository */
+ unsigned int stale_repository_period;
};
static void print_usage(FILE *, bool);
.min = 1,
.max = UINT_MAX,
},
+ {
+ .id = 8001,
+ .name = "stale-repository-period",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, stale_repository_period),
+ .doc = "Time period that must lapse to warn about stale repositories",
+ .min = 0,
+ .max = UINT_MAX,
+ },
{ 0 },
};
rpki_config.output.bgpsec = NULL;
rpki_config.asn1_decode_max_stack = 4096; /* 4kB */
+ rpki_config.stale_repository_period = 43200; /* 12 hours */
return 0;
revert_flat_array:
return rpki_config.asn1_decode_max_stack;
}
+unsigned int
+config_get_stale_repository_period(void)
+{
+ return rpki_config.stale_repository_period;
+}
+
void
config_set_rsync_enabled(bool value)
{
char const *config_get_output_roa(void);
char const *config_get_output_bgpsec(void);
unsigned int config_get_asn1_decode_max_stack(void);
+unsigned int config_get_stale_repository_period(void);
/*
* Public, so that work-offline can set them, or (to be deprecated)
return 0;
free_mem:
BIO_free_all(b64);
- return error ? error_ul2i(error) : -ENOMEM;;
+ return error ? error_ul2i(error) : -ENOMEM;
}
*/
static int
http_fetch(struct http_handler *handler, char const *uri, long *response_code,
- long *cond_met, http_write_cb cb, void *arg)
+ long *cond_met, bool log_operation, http_write_cb cb, void *arg)
{
CURLcode res;
long unmet = 0;
return pr_err("Error requesting URL %s (received HTTP code %ld): %s",
uri, *response_code, curl_err_string(handler, res));
- return pr_err("Error requesting URL %s: %s", uri,
+ /* FIXME (NOW) Always log to validation log */
+ pr_err("[VALIDATION] Error requesting URL %s: %s", uri,
curl_err_string(handler, res));
+ /* FIXME (NOW) and send to operation log when requested */
+ if (log_operation)
+ pr_err("[OPERATION] Error requesting URL %s: %s", uri,
+ curl_err_string(handler, res));
+
+ return EREQFAILED;
}
static void
static int
__http_download_file(struct rpki_uri *uri, http_write_cb cb,
- long *response_code, long ims_value, long *cond_met)
+ long *response_code, long ims_value, long *cond_met, bool log_operation)
{
struct http_handler handler;
struct stat stat;
}
error = http_fetch(&handler, uri_get_global(uri), response_code,
- cond_met, cb, out);
+ cond_met, log_operation, cb, out);
http_easy_cleanup(&handler);
file_close(out);
* from local @uri. The @cb should be utilized to write into a file; the file
* will be sent to @cb as the last argument (its a FILE reference).
*
- * Regular return value: 0 on success, any other value is an error.
+ * Return values: 0 on success, negative value on error, EREQFAILED if the
+ * request to the server failed.
*/
int
-http_download_file(struct rpki_uri *uri, http_write_cb cb)
+http_download_file(struct rpki_uri *uri, http_write_cb cb, bool log_operation)
{
long response;
long cond_met;
- return __http_download_file(uri, cb, &response, 0, &cond_met);
+ return __http_download_file(uri, cb, &response, 0, &cond_met,
+ log_operation);
}
/*
* of @value (if @value is 0, the header isn't set).
*
* Returns:
+ * EREQFAILED the request to the server has failed.
* > 0 file was requested but wasn't downloaded since the server didn't sent
* a response due to its policy using the header 'If-Modified-Since'.
* = 0 file successfully downloaded.
* < 0 an actual error happened.
*/
int
-http_download_file_with_ims(struct rpki_uri *uri, http_write_cb cb, long value)
+http_download_file_with_ims(struct rpki_uri *uri, http_write_cb cb, long value,
+ bool log_operation)
{
long response;
long cond_met;
int error;
- error = __http_download_file(uri, cb, &response, value, &cond_met);
+ error = __http_download_file(uri, cb, &response, value, &cond_met,
+ log_operation);
if (error)
return error;
if (cond_met)
return 0;
- return __http_download_file(uri, cb, &response, 0, &cond_met);
+ return __http_download_file(uri, cb, &response, 0, &cond_met,
+ log_operation);
}
#ifndef SRC_HTTP_HTTP_H_
#define SRC_HTTP_HTTP_H_
+#include <stdbool.h>
#include <stddef.h>
#include "uri.h"
void http_cleanup(void);
typedef size_t (http_write_cb)(unsigned char *, size_t, size_t, void *);
-int http_download_file(struct rpki_uri *, http_write_cb);
-int http_download_file_with_ims(struct rpki_uri *, http_write_cb, long);
+int http_download_file(struct rpki_uri *, http_write_cb, bool);
+int http_download_file_with_ims(struct rpki_uri *, http_write_cb, long, bool);
#endif /* SRC_HTTP_HTTP_H_ */
#include "debug.h"
#include "extension.h"
#include "nid.h"
+#include "reqs_errors.h"
#include "thread_var.h"
#include "http/http.h"
#include "rtr/rtr.h"
if (error)
goto vrps_cleanup;
+ error = reqs_errors_init();
+ if (error)
+ goto db_rrdp_cleanup;
+
error = rtr_listen();
+ reqs_errors_cleanup();
+db_rrdp_cleanup:
db_rrdp_cleanup();
vrps_cleanup:
vrps_destroy();
* children CAs being the same as the parent CA.
*
* Two possible scenarios arise:
- * 1) CA Parent didn't utilized (or didn't had) and RRDP update
+ * 1) CA Parent didn't utilized (or didn't had) an RRDP update
* notification URI.
* 2) CA Parent successfully utilized an RRDP update notification URI.
*
}
if (primary_rrdp) {
+ working_repo_push(uri_get_global(sia_uris->rpkiNotify.uri));
if (error != -EPERM)
pr_info("Couldn't fetch data from RRDP repository '%s', trying to fetch data now from '%s'.",
uri_get_global(sia_uris->rpkiNotify.uri),
uri_get_global(sia_uris->rpkiNotify.uri),
uri_get_global(sia_uris->caRepository.uri));
} else {
+ working_repo_push(uri_get_global(sia_uris->caRepository.uri));
pr_info("Couldn't fetch data from repository '%s', trying to fetch data now from RRDP '%s'.",
uri_get_global(sia_uris->caRepository.uri),
uri_get_global(sia_uris->rpkiNotify.uri));
}
(*rsync_utilized) = primary_rrdp;
- return cb_secondary(sia_uris);
+ error = cb_secondary(sia_uris);
+ /* No need to remember the working repository anymore */
+ working_repo_pop();
+
+ return error;
}
/** Boilerplate code for CA certificate validation and recursive traversal. */
if (error == 0 || !mft_retry)
break;
+ /*
+ * Don't reach here if:
+ * - Manifest is valid.
+ * - Working with local files due to a download error.
+ * - RRDP was utilized to fetch the manifest.
+ * - There was a previous attempt to re-fetch the repository.
+ */
pr_info("Retrying repository download to discard 'transient inconsistency' manifest issue (see RFC 6481 section 5) '%s'",
uri_get_printable(sia_uris.caRepository.uri));
error = download_files(sia_uris.caRepository.uri, false, true);
#include <errno.h>
#include "algorithm.h"
+#include "common.h"
#include "log.h"
#include "thread_var.h"
#include "asn1/decode.h"
time_t now;
struct tm thisUpdate_tm;
struct tm nextUpdate_tm;
+ int error;
/*
* BTW: We only need the tm variables for error messages, which are
TM_ARGS(nextUpdate_tm));
}
- now = time(NULL);
- if (now == ((time_t) -1))
- return pr_errno(errno, "Error getting the current time");
+ now = 0;
+ error = get_current_time(&now);
+ if (error)
+ return error;
if (difftime(now, thisUpdate) < 0) {
return pr_err(
#include "line_file.h"
#include "log.h"
#include "random.h"
+#include "reqs_errors.h"
#include "state.h"
#include "thread_var.h"
#include "validation_handler.h"
static int
handle_https_uri(struct rpki_uri *uri)
{
- return http_download_file(uri, write_http_cer);
+ return http_download_file(uri, write_http_cer,
+ reqs_errors_log_uri(uri_get_global(uri)));
}
/**
else
error = handle_https_uri(uri);
+ /* FIXME (NOW) Try to work with local data on the first run? */
if (error) {
validation_destroy(state);
return pr_warn("TAL '%s' could not be downloaded.",
- uri_get_printable(uri));;
+ uri_get_printable(uri));
}
pr_debug("TAL URI '%s' {", uri_get_printable(uri));
fnstack_init();
fnstack_push(thread->tal_file);
+ working_repo_init();
+
error = tal_load(thread->tal_file, &tal);
if (error)
goto end;
tal_destroy(tal);
end:
+ working_repo_cleanup();
fnstack_cleanup();
thread->exit_status = error;
return NULL;
/* The parameter isn't needed anymore */
free(param);
+ /* FIXME (NOW) Clarify if this really belongs here */
+ reqs_errors_log_summary();
+
/* One thread has errors, validation can't keep the resulting table */
if (t_error)
return t_error;
--- /dev/null
+#include "reqs_errors.h"
+
+#include <pthread.h>
+#include <time.h>
+#include "data_structure/uthash_nonfatal.h"
+#include "common.h"
+#include "config.h"
+#include "log.h"
+#include "thread_var.h"
+
+struct error_uri {
+ /* Key */
+ char *uri;
+ /* Date when the first attempt was made */
+ time_t first_attempt;
+ /* Related URI (points to a key of another element) */
+ char *uri_related;
+ UT_hash_handle hh;
+};
+
+static struct error_uri *err_uris_db;
+
+/* Prepare for multithreading. */
+static pthread_rwlock_t db_lock;
+
+static int
+error_uri_create(char const *uri, struct error_uri **err_uri)
+{
+ struct error_uri *tmp;
+ int error;
+
+ tmp = malloc(sizeof(struct error_uri));
+ if (tmp == NULL)
+ return pr_enomem();
+
+ /* Needed by uthash */
+ memset(tmp, 0, sizeof(struct error_uri));
+
+ tmp->uri = strdup(uri);
+ if (tmp->uri == NULL) {
+ error = pr_enomem();
+ goto release_tmp;
+ }
+
+ error = get_current_time(&tmp->first_attempt);
+ if (error)
+ goto release_uri;
+
+ *err_uri = tmp;
+ return 0;
+release_uri:
+ free(tmp->uri);
+release_tmp:
+ free(tmp);
+ return error;
+}
+
+static void
+error_uri_destroy(struct error_uri *err_uri)
+{
+ free(err_uri->uri);
+ free(err_uri);
+}
+
+int
+reqs_errors_init(void)
+{
+ int error;
+
+ error = pthread_rwlock_init(&db_lock, NULL);
+ if (error)
+ return pr_errno(error, "pthread_rwlock_init() errored");
+
+ err_uris_db = NULL;
+
+ return 0;
+}
+
+void
+reqs_errors_cleanup(void)
+{
+ /* Remove all the uris */
+ struct error_uri *node, *tmp;
+
+ HASH_ITER(hh, err_uris_db, node, tmp) {
+ HASH_DEL(err_uris_db, node);
+ error_uri_destroy(node);
+ }
+
+ pthread_rwlock_destroy(&db_lock); /* Nothing to do with error code */
+}
+
+static struct error_uri *
+find_error_uri(char const *search)
+{
+ struct error_uri *found;
+
+ rwlock_read_lock(&db_lock);
+ HASH_FIND_STR(err_uris_db, search, found);
+ rwlock_unlock(&db_lock);
+
+ return found;
+}
+
+static void
+set_working_repo(struct error_uri *err_uri)
+{
+ struct error_uri *ref;
+ char const *work_uri;
+
+ err_uri->uri_related = NULL;
+ work_uri = working_repo_peek();
+ if (work_uri == NULL)
+ return;
+
+ ref = find_error_uri(work_uri);
+ if (ref == NULL)
+ return;
+
+ err_uri->uri_related = ref->uri;
+}
+
+int
+reqs_errors_add_uri(char const *uri)
+{
+ struct error_uri *new_uri, *found_uri;
+ int error;
+
+ /* Don't overwrite if it already exists */
+ found_uri = find_error_uri(uri);
+ if (found_uri != NULL)
+ return 0;
+
+ new_uri = NULL;
+ error = error_uri_create(uri, &new_uri);
+ if (error)
+ return error;
+
+ set_working_repo(new_uri);
+
+ rwlock_write_lock(&db_lock);
+ HASH_ADD_KEYPTR(hh, err_uris_db, new_uri->uri, strlen(new_uri->uri),
+ new_uri);
+ rwlock_unlock(&db_lock);
+
+ return 0;
+}
+
+void
+reqs_errors_rem_uri(char const *uri)
+{
+ struct error_uri *found_uri;
+
+ found_uri = find_error_uri(uri);
+ if (found_uri == NULL)
+ return;
+
+ /* Remove also its related repository */
+ if (found_uri->uri_related != NULL)
+ reqs_errors_rem_uri(found_uri->uri_related);
+
+ rwlock_write_lock(&db_lock);
+ HASH_DELETE(hh, err_uris_db, found_uri);
+ error_uri_destroy(found_uri);
+ rwlock_unlock(&db_lock);
+}
+
+bool
+reqs_errors_log_uri(char const *uri)
+{
+ struct error_uri *node;
+ time_t now;
+ int error;
+
+ now = 0;
+ error = get_current_time(&now);
+ if (error)
+ return false;
+
+ node = find_error_uri(uri);
+ if (node == NULL)
+ return false;
+
+ return difftime(now, node->first_attempt) >=
+ (double)config_get_stale_repository_period();
+}
+
+/*
+ * Logs the repository errors and return the number of current errors.
+ */
+void
+reqs_errors_log_summary(void)
+{
+ /* Remove all the uris */
+ struct error_uri *node, *tmp;
+ time_t now;
+ bool first;
+ int error;
+
+ first = true;
+ now = 0;
+ error = get_current_time(&now);
+ if (error)
+ return;
+
+ /*
+ * FIXME (NOW) Log a friendly warning, listing the URIs that error'd.
+ * The time diff (difftime) must be from the same date when
+ * reqs_errors_log_uri was called.
+ */
+ rwlock_read_lock(&db_lock);
+ HASH_ITER(hh, err_uris_db, node, tmp) {
+ if (difftime(now, node->first_attempt) <
+ (double)config_get_stale_repository_period())
+ continue;
+ if (first) {
+ /* FIXME (NOW) Send to operation log */
+ pr_warn("The following repositories URIs couldn't be fetched (it can be a local issue or a server issue), please review previous log messages related to such URIs/servers:");
+ first = false;
+ }
+ /* FIXME (NOW) Send to operation log */
+ pr_warn("- '%s': can't be downloaded since %s", node->uri,
+ asctime(localtime(&node->first_attempt)));
+ }
+
+ rwlock_unlock(&db_lock);
+}
--- /dev/null
+#ifndef SRC_REQS_ERRORS_H_
+#define SRC_REQS_ERRORS_H_
+
+#include <stdbool.h>
+
+int reqs_errors_init(void);
+void reqs_errors_cleanup(void);
+
+int reqs_errors_add_uri(char const *);
+void reqs_errors_rem_uri(char const *);
+
+bool reqs_errors_log_uri(char const *);
+
+void reqs_errors_log_summary(void);
+
+#endif /* SRC_REQS_ERRORS_H_ */
#include <string.h>
#include <time.h>
#include "data_structure/uthash_nonfatal.h"
+#include "common.h"
#include "log.h"
#include "thread_var.h"
-#include "visited_uris.h"
struct uris_table {
/* Key */
return 0;
}
-static int
-get_current_time(long *result)
-{
- time_t now;
-
- now = time(NULL);
- if (now == ((time_t) -1))
- return pr_errno(errno, "Error getting the current time");
-
- *result = now;
- return 0;
-}
-
/* Set the last update to now */
int
db_rrdp_uris_set_last_update(char const *uri)
{
struct db_rrdp_uri *uris;
struct uris_table *found;
+ time_t now;
int error;
uris = NULL;
return error;
RET_NOT_FOUND_URI(uris, uri, found)
- return get_current_time(&found->last_update);
+
+ now = 0;
+ error = get_current_time(&now);
+ if (error)
+ return error;
+
+ found->last_update = (long)now;
+ return 0;
}
int
#include "rrdp/rrdp_objects.h"
#include "rrdp/rrdp_parser.h"
#include "rsync/rsync.h"
+#include "common.h"
#include "config.h"
#include "log.h"
+#include "reqs_errors.h"
#include "thread_var.h"
#include "visited_uris.h"
/* Fetch and process the deltas from the @notification */
static int
process_diff_serial(struct update_notification *notification,
- struct visited_uris **visited)
+ bool log_operation, struct visited_uris **visited)
{
unsigned long serial;
int error;
if (error)
return error;
- return rrdp_process_deltas(notification, serial, *visited);
+ return rrdp_process_deltas(notification, serial, *visited,
+ log_operation);
}
/* Fetch and process the snapshot from the @notification */
static int
-process_snapshot(struct update_notification *notification,
+process_snapshot(struct update_notification *notification, bool log_operation,
struct visited_uris **visited)
{
struct visited_uris *tmp;
if (error)
return error;
- error = rrdp_parse_snapshot(notification, tmp);
+ error = rrdp_parse_snapshot(notification, tmp, log_operation);
if (error) {
visited_uris_refput(tmp);
return error;
struct visited_uris *visited;
rrdp_req_status_t requested;
rrdp_uri_cmp_result_t res;
+ bool log_operation;
int error, upd_error;
if (!config_get_rrdp_enabled())
/* Avoid multiple requests on the same run */
requested = RRDP_URI_REQ_UNVISITED;
- error = db_rrdp_uris_get_request_status(uri_get_global(uri), &requested);
+ error = db_rrdp_uris_get_request_status(uri_get_global(uri),
+ &requested);
if (error && error != -ENOENT)
return error;
return -EPERM;
}
- error = rrdp_parse_notification(uri, &upd_notification);
+ log_operation = reqs_errors_log_uri(uri_get_global(uri));
+ error = rrdp_parse_notification(uri, log_operation, &upd_notification);
if (error)
- goto upd_error;
+ goto upd_end;
/* No updates at the file (yet), didn't pushed to fnstack */
if (upd_notification == NULL) {
pr_debug("No updates yet at '%s'.", uri_get_global(uri));
- return 0;
+ goto upd_end;
}
error = db_rrdp_uris_cmp(uri_get_global(uri),
error = remove_rrdp_uri_files(upd_notification->uri);
if (error)
goto upd_destroy;
- error = process_snapshot(upd_notification, &visited);
+ error = process_snapshot(upd_notification, log_operation,
+ &visited);
if (error)
goto upd_destroy;
break;
case RRDP_URI_DIFF_SERIAL:
- error = process_diff_serial(upd_notification, &visited);
+ error = process_diff_serial(upd_notification, log_operation,
+ &visited);
if (!error) {
visited_uris_refget(visited);
break;
/* Something went wrong, use snapshot */
pr_info("There was an error processing RRDP deltas, using the snapshot instead.");
case RRDP_URI_NOTFOUND:
- error = process_snapshot(upd_notification, &visited);
+ error = process_snapshot(upd_notification, log_operation,
+ &visited);
if (error)
goto upd_destroy;
break;
update_notification_destroy(upd_notification);
fnstack_pop(); /* Pop from rrdp_parse_notification */
}
-upd_error:
- /* Don't fall here on success */
- if (error) {
- /* Reset RSYNC visited URIs, this may force the update */
- reset_downloaded();
- upd_error = mark_rrdp_uri_request_err(uri_get_global(uri));
+upd_end:
+ /* Just return on success */
+ if (!error) {
+ /* The repository URI is the notification file URI */
+ reqs_errors_rem_uri(uri_get_global(uri));
+ return 0;
+ }
+
+ /* Request failed, store the repository URI */
+ if (error == EREQFAILED) {
+ upd_error = reqs_errors_add_uri(uri_get_global(uri));
if (upd_error)
return upd_error;
}
+
+ /* Reset RSYNC visited URIs, this may force the update */
+ reset_downloaded();
+ upd_error = mark_rrdp_uri_request_err(uri_get_global(uri));
+ if (upd_error)
+ return upd_error;
+
return error;
}
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct proc_upd_args {
struct update_notification *parent;
struct visited_uris *visited_uris;
+ bool log_operation;
};
static int
}
static int
-download_file(struct rpki_uri *uri, long last_update)
+download_file(struct rpki_uri *uri, long last_update, bool log_operation)
{
unsigned int retries;
int error;
do {
if (last_update > 0)
error = http_download_file_with_ims(uri, write_local,
- last_update);
+ last_update, log_operation);
else
- error = http_download_file(uri, write_local);
+ error = http_download_file(uri, write_local,
+ log_operation);
/* Remember: positive values are expected */
if (error >= 0)
if (retries == config_get_rrdp_retry_count()) {
pr_info("Max RRDP retries (%u) reached fetching '%s', won't retry again.",
retries, uri_get_global(uri));
- return error;
+ /*
+ * Since distinct files can be downloaded (notification,
+ * snapshot, delta) just return the error and let the
+ * caller to add only the update notification URI to
+ * the request errors DB.
+ */
+ return EREQFAILED;
}
pr_info("Retrying RRDP file download '%s' in %u seconds, %u attempts remaining.",
uri_get_global(uri),
}
static int
-parse_delta(struct rpki_uri *uri, struct delta_head *parents_data, void *arg)
+parse_delta(struct rpki_uri *uri, struct delta_head *parents_data,
+ struct proc_upd_args *args)
{
- struct proc_upd_args *args = arg;
struct rdr_delta_ctx ctx;
struct delta *delta;
struct doc_data *expected_data;
static int
process_delta(struct delta_head *delta_head, void *arg)
{
+ struct proc_upd_args *args = arg;
struct rpki_uri *uri;
struct doc_data *head_data;
int error;
if (error)
return error;
- error = download_file(uri, 0);
+ error = download_file(uri, 0, args->log_operation);
if (error)
goto release_uri;
- error = parse_delta(uri, delta_head, arg);
+ error = parse_delta(uri, delta_head, args);
delete_from_uri(uri, NULL);
/* Error 0 its ok */
* 'If-Modified-Since' header, return 0 and set @result to NULL.
*/
int
-rrdp_parse_notification(struct rpki_uri *uri,
+rrdp_parse_notification(struct rpki_uri *uri, bool log_operation,
struct update_notification **result)
{
long last_update;
if (error && error != -ENOENT)
return error;
- error = download_file(uri, last_update);
+ error = download_file(uri, last_update, log_operation);
if (error < 0)
return error;
+ /* Request error, stop processing to handle as such */
+ if (error == EREQFAILED)
+ return error;
+
/*
* Mark as visited, if it doesn't exists yet, there's no problem since
* this is probably the first time is visited (first run), so it will
int
rrdp_parse_snapshot(struct update_notification *parent,
- struct visited_uris *visited_uris)
+ struct visited_uris *visited_uris, bool log_operation)
{
struct proc_upd_args args;
struct rpki_uri *uri;
if (error)
return error;
- error = download_file(uri, 0);
+ error = download_file(uri, 0, log_operation);
if (error)
goto release_uri;
int
rrdp_process_deltas(struct update_notification *parent,
- unsigned long cur_serial, struct visited_uris *visited_uris)
+ unsigned long cur_serial, struct visited_uris *visited_uris,
+ bool log_operation)
{
struct proc_upd_args args;
args.parent = parent;
args.visited_uris = visited_uris;
+ args.log_operation = log_operation;
return deltas_head_for_each(parent->deltas_list,
parent->global_data.serial, cur_serial, process_delta, &args);
#ifndef SRC_RRDP_RRDP_PARSER_H_
#define SRC_RRDP_RRDP_PARSER_H_
+#include <stdbool.h>
#include "rrdp/rrdp_objects.h"
#include "uri.h"
#include "visited_uris.h"
-int rrdp_parse_notification(struct rpki_uri *, struct update_notification **);
-int rrdp_parse_snapshot(struct update_notification *, struct visited_uris *);
+int rrdp_parse_notification(struct rpki_uri *, bool,
+ struct update_notification **);
+int rrdp_parse_snapshot(struct update_notification *, struct visited_uris *,
+ bool);
int rrdp_process_deltas(struct update_notification *,
- unsigned long serial, struct visited_uris *);
+ unsigned long serial, struct visited_uris *, bool);
#endif /* SRC_RRDP_RRDP_PARSER_H_ */
#include "common.h"
#include "config.h"
#include "log.h"
+#include "reqs_errors.h"
#include "str.h"
#include "thread_var.h"
}
static void
-log_buffer(char const *buffer, ssize_t read, int type)
+log_buffer(char const *buffer, ssize_t read, int type, bool log_operation)
{
#define PRE_RSYNC "[RSYNC exec]: "
char *cpy, *cur, *tmp;
cur = tmp + 1;
continue;
}
- if (type == 0)
- pr_err(PRE_RSYNC "%s", cur);
- else
- pr_info(PRE_RSYNC "%s", cur);
+ if (type == 0) {
+ /* FIXME (NOW) Send to operation log if requested */
+ if (log_operation)
+ pr_err(PRE_RSYNC " [OPERATION]: %s", cur);
+ /* FIXME (NOW) Always send to validation log */
+ pr_err(PRE_RSYNC " [VALIDATION]: %s", cur);
+ } else {
+ /* FIXME (NOW) Send to operation log if requested */
+ if (log_operation)
+ pr_info(PRE_RSYNC " [OPERATION]: %s", cur);
+ /* FIXME (NOW) Always send to validation log */
+ pr_info(PRE_RSYNC " [VALIDATION]: %s", cur);
+ }
cur = tmp + 1;
}
free(cpy);
}
static int
-read_pipe(int fd_pipe[2][2], int type)
+read_pipe(int fd_pipe[2][2], int type, bool log_operation)
{
char buffer[4096];
ssize_t count;
if (count == 0)
break;
- log_buffer(buffer, count, type);
+ log_buffer(buffer, count, type, log_operation);
}
close(fd_pipe[type][0]);
return 0;
}
static int
-read_pipes(int fds[2][2])
+read_pipes(int fds[2][2], bool log_operation)
{
int error;
close(fds[1][1]);
/* stderr pipe */
- error = read_pipe(fds, 0);
+ error = read_pipe(fds, 0, log_operation);
if (error)
return error;
/* stdout pipe */
- return read_pipe(fds, 1);
+ return read_pipe(fds, 1, log_operation);
}
/*
* Downloads the @uri->global file into the @uri->local path.
*/
static int
-do_rsync(struct rpki_uri *uri, bool is_ta)
+do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
{
/* Descriptors to pipe stderr (first element) and stdout (second) */
int fork_fds[2][2];
}
/* This code is run by us. */
- error = read_pipes(fork_fds);
+ error = read_pipes(fork_fds, log_operation);
if (error)
return error;
/* Happy path (but also sad path sometimes). */
error = WEXITSTATUS(child_status);
pr_debug("Child terminated with error code %d.", error);
- if (!error)
+ if (!error) {
+ reqs_errors_rem_uri(uri_get_global(uri));
return 0;
+ }
if (retries == config_get_rsync_retry_count()) {
pr_info("Max RSYNC retries (%u) reached on '%s', won't retry again.",
retries, uri_get_global(uri));
- return error;
+
+ return EREQFAILED;
}
pr_info("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.",
uri_get_global(uri),
struct validation *state;
struct uri_list *visited_uris;
struct rpki_uri *rsync_uri;
+ bool to_op_log;
int error;
if (!config_get_rsync_enabled())
pr_debug("Going to RSYNC '%s'.", uri_get_printable(rsync_uri));
- /* Don't store when "force" and if its already downloaded */
- error = do_rsync(rsync_uri, is_ta);
- if (!error &&
- !(force && is_already_downloaded(rsync_uri, visited_uris)))
+ to_op_log = reqs_errors_log_uri(uri_get_global(requested_uri));
+ error = do_rsync(rsync_uri, is_ta, to_op_log);
+ switch(error) {
+ case 0:
+ /* Don't store when "force" and if its already downloaded */
+ if (!(force && is_already_downloaded(rsync_uri, visited_uris)))
+ error = mark_as_downloaded(rsync_uri, visited_uris);
+ break;
+ case EREQFAILED:
+ /* All attempts failed, avoid future requests */
+ error = reqs_errors_add_uri(uri_get_global(requested_uri));
+ if (error)
+ break;
error = mark_as_downloaded(rsync_uri, visited_uris);
+ break;
+ default:
+ break;
+ }
uri_refput(rsync_uri);
return error;
int
vrps_init(void)
{
+ time_t now;
int error;
state.base = NULL;
state.next_serial = START_SERIAL;
/* Get the bits that'll fit in session_id */
- state.v0_session_id = time(NULL) & 0xFFFF;
+ now = 0;
+ error = get_current_time(&now);
+ if (error)
+ goto release_deltas;
+ state.v0_session_id = now & 0xFFFF;
+
/* Minus 1 to prevent same ID */
state.v1_session_id = (state.v0_session_id != 0)
? (state.v0_session_id - 1)
static pthread_key_t state_key;
static pthread_key_t filenames_key;
+static pthread_key_t repository_key;
struct filename_stack {
/* This can be NULL. Abort all operations if this is the case. */
unsigned int size;
};
+struct working_repo {
+ char const *uri;
+};
+
static void
fnstack_discard(void *arg)
{
free(files);
}
+static void
+working_repo_discard(void *arg)
+{
+ struct working_repo *repo = arg;
+ free(repo);
+}
+
/** Initializes this entire module. Call once per runtime lifetime. */
int
thvar_init(void)
return error;
}
+ error = pthread_key_create(&repository_key, working_repo_discard);
+ if (error) {
+ pr_err(
+ "Fatal: Errcode %d while initializing the 'working repository' thread variable.",
+ error);
+ return error;
+ }
+
return 0;
}
files->len--;
}
+/** Initializes the current thread's working repo. Call once per thread. */
+void
+working_repo_init(void)
+{
+ struct working_repo *repo;
+ int error;
+
+ repo = malloc(sizeof(struct working_repo));
+ if (repo == NULL)
+ return;
+
+ repo->uri = NULL;
+
+ error = pthread_setspecific(repository_key, repo);
+ if (error)
+ pr_err("pthread_setspecific() returned %d.", error);
+}
+
+void
+working_repo_cleanup(void)
+{
+ struct working_repo *repo;
+ int error;
+
+ repo = pthread_getspecific(repository_key);
+ if (repo == NULL)
+ return;
+
+ working_repo_discard(repo);
+
+ error = pthread_setspecific(repository_key, NULL);
+ if (error)
+ pr_err("pthread_setspecific() returned %d.", error);
+}
+
+/*
+ * Call whenever a certificate has more than one repository where its childs
+ * live (rsync or RRDP).
+ */
+void
+working_repo_push(char const *location)
+{
+ struct working_repo *repo;
+
+ repo = pthread_getspecific(repository_key);
+ if (repo == NULL)
+ return;
+
+ repo->uri = location;
+}
+
+char const *
+working_repo_peek(void)
+{
+ struct working_repo *repo;
+
+ repo = pthread_getspecific(repository_key);
+
+ return repo == NULL ? NULL : repo->uri;
+}
+
+/*
+ * Call once the certificate's repositories were downloaded (either successful
+ * or erroneously).
+ */
+void
+working_repo_pop(void)
+{
+ struct working_repo *repo;
+
+ repo = pthread_getspecific(repository_key);
+ if (repo == NULL)
+ return;
+
+ repo->uri = NULL;
+}
+
static char const *
addr2str(int af, void const *addr, char *(*buffer_cb)(struct validation *))
{
char const *fnstack_peek(void);
void fnstack_pop(void);
+void working_repo_init(void);
+void working_repo_cleanup(void);
+
+void working_repo_push(char const *);
+char const *working_repo_peek(void);
+void working_repo_pop(void);
+
/* Please remember that these functions can only be used during validations. */
char const *v4addr2str(struct in_addr const *);
char const *v4addr2str2(struct in_addr const *);
if (error)
return error;
- error = http_fetch(&handler, url, response_code, &cond, write_cb, resp);
+ error = http_fetch(&handler, url, response_code, &cond, false,
+ write_cb, resp);
http_easy_cleanup(&handler);
return error;
}
return NULL;
}
+void
+reqs_errors_log_summary(void)
+{
+ /* Nothing here */
+}
+
char const *
config_get_tal(void)
{