Simple:
	step1(conn): read(conn), then step2
	step2(conn): write(conn), then close

Pass-through:
	step1(conn): read(conn), then step2
	step2(conn): write(otherconn), then step1

Pass-through-and-connect:
	step1(conn): read(conn), then step2
	step2(conn): connect(otherconn), then step3
	step3(conn): write(otherconn), then step1

Chatroom:
	step1(conn): read(conn), then step2
	step2(conn): for c in allcons: write(c).  goto step1

Simple:

void event(struct io_event *done)
{
	char *buf = done->priv;
	struct io_event *e;

	e = queue_read(done, done->conn, buf, 100);
	e = queue_write(e, done->conn, buf, 100);
	queue_close(e, done->conn);
}

Pass-through:
struct passthru {
	char buf[100];
	struct conn *rconn, *wconn;
};

void event(struct io_event *done)
{
	struct passthru *p = done->priv;
	struct io_event *e;

	e = queue_read(done, p->rconn, p->buf, 100);
	e = queue_write(e, p->wconn, buf, 100);
	queue_event(e, event);
}

Chatroom:
struct list_head clients;

struct buffer {
	char buf[100];
	unsigned int ref;
};

struct client {
	struct list_node list;
	struct connection *conn;
	struct buffer *rbuf, *wbuf;
};

void broadcast(struct io_event *done)
{
	struct client *i, *c = done->conn->priv;
	struct io_event *e;

	list_for_each(&clients, i, list) {
		e = queue_write(done, i->conn, c->buf->buf, 100);
		e->priv = c->buf;
		c->buf->ref++;
		queue_event(e, drop_ref);
	}



void event(struct io_event *done)
{
	struct client *c = done->conn->priv;
	struct io_event *e;

	assert(c->conn == done->conn);
	c->buf = malloc(sizeof(*c->buf));
	c->buf->ref = 0;
	e = queue_read(done, c->conn, c->buf->buf, 100);
	e = queue_event(e, broadcast);
}


	step1(conn): read(conn), then step2
	step2(conn): for c in allcons: write(c).  goto step1
