#include "deluge.h" void strategy(Torrent *t) { Peer *p; int new; if(bitnhave(t->haves) == t->npieces) new = Seeding; else if(bithaveall(t->reqpieces)) new = Endgame; else if(bitnhave(t->haves) > 0) new = Rarestfirst; else new = Random; if(t->strategy == new) return; if(new == Seeding){ if(t->dl != 0) trackrequest(t, "completed"); DEBUG(2, "DOWNLOAD COMPLETED %R\n", t->rate); } if(new == Endgame){ t->strategy = new; for(p = t->peers; p; p = p->next) if(!IsChoking(p)) piecepeerschedule(t, p); }else{ t->strategy = new; } } void bitesrequested(Peer *p, Piece *pc, Bits *bits) { Bite *b; bitclear(bits); for(b = p->lreq; b; b = b->next) if(b->piecen == pc->n) bitset(bits, b->n); } Piece * nextpiece(Torrent *t, Peer *p) { Piece *r, *n; int start; int i, index; Bits *bits; switch(t->strategy){ case Random: assert(!bithaveall(t->reqpieces)); start = rand() % t->npieces; for(i = 0; i < bitlen(t->reqpieces); i++){ index = (start+i) % t->npieces; n = &t->pieces[index]; if(!bitget(t->haves, index) && !bitget(t->reqpieces, index) && n->nids > 0) return n; } DEBUG(2, "nextpiece: no random piece to start on\n"); return nil; break; case Rarestfirst: r = nil; for(i = 0; i < t->npieces; i++){ n = &t->pieces[i]; if(!bitget(t->haves, i) && !bitget(t->reqpieces, i) && n->nids > 0 && (r == nil || n->nids < r->nids)){ r = n; if(r->nids == 1) break; } } return r; case Endgame: start = rand() % t->npieces; bits = bitnew((t->piecelen+Bitelength-1) / Bitelength, nil); for(i = 0; i < t->npieces; i++){ index = (start+i) % t->npieces; if(bitget(t->haves, index)) continue; bitesrequested(p, &t->pieces[index], bits); if(!bithaveall(bits)){ bitfree(bits); return &t->pieces[index]; } } bitfree(bits); return nil; case Seeding: DEBUG(2, "nextpiece: called when in state Seeding\n"); return nil; default: sysfatal("nextpiece: cannot happen"); } return nil; } Bite * piecenextbite(Torrent *t, Peer *p, Piece *pc) { int i; int bitelen; Bits *bits; if(bithaveall(pc->bites)) return nil; switch(t->strategy){ case Random: case Rarestfirst: if(bitnhave(pc->bites) + bitnhave(pc->reqbites) >= bitlen(pc->reqbites)) return nil; for(i = 0; i < bitlen(pc->reqbites); i++){ if(!bitget(pc->bites, i) && !bitget(pc->reqbites, i)){ bitelen = MIN(Bitelength, t->length - pc->n * t->piecelen - i*Bitelength); return bitenew(i, pc->n, i*Bitelength, bitelen); } } sysfatal("piecenextbite: cannot happen, no bite in piece after all (rarest/random)"); case Endgame: bits = bitnew(bitlen(pc->reqbites), nil); bitesrequested(p, pc, bits); if(bitnhave(pc->bites) + bitnhave(bits) >= bitlen(bits)){ bitfree(bits); return nil; } for(i = 0; i < bitlen(bits); i++){ if(!bitget(pc->bites, i) && !bitget(bits, i)){ bitfree(bits); bitelen = MIN(Bitelength, t->length - pc->n * t->piecelen - i*Bitelength); return bitenew(i, pc->n, i*Bitelength, bitelen); } } sysfatal("piecenextbite: cannot happen, no bite in piece after all (endgame)"); case Seeding: DEBUG(2, "piecenextbite: next bite requested for strategy Seeding\n"); return nil; default: sysfatal("piecenextbite: cannot happen"); } return nil; } Bite * nextbite(Torrent *t, Peer *p) { Bite *b, *rb; Piece *pc; for(b = p->lreq; b; b = b->next){ pc = &t->pieces[b->piecen]; rb = piecenextbite(t, p, pc); if(rb) return rb; } pc = nextpiece(t, p); if(pc){ return piecenextbite(t, p, pc); } DEBUG(2, "nextbite: no new pieces to start on\n"); return nil; } void piecepeerschedule(Torrent *t, Peer *p) { Bite *b; strategy(t); while(bitelen(p->lreq) < Minscheduled){ b = nextbite(t, p); if(b == nil){ DEBUG(2, "no more bites to schedule\n"); return; } request(t, p, b); strategy(t); } }