X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2Fcmd%2Fip%2Ftorrent.c;h=54d631e0399db898002e206c426a9b0b5443785c;hb=7aac23b02baedfcaec2066da5b137fcbb97b3efe;hp=5e86c27e6b1ca7e1d9fcf1e349d2ec18b7ac03f9;hpb=0c0b874d49a51c09c1d2e97e9fdb9a480407d938;p=plan9front.git diff --git a/sys/src/cmd/ip/torrent.c b/sys/src/cmd/ip/torrent.c index 5e86c27e6..54d631e03 100644 --- a/sys/src/cmd/ip/torrent.c +++ b/sys/src/cmd/ip/torrent.c @@ -44,14 +44,18 @@ struct Stats enum { MAXIO = 16*1024, + SRVPROCS = 16, + CLIPROCS = 16, }; int debug; +int nproc = 1; int killgroup = -1; int port = 6881; char *deftrack = "http://exodus.desync.com/announce"; char *mntweb = "/mnt/web"; -uchar infohash[20]; +char *useragent = "torrent"; +uchar infohash[SHA1dlen]; uchar peerid[20]; int blocksize; @@ -189,11 +193,11 @@ rwpiece(int wr, int index, uchar *data, int len, int poff) int n, m; File *f; - if(len <= 0 || poff >= pieces[index].len) + if(len <= 0 || poff < 0 || poff >= pieces[index].len) return 0; if(len+poff > pieces[index].len) len = pieces[index].len - poff; - off = (vlong)index * blocksize; + off = (vlong)index * (vlong)blocksize; off += poff; for(f = files; f; f = f->next) if((f->off+f->len) > off) @@ -208,9 +212,9 @@ rwpiece(int wr, int index, uchar *data, int len, int poff) } int -havepiece(int x) +havepiece(int x, char *from) { - uchar *p, m, hash[20]; + uchar *p, m, hash[SHA1dlen]; int n; m = 0x80>>(x&7); @@ -224,8 +228,11 @@ havepiece(int x) } sha1(p, n, hash, nil); free(p); - if(memcmp(hash, pieces[x].hash, 20)) + if(memcmp(hash, pieces[x].hash, sizeof(hash))){ + if(debug && from != nil) + fprint(2, "peer %s: damaged piece %d\n", from, x); return 0; + } lock(&stats); if((havemap[x>>3] & m) == 0){ havemap[x>>3] |= m; @@ -233,6 +240,8 @@ havepiece(int x) stats.left -= pieces[x].len; } unlock(&stats); + if(debug && from != nil) + fprint(2, "peer %s: completed piece %d\n", from, x); return 1; } @@ -378,7 +387,7 @@ peer(int fd, int incoming, char *addr) uchar buf[64+MAXIO], *map, *told, *p, m; int mechoking, hechoking; int mewant, hewant; - int workpiece; + int workpiece, workoffset; int i, o, l, x, n; if(debug) fprint(2, "peer %s: %s connected\n", addr, incoming ? "incoming" : "outgoing"); @@ -415,6 +424,8 @@ peer(int fd, int incoming, char *addr) mewant = 0; hewant = 0; workpiece = -1; + workoffset = 0; + map = mallocz(nhavemap, 1); told = malloc(nhavemap); @@ -447,19 +458,19 @@ peer(int fd, int incoming, char *addr) } if(!hechoking && mewant){ x = workpiece; - if(x >= 0 && pieces[x].brk < pieces[x].len) - {} - else x = pickpiece(map); + if(x < 0 || (havemap[x>>3]&(0x80>>(x&7))) != 0 || workoffset >= pieces[x].len) + x = pickpiece(map); if(x >= 0){ - o = pieces[x].brk; + o = workpiece != x ? pieces[x].brk : workoffset; l = pieces[x].len - o; if(l > MAXIO) l = MAXIO; + workpiece = x; + workoffset = o + l; if(debug) fprint(2, "peer %s: -> request %d %d %d\n", addr, x, o, l); n = pack(buf, sizeof(buf), "lblll", 1+4+4+4, 0x06, x, o, l); if(write(fd, buf, n) != n) goto Out; - workpiece = x; } } if(mechoking && hewant){ @@ -547,13 +558,23 @@ peer(int fd, int incoming, char *addr) if(debug) fprint(2, "peer %s: <- piece %d %d %d\n", addr, x, o, n); if(x < 0 || x >= npieces) continue; - if((pieces[x].brk != o) || (havemap[x>>3]&(0x80>>(x&7)))) + if((havemap[x>>3]&(0x80>>(x&7))) != 0) continue; - if(rwpiece(1, x, p, n, o) == n){ - if((pieces[x].brk = o+n) == pieces[x].len){ - if(!havepiece(x)) - pieces[x].brk = 0; - } + if(o < 0 || o >= pieces[x].len) + continue; + if(o+n > pieces[x].len) + n = o - pieces[x].len; + if((o > pieces[x].brk) || (o+n <= pieces[x].brk)) + continue; + n = rwpiece(1, x, p, n, o); + if(n <= 0) + continue; + pieces[x].brk = o+n; + if(o+n >= pieces[x].len && !havepiece(x, addr)){ + pieces[x].brk = 0; + /* backoff from this piece for a while */ + if(x == workpiece) + workpiece = -1; } break; case 0x08: // Cancel @@ -579,10 +600,11 @@ void server(void) { char addr[64], adir[40], ldir[40]; - int afd, lfd, dfd; + int afd, lfd, dfd, pid, nprocs; NetConnInfo *ni; afd = -1; + nprocs = 0; for(port=6881; port<6890; port++){ snprint(addr, sizeof(addr), "tcp!*!%d", port); if((afd = announce(addr, adir)) >= 0) @@ -599,7 +621,13 @@ server(void) fprint(2, "listen: %r"); break; } - if(rfork(RFFDG|RFPROC|RFMEM)){ + while(nprocs >= SRVPROCS) + if(waitpid() > 0) + nprocs--; + nprocs++; + if(pid = rfork(RFFDG|RFPROC|RFMEM)){ + if(pid < 0) + nprocs--; close(lfd); continue; } @@ -609,8 +637,8 @@ server(void) } ni = getnetconninfo(ldir, dfd); peer(dfd, 1, ni ? ni->raddr : "???"); - if(ni) freenetconninfo(ni); - break; + if(ni) freenetconninfo(ni); + break; } exits(0); } @@ -618,11 +646,12 @@ server(void) void client(char *ip, char *port) { - static Dict *peers; + static Dict *peerqh, *peerqt; static QLock peerslk; - int try, fd; + static int nprocs; char *addr; Dict *d; + int fd; if(ip == nil || port == nil) return; @@ -630,7 +659,7 @@ client(char *ip, char *port) d = mallocz(sizeof(*d) + 64, 1); snprint(addr = d->str, 64, "tcp!%s!%s", ip, port); qlock(&peerslk); - if(dlook(peers, addr)){ + if(dlook(peerqh, addr)){ qunlock(&peerslk); free(d); return; @@ -638,23 +667,44 @@ client(char *ip, char *port) d->len = strlen(addr); d->typ = 'd'; d->val = d; - d->next = peers; - peers = d; + /* enqueue to front */ + if((d->next = peerqh) == nil) + peerqt = d; + peerqh = d; + if(nprocs >= CLIPROCS){ + qunlock(&peerslk); + return; + } + nprocs++; qunlock(&peerslk); - - if(debug) fprint(2, "client %s\n", addr); - - if(rfork(RFFDG|RFPROC|RFMEM)) + if(rfork(RFFDG|RFPROC|RFMEM|RFNOWAIT)) return; - for(try = 0; try < 10; try++){ + + for(;;){ + qlock(&peerslk); + /* dequeue and put to tail */ + if(d = peerqh){ + if((peerqh = d->next) == nil) + peerqt = nil; + d->next = nil; + if(peerqt) + peerqt->next = d; + else + peerqh = d; + peerqt = d; + } else + nprocs--; + qunlock(&peerslk); + if(d == nil) + exits(0); + addr = d->str; + if(debug) fprint(2, "client %s\n", addr); if((fd = dial(addr, nil, nil, nil)) >= 0){ - if(!peer(fd, 0, addr)) - break; + peer(fd, 0, addr); close(fd); } - sleep((1000<str)) continue; if(++err > 10){ close(fd); @@ -757,8 +811,9 @@ Error: } } } - havepiece(off / blocksize); - havepiece(f->off / blocksize); + if(off < f->off + f->len) + havepiece(off / blocksize, w->str); + havepiece(f->off / blocksize, w->str); close(fd); exits(0); } @@ -809,6 +864,15 @@ webtracker(char *url) bparse(p, p+n, &d); free(p); } else if(debug) fprint(2, "tracker %s: %r\n", url); + /* check errors and warnings */ + if(p = dstr(dlook(d, "failure reason"))) { + if(debug) + fprint(2, "tracker failure: %s\n", p); + exits(0); + } + if(p = dstr(dlook(d, "warning message"))) + if(debug) + fprint(2, "tracker warning: %s\n", p); if(l = dlook(d, "peers")){ if(l->typ == 's') clients4((uchar*)l->str, l->len); @@ -843,7 +907,7 @@ udpaddr(char addr[64], int naddr, char *url) if((x = strchr(url, '/')) == nil) x = strchr(url, 0); } - snprint(addr, naddr, "udp!%.*s!%d", (int)(x-url), url, port); + snprint(addr, naddr, "udp!%.*s!%d", utfnlen(url, x-url), url, port); return 0; } @@ -975,7 +1039,7 @@ Hfmt(Fmt *f) int mktorrent(int fd, Dict *alist, Dict *wlist) { - uchar *b, h[20]; + uchar *b, h[SHA1dlen]; Dir *d; int n; @@ -991,7 +1055,6 @@ mktorrent(int fd, Dict *alist, Dict *wlist) werrstr("empty file"); return -1; } - npieces = 1; for(blocksize = 256*1024;;blocksize<<=1){ npieces = (d->length + blocksize-1) / blocksize; if(npieces <= 8*1024 || blocksize >= 2*1024*1024) @@ -1105,7 +1168,7 @@ void usage(void) { fprint(2, "usage: %s [ -vsdpc ] [ -m mtpt ] [ -t tracker-url ] " - "[ -w webseed-url ] [ file ]\n", argv0); + "[ -w webseed-url ] [ -i peerid ] [ -A useragent ] [ file ]\n", argv0); exits("usage"); } @@ -1162,10 +1225,22 @@ main(int argc, char *argv[]) case 'd': debug++; break; + case 'i': + strncpy((char*)peerid, EARGF(usage()), sizeof(peerid)); + break; + case 'A': + useragent = EARGF(usage()); + break; default: usage(); } ARGEND; + if((s = getenv("NPROC")) != 0){ + if((nproc = atoi(s)) <= 0) + nproc = 1; + free(s); + } + fd = 0; if(*argv) if((fd = open(*argv, OREAD)) < 0) @@ -1252,14 +1327,14 @@ main(int argc, char *argv[]) if((blocksize = atoi(s)) <= 0) sysfatal("bogus piece length in meta info"); d = dlook(info, "pieces"); - if(d == nil || d->typ != 's' || d->len <= 0 || d->len % 20) + if(d == nil || d->typ != 's' || d->len <= 0 || d->len % SHA1dlen) sysfatal("bad or no pices in meta info"); - npieces = d->len / 20; + npieces = d->len / SHA1dlen; pieces = mallocz(sizeof(Piece) * npieces, 1); nhavemap = (npieces+7) / 8; havemap = mallocz(nhavemap, 1); for(i = 0; istr + i*20; + pieces[i].hash = (uchar*)d->str + i*SHA1dlen; if(len < blocksize) pieces[i].len = len; else @@ -1270,17 +1345,31 @@ main(int argc, char *argv[]) if(len) sysfatal("pieces do not match file length"); - for(i = 0; i= 0) + ; + + if(finished() && !sflag) + exits(0); - srand(time(0)); + srand(truerand()); atnotify(catch, 1); switch(i = rfork(RFPROC|RFMEM|RFNOTEG)){ case -1: sysfatal("fork: %r"); case 0: - memmove(peerid, "-NF9001-", 8); - for(i=8; i= 0 && peerid[i] == 0; i--) peerid[i] = nrand(10)+'0'; server(); for(; alist; alist = alist->next)