Back in May, I tried creating unit tests for the cache's new stateful features.
This scaled poorly, which later led to the creation of the Barry/RPT framework.
I'm throwing away those failed unit tests, but I'm keeping the few bugfixes I
managed to whip up while I was coding them.
The only special mention is "separate cache_setup() into two steps."
This is needed because all involved processes need to work in the cache
directory. Ensuring the directory exists and has been chdir'd into before
subprocesses are spawned is a simple means to achieve that.
goto fail;
if (json_add_str(json, "path", node->path))
goto fail;
- if (node->verdict && json_add_str(json, "error", node->verdict))
- goto fail;
if (node->attempt_ts && json_add_ts(json, "attempt", node->attempt_ts))
goto fail;
if (node->success_ts && json_add_ts(json, "success", node->success_ts))
}
int
-cache_setup(void)
+cache_setup1(void)
{
char const *cachedir;
int error;
return error;
}
+ return 0;
+}
+
+int
+cache_setup2(void)
+{
+ int error;
+
init_tables();
errno = 0;
return (difftime(rsync->success_ts, rrdp->success_ts) > 0) ? rsync : rrdp;
}
-/* Do not free nor modify the result. */
validation_verdict
-cache_refresh_by_url(struct uri const *url, char const **result)
+cache_refresh_by_url(struct uri const *url, char **result)
{
struct cache_node *node = NULL;
validation_verdict vv;
- if (uri_is_https(url))
+ if (uri_is_https(url)) {
vv = do_refresh(&cache.https, url, &node);
- else if (uri_is_rsync(url))
+ if (vv != VV_CONTINUE)
+ goto oops;
+ *result = node ? pstrdup(node->path) : NULL;
+ return VV_CONTINUE;
+ }
+
+ if (uri_is_rsync(url)) {
vv = do_refresh(&cache.rsync, url, &node);
- else
- vv = VV_FAIL;
+ if (vv != VV_CONTINUE)
+ goto oops;
+ *result = path_join(node->path, strip_rsync_module(uri_str(url)));
+ return VV_CONTINUE;
+ }
- *result = node ? node->path : NULL;
+ vv = VV_FAIL;
+oops: *result = NULL;
return vv;
}
-/*
- * HTTPS (TAs) and rsync only; don't use this for RRDP.
- * Do not free nor modify the result.
- */
+/* HTTPS (TAs) and rsync only; don't use this for RRDP. */
validation_verdict
-cache_get_fallback(struct uri const *url, char const **result)
+cache_get_fallback(struct uri const *url, char **result)
{
struct cache_node *node;
return VV_CONTINUE;
}
- *result = node->path;
+ *result = pstrdup(node->path);
return VV_CONTINUE;
}
#include "types/rpp.h"
#include "types/uri.h"
-int cache_setup(void); /* Init this module */
+int cache_setup1(void);
+int cache_setup2(void);
void cache_atexit(void);
int cache_prepare(void); /* Prepare cache for new validation cycle */
void exturis_init(struct extension_uris *);
void exturis_cleanup(struct extension_uris *);
-validation_verdict cache_refresh_by_url(struct uri const *, char const **);
-validation_verdict cache_get_fallback(struct uri const *, char const **);
+validation_verdict cache_refresh_by_url(struct uri const *, char **);
+validation_verdict cache_get_fallback(struct uri const *, char **);
struct cache_cage;
validation_verdict cache_refresh_by_uris(struct extension_uris *,
#include "libcrypto_util.h"
#include "log.h"
#include "nid.h"
-#include "thread_var.h"
static json_t *
unimplemented(void const *arg)
if (error)
goto revert_log;
+ error = cache_setup1();
+ if (error)
+ goto revert_config;
+
rsync_setup(NULL, NULL); /* Fork rsync spawner ASAP */
register_signal_handlers();
error = vrps_init();
if (error)
goto revert_relax_ng;
- error = cache_setup();
+ error = cache_setup2();
if (error)
goto revert_vrps;
error = output_setup();
nid_destroy();
revert_rsync:
rsync_teardown();
+revert_config:
free_rpki_config();
revert_log:
log_teardown();
return 0;
}
-/*
- * Compare public keys, call @diff_alg_cb when the algorithm is different, call
- * @diff_pk_cb when the public key is different; return 0 if both are equal.
- */
static int
spki_cmp(X509_PUBKEY *tal_spki, X509_PUBKEY *cert_spki)
{
spki = d2i_X509_PUBKEY(NULL, &cursor, len);
if (spki == NULL) {
- op_crypto_err("The public key cannot be decoded.");
+ op_crypto_err("The TAL's public key cannot be decoded.");
goto fail;
}
if (cursor != origin + len) {
X509_PUBKEY_free(spki);
- op_crypto_err("The public key contains trailing garbage.");
+ op_crypto_err("The TAL's public key contains trailing garbage.");
goto fail;
}
if ((evppkey = X509_get0_pubkey(cert->x509)) == NULL)
return val_crypto_err("X509_get0_pubkey() returned NULL");
if (X509_verify(cert->x509, evppkey) != 1)
- return EINVAL;
+ return val_crypto_err("Invalid signature.");
}
return 0;
char const *cr;
cr = uri_str(uri);
- pr_clutter("caRepository: %s", caRepo);
+ pr_clutter("caRepository: %s", cr);
if (!uri_is_rsync(uri)) {
pr_val_debug("Ignoring non-rsync caRepository '%s'.", cr);
static validation_verdict
try_urls(struct tal *tal, bool (*url_is_protocol)(struct uri const *),
- validation_verdict (*get_path)(struct uri const *, char const **))
+ validation_verdict (*get_path)(struct uri const *, char **))
{
struct uri *url;
- char const *path;
+ char *path;
struct cache_mapping map;
validation_verdict vv;
continue;
map.url = *url;
- map.path = (char *)path;
+ map.path = path;
vv = validate_ta(tal, &map);
- if (vv == VV_BUSY)
+ if (vv == VV_BUSY) {
+ free(path);
return VV_BUSY;
- if (vv == VV_FAIL)
+ }
+ if (vv == VV_FAIL) {
+ free(path);
continue;
+ }
cache_commit_file(&map);
+ free(path);
return VV_CONTINUE;
}
if (tasks->a >= config_rsync_max()) {
LIST_INSERT_HEAD(&tasks->queued, task, lh);
- pr_op_debug(RSP "Queued new task.");
+ pr_op_debug(RSP "Queued task %d: %s -> %s",
+ task->pid, uri_str(&task->url), task->path);
} else {
activate_task(tasks, task, now);
- pr_op_debug(RSP "Got new task: %d", task->pid);
+ pr_op_debug(RSP "Got new task %d: %s -> %s",
+ task->pid, uri_str(&task->url), task->path);
}
}
char const *arg;
int error;
+ if (!config_get_rsync_enabled())
+ return;
+
if (program != NULL) {
rsync_args[0] = arg = program;
va_start(args, program);
void
rsync_teardown(void)
{
+ if (!config_get_rsync_enabled())
+ return;
+
spsk_cleanup();
wait_subprocess("rsync spawner", spawner);
}
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t awakener = PTHREAD_COND_INITIALIZER;
+static char const *
+task_name(struct validation_task *task)
+{
+ switch (task->type) {
+ case VTT_RPP:
+ return uri_str(&task->u.ca->map.url);
+ case VTT_TAL:
+ return task->u.tal;
+ }
+
+ pr_crit("Unknown task type: %u", task->type);
+ return NULL;
+}
+
static void
task_free(struct validation_task *task)
{
STAILQ_REMOVE_HEAD(&waiting, lh);
mutex_unlock(&lock);
pr_op_debug("task_dequeue(): Claimed task '%s'.",
- uri_str(&task->u.ca->map.url));
+ task_name(task));
return task;
}
#include "alloc.h"
#include "log.h"
-#include "thread_var.h"
/**
* It's an RFC5280 name, but from RFC 6487's perspective.
void
x509_name_pr_clutter(const char *prefix, X509_NAME *name)
{
+ struct rfc5280_name *printable;
+
if (!pr_clutter_enabled())
return;
- struct rfc5280_name *printable;
-
if (name == NULL) {
pr_clutter("%s: (null)", prefix);
return;
rsync_dance(char *url)
{
/* Queue the rsync (includes rsync simulation) */
+ dl_error = 0;
ck_assert_ptr_eq(NULL, run_dl_rsync(url, VV_BUSY, 1));
/* Signal rsync completion; no need to wait */
finish_rsync();
validation_verdict expected_vv, char const *expected_result)
{
struct uri uri;
- char const *result;
+ char *result = NULL;
ck_assert_ptr_eq(NULL, uri_init(&uri, url));
ck_assert_uint_eq(expected_calls, https_counter);
ck_assert_pstr_eq(expected_result, result);
+ free(result);
ck_assert_str_eq(VV_CONTINUE, cache_get_fallback(&uri, &result));
ck_assert_ptr_eq(NULL, result);
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
+#include <openssl/err.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
MOCK_VOID_PRINT(pr_val_info, PR_COLOR_INF)
MOCK_INT_PRINT(pr_val_warn, PR_COLOR_WRN, 0)
MOCK_INT_PRINT(pr_val_err, PR_COLOR_ERR, EINVAL)
-MOCK_INT_PRINT(val_crypto_err, PR_COLOR_ERR, EINVAL)
+
+struct crypto_cb_arg {
+ unsigned int stack_size;
+ int (*error_fn)(const char *, ...);
+};
+
+static int
+log_crypto_error(const char *str, size_t len, void *_arg)
+{
+ struct crypto_cb_arg *arg = _arg;
+ arg->error_fn("-> %s", str);
+ arg->stack_size++;
+ return 1;
+}
+
+static int
+crypto_err(int (*error_fn)(const char *, ...))
+{
+ struct crypto_cb_arg arg;
+
+ error_fn("libcrypto error stack:");
+
+ arg.stack_size = 0;
+ arg.error_fn = error_fn;
+ ERR_print_errors_cb(log_crypto_error, &arg);
+ if (arg.stack_size == 0)
+ error_fn(" <Empty>");
+ else
+ error_fn("End of libcrypto stack.");
+
+ return EINVAL;
+}
+
+int
+val_crypto_err(const char *format, ...)
+{
+ MOCK_PRINT(PR_COLOR_ERR);
+ return crypto_err(pr_val_err);
+}
void
enomem_panic(void)
printf("th%d: Started.\n", thid);
while ((task = task_dequeue(task)) != NULL) {
- printf("- th%d: Dequeued '%s'\n", thid, uri_str(&task->u.ca->map.url));
+ printf("- th%d: Dequeued '%s'\n", thid, task_name(task));
total_dequeued++;
if (certificate_traverse_mock(task->u.ca, thid) == EBUSY) {
- printf("+ th%d: Requeuing '%s'\n",
- thid, uri_str(&task->u.ca->map.url));
+ printf("+ th%d: Requeuing '%s'\n", thid, task_name(task));
task_requeue_dormant(task);
task = NULL;
}