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);

Reply via email to