ip/torrent: webseed support

This commit is contained in:
cinap_lenrek 2012-04-16 00:50:25 +02:00
parent 53511a9097
commit fd02ddae19
2 changed files with 131 additions and 17 deletions

View file

@ -14,7 +14,10 @@ torrent \- bittorrent client
.I mtpt .I mtpt
] [ ] [
.B -t .B -t
.I url .I tracker-url
] [
.B -w
.I webseed-url
] [ ] [
.B -s .B -s
] [ ] [
@ -44,13 +47,22 @@ reads the file given at the final
.I file .I file
argument (or standard-input when omited) and writes argument (or standard-input when omited) and writes
a torrent file to standard-output and exits. a torrent file to standard-output and exits.
A tracker A
.I url .I tracker-url
should be given with the should be given with the
.B -t .B -t
option in that case. A list of trackers can be obtained option in that case. A list of trackers can be obtained
on the web, see the examples below. on the web, see the examples below.
.PP .PP
If the files in the torrent are also available from a url, a
.I webseed-url
can be passed with the
.B -w
option. If
.I webseed-url
ends with a slash, the filename, from the torrent, concatinated
with the url forms the target url.
.PP
Without the Without the
.B -c .B -c
option, option,

View file

@ -65,6 +65,12 @@ int nhavepieces;
File *files; File *files;
Stats stats; Stats stats;
int
finished(void)
{
return nhavepieces >= npieces;
}
void void
freedict(Dict *d) freedict(Dict *d)
{ {
@ -646,6 +652,78 @@ hopen(char *url, ...)
return fd; return fd;
} }
void
webseed(Dict *w, File *f)
{
vlong off, woff;
int fd, n, m, r, p, x, y, err;
uchar buf[MAXIO];
Dict *w0;
char *s;
if(w == nil || f == nil || finished())
return;
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){
if(finished())
exits(0);
if((w = w->next) == w0)
exits(0);
goto Retry;
}
off = 0;
err = 0;
while(off < f->len){
if(finished())
break;
n = MAXIO;
if((f->len - off) < n)
n = (f->len - off);
if((n = read(fd, buf, n)) <= 0)
break;
woff = f->off + off;
x = woff / blocksize;
off += n;
y = (f->off + off) / blocksize;
p = woff - x*blocksize;
m = 0;
while(m < n){
r = pieces[x].len - p;
if(r > (n-m))
r = n-m;
if((havemap[x>>3] & (0x80>>(x&7))) == 0)
if(rwpiece(1, x, buf+m, r, p) != r)
goto Err;
if(x == y)
break;
m += r;
p = 0;
if(!havepiece(x++)){
if(++err > 10){
fprint(2, "webseed corrupt %s / %s\n",
w->str, f->name);
goto Err;
}
}
}
}
havepiece(f->off / blocksize);
havepiece((f->off+f->len) / blocksize);
Err:
close(fd);
exits(0);
}
void void
tracker(char *url) tracker(char *url)
{ {
@ -746,7 +824,7 @@ Hfmt(Fmt *f)
} }
int int
mktorrent(int fd, Dict *alist) mktorrent(int fd, Dict *alist, Dict *wlist)
{ {
uchar *b, h[20]; uchar *b, h[20];
Dir *d; Dir *d;
@ -779,6 +857,15 @@ mktorrent(int fd, Dict *alist)
print("l%ld:%se", strlen(alist->str), alist->str); print("l%ld:%se", strlen(alist->str), alist->str);
print("e"); 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("4:info"); print("4:info");
print("d"); print("d");
print("4:name%ld:%s", strlen(d->name), d->name); print("4:name%ld:%s", strlen(d->name), d->name);
@ -885,13 +972,13 @@ void
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int sflag, pflag, vflag, cflag, fd, i, n; 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; char *p, *s, *e;
File **fp, *f; File **fp, *f;
vlong len; vlong len;
fmtinstall('H', Hfmt); fmtinstall('H', Hfmt);
alist = nil; alist = wlist = nil;
sflag = pflag = vflag = cflag = 0; sflag = pflag = vflag = cflag = 0;
ARGBEGIN { ARGBEGIN {
case 'm': case 'm':
@ -900,6 +987,9 @@ main(int argc, char *argv[])
case 't': case 't':
alist = scons(EARGF(usage()), alist); alist = scons(EARGF(usage()), alist);
break; break;
case 'w':
wlist = scons(EARGF(usage()), wlist);
break;
case 's': case 's':
sflag = 1; sflag = 1;
break; break;
@ -926,7 +1016,7 @@ main(int argc, char *argv[])
if(cflag){ if(cflag){
if(alist == nil) if(alist == nil)
alist = scons(deftrack, alist); alist = scons(deftrack, alist);
if(mktorrent(fd, alist) < 0) if(mktorrent(fd, alist, wlist) < 0)
sysfatal("%r"); sysfatal("%r");
exits(0); exits(0);
} }
@ -937,8 +1027,18 @@ main(int argc, char *argv[])
for(d = dlook(torrent, "announce-list"); d && d->typ == 'l'; d = d->next) for(d = dlook(torrent, "announce-list"); d && d->typ == 'l'; d = d->next)
for(l = d->val; l && l->typ == 'l'; l = l->next) for(l = d->val; l && l->typ == 'l'; l = l->next)
alist = scons(dstr(l->val), alist); alist = scons(dstr(l->val), alist);
if(alist == nil) if(d = dlook(torrent, "url-list")){
sysfatal("no trackers in torrent"); if(d->typ == 's')
wlist = scons(dstr(d->val), wlist);
else for(; d && d->typ == 'l'; d = d->next)
wlist = scons(dstr(d->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) if((d = info = dlook(torrent, "info")) == nil)
sysfatal("no meta info in torrent"); sysfatal("no meta info in torrent");
for(s = e = d->start; d && d->typ == 'd'; d = d->next) for(s = e = d->start; d && d->typ == 'd'; d = d->next)
@ -972,12 +1072,12 @@ main(int argc, char *argv[])
for(f = files; f; f = f->next){ for(f = files; f; f = f->next){
if(f->name == nil || f->len <= 0) if(f->name == nil || f->len <= 0)
sysfatal("bogus file entry in meta info"); sysfatal("bogus file entry in meta info");
f->name = fixnamedup(f->name); s = fixnamedup(f->name);
if(vflag) fprint(pflag ? 2 : 1, "%s\n", f->name); if(vflag) fprint(pflag ? 2 : 1, "%s\n", s);
if((f->fd = open(f->name, ORDWR)) < 0){ if((f->fd = open(s, ORDWR)) < 0){
if(mkdirs(f->name) < 0) if(mkdirs(s) < 0)
sysfatal("mkdirs: %r"); sysfatal("mkdirs: %r");
if((f->fd = create(f->name, ORDWR, 0666)) < 0) if((f->fd = create(s, ORDWR, 0666)) < 0)
sysfatal("create: %r"); sysfatal("create: %r");
} }
f->off = len; f->off = len;
@ -1024,16 +1124,18 @@ main(int argc, char *argv[])
server(); server();
for(; alist; alist = alist->next) for(; alist; alist = alist->next)
tracker(alist->str); tracker(alist->str);
for(f = files, l = wlist; f && l; f = f->next, l = l->next)
webseed(l, f);
while(waitpid() != -1) while(waitpid() != -1)
; ;
break; break;
default: default:
killgroup = i; killgroup = i;
while((nhavepieces < npieces) || sflag){ do {
sleep(1000);
if(pflag) if(pflag)
print("%d %d\n", nhavepieces, npieces); print("%d %d\n", nhavepieces, npieces);
sleep(1000); } while(!finished() || sflag);
}
} }
postnote(PNGROUP, killgroup, "kill"); postnote(PNGROUP, killgroup, "kill");
exits(0); exits(0);