On Thu, Apr 08, 2021 at 07:43:47PM +0200, Theo Buehler wrote:
> On Thu, Apr 08, 2021 at 07:18:39PM +0200, Claudio Jeker wrote:
> > On Thu, Apr 08, 2021 at 06:22:16PM +0200, Theo Buehler wrote:
> > > On Thu, Apr 08, 2021 at 04:47:15PM +0200, Claudio Jeker wrote:
> > > > This diff is a first step in tightening the code in http.c
> > > > It should cleanup the poll handling and make adds some code to ensure 
> > > > that
> > > > only expected results are returned. The goal is that http_handle() only
> > > > does IO processing and http_nextstep() is used for transitions into new
> > > > states.
> > > 
> > > I like this direction.
> > > 
> > > > I did shuffle the code around a bit. So that similar functions are 
> > > > together.
> > > > Also by shuffling the poll loop now connections are added after the all
> > > > active connections have been processed.
> > > 
> > > This added quite a bit of noise to the diff (especially some parts
> > > shuffling _write() functions are hard to read).
> > > 
> > > I'm ok with this, one small comment below.
> > > 
> > 
> > Sorry about that. I committed the deck chair shuffle and some other minor
> > bits. Here is the part that replaces the regular and chunked write
> > functions with a single data_write one.
> > 
> > I made the strtoul() check look like the man page example to detect
> > overflows. There is some off_t vs size_t casts required but in that case
> > the size limited bufpos is casted.
> 
> 
> > On Thu, Apr 08, 2021 at 06:22:16PM +0200, Theo Buehler wrote:
> > > On Thu, Apr 08, 2021 at 04:47:15PM +0200, Claudio Jeker wrote:
> > > > This diff is a first step in tightening the code in http.c
> > > > It should cleanup the poll handling and make adds some code to ensure 
> > > > that
> > > > only expected results are returned. The goal is that http_handle() only
> > > > does IO processing and http_nextstep() is used for transitions into new
> > > > states.
> > > 
> > > I like this direction.
> > > 
> > > > I did shuffle the code around a bit. So that similar functions are 
> > > > together.
> > > > Also by shuffling the poll loop now connections are added after the all
> > > > active connections have been processed.
> > > 
> > > This added quite a bit of noise to the diff (especially some parts
> > > shuffling _write() functions are hard to read).
> > > 
> > > I'm ok with this, one small comment below.
> > > 
> > 
> > Sorry about that. I committed the deck chair shuffle and some other minor
> > bits. Here is the part that replaces the regular and chunked write
> > functions with a single data_write one.
> > 
> > I made the strtoul() check look like the man page example to detect
> > overflows. There is some off_t vs size_t casts required but in that case
> > the size limited bufpos is casted.
> 
> Thanks. Still looks good. Tiny suggestion below, but ok either way.

Yes, your right. I over optimised it a bit and triggered on the less
common iosz == 0 first.

Also here is the last bit of the http work. This changes http_handle() and
ensures that http_nextstep() never returns 0. For http_tls_connect() this
requires a fall through to the next stage in case it returns 0.
Also http_redirect() now calls http_connect() directly and no longer
requires an extra state machine step.

-- 
:wq Claudio

