+struct io_plan io_idle(void);
+
+/**
+ * io_timeout - set timeout function if the callback doesn't fire.
+ * @conn: the current connection.
+ * @ts: how long until the timeout should be called.
+ * @cb to call.
+ * @arg: argument to @cb.
+ *
+ * If the usual next callback is not called for this connection before @ts,
+ * this function will be called. If next callback is called, the timeout
+ * is automatically removed.
+ *
+ * Returns false on allocation failure. A connection can only have one
+ * timeout.
+ */
+#define io_timeout(conn, ts, fn, arg) \
+ io_timeout_((conn), (ts), \
+ typesafe_cb_preargs(struct io_plan, void *, \
+ (fn), (arg), \
+ struct io_conn *), \
+ (arg))
+bool io_timeout_(struct io_conn *conn, struct timespec ts,
+ struct io_plan (*fn)(struct io_conn *, void *), void *arg);
+
+/**
+ * io_duplex - split an fd into two connections.
+ * @conn: a connection.
+ * @plan: the first I/O function to call.
+ * @finish: the function to call when it's closed or fails.
+ * @arg: the argument to @finish.
+ *
+ * Sometimes you want to be able to simultaneously read and write on a
+ * single fd, but io forces a linear call sequence. The solition is
+ * to have two connections for the same fd, and use one for read
+ * operations and one for write.
+ *
+ * You must io_close() both of them to close the fd.
+ */
+#define io_duplex(conn, plan, finish, arg) \
+ io_duplex_((conn), (plan), \
+ typesafe_cb_preargs(void, void *, (finish), (arg), \
+ struct io_conn *), \
+ (arg))
+
+struct io_conn *io_duplex_(struct io_conn *conn,
+ struct io_plan plan,
+ void (*finish)(struct io_conn *, void *),
+ void *arg);