#include #include #include #include #include #include #include #include #include #include "meta.h" #include "files.h" #include "peer.h" #include "netio.h" LIST_HEAD(btclist, btchunk) chead; LIST_HEAD(btrlist, btrequest) rhead; struct btrequest *allocrequest(struct btmeta *, struct btpeer *, int, off_t, off_t); int freerequest(struct btmeta *, struct btpeer *, int n, off_t, off_t); struct btchunk *allocchunk(struct btmeta *, int); int freechunk(struct btmeta *, int); /* DON'T FORGET: LIST_INIT(&chead); LIST_INIT(&rhead); */ struct btrequest * btallocrequest(struct btmeta *mp, struct btpeer *p, int n, off_t off, off_t len) { struct btrequest *r; r = malloc(sizeof(struct btrequest)); assert(r); r->peer = p; r->offset = off; r->length = len; r->chunk = allocchunk(mp, n); r->transmitted = 0; LIST_INSERT_HEAD(&rhead, r, link); return r; } int btfreerequest(struct btmeta *mp, struct btpeer *p, int n, off_t off, off_t len) { struct btrequest *r, *nxt; for (r = LIST_FIRST(&rhead); r != LIST_END(&rhead); r = nxt) { nxt = LIST_NEXT(r, link); if (r->peer == p && r->offset == off && r->length == len) { if (freechunk(mp, r->chunk->piece) == -1) return -1; LIST_REMOVE(r, link); free(r); return 0; } } return -1; } int btwriterequest(struct btpeer *p, int n, off_t off, off_t len) { struct btrequest *r, *nxt; for (r = LIST_FIRST(&rhead); r != LIST_END(&rhead); r = nxt) { nxt = LIST_NEXT(r, link); if (r->peer == p && r->offset == off && r->length == len) { memcpy(r->chunk->data + r->offset, p->msgbuf, p->buflen); return 0; } } return -1; } struct btchunk * allocchunk(struct btmeta *mp, int n) { struct btchunk *p; /* look if we have already that chunk */ LIST_FOREACH(p, &chead, link) { if (p->piece == n) { ++p->ref; return p; } } /* not found, allocate a new one */ p = malloc(sizeof(struct btchunk)); assert(p); p->ref = 1; p->piece = n; p->sha1 = mp->pieces[n]; p->len = btsizeofpiece(mp, n); p->data = calloc(p->len, sizeof(char)); assert(p->data); if (btisset(mp->bitfield, n)) btread(mp, p->data, p->len, n); return p; } int freechunk(struct btmeta *mp, int n) { struct btchunk *p, *nxt; for (p = LIST_FIRST(&chead); p != LIST_END(&chead); p = nxt) { nxt = LIST_NEXT(p, link); if (p->piece == n) { /* do we have it already? */ if (btisset(mp->bitfield, n)) return 1; /* check and write */ if (!btcheck(p->sha1, p->data, p->len) || !btwrite(mp, p->data, p->len, n)) return -1; btsetbit(mp->bitfield, n); if (--p->ref <= 0) { /* nobody refers anymore to this piece */ LIST_REMOVE(p, link); free(p->data); free(p); } /* announce all that we have that piece */ return 0; } } /* nothing found */ return -1; } #if 0 /* put message on queue */ /* needed vars: data, length, send/recv (*fp)() socket */ void btputqueue(struct btqueue *head, struct btpeer *p, ssize_t (*fp)(int, void *, size_t, int)) { struct btqentry *q; q = malloc(sizeof(struct btqentry)); assert(q); q->data = p->data + p->offset; q->length = p->length; q->doit = fp; q->sockd = p->sockd; SIMPLEQ_INSERT_TAIL(head, q, link); } int nonblock(int s) { int flags; flags = fcntl(s, F_GETFL); if (flags < 0 || fcntl(s, F_SETFL, flags|O_NONBLOCK) < 0) return -1; return s; } #endif