? obj
Index: http.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/http.c,v
retrieving revision 1.26
diff -u -p -r1.26 http.c
--- http.c      8 Apr 2021 18:35:02 -0000       1.26
+++ http.c      8 Apr 2021 18:38:22 -0000
@@ -410,6 +410,8 @@ http_connect(struct http_connection *con
 {
        const char *cause = NULL;
 
+       conn->state = STATE_CONNECT;
+
        if (conn->fd != -1) {
                close(conn->fd);
                conn->fd = -1;
@@ -702,7 +704,7 @@ http_redirect(struct http_connection *co
        if (http_resolv(conn, host, port) == -1)
                return -1;
 
-       return 0;
+       return http_connect(conn);
 }
 
 static int
@@ -995,12 +997,34 @@ data_write(struct http_connection *conn)
        return WANT_POLLOUT;
 }
 
+/*
+ * Do one IO call depending on the connection state.
+ * Return WANT_POLLIN or WANT_POLLOUT to poll for more data.
+ * If 0 is returned this stage is finished and the protocol should move
+ * to the next stage by calling http_nextstep(). On error return -1.
+ */
 static int
-http_handle(struct http_connection *conn)
+http_handle(struct http_connection *conn, int events)
 {
+       /* special case for INIT,  there is no event to start a request */
+       if (conn->state == STATE_INIT)
+               return http_connect(conn);
+
+       if (events & POLLHUP) {
+               if (conn->state == STATE_WRITE_DATA)
+                       warnx("%s: output pipe closed", http_info(conn->url));
+               else
+                       warnx("%s: server closed connection",
+                           http_info(conn->url));
+               return -1;
+       }
+
+       if ((events & conn->events) == 0) {
+               warnx("%s: unexpected event", http_info(conn->url));
+               return -1;
+       }
+
        switch (conn->state) {
-       case STATE_INIT:
-               return 0;
        case STATE_CONNECT:
                if (http_finish_connect(conn) == -1)
                        /* something went wrong, try other host */
@@ -1019,22 +1043,31 @@ http_handle(struct http_connection *conn
                return data_write(conn);
        case STATE_DONE:
                return http_close(conn);
+       case STATE_INIT:
        case STATE_FREE:
                errx(1, "bad http state");
        }
        errx(1, "unknown http state");
 }
 
+/*
+ * Move the state machine forward until IO needs to happen.
+ * Returns either WANT_POLLIN or WANT_POLLOUT or -1 on error.
+ */
 static int
 http_nextstep(struct http_connection *conn)
 {
+       int r;
+
        switch (conn->state) {
        case STATE_INIT:
-               conn->state = STATE_CONNECT;
-               return http_connect(conn);
+               errx(1, "bad http state");
        case STATE_CONNECT:
                conn->state = STATE_TLSCONNECT;
-               return http_tls_connect(conn);
+               r = http_tls_connect(conn);
+               if (r != 0)
+                       return r;
+               /* FALLTHROUGH */
        case STATE_TLSCONNECT:
                conn->state = STATE_REQUEST;
                return http_request(conn);
@@ -1082,9 +1115,9 @@ http_nextstep(struct http_connection *co
 }
 
 static int
-http_do(struct http_connection *conn)
+http_do(struct http_connection *conn, int events)
 {
-       switch (http_handle(conn)) {
+       switch (http_handle(conn, events)) {
        case -1:
                /* connection failure */
                if (conn->state != STATE_DONE)
@@ -1104,6 +1137,9 @@ http_do(struct http_connection *conn)
                                http_fail(conn->id);
                        http_free(conn);
                        return -1;
+               case 0:
+                       errx(1, "%s: http_nextstep returned 0, state %d",
+                           http_info(conn->url), conn->state);
                }
                break;
        case WANT_POLLIN:
@@ -1194,18 +1230,22 @@ proc_http(char *bind_addr, int fd)
                                err(1, "write");
                        }
                }
+
+               /* process active http requests */
                for (i = 0; i < MAX_CONNECTIONS; i++) {
                        struct http_connection *conn = http_conns[i];
 
                        if (conn == NULL)
                                continue;
                        /* event not ready */
-                       if (!(pfds[i].revents & (conn->events | POLLHUP)))
+                       if (pfds[i].revents == 0)
                                continue;
 
-                       if (http_do(conn) == -1)
+                       if (http_do(conn, pfds[i].revents) == -1)
                                http_conns[i] = NULL;
                }
+
+               /* process new requests last */
                if (pfds[MAX_CONNECTIONS].revents & POLLIN) {
                        struct http_connection *h;
                        size_t id;
@@ -1223,7 +1263,7 @@ proc_http(char *bind_addr, int fd)
                                        if (http_conns[i] != NULL)
                                                continue;
                                        http_conns[i] = h;
-                                       if (http_do(h) == -1)
+                                       if (http_do(h, 0) == -1)
                                                http_conns[i] = NULL;
                                        break;
                                }

Reply via email to