I'm currently facing some decisions, about how to use the library. These decisions will define how the PWP functions will be used. Here is a pseudo code of how I imagine the interface. Feel free to discuss:
Code:
int interval = 0, last = 0;
uint8_t msg[MESSAGE_MAX];
off_t offset = 0;
interval = thpsend(torrent, "started");
last = time(NULL);
/* everything is wrapped within an infinite loop
for (;;) {
    if (time(NULL) - interval > last)
        interval = thpsend(torrent, NULL);
    foreach(torrent->peers as peer) {
        if (!peer->connected) {
            pwpsend(torrent, peer, PWP_HANDSHAKE);
            pwpsend(torrent, peer, PWP_BITFIELD);
            pwpsend(torrent, peer, PWP_INTERESTED);
            pwpsend(torrent, peer, PWP_UNCHOKED);
        } else {
            if (!peer->ischoked)
                pwpsend(torrent, peer, PWP_REQUEST); /* Request a new random block */
        }
        switch (pwprecv(torrent, peer, &msg)) {
        case PWP_REQUEST:
            pwpsendblock(torrent, peer, msg);
            break;
        case PWP_PIECE:
             offset = pwprecvblock(torrent, peer, msg);
             if (sha1(torrent->pieces[offset]) == torrent->sha1[offset]) {
                 endgame(torrent, offset); /* sends PWP_CANCEL message to all peers */
                 interval = thpsend(torrent, torrent, "completed");
            }
            break;
        }
    }
}
Does that make any sense? Would you change anything?