ccan/io: io_halfclose.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Aug 2014 08:16:21 +0000 (17:46 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Aug 2014 08:16:21 +0000 (17:46 +0930)
Helper for a common case.  Replace all but 1 in tests.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/io/io.c
ccan/io/io.h
ccan/io/test/run-12-bidir.c
ccan/io/test/run-14-duplex-both-read.c
ccan/io/test/run-16-duplex-test.c

index 6d1c0522d131c8e15809b8deb2e84ba752710302..7f5113d344c4b5ba199121593c2d5903e236dfd9 100644 (file)
@@ -437,6 +437,24 @@ struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan)
        return out_plan + 1;
 }
 
+struct io_plan *io_halfclose(struct io_conn *conn)
+{
+       /* Already closing?  Don't close twice. */
+       if (conn->plan[IO_IN].status == IO_CLOSING)
+               return &conn->plan[IO_IN];
+
+       /* Both unset?  OK. */
+       if (conn->plan[IO_IN].status == IO_UNSET
+           && conn->plan[IO_OUT].status == IO_UNSET)
+               return io_close(conn);
+
+       /* We leave this unset then. */
+       if (conn->plan[IO_IN].status == IO_UNSET)
+               return &conn->plan[IO_IN];
+       else
+               return &conn->plan[IO_OUT];
+}
+
 struct io_plan *io_set_plan(struct io_conn *conn, enum io_direction dir,
                            int (*io)(int fd, struct io_plan_arg *arg),
                            struct io_plan *(*next)(struct io_conn *, void *),
index 1341b6f209010861958dda6de1335e4e8518e161..d0c0a39a3888526df10c4174ed4dd8e69b8e7153 100644 (file)
@@ -443,6 +443,34 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr,
 struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan);
 void io_duplex_prepare(struct io_conn *conn);
 
+/**
+ * io_halfclose - close half of an io_duplex connection.
+ * @conn: the connection that plan is for.
+ *
+ * It's common to want to close a duplex connection after both input and
+ * output plans have completed.  If either calls io_close() the connection
+ * closes immediately.  Instead, io_halfclose() needs to be called twice.
+ *
+ * Example:
+ * struct buf {
+ *     char in[100];
+ *     char out[100];
+ * };
+ *
+ * static struct io_plan *finish(struct io_conn *conn, struct buf *b)
+ * {
+ *     return io_halfclose(conn);
+ * }
+ *
+ * static struct io_plan *read_and_write(struct io_conn *conn, struct buf *b)
+ * {
+ *     return io_duplex(conn,
+ *                      io_read(conn, b->in, sizeof(b->in), finish, b),
+ *                      io_write(conn, b->out, sizeof(b->out), finish, b));
+ * }
+ */
+struct io_plan *io_halfclose(struct io_conn *conn);
+
 /**
  * io_wait - leave a plan idle until something wakes us.
  * @conn: the connection that plan is for.
index 2ecc5470e7ef5a8d2ec22469bbb119a82833ba60..10f84295cb8650e6c8566289b9467fd9608561a6 100644 (file)
@@ -15,7 +15,6 @@
 struct data {
        struct io_listener *l;
        int state;
-       int done;
        char buf[4];
        char wbuf[32];
 };
@@ -28,10 +27,7 @@ static void finish_ok(struct io_conn *conn, struct data *d)
 static struct io_plan *rw_done(struct io_conn *conn, struct data *d)
 {
        d->state++;
-       d->done++;
-       if (d->done == 2)
-               return io_close(conn);
-       return io_wait(conn, NULL, io_never, NULL);
+       return io_halfclose(conn);
 }
 
 static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
@@ -91,9 +87,8 @@ int main(void)
        int fd, status;
 
        /* This is how many tests you plan to run */
-       plan_tests(10);
+       plan_tests(9);
        d->state = 0;
-       d->done = 0;
        fd = make_listen_fd(PORT, &addrinfo);
        ok1(fd >= 0);
        d->l = io_new_listener(NULL, fd, init_conn, d);
@@ -127,7 +122,6 @@ int main(void)
        freeaddrinfo(addrinfo);
        ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 4);
-       ok1(d->done == 2);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
 
index ac334e7837be7d057e307b5e4aa1caa0f453878e..30c46cd5dbd79fd2909a5a36339cd2b7a8089a88 100644 (file)
@@ -29,10 +29,11 @@ static void finish_ok(struct io_conn *conn, struct data *d)
 static struct io_plan *end(struct io_conn *conn, struct data *d)
 {
        d->state++;
+       /* Close on top of halfclose should work. */
        if (d->state == 4)
                return io_close(conn);
        else
-               return io_wait(conn, NULL, io_never, NULL);
+               return io_halfclose(conn);
 }
 
 static struct io_plan *make_duplex(struct io_conn *conn, struct data *d)
index 2081418334ba51b90f20dfe04edad5ea0f4053a8..8631be4519f58a0e0603da35e1d539b34af1dcd8 100644 (file)
@@ -29,9 +29,7 @@ static void finish_ok(struct io_conn *conn, struct data *d)
 static struct io_plan *io_done(struct io_conn *conn, struct data *d)
 {
        d->state++;
-       if (d->state == 3)
-               return io_close(conn);
-       return io_wait(conn, d, io_close_cb, NULL);
+       return io_halfclose(conn);
 }
 
 static struct io_plan *init_conn(struct io_conn *conn, struct data *d)