-struct io_conn *io_new_conn_(int fd,
- struct io_plan *(*start)(struct io_conn *, void *),
- void (*finish)(struct io_conn *, void *),
+static struct io_plan *io_never_called(struct io_conn *conn, void *arg)
+{
+ abort();
+}
+
+/* Returns false if conn was freed. */
+static bool next_plan(struct io_conn *conn, struct io_plan *plan)
+{
+ struct io_plan *(*next)(struct io_conn *, void *arg);
+
+ next = plan->next;
+
+ plan->status = IO_UNSET;
+ plan->io = NULL;
+ plan->next = io_never_called;
+
+ plan = next(conn, plan->next_arg);
+
+ if (plan == &io_conn_freed)
+ return false;
+
+ /* It should have set a plan inside this conn (or duplex) */
+ assert(plan == &conn->plan[IO_IN]
+ || plan == &conn->plan[IO_OUT]
+ || plan == &conn->plan[2]);
+ assert(conn->plan[IO_IN].status != IO_UNSET
+ || conn->plan[IO_OUT].status != IO_UNSET);
+
+ backend_new_plan(conn);
+ return true;
+}
+
+static void set_blocking(int fd, bool block)
+{
+ int flags = fcntl(fd, F_GETFL);
+
+ if (block)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+
+ fcntl(fd, F_SETFL, flags);
+}
+
+struct io_conn *io_new_conn_(const tal_t *ctx, int fd,
+ struct io_plan *(*init)(struct io_conn *, void *),