- conn->u.writepart.buf = data;
- conn->u.writepart.lenp = len;
- conn->fd.next = cb;
- conn->fd.next_arg = arg;
- conn->pollflag = POLLOUT;
- return to_ioplan(WRITEPART);
-}
-
-struct io_plan *io_idle(struct io_conn *conn)
-{
- conn->pollflag = 0;
- return to_ioplan(IDLE);
-}
-
-void io_wake_(struct io_conn *conn,
- struct io_plan *(*fn)(struct io_conn *, void *), void *arg)
-
-{
- /* It might have finished, but we haven't called its finish() yet. */
- if (conn->state == FINISHED)
- return;
- assert(conn->state == IDLE);
- conn->fd.next = fn;
- conn->fd.next_arg = arg;
- backend_set_state(conn, to_ioplan(NEXT));
-}
-
-static struct io_plan *do_next(struct io_conn *conn)
-{
- if (timeout_active(conn))
- backend_del_timeout(conn);
- return conn->fd.next(conn, conn->fd.next_arg);
-}
-
-struct io_plan *do_ready(struct io_conn *conn)
-{
- ssize_t ret;
- bool finished;
-
- switch (conn->state) {
- case WRITE:
- ret = write(conn->fd.fd, conn->u.write.buf, conn->u.write.len);
- if (ret < 0)
- return io_close(conn, NULL);
- conn->u.write.buf += ret;
- conn->u.write.len -= ret;
- finished = (conn->u.write.len == 0);
- break;
- case WRITEPART:
- ret = write(conn->fd.fd, conn->u.writepart.buf,
- *conn->u.writepart.lenp);
- if (ret < 0)
- return io_close(conn, NULL);
- *conn->u.writepart.lenp = ret;
- finished = true;
- break;
- case READ:
- ret = read(conn->fd.fd, conn->u.read.buf, conn->u.read.len);
- if (ret <= 0)
- return io_close(conn, NULL);
- conn->u.read.buf += ret;
- conn->u.read.len -= ret;
- finished = (conn->u.read.len == 0);
- break;
- case READPART:
- ret = read(conn->fd.fd, conn->u.readpart.buf,
- *conn->u.readpart.lenp);
- if (ret <= 0)
- return io_close(conn, NULL);
- *conn->u.readpart.lenp = ret;
- finished = true;
- break;
+ struct io_plan_arg *arg = io_plan_arg(conn, IO_OUT);
+
+ if (maxlen == 0)
+ return set_always(conn, IO_OUT, next, next_arg);
+
+ arg->u1.const_vp = data;
+ /* We store the max len in here temporarily. */
+ *len = maxlen;
+ arg->u2.vp = len;
+
+ return io_set_plan(conn, IO_OUT, do_write_partial, next, next_arg);
+}
+
+static int do_connect(int fd, struct io_plan_arg *arg)
+{
+ int err, ret;
+ socklen_t len = sizeof(err);
+
+ /* Has async connect finished? */
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ if (ret < 0)
+ return -1;
+
+ if (err == 0) {
+ return 1;
+ } else if (err == EINPROGRESS)
+ return 0;
+
+ errno = err;
+ return -1;
+}
+
+struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr,
+ struct io_plan *(*next)(struct io_conn *, void *),
+ void *next_arg)
+{
+ int fd = io_conn_fd(conn);
+
+ /* We don't actually need the arg, but we need it polling. */
+ io_plan_arg(conn, IO_OUT);
+
+ /* Note that io_new_conn() will make fd O_NONBLOCK */
+
+ /* Immediate connect can happen. */
+ if (connect(fd, addr->ai_addr, addr->ai_addrlen) == 0)
+ return set_always(conn, IO_OUT, next, next_arg);
+
+ if (errno != EINPROGRESS)
+ return io_close(conn);
+
+ return io_set_plan(conn, IO_OUT, do_connect, next, next_arg);
+}
+
+static struct io_plan *io_wait_dir(struct io_conn *conn,
+ const void *wait,
+ enum io_direction dir,
+ struct io_plan *(*next)(struct io_conn *,
+ void *),
+ void *next_arg)
+{
+ struct io_plan_arg *arg = io_plan_arg(conn, dir);
+ arg->u1.const_vp = wait;
+
+ conn->plan[dir].status = IO_WAITING;
+
+ return io_set_plan(conn, dir, NULL, next, next_arg);
+}
+
+struct io_plan *io_wait_(struct io_conn *conn,
+ const void *wait,
+ struct io_plan *(*next)(struct io_conn *, void *),
+ void *next_arg)
+{
+ return io_wait_dir(conn, wait, IO_IN, next, next_arg);
+}
+
+struct io_plan *io_out_wait_(struct io_conn *conn,
+ const void *wait,
+ struct io_plan *(*next)(struct io_conn *, void *),
+ void *next_arg)
+{
+ return io_wait_dir(conn, wait, IO_OUT, next, next_arg);
+}
+
+void io_wake(const void *wait)
+{
+ backend_wake(wait);
+}
+
+/* Returns false if this has been freed. */
+static bool do_plan(struct io_conn *conn, struct io_plan *plan)
+{
+ /* We shouldn't have polled for this event if this wasn't true! */
+ assert(plan->status == IO_POLLING);
+
+ switch (plan->io(conn->fd.fd, &plan->arg)) {
+ case -1:
+ io_close(conn);
+ return false;
+ case 0:
+ return true;
+ case 1:
+ return next_plan(conn, plan);