We want to be able to abort RRDP syncs. Now the problem is that depending on the state the abort request is more or less complex. What needs to be avoided is that a message received after the corresponding RRDP session was removed. This is mainly the RRDP_FILE and RRDP_HTTP_FIN messages that cause this.
So once a RRDP_HTTP_INI message was received the abort code goes through most states, it just aborts the internal XML parser and closes the input fd. -- :wq Claudio Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.151 diff -u -p -r1.151 extern.h --- extern.h 30 Aug 2022 18:56:49 -0000 1.151 +++ extern.h 2 Sep 2022 17:41:07 -0000 @@ -408,6 +408,7 @@ enum rrdp_msg { RRDP_HTTP_REQ, RRDP_HTTP_INI, RRDP_HTTP_FIN, + RRDP_ABORT, }; /* Index: rrdp.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/rrdp.c,v retrieving revision 1.24 diff -u -p -r1.24 rrdp.c --- rrdp.c 15 May 2022 16:43:35 -0000 1.24 +++ rrdp.c 2 Sep 2022 17:54:58 -0000 @@ -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) @@ -256,7 +257,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; @@ -289,7 +290,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; } @@ -372,6 +373,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) { static struct ibuf *inbuf; @@ -408,12 +437,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)); @@ -423,20 +455,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)); @@ -445,6 +476,13 @@ rrdp_input_handler(int fd) s->file_pending--; 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);