-/* $OpenBSD: extern.h,v 1.94 2021/11/05 10:50:41 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.95 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
extern int verbose;
extern const char *tals[];
extern const char *taldescs[];
+extern unsigned int talrepocnt[];
extern size_t talsz;
/* Routines for RPKI entities. */
int rrdp_handle_file(size_t, enum publish_type, char *,
char *, size_t, char *, size_t);
char *repo_filename(const struct repo *, const char *);
-struct repo *ta_lookup(struct tal *);
-struct repo *repo_lookup(const char *, const char *);
+struct repo *ta_lookup(int, struct tal *);
+struct repo *repo_lookup(int, const char *, const char *);
int repo_queued(struct repo *, struct entity *);
void repo_cleanup(struct filepath_tree *);
void repo_free(void);
struct rrdp_session *);
void rrdp_http_done(size_t, enum http_result, const char *);
+int repo_next_timeout(int);
+void repo_check_timeout(void);
/* Logging (though really used for OpenSSL errors). */
/* Maximum number of concurrent rsync processes. */
#define MAX_RSYNC_PROCESSES 16
+/* Maximum allowd repositories per tal */
+#define MAX_REPO_PER_TAL 1000
+
+/* Timeout for repository synchronisation, in seconds */
+#define MAX_REPO_TIMEOUT (15 * 60)
+
#endif /* ! EXTERN_H */
-/* $OpenBSD: main.c,v 1.163 2021/11/04 18:00:07 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.164 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
const char *tals[TALSZ_MAX];
const char *taldescs[TALSZ_MAX];
+unsigned int talrepocnt[TALSZ_MAX];
size_t talsz;
size_t entity_queue;
err(1, NULL);
/* Look up the repository. */
- repo = ta_lookup(tal);
+ repo = ta_lookup(tal->id, tal);
+ if (repo == NULL)
+ return;
/* steal the pkey from the tal structure */
data = tal->pkey;
struct repo *repo;
char *nfile;
- repo = repo_lookup(cert->repo, rrdpon ? cert->notify : NULL);
- if (repo == NULL) {
- warnx("%s: repository lookup failed", cert->repo);
+ repo = repo_lookup(cert->talid, cert->repo,
+ rrdpon ? cert->notify : NULL);
+ if (repo == NULL)
return;
- }
if ((nfile = strdup(cert->mft)) == NULL)
err(1, NULL);
err(1, "fchdir");
while (entity_queue > 0 && !killme) {
+ int polltim;
+
for (i = 0; i < NPFD; i++) {
pfd[i].events = POLLIN;
if (queues[i]->queued)
pfd[i].events |= POLLOUT;
}
- if ((c = poll(pfd, NPFD, INFTIM)) == -1) {
+ polltim = repo_next_timeout(INFTIM);
+
+ if ((c = poll(pfd, NPFD, polltim)) == -1) {
if (errno == EINTR)
continue;
err(1, "poll");
if (hangup)
break;
+ repo_check_timeout();
+
/*
* Check the rsync and http process.
* This means that one of our modules has completed
-/* $OpenBSD: repo.c,v 1.10 2021/11/04 17:35:09 claudio Exp $ */
+/* $OpenBSD: repo.c,v 1.11 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
#include <fcntl.h>
#include <fts.h>
#include <limits.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const struct rsyncrepo *rsync;
const struct tarepo *ta;
struct entityq queue; /* files waiting for repo */
+ time_t alarm; /* sync timeout */
+ int talid;
size_t id; /* identifier */
};
SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
* Allocate and insert a new repository.
*/
static struct repo *
-repo_alloc(void)
+repo_alloc(int talid)
{
struct repo *rp;
+ if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) {
+ if (talrepocnt[talid] == MAX_REPO_PER_TAL)
+ warnx("too many repositories under %s", tals[talid]);
+ return NULL;
+ }
+
if ((rp = calloc(1, sizeof(*rp))) == NULL)
err(1, NULL);
rp->id = ++repoid;
+ rp->talid = talid;
+ rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
TAILQ_INIT(&rp->queue);
SLIST_INSERT_HEAD(&repos, rp, entry);
tr = ta_find(id);
if (tr != NULL) {
+ /* repository changed state already, ignore request */
+ if (tr->state != REPO_LOADING)
+ return;
if (ok) {
logx("ta/%s: loaded from network", tr->descr);
stats.rsync_repos++;
if (rr == NULL)
errx(1, "unknown rsync repo %zu", id);
+ /* repository changed state already, ignore request */
+ if (rr->state != REPO_LOADING)
+ return;
if (ok) {
logx("%s: loaded from network", rr->basedir);
stats.rsync_repos++;
rr = rrdp_find(id);
if (rr == NULL)
errx(1, "unknown RRDP repo %zu", id);
+ /* repository changed state already, ignore request */
+ if (rr->state != REPO_LOADING)
+ return;
if (ok && rrdp_merge_repo(rr)) {
logx("%s: loaded from network", rr->notifyuri);
return;
}
+ /* repository changed state already, ignore request */
+ if (tr->state != REPO_LOADING)
+ return;
+
/* Move downloaded TA file into place, or unlink on failure. */
if (res == HTTP_OK) {
char *file;
* Look up a trust anchor, queueing it for download if not found.
*/
struct repo *
-ta_lookup(struct tal *tal)
+ta_lookup(int id, struct tal *tal)
{
struct repo *rp;
return rp;
}
- rp = repo_alloc();
+ rp = repo_alloc(id);
+ if (rp == NULL)
+ return NULL;
+
if ((rp->repouri = strdup(tal->descr)) == NULL)
err(1, NULL);
rp->ta = ta_get(tal);
* Look up a repository, queueing it for discovery if not found.
*/
struct repo *
-repo_lookup(const char *uri, const char *notify)
+repo_lookup(int id, const char *uri, const char *notify)
{
struct repo *rp;
char *repouri;
return rp;
}
- rp = repo_alloc();
+ rp = repo_alloc(id);
+ if (rp == NULL) {
+ free(repouri);
+ return NULL;
+ }
+
rp->repouri = repouri;
if (notify != NULL)
if ((rp->notifyuri = strdup(notify)) == NULL)
return 0;
}
+int
+repo_next_timeout(int timeout)
+{
+ struct repo *rp;
+ time_t now;
+
+ now = getmonotime();
+ /* Look up in repository table. (Lookup should actually fail here) */
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (repo_state(rp) == REPO_LOADING) {
+ int diff = rp->alarm - now;
+ diff *= 1000;
+ if (timeout == INFTIM || diff < timeout)
+ timeout = diff;
+ }
+ }
+ return timeout;
+}
+
+static void
+repo_fail(struct repo *rp)
+{
+ /* reset the alarm since code may fallback to rsync */
+ rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
+
+ if (rp->ta)
+ http_finish(rp->ta->id, HTTP_FAILED, NULL);
+ else if (rp->rrdp)
+ rrdp_finish(rp->rrdp->id, 0);
+ else if (rp->rsync)
+ rsync_finish(rp->rsync->id, 0);
+ else
+ errx(1, "%s: bad repo", rp->repouri);
+}
+
+void
+repo_check_timeout(void)
+{
+ struct repo *rp;
+ time_t now;
+
+ now = getmonotime();
+ /* Look up in repository table. (Lookup should actually fail here) */
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (repo_state(rp) == REPO_LOADING) {
+ if (rp->alarm <= now) {
+ warnx("%s: synchronisation timeout",
+ rp->repouri);
+ repo_fail(rp);
+ }
+ }
+ }
+}
+
static char **
add_to_del(char **del, size_t *dsz, char *file)
{