summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-04-16 00:50:25 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-04-16 00:50:25 +0200
commitfd02ddae19dd91a94edd5d6a67b854750df8ec34 (patch)
tree5e670bea58226b9e953a0a3dfab817d934ab17cc /sys
parent53511a90972162053ffdc1daf23ffa063476c9a6 (diff)
ip/torrent: webseed support
Diffstat (limited to 'sys')
-rw-r--r--sys/man/1/torrent18
-rw-r--r--sys/src/cmd/ip/torrent.c130
2 files changed, 131 insertions, 17 deletions
diff --git a/sys/man/1/torrent b/sys/man/1/torrent
index 61ab3a552..d0502975a 100644
--- a/sys/man/1/torrent
+++ b/sys/man/1/torrent
@@ -14,7 +14,10 @@ torrent \- bittorrent client
.I mtpt
] [
.B -t
-.I url
+.I tracker-url
+] [
+.B -w
+.I webseed-url
] [
.B -s
] [
@@ -44,13 +47,22 @@ reads the file given at the final
.I file
argument (or standard-input when omited) and writes
a torrent file to standard-output and exits.
-A tracker
-.I url
+A
+.I tracker-url
should be given with the
.B -t
option in that case. A list of trackers can be obtained
on the web, see the examples below.
.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
.B -c
option,
diff --git a/sys/src/cmd/ip/torrent.c b/sys/src/cmd/ip/torrent.c
index ad62f7b84..de7a054c3 100644
--- a/sys/src/cmd/ip/torrent.c
+++ b/sys/src/cmd/ip/torrent.c
@@ -65,6 +65,12 @@ int nhavepieces;
File *files;
Stats stats;
+int
+finished(void)
+{
+ return nhavepieces >= npieces;
+}
+
void
freedict(Dict *d)
{
@@ -647,6 +653,78 @@ hopen(char *url, ...)
}
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
tracker(char *url)
{
static Dict *trackers;
@@ -746,7 +824,7 @@ Hfmt(Fmt *f)
}
int
-mktorrent(int fd, Dict *alist)
+mktorrent(int fd, Dict *alist, Dict *wlist)
{
uchar *b, h[20];
Dir *d;
@@ -779,6 +857,15 @@ mktorrent(int fd, Dict *alist)
print("l%ld:%se", strlen(alist->str), alist->str);
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("d");
print("4:name%ld:%s", strlen(d->name), d->name);
@@ -885,13 +972,13 @@ void
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':
@@ -900,6 +987,9 @@ main(int argc, char *argv[])
case 't':
alist = scons(EARGF(usage()), alist);
break;
+ case 'w':
+ wlist = scons(EARGF(usage()), wlist);
+ break;
case 's':
sflag = 1;
break;
@@ -926,7 +1016,7 @@ main(int argc, char *argv[])
if(cflag){
if(alist == nil)
alist = scons(deftrack, alist);
- if(mktorrent(fd, alist) < 0)
+ if(mktorrent(fd, alist, wlist) < 0)
sysfatal("%r");
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(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(; 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)
sysfatal("no meta info in torrent");
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){
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;
@@ -1024,16 +1124,18 @@ main(int argc, char *argv[])
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);