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;
File *files;
Stats stats;
+int
+finished(void)
+{
+ return nhavepieces >= npieces;
+}
+
void
freedict(Dict *d)
{
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)
}
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);
}
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;
stats.left -= pieces[x].len;
}
unlock(&stats);
+ if(debug && from != nil)
+ fprint(2, "peer %s: completed piece %d\n", from, x);
return 1;
}
if(s+1 > e) goto Err;
*va_arg(arg, int*) = *s++;
break;
+ case 'w':
+ if(s+2 > e) goto Err;
+ *va_arg(arg, int*) = s[0]<<8 | s[1];
+ s += 2;
+ break;
case 'l':
if(s+4 > e) goto Err;
*va_arg(arg, int*) = s[0]<<24 | s[1]<<16 | s[2]<<8 | s[3];
s += 4;
break;
+ case 'v':
+ if(s+8 > e) goto Err;
+ *va_arg(arg, vlong*) =
+ (vlong)s[0]<<56 |
+ (vlong)s[1]<<48 |
+ (vlong)s[2]<<40 |
+ (vlong)s[3]<<32 |
+ (vlong)s[4]<<24 |
+ (vlong)s[5]<<16 |
+ (vlong)s[6]<<8 |
+ (vlong)s[7];
+ s += 8;
+ break;
}
}
va_end(arg);
{
va_list arg;
uchar *b, *e;
+ vlong v;
int i;
b = s;
if(s+1 > e) goto Err;
*s++ = i & 0xFF;
break;
+ case 'w':
+ i = va_arg(arg, int);
+ if(s+2 > e) goto Err;
+ *s++ = (i>>8) & 0xFF;
+ *s++ = i & 0xFF;
+ break;
case 'l':
i = va_arg(arg, int);
if(s+4 > e) goto Err;
*s++ = (i>>8) & 0xFF;
*s++ = i & 0xFF;
break;
+ case 'v':
+ v = va_arg(arg, vlong);
+ if(s+8 > e) goto Err;
+ *s++ = (v>>56) & 0xFF;
+ *s++ = (v>>48) & 0xFF;
+ *s++ = (v>>40) & 0xFF;
+ *s++ = (v>>32) & 0xFF;
+ *s++ = (v>>24) & 0xFF;
+ *s++ = (v>>16) & 0xFF;
+ *s++ = (v>>8) & 0xFF;
+ *s++ = v & 0xFF;
+ break;
case '*':
i = va_arg(arg, int);
if(s+i > e) goto Err;
- memmove(s, va_arg(arg, uchar*), i);
+ memmove(s, va_arg(arg, void*), i);
s += i;
break;
}
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");
mewant = 0;
hewant = 0;
workpiece = -1;
+ workoffset = 0;
+
map = mallocz(nhavemap, 1);
told = malloc(nhavemap);
}
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){
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 <index> <begin> <length>
server(void)
{
char addr[64], adir[40], ldir[40];
- int afd, lfd, dfd;
+ int afd, lfd, dfd, pid, nprocs;
NetConnInfo *ni;
afd = -1;
- for(port=6881; port<6890; port++){
+ nprocs = 0;
+ for(port=6881; port<9000; port++){
snprint(addr, sizeof(addr), "tcp!*!%d", port);
if((afd = announce(addr, adir)) >= 0)
break;
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;
}
}
ni = getnetconninfo(ldir, dfd);
peer(dfd, 1, ni ? ni->raddr : "???");
- if(ni) freenetconninfo(ni);
- break;
+ if(ni) freenetconninfo(ni);
+ break;
}
exits(0);
}
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;
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;
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<<try)+nrand(5000));
+ sleep(1000+nrand(5000));
}
- exits(0);
}
int
close(ctlfd);
return -1;
}
+ if(useragent != nil && useragent[0] != '\0'){
+ n = snprint(buf, sizeof buf, "useragent %s", useragent);
+ write(ctlfd, buf, n);
+ }
snprint(buf, sizeof buf, "%s/%d/body", mntweb, conn);
if((fd = open(buf, OREAD)) < 0)
goto ErrOut;
}
void
-tracker(char *url)
+webseed(Dict *w, File *f)
{
- static Dict *trackers;
- static QLock trackerslk;
-
- char *event, *p;
- Dict *d, *l;
- int n, fd;
+ int fd, err, n, m, o, p, x, y;
+ uchar buf[MAXIO];
+ vlong off, len;
+ Dict *w0;
+ char *s;
- if(url == nil)
+ if(w == nil || f == nil || finished())
return;
-
- qlock(&trackerslk);
- if(dlook(trackers, url)){
- qunlock(&trackerslk);
+ if(rfork(RFPROC|RFMEM))
return;
+ w0 = w;
+Retry:
+ if(debug) fprint(2, "webseed %s %s\n", w->str, f->name);
+ s = strrchr(w->str, '/');
+ if(s && s[1] == 0)
+ fd = hopen("%s%s", w->str, f->name);
+ else
+ fd = hopen("%s", w->str);
+ if(fd < 0){
+Error:
+ if(debug) fprint(2, "webseed %s %s: %r\n", w->str, f->name);
+ if(finished())
+ exits(0);
+ if((w = w->next) == w0)
+ exits(0);
+ goto Retry;
}
- n = strlen(url);
- d = mallocz(sizeof(*d) + n+1, 1);
- strcpy(d->str, url);
- d->len = n;
- d->typ = 'd';
- d->val = d;
- d->next = trackers;
- trackers = d;
- url = d->str;
- qunlock(&trackerslk);
- if(debug) fprint(2, "tracker %s\n", url);
+ err = 0;
+ off = f->off;
+ len = f->len;
+ while(len > 0 && !finished()){
+ m = sizeof(buf);
+ if(len < m)
+ m = len;
+ if((n = read(fd, buf, m)) <= 0)
+ break;
+
+ x = off / blocksize;
+ p = off - (vlong)x*blocksize;
+ off += n;
+ len -= n;
+ y = off / blocksize;
+
+ o = 0;
+ while(n > 0){
+ m = pieces[x].len - p;
+ if(m > n)
+ m = n;
+ if((havemap[x>>3] & (0x80>>(x&7))) == 0)
+ rwpiece(1, x, buf+o, m, p);
+ if(x == y)
+ break;
+ o += m;
+ n -= m;
+ p = 0;
+ if(havepiece(x++, w->str))
+ continue;
+ if(++err > 10){
+ close(fd);
+ werrstr("file corrupted");
+ goto Error;
+ }
+ }
+ }
+ if(off < f->off + f->len)
+ havepiece(off / blocksize, w->str);
+ havepiece(f->off / blocksize, w->str);
+ close(fd);
+ exits(0);
+}
+
+void
+clients4(uchar *p, int len)
+{
+ char ip[16], port[6];
+
+ while(len >= 6){
+ len -= 6;
+ snprint(ip, sizeof(ip), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ snprint(port, sizeof(port), "%d", p[4]<<8 | p[5]);
+ p += 6;
+ client(ip, port);
+ }
+}
+
+void
+webtracker(char *url)
+{
+ char *event, *p;
+ Dict *d, *l;
+ int n, fd;
if(rfork(RFPROC|RFMEM))
return;
+ if(debug) fprint(2, "webtracker %s\n", url);
event = "&event=started";
for(;;){
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'){
- uchar *b, *e;
-
- b = (uchar*)l->str;
- e = b + l->len;
- for(; b+6 <= e; b += 6){
- char ip[16], port[6];
-
- snprint(ip, sizeof(ip), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
- snprint(port, sizeof(port), "%d", b[4]<<8 | b[5]);
- client(ip, port);
- }
- } else for(; l && l->typ == 'l'; l = l->next)
+ if(l->typ == 's')
+ clients4((uchar*)l->str, l->len);
+ else for(; l && l->typ == 'l'; l = l->next)
client(dstr(dlook(l->val, "ip")), dstr(dlook(l->val, "port")));
}
n = 0;
}
}
+int
+udpaddr(char addr[64], int naddr, char *url)
+{
+ int port;
+ char *x;
+
+ if((url = strchr(url, ':')) == nil)
+ return -1;
+ url++;
+ while(*url == '/')
+ url++;
+ if(x = strchr(url, ':')){
+ port = atoi(x+1);
+ } else {
+ port = 80;
+ if((x = strchr(url, '/')) == nil)
+ x = strchr(url, 0);
+ }
+ snprint(addr, naddr, "udp!%.*s!%d", utfnlen(url, x-url), url, port);
+ return 0;
+}
+
+void
+udptracker(char *url)
+{
+ int fd, event, n, m, a, i;
+ int transid, interval;
+ vlong connid;
+ uchar buf[MAXIO];
+ char addr[64];
+
+ if(udpaddr(addr, sizeof(addr), url) < 0)
+ return;
+ if(rfork(RFPROC|RFMEM))
+ return;
+ if(debug) fprint(2, "udptracker %s\n", addr);
+
+ event = 1;
+ for(;;){
+ alarm(30000);
+ if((fd = dial(addr, 0, 0, 0)) < 0)
+ goto Sleep;
+
+ /* connect */
+ transid = rand();
+ n = pack(buf, sizeof(buf), "vll", 0x41727101980LL, 0, transid);
+ if(write(fd, buf, n) != n)
+ goto Sleep;
+ for(;;){
+ if((n = read(fd, buf, sizeof(buf))) <= 0)
+ goto Sleep;
+ if(unpack(buf, n, "llv", &a, &i, &connid) < 0)
+ continue;
+ if(a == 0 && i == transid)
+ break;
+ }
+ alarm(0);
+
+ /* announce */
+ transid = rand();
+ lock(&stats);
+ n = pack(buf, sizeof(buf), "vll**vvvl____llw",
+ connid, 1, transid,
+ sizeof(infohash), infohash,
+ sizeof(peerid), peerid,
+ stats.down,
+ stats.left,
+ stats.up,
+ event,
+ 0, -1,
+ port);
+ unlock(&stats);
+
+ interval = 0;
+ alarm(30000);
+ if(write(fd, buf, n) != n)
+ goto Sleep;
+ for(;;){
+ if((n = read(fd, buf, sizeof(buf))) <= 0)
+ goto Sleep;
+ if((m = unpack(buf, n, "lll________", &a, &i, &interval)) < 0)
+ continue;
+ if(a == 1 && i == transid){
+ clients4(buf+m, n - m);
+ break;
+ }
+ }
+ event = 0;
+Sleep:
+ alarm(0);
+ if(fd >= 0)
+ close(fd);
+ if(interval < 10 | interval > 60*60)
+ interval = 2*60;
+ sleep(interval * 1000 + nrand(5000));
+ }
+}
+
+void
+tracker(char *url)
+{
+ static Dict *trackers;
+ static QLock trackerslk;
+ Dict *d;
+ int n;
+
+ if(url == nil)
+ return;
+ qlock(&trackerslk);
+ if(dlook(trackers, url)){
+ qunlock(&trackerslk);
+ return;
+ }
+ n = strlen(url);
+ d = mallocz(sizeof(*d) + n+1, 1);
+ strcpy(d->str, url);
+ d->len = n;
+ d->typ = 'd';
+ d->val = d;
+ d->next = trackers;
+ trackers = d;
+ url = d->str;
+ qunlock(&trackerslk);
+ if(!cistrncmp(url, "udp:", 4))
+ udptracker(url);
+ else
+ webtracker(url);
+}
+
int
Hfmt(Fmt *f)
{
}
int
-mktorrent(int fd, Dict *alist)
+mktorrent(int fd, Dict *alist, Dict *wlist)
{
- uchar *b, h[20];
+ uchar *b, h[SHA1dlen];
Dir *d;
int n;
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)
break;
}
- print("d");
- print("8:announce%ld:%s", strlen(alist->str), alist->str);
+
+ /*
+ * keys in dictionaries have to be ordered alphabetically
+ */
+ print("d8:announce%ld:%s", strlen(alist->str), alist->str);
if(alist->next){
print("13:announce-listl");
print("l%ld:%se", strlen(alist->str), alist->str);
print("l%ld:%se", strlen(alist->str), alist->str);
print("e");
}
- print("4:info");
- print("d");
- print("4:name%ld:%s", strlen(d->name), d->name);
+
+ print("4:infod");
print("6:lengthi%llde", d->length);
+ print("4:name%ld:%s", strlen(d->name), d->name);
print("12:piece lengthi%de", blocksize);
print("6:pieces%d:", npieces*sizeof(h));
free(d);
}
npieces--;
}
- free(b);
if(npieces){
werrstr("read failed: %r");
return -1;
}
+ free(b);
print("e");
+
+ if(wlist){
+ if(wlist->next){
+ print("8:url-listl");
+ for(; wlist; wlist = wlist->next)
+ print("%ld:%s", strlen(wlist->str), wlist->str);
+ print("e");
+ } else
+ print("8:url-list%ld:%s", strlen(wlist->str), wlist->str);
+ }
print("e");
+
return 0;
}
}
int
-killnote(void *, char *)
+catch(void *, char *msg)
{
+ if(strstr(msg, "alarm"))
+ return 1;
postnote(PNGROUP, killgroup, "kill");
return 0;
}
void
usage(void)
{
- fprint(2, "usage: %s [ -vsdpc ] [ -m mtpt ] [ -t url ] [ file ]\n", argv0);
+ fprint(2, "usage: %s [ -vsdpc ] [ -m mtpt ] [ -t tracker-url ] "
+ "[ -w webseed-url ] [ -i peerid ] [ -A useragent ] [ file ]\n", argv0);
exits("usage");
}
if(s == nil)
return t;
for(l = t; l; l = l->next)
- if(cistrcmp(l->str, s) == 0)
+ if(strcmp(l->str, s) == 0)
return t;
l = mallocz(sizeof(*l) + strlen(s)+1, 1);
l->next = t;
main(int argc, char *argv[])
{
int sflag, pflag, vflag, cflag, fd, i, n;
- Dict *alist, *info, *torrent, *d, *l;
+ Dict *alist, *wlist, *info, *torrent, *d, *l;
char *p, *s, *e;
File **fp, *f;
vlong len;
fmtinstall('H', Hfmt);
- alist = nil;
+ alist = wlist = nil;
sflag = pflag = vflag = cflag = 0;
ARGBEGIN {
case 'm':
case 't':
alist = scons(EARGF(usage()), alist);
break;
+ case 'w':
+ wlist = scons(EARGF(usage()), wlist);
+ break;
case 's':
sflag = 1;
break;
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)
if(cflag){
if(alist == nil)
alist = scons(deftrack, alist);
- if(mktorrent(fd, alist) < 0)
+ if(mktorrent(fd, alist, wlist) < 0)
sysfatal("%r");
exits(0);
}
if((n = readall(fd, &p)) <= 0)
sysfatal("read torrent: %r");
bparse(p, p+n, &torrent);
+
alist = scons(dstr(dlook(torrent, "announce")), alist);
for(d = dlook(torrent, "announce-list"); d && d->typ == 'l'; d = d->next)
for(l = d->val; l && l->typ == 'l'; l = l->next)
alist = scons(dstr(l->val), alist);
- if(alist == nil)
- sysfatal("no trackers in torrent");
+
+ if(d = dlook(torrent, "url-list")){
+ if(d->typ == 's')
+ wlist = scons(dstr(d->val), wlist);
+ else for(l = d; l && l->typ == 'l'; l = l->next)
+ wlist = scons(dstr(l->val), wlist);
+ /* make wlist into a ring */
+ for(l = wlist; l && l->next; l = l->next)
+ ;
+ if(l) l->next = wlist;
+ }
+
+ if(alist == nil && wlist == nil)
+ sysfatal("no trackers or webseeds in torrent");
+
if((d = info = dlook(torrent, "info")) == nil)
sysfatal("no meta info in torrent");
for(s = e = d->start; d && d->typ == 'd'; d = d->next)
for(f = files; f; f = f->next){
if(f->name == nil || f->len <= 0)
sysfatal("bogus file entry in meta info");
- f->name = fixnamedup(f->name);
- if(vflag) fprint(pflag ? 2 : 1, "%s\n", f->name);
- if((f->fd = open(f->name, ORDWR)) < 0){
- if(mkdirs(f->name) < 0)
+ s = fixnamedup(f->name);
+ if(vflag) fprint(pflag ? 2 : 1, "%s\n", s);
+ if((f->fd = open(s, ORDWR)) < 0){
+ if(mkdirs(s) < 0)
sysfatal("mkdirs: %r");
- if((f->fd = create(f->name, ORDWR, 0666)) < 0)
+ if((f->fd = create(s, ORDWR, 0666)) < 0)
sysfatal("create: %r");
}
f->off = len;
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; i<npieces; i++){
- pieces[i].hash = (uchar*)d->str + i*20;
+ pieces[i].hash = (uchar*)d->str + i*SHA1dlen;
if(len < blocksize)
pieces[i].len = len;
else
if(len)
sysfatal("pieces do not match file length");
- for(i = 0; i<npieces; i++)
- havepiece(i);
+ for(i=0; i<nproc; i++){
+ switch(rfork(RFPROC|RFMEM)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ for(; i<npieces; i+=nproc)
+ havepiece(i, nil);
+ exits(0);
+ }
+ }
+ while(waitpid() >= 0)
+ ;
+
+ if(finished() && !sflag)
+ exits(0);
- srand(time(0));
- atnotify(killnote, 1);
+ 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<sizeof(peerid); i++)
+ if(peerid[0] == 0)
+ strncpy((char*)peerid, "-NF9001-", 9);
+ for(i=sizeof(peerid)-1; i >= 0 && peerid[i] == 0; i--)
peerid[i] = nrand(10)+'0';
server();
for(; alist; alist = alist->next)
tracker(alist->str);
+ for(f = files, l = wlist; f && l; f = f->next, l = l->next)
+ webseed(l, f);
while(waitpid() != -1)
;
break;
default:
killgroup = i;
- while((nhavepieces < npieces) || sflag){
+ do {
+ sleep(1000);
if(pflag)
print("%d %d\n", nhavepieces, npieces);
- sleep(1000);
- }
+ } while(!finished() || sflag);
}
postnote(PNGROUP, killgroup, "kill");
exits(0);