From: claudio Date: Fri, 2 Sep 2022 18:37:17 +0000 (+0000) Subject: Implement RRDP_ABORT, a message to abort a inflight RRDP request. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=4673c6835c38c0985b126bb392495cafe0e8d65e;p=openbsd Implement RRDP_ABORT, a message to abort a inflight RRDP request. The abort is done in a way that waits for any inflight files or http requests to finish before removing the rrdp state and before sending the rrdp done message indicating failure. OK tb@ and benno@ --- diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index f2c493c962f..f385359cca7 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.151 2022/08/30 18:56:49 job Exp $ */ +/* $OpenBSD: extern.h,v 1.152 2022/09/02 18:37:17 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -408,6 +408,7 @@ enum rrdp_msg { RRDP_HTTP_REQ, RRDP_HTTP_INI, RRDP_HTTP_FIN, + RRDP_ABORT, }; /* diff --git a/usr.sbin/rpki-client/rrdp.c b/usr.sbin/rpki-client/rrdp.c index e997e06d117..91904ff60c8 100644 --- a/usr.sbin/rpki-client/rrdp.c +++ b/usr.sbin/rpki-client/rrdp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rrdp.c,v 1.25 2022/09/02 18:08:43 tb Exp $ */ +/* $OpenBSD: rrdp.c,v 1.26 2022/09/02 18:37:17 claudio Exp $ */ /* * Copyright (c) 2020 Nils Fisher * Copyright (c) 2021 Claudio Jeker @@ -57,6 +57,7 @@ struct rrdp { struct pollfd *pfd; int infd; int state; + int aborted; unsigned int file_pending; unsigned int file_failed; enum http_result res; @@ -73,7 +74,7 @@ struct rrdp { struct delta_xml *dxml; }; -TAILQ_HEAD(, rrdp) states = TAILQ_HEAD_INITIALIZER(states); +static TAILQ_HEAD(, rrdp) states = TAILQ_HEAD_INITIALIZER(states); char * xstrdup(const char *s) @@ -254,7 +255,7 @@ rrdp_failed(struct rrdp *s) /* reset file state before retrying */ s->file_failed = 0; - if (s->task == DELTA) { + if (s->task == DELTA && !s->aborted) { /* fallback to a snapshot as per RFC8182 */ free_delta_xml(s->dxml); s->dxml = NULL; @@ -287,7 +288,7 @@ rrdp_finished(struct rrdp *s) if (s->file_pending > 0) return; - if (s->state & RRDP_STATE_PARSE_ERROR) { + if (s->state & RRDP_STATE_PARSE_ERROR || s->aborted) { rrdp_failed(s); return; } @@ -369,6 +370,34 @@ rrdp_finished(struct rrdp *s) } } +static void +rrdp_abort_req(struct rrdp *s) +{ + unsigned int id = s->id; + + s->aborted = 1; + if (s->state == RRDP_STATE_REQ) { + /* nothing is pending, just abort */ + rrdp_free(s); + rrdp_done(id, 1); + return; + } + if (s->state == RRDP_STATE_WAIT) + /* wait for HTTP_INI which will progress the state */ + return; + + /* + * RRDP_STATE_PARSE or later, close infd, abort parser but + * wait for HTTP_FIN and file_pending to drop to 0. + */ + if (s->infd != -1) { + close(s->infd); + s->infd = -1; + s->state |= RRDP_STATE_PARSE_DONE | RRDP_STATE_PARSE_ERROR; + } + rrdp_finished(s); +} + static void rrdp_input_handler(int fd) { @@ -406,12 +435,15 @@ rrdp_input_handler(int fd) errx(1, "expected fd not received"); s = rrdp_get(id); if (s == NULL) - errx(1, "rrdp session %u does not exist", id); + errx(1, "http ini, rrdp session %u does not exist", id); if (s->state != RRDP_STATE_WAIT) errx(1, "%s: bad internal state", s->local); - s->infd = b->fd; s->state = RRDP_STATE_PARSE; + if (s->aborted) { + rrdp_abort_req(s); + break; + } break; case RRDP_HTTP_FIN: io_read_buf(b, &res, sizeof(res)); @@ -421,20 +453,19 @@ rrdp_input_handler(int fd) s = rrdp_get(id); if (s == NULL) - errx(1, "rrdp session %u does not exist", id); + errx(1, "http fin, rrdp session %u does not exist", id); if (!(s->state & RRDP_STATE_PARSE)) errx(1, "%s: bad internal state", s->local); - + s->state |= RRDP_STATE_HTTP_DONE; s->res = res; free(s->last_mod); s->last_mod = last_mod; - s->state |= RRDP_STATE_HTTP_DONE; rrdp_finished(s); break; case RRDP_FILE: s = rrdp_get(id); if (s == NULL) - errx(1, "rrdp session %u does not exist", id); + errx(1, "file, rrdp session %u does not exist", id);; if (b->fd != -1) errx(1, "received unexpected fd"); io_read_buf(b, &ok, sizeof(ok)); @@ -444,6 +475,13 @@ rrdp_input_handler(int fd) if (s->file_pending == 0) rrdp_finished(s); break; + case RRDP_ABORT: + if (b->fd != -1) + errx(1, "received unexpected fd"); + s = rrdp_get(id); + if (s != NULL) + rrdp_abort_req(s); + break; default: errx(1, "unexpected message %d", type); }