Commit d8ecdc80 authored by Rusty Russell's avatar Rusty Russell

ccan/io: io_halfclose.

Helper for a common case.  Replace all but 1 in tests.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 43185ec6
...@@ -437,6 +437,24 @@ struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan) ...@@ -437,6 +437,24 @@ struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan)
return out_plan + 1; 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, struct io_plan *io_set_plan(struct io_conn *conn, enum io_direction dir,
int (*io)(int fd, struct io_plan_arg *arg), int (*io)(int fd, struct io_plan_arg *arg),
struct io_plan *(*next)(struct io_conn *, void *), struct io_plan *(*next)(struct io_conn *, void *),
......
...@@ -443,6 +443,34 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, ...@@ -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); struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan);
void io_duplex_prepare(struct io_conn *conn); 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. * io_wait - leave a plan idle until something wakes us.
* @conn: the connection that plan is for. * @conn: the connection that plan is for.
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
struct data { struct data {
struct io_listener *l; struct io_listener *l;
int state; int state;
int done;
char buf[4]; char buf[4];
char wbuf[32]; char wbuf[32];
}; };
...@@ -28,10 +27,7 @@ static void finish_ok(struct io_conn *conn, struct data *d) ...@@ -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) static struct io_plan *rw_done(struct io_conn *conn, struct data *d)
{ {
d->state++; d->state++;
d->done++; return io_halfclose(conn);
if (d->done == 2)
return io_close(conn);
return io_wait(conn, NULL, io_never, NULL);
} }
static struct io_plan *init_conn(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
...@@ -91,9 +87,8 @@ int main(void) ...@@ -91,9 +87,8 @@ int main(void)
int fd, status; int fd, status;
/* This is how many tests you plan to run */ /* This is how many tests you plan to run */
plan_tests(10); plan_tests(9);
d->state = 0; d->state = 0;
d->done = 0;
fd = make_listen_fd(PORT, &addrinfo); fd = make_listen_fd(PORT, &addrinfo);
ok1(fd >= 0); ok1(fd >= 0);
d->l = io_new_listener(NULL, fd, init_conn, d); d->l = io_new_listener(NULL, fd, init_conn, d);
...@@ -127,7 +122,6 @@ int main(void) ...@@ -127,7 +122,6 @@ int main(void)
freeaddrinfo(addrinfo); freeaddrinfo(addrinfo);
ok1(io_loop(NULL, NULL) == NULL); ok1(io_loop(NULL, NULL) == NULL);
ok1(d->state == 4); ok1(d->state == 4);
ok1(d->done == 2);
ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0); ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
free(d); free(d);
......
...@@ -29,10 +29,11 @@ static void finish_ok(struct io_conn *conn, struct data *d) ...@@ -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) static struct io_plan *end(struct io_conn *conn, struct data *d)
{ {
d->state++; d->state++;
/* Close on top of halfclose should work. */
if (d->state == 4) if (d->state == 4)
return io_close(conn); return io_close(conn);
else 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) static struct io_plan *make_duplex(struct io_conn *conn, struct data *d)
......
...@@ -29,9 +29,7 @@ static void finish_ok(struct io_conn *conn, struct data *d) ...@@ -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) static struct io_plan *io_done(struct io_conn *conn, struct data *d)
{ {
d->state++; d->state++;
if (d->state == 3) return io_halfclose(conn);
return io_close(conn);
return io_wait(conn, d, io_close_cb, NULL);
} }
static struct io_plan *init_conn(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment