]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/torrent.c
merge
[plan9front.git] / sys / src / cmd / ip / torrent.c
1 #include <u.h>
2 #include <libc.h>
3 #include <mp.h>
4 #include <libsec.h>
5
6 typedef struct Dict Dict;
7 typedef struct Piece Piece;
8 typedef struct File File;
9 typedef struct Stats Stats;
10
11 struct Dict
12 {
13         char    typ;    // i, d, s, l
14         Dict    *val;
15         Dict    *next;
16         char    *start, *end;
17         int     len;
18         char    str[];
19 };
20
21 struct Piece
22 {
23         uchar   *hash;
24         int     len;
25         int     brk;
26 };
27
28 struct File
29 {
30         File    *next;
31         char    *name;
32         int     fd;
33         vlong   off;
34         vlong   len;
35 };
36
37 struct Stats
38 {
39         Lock;
40         vlong   up;
41         vlong   down;
42         vlong   left;
43 };
44
45 enum {
46         MAXIO = 16*1024,
47 };
48
49 int debug, sflag, pflag, vflag;
50 int killgroup = -1;
51 int port = 6881;
52 char *mntweb = "/mnt/web";
53 uchar infohash[20];
54 uchar peerid[20];
55 int blocksize;
56
57 int npieces;
58 Piece *pieces;
59
60 int nhavemap;
61 uchar *havemap;
62 int nhavepieces;
63
64 File *files;
65 Stats stats;
66
67 void
68 freedict(Dict *d)
69 {
70         if(d){
71                 if(d->val != d)
72                         freedict(d->val);
73                 freedict(d->next);
74                 free(d);
75         }
76 }
77
78 char*
79 bparse(char *s, char *e, Dict **dp)
80 {
81         char *x, t;
82         Dict *d;
83         int n;
84
85         *dp = nil;
86         if(s >= e)
87                 return e;
88
89         t = *s;
90         switch(t){
91         case 'd':
92         case 'l':
93                 x = s++;
94                 d = nil;
95                 while(s < e){
96                         if(*s == 'e'){
97                                 s++;
98                                 break;
99                         }
100                         if(t == 'd'){
101                                 s = bparse(s, e, dp);
102                                 if((d = *dp) == nil)
103                                         break;
104                         } else
105                                 d = *dp = mallocz(sizeof(*d), 1);
106                         d->typ = t;
107                         d->start = x;
108                         if(s < e){
109                                 s = bparse(s, e, &d->val);
110                                 dp = &d->next;
111                                 d->end = s;
112                         }
113                         x = s;
114                 }
115                 if(d)
116                         d->end = s;
117                 return s;
118         case 'i':
119                 x = ++s;
120                 if((s = memchr(x, 'e', e - x)) == nil)
121                         return e;
122                 n = s - x;
123                 s++;
124                 break;
125         default:
126                 if((x = memchr(s, ':', e - s)) == nil)
127                         return e;
128                 x++;
129                 if((n = atoi(s)) < 0)
130                         return e;
131                 s = x + n;
132                 if((s > e) || (s < x)){
133                         n = e - x;
134                         s = e;
135                 }
136                 t = 's';
137         }
138         d = mallocz(sizeof(*d) + n+1, 1);
139         d->typ = t;
140         memmove(d->str, x, d->len = n);
141         d->str[n] = 0;
142         *dp = d;
143         return s;
144 }
145
146 char*
147 dstr(Dict *d)
148 {
149         if(d && (d->typ == 's' || d->typ == 'i'))
150                 return d->str;
151         return nil;
152 }
153
154 Dict*
155 dlook(Dict *d, char *s)
156 {
157         for(; d && d->typ == 'd'; d = d->next)
158                 if(d->len && strcmp(d->str, s) == 0)
159                         return d->val;
160         return nil;
161 }
162
163 int
164 readall(int fd, char **p)
165 {
166         int n, r;
167
168         n = 0;
169         *p = nil;
170         while(*p = realloc(*p, n+1024)){
171                 if((r = read(fd, *p+n, 1024)) <= 0)
172                         break;
173                 n += r;
174         }
175         return n;
176 }
177
178 int
179 rwpiece(int wr, int index, uchar *data, int len, int poff)
180 {
181         vlong off;
182         int n, m;
183         File *f;
184
185         if(len <= 0 || poff >= pieces[index].len)
186                 return 0;
187         if(len+poff > pieces[index].len)
188                 len = pieces[index].len - poff;
189         off = (vlong)index * blocksize;
190         off += poff;
191         for(f = files; f; f = f->next)
192                 if((f->off+f->len) > off)
193                         break;
194         off -= f->off;
195         n = ((off + len) > f->len) ? f->len - off : len;
196         if((n = (wr ? pwrite(f->fd, data, n, off) : pread(f->fd, data, n, off))) <= 0)
197                 return -1;
198         if((m = rwpiece(wr, index, data + n, len - n, poff + n)) < 0)
199                 return -1;
200         return n+m;
201 }
202
203 int
204 havepiece(int x)
205 {
206         uchar *p, m, hash[20];
207         int n;
208
209         m = 0x80>>(x&7);
210         if(havemap[x>>3] & m)
211                 return 1;
212         p = malloc(blocksize);
213         n = pieces[x].len;
214         if(rwpiece(0, x, p, n, 0) != n){
215                 free(p);
216                 return 0;
217         }
218         sha1(p, n, hash, nil);
219         free(p);
220         if(memcmp(hash, pieces[x].hash, 20))
221                 return 0;
222         lock(&stats);
223         if((havemap[x>>3] & m) == 0){
224                 havemap[x>>3] |= m;
225                 nhavepieces++;
226                 stats.left -= pieces[x].len;
227         }
228         unlock(&stats);
229         return 1;
230 }
231
232 int
233 pickpiece(uchar *map)
234 {
235         int i, x, r, k;
236         uchar m;
237
238         r = -1;
239         k = 0;
240         for(i = 0; i<nhavemap; i++){
241                 if(map[i] == 0)
242                         continue;
243                 for(x = i<<3, m = 0x80; m; m >>= 1, x++){
244                         if((~map[i] | havemap[i]) & m)
245                                 continue;
246                         if(nrand(++k) == 0)
247                                 r = x;
248                 }
249         }
250         return r;
251 }
252
253 int
254 unpack(uchar *s, int n, char *fmt, ...)
255 {
256         va_list arg;
257         uchar *b, *e;
258
259         b = s;
260         e = b + n;
261         va_start(arg, fmt);
262         for(; *fmt; fmt++) {
263                 switch(*fmt){
264                 case '_':
265                         s++;
266                         break;
267                 case 'b':
268                         if(s+1 > e) goto Err;
269                         *va_arg(arg, int*) = *s++;
270                         break;
271                 case 'l':
272                         if(s+4 > e) goto Err;
273                         *va_arg(arg, int*) = s[0]<<24 | s[1]<<16 | s[2]<<8 | s[3];
274                         s += 4;
275                         break;
276                 }
277         }
278         va_end(arg);
279         return s - b;
280 Err:
281         va_end(arg);
282         return -1;
283 }
284
285 int
286 pack(uchar *s, int n, char *fmt, ...)
287 {
288         va_list arg;
289         uchar *b, *e;
290         int i;
291
292         b = s;
293         e = b + n;
294         va_start(arg, fmt);
295         for(; *fmt; fmt++) {
296                 switch(*fmt){
297                 case '_':
298                         i = 0;
299                         if(0){
300                 case 'b':
301                         i = va_arg(arg, int);
302                         }
303                         if(s+1 > e) goto Err;
304                         *s++ = i & 0xFF;
305                         break;
306                 case 'l':
307                         i = va_arg(arg, int);
308                         if(s+4 > e) goto Err;
309                         *s++ = (i>>24) & 0xFF;
310                         *s++ = (i>>16) & 0xFF;
311                         *s++ = (i>>8) & 0xFF;
312                         *s++ = i & 0xFF;
313                         break;
314                 case '*':
315                         i = va_arg(arg, int);
316                         if(s+i > e) goto Err;
317                         memmove(s, va_arg(arg, uchar*), i);
318                         s += i;
319                         break;
320                 }
321         }
322         va_end(arg);
323         return s - b;
324 Err:
325         va_end(arg);
326         return -1;
327 }
328
329
330
331 int
332 peer(int fd, int incoming, char *addr)
333 {
334         uchar buf[64+MAXIO], *map, *told, *p, m;
335         int mechoking, hechoking;
336         int mewant, hewant;
337         int workpiece;
338         int i, o, l, x, n;
339
340         if(debug) fprint(2, "peer %s: %s connected\n", addr, incoming ? "incoming" : "outgoing");
341
342         for(i=0; i<2; i++){
343                 if((incoming && i) || (!incoming && !i)){
344                         if(debug) fprint(2, "peer %s: -> handshake\n", addr);
345                         n = pack(buf, sizeof(buf), "*________**", 
346                                 20, "\x13BitTorrent protocol",
347                                 sizeof(infohash), infohash,
348                                 sizeof(peerid), peerid);
349                         if(write(fd, buf, n) != n)
350                                 return 1;
351                 }
352                 if((incoming && !i) || (!incoming && i)){
353                         n = 20 + 8 + sizeof(infohash);
354                         if((n = readn(fd, buf, n)) != n)
355                                 return 1;
356                         if(memcmp(buf, "\x13BitTorrent protocol", 20))
357                                 return 0;
358                         if(debug) fprint(2, "peer %s: <- handshake\n", addr);
359                         if(memcmp(infohash, buf + 20 + 8, sizeof(infohash)))
360                                 return 0;
361                 }
362         }
363         if(readn(fd, buf, sizeof(peerid)) != sizeof(peerid))
364                 return 1;
365         if(memcmp(peerid, buf, sizeof(peerid)) == 0)
366                 return 0;
367         if(debug) fprint(2, "peer %s: peerid %.*s\n", addr, sizeof(peerid), (char*)buf);
368
369         mechoking = 1;
370         hechoking = 1;
371         mewant = 0;
372         hewant = 0;
373         workpiece = -1;
374         map = mallocz(nhavemap, 1);
375         told = malloc(nhavemap);
376
377         if(debug) fprint(2, "peer %s: -> bitfield %d\n", addr, nhavemap);
378         memmove(told, havemap, nhavemap);
379         n = pack(buf, sizeof(buf), "lb*", nhavemap+1, 0x05, nhavemap, havemap);
380         if(write(fd, buf, n) != n)
381                 goto Out;
382
383         for(;;){
384                 for(i=0; i<nhavemap; i++){
385                         if(told[i] != havemap[i]){
386                                 for(x = i<<3, m = 0x80; m; m >>= 1, x++){
387                                         if((~havemap[i] | told[i] | map[i]) & m)
388                                                 continue;
389                                         told[i] |= m;
390                                         if(debug) fprint(2, "peer %s: -> have %d\n", addr, x);
391                                         n = pack(buf, sizeof(buf), "lbl", 1+4, 0x04, x);
392                                         if(write(fd, buf, n) != n)
393                                                 goto Out;
394                                 }
395                         }
396                         if(!mewant && (map[i] & ~havemap[i])){
397                                 mewant = 1;
398                                 if(debug) fprint(2, "peer %s: -> interested\n", addr);
399                                 n = pack(buf, sizeof(buf), "lb", 1, 0x02);
400                                 if(write(fd, buf, n) != n)
401                                         goto Out;
402                         }
403                 }
404                 if(!hechoking && mewant){
405                         x = workpiece;
406                         if(x >= 0 && pieces[x].brk < pieces[x].len)
407                                 {}
408                         else x = pickpiece(map);
409                         if(x >= 0){
410                                 o = pieces[x].brk;
411                                 l = pieces[x].len - o;
412                                 if(l > MAXIO)
413                                         l = MAXIO;
414                                 if(debug) fprint(2, "peer %s: -> request %d %d %d\n", addr, x, o, l);
415                                 n = pack(buf, sizeof(buf), "lblll", 1+4+4+4, 0x06, x, o, l);
416                                 if(write(fd, buf, n) != n)
417                                         goto Out;
418                                 workpiece = x;
419                         }
420                 }
421                 if(mechoking && hewant){
422                         mechoking = 0;
423                         if(debug) fprint(2, "peer %s: -> unchoke\n", addr);
424                         n = pack(buf, sizeof(buf), "lb", 1, 0x01);
425                         if(write(fd, buf, n) != n)
426                                 goto Out;
427                 }
428
429                 if(readn(fd, buf, 4) != 4)
430                         break;
431                 unpack(buf, 4, "l", &n);
432                 if(n < 0 || n > sizeof(buf))
433                         break;
434                 if(n == 0)
435                         continue;
436                 if(readn(fd, buf, n) != n)
437                         break;
438
439                 n--;
440                 p = buf+1;
441                 switch(*buf){
442                 case 0x00:      // Choke
443                         hechoking = 1;
444                         workpiece = -1;
445                         if(debug) fprint(2, "peer %s: <- choke\n", addr);
446                         break;
447                 case 0x01:      // Unchoke
448                         hechoking = 0;
449                         if(debug) fprint(2, "peer %s: <- unchoke\n", addr);
450                         break;
451                 case 0x02:      // Interested
452                         hewant = 1;
453                         if(debug) fprint(2, "peer %s: <- interested\n", addr);
454                         break;
455                 case 0x03:      // Notinterested
456                         hewant = 0;
457                         if(debug) fprint(2, "peer %s: <- notinterested\n", addr);
458                         break;
459                 case 0x04:      // Have <piceindex>
460                         if(unpack(p, n, "l", &x) < 0)
461                                 goto Out;
462                         if(debug) fprint(2, "peer %s: <- have %d\n", addr, x);
463                         if(x < 0 || x >= npieces)
464                                 continue;
465                         map[x>>3] |= 0x80>>(x&7);
466                         break;
467                 case 0x05:      // Bitfield
468                         if(debug) fprint(2, "peer %s: <- bitfield %d\n", addr, n);
469                         if(n != nhavemap)
470                                 continue;
471                         memmove(map, p, n);
472                         break;
473                 case 0x06:      // Request <index> <begin> <length>
474                         if(unpack(p, n, "lll", &x, &o, &l) < 0)
475                                 goto Out;
476                         if(debug) fprint(2, "peer %s: <- request %d %d %d\n", addr, x, o, l);
477                         if(x < 0 || x >= npieces)
478                                 continue;
479                         if(!hewant || mechoking || (~havemap[x>>3]&(0x80>>(x&7))))
480                                 continue;
481                         if(debug) fprint(2, "peer %s: -> piece %d %d\n", addr, x, o);
482                         n = 4+1+4+4;
483                         if(l > MAXIO)
484                                 l = MAXIO;
485                         if((l = rwpiece(0, x, buf + n, l, o)) <= 0)
486                                 continue;
487                         n = pack(buf, sizeof(buf), "lbll", 1+4+4+l, 0x07, x, o);
488                         n += l;
489                         if(write(fd, buf, n) != n)
490                                 goto Out;
491                         lock(&stats);
492                         stats.up += n;
493                         unlock(&stats);
494                         break;
495                 case 0x07:      // Piece <index> <begin> <block>
496                         if(unpack(p, n, "ll", &x, &o) != 8)
497                                 goto Out;
498                         p += 8;
499                         n -= 8;
500                         lock(&stats);
501                         stats.down += n;
502                         unlock(&stats);
503                         if(debug) fprint(2, "peer %s: <- piece %d %d %d\n", addr, x, o, n);
504                         if(x < 0 || x >= npieces)
505                                 continue;
506                         if((pieces[x].brk != o) || (havemap[x>>3]&(0x80>>(x&7))))
507                                 continue;
508                         if(rwpiece(1, x, p, n, o) == n){
509                                 if((pieces[x].brk = o+n) == pieces[x].len){
510                                         if(!havepiece(x))
511                                                 pieces[x].brk = 0;
512                                 }
513                         }
514                         break;
515                 case 0x08:      // Cancel <index> <begin> <length>
516                         if(unpack(p, n, "lll", &x, &o, &l) < 0)
517                                 goto Out;
518                         if(debug) fprint(2, "peer %s: <- cancel %d %d %d\n", addr, x, o, l);
519                         break;
520                 case 0x09:      // Port <port>
521                         if(unpack(p, n, "l", &x) < 0)
522                                 goto Out;
523                         if(debug) fprint(2, "peer %s: <- port %d\n", addr, x);
524                         break;
525                 }
526         }
527
528 Out:
529         free(told);
530         free(map);
531         return 1;
532 }
533
534 void
535 server(void)
536 {
537         char addr[64], adir[40], ldir[40];
538         int afd, lfd, dfd;
539         NetConnInfo *ni;
540
541         afd = -1;
542         for(port=6881; port<6890; port++){
543                 snprint(addr, sizeof(addr), "tcp!*!%d", port);
544                 if((afd = announce(addr, adir)) >= 0)
545                         break;
546         }
547         if(afd < 0){
548                 fprint(2, "announce: %r");
549                 return;
550         }
551         if(rfork(RFFDG|RFPROC|RFMEM))
552                 return;
553         for(;;){
554                 if((lfd = listen(adir, ldir)) < 0){
555                         fprint(2, "listen: %r");
556                         break;
557                 }
558                 if(rfork(RFFDG|RFPROC|RFMEM)){
559                         close(lfd);
560                         continue;
561                 }
562                 if((dfd = accept(lfd, ldir)) < 0){
563                         fprint(2, "accept: %r");
564                         break;
565                 }
566                 ni = getnetconninfo(ldir, dfd);
567                 peer(dfd, 1, ni ? ni->raddr : "???");
568                 if(ni) freenetconninfo(ni);     
569                 break;
570         }
571         exits(0);
572 }
573
574 void
575 client(char *ip, char *port)
576 {
577         static Dict *peers;
578         static QLock peerslk;
579         int try, fd;
580         char *addr;
581         Dict *d;
582
583         if(ip == nil || port == nil)
584                 return;
585
586         d = mallocz(sizeof(*d) + 64, 1);
587         snprint(addr = d->str, 64, "tcp!%s!%s", ip, port);
588         qlock(&peerslk);
589         if(dlook(peers, addr)){
590                 qunlock(&peerslk);
591                 free(d);
592                 return;
593         }
594         d->len = strlen(addr);
595         d->typ = 'd';
596         d->val = d;
597         d->next = peers;
598         peers = d;
599         qunlock(&peerslk);
600
601         if(debug) fprint(2, "client %s\n", addr);
602
603         if(rfork(RFFDG|RFPROC|RFMEM))
604                 return;
605         for(try = 0; try < 10; try++){
606                 if((fd = dial(addr, nil, nil, nil)) >= 0){
607                         if(!peer(fd, 0, addr))
608                                 break;
609                         close(fd);
610                 }
611                 sleep((1000<<try)+nrand(5000));
612         }
613         exits(0);
614 }
615
616 int
617 hopen(char *url, ...)
618 {
619         int conn, ctlfd, fd, n;
620         char buf[1024+1];
621         va_list arg;
622
623         snprint(buf, sizeof buf, "%s/clone", mntweb);
624         if((ctlfd = open(buf, ORDWR)) < 0)
625                 return -1;
626         if((n = read(ctlfd, buf, sizeof buf-1)) <= 0){
627                 close(ctlfd);
628                 return -1;
629         }
630         buf[n] = 0;
631         conn = atoi(buf);
632         va_start(arg, url);
633         strcpy(buf, "url ");
634         n = 4+vsnprint(buf+4, sizeof(buf)-4, url, arg);
635         va_end(arg);
636         if(write(ctlfd, buf, n) != n){
637         ErrOut:
638                 close(ctlfd);
639                 return -1;
640         }
641         snprint(buf, sizeof buf, "%s/%d/body", mntweb, conn);
642         if((fd = open(buf, OREAD)) < 0)
643                 goto ErrOut;
644         close(ctlfd);
645         return fd;
646 }
647
648 void
649 tracker(char *url)
650 {
651         static Dict *trackers;
652         static QLock trackerslk;
653
654         Dict *d, *l;
655         int n, fd;
656         char *p;
657
658         if(url == nil)
659                 return;
660
661         qlock(&trackerslk);
662         if(dlook(trackers, url)){
663                 qunlock(&trackerslk);
664                 return;
665         }
666         n = strlen(url);
667         d = mallocz(sizeof(*d) + n+1, 1);
668         strcpy(d->str, url);
669         d->len = n;
670         d->typ = 'd';
671         d->val = d;
672         d->next = trackers;
673         trackers = d;
674         url = d->str;
675         qunlock(&trackerslk);
676
677         if(debug) fprint(2, "tracker %s\n", url);
678
679         if(rfork(RFPROC|RFMEM))
680                 return;
681
682         for(;;){
683                 vlong up, down, left;
684
685                 lock(&stats);
686                 up = stats.up;
687                 down = stats.down;
688                 left = stats.left;
689                 unlock(&stats);
690
691                 d = nil;
692                 if((fd = hopen("%s?info_hash=%.*H&peer_id=%.*H&port=%d&"
693                         "uploaded=%lld&downloaded=%lld&left=%lld&"
694                         "compact=1",
695                         url, sizeof(infohash), infohash, sizeof(peerid), peerid, port,
696                         up, down, left)) >= 0){
697                         n = readall(fd, &p);
698                         close(fd);
699                         bparse(p, p+n, &d);
700                         free(p);
701                 } else {
702                         if(debug) fprint(2, "tracker %s: %r\n", url);
703                 }
704                 if(l = dlook(d, "peers")){
705                         if(l->typ == 's'){
706                                 uchar *b, *e;
707
708                                 b = (uchar*)l->str;
709                                 e = b + l->len;
710                                 for(; b+6 <= e; b += 6){
711                                         char ip[16], port[6];
712
713                                         snprint(ip, sizeof(ip), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
714                                         snprint(port, sizeof(port), "%d", b[4]<<8 | b[5]);
715                                         client(ip, port);
716                                 }
717                         } else for(; l && l->typ == 'l'; l = l->next)
718                                 client(dstr(dlook(l->val, "ip")), dstr(dlook(l->val, "port")));
719                 }
720                 n = 0;
721                 if(p = dstr(dlook(d, "interval")))
722                         n = atoi(p);
723                 if(n < 10 | n > 60*60)
724                         n = 2*60;
725                 freedict(d);
726                 sleep(n * 1000 + nrand(5000));
727         }
728 }
729
730 int
731 Hfmt(Fmt *f)
732 {
733         uchar *s, *e;
734         s = va_arg(f->args, uchar*);
735         if(f->flags & FmtPrec)
736                 e = s + f->prec;
737         else
738                 e = s + strlen((char*)s);
739         for(; s < e; s++)
740                 if(fmtprint(f, ((*s >= '0' && *s <= '9') || 
741                         (*s >= 'a' && *s <= 'z') ||
742                         (*s >= 'A' && *s <= 'Z') || 
743                         strchr(".-_~", *s)) ? "%c" : "%%%.2x", *s) < 0)
744                         return -1;
745         return 0;
746 }
747
748 int
749 killnote(void *, char *)
750 {
751         postnote(PNGROUP, killgroup, "kill");
752         return 0;
753 }
754
755 void
756 usage(void)
757 {
758         fprint(2, "usage: %s [ -vsdp ] [ -m mtpt ] [ torrentfile ]\n", argv0);
759         exits("usage");
760 }
761
762 void
763 main(int argc, char *argv[])
764 {
765         Dict *info, *torrent, *d;
766         File **fp, *f;
767         char *p, *s, *e;
768         int fd, i, n;
769         vlong len;
770
771         fmtinstall('H', Hfmt);
772
773         ARGBEGIN {
774         case 'm':
775                 mntweb = EARGF(usage());
776                 break;
777         case 's':
778                 sflag = 1;
779                 break;
780         case 'p':
781                 pflag = 1;
782                 break;
783         case 'v':
784                 vflag = 1;
785                 break;
786         case 'd':
787                 debug++;
788                 break;
789         default:
790                 usage();
791         } ARGEND;
792
793         fd = 0;
794         if(*argv)
795                 if((fd = open(*argv, OREAD)) < 0)
796                         sysfatal("open torrent: %r");
797         if((n = readall(fd, &p)) <= 0)
798                 sysfatal("read torrent: %r");
799         bparse(p, p+n, &torrent);
800         if((d = info = dlook(torrent, "info")) == nil)
801                 sysfatal("no meta info in torrent");
802         for(s = e = d->start; d && d->typ == 'd'; d = d->next)
803                 e = d->end;
804         sha1((uchar*)s, e - s, (uchar*)infohash, nil);
805         free(p);
806
807         fp = &files;
808         if(d = dlook(info, "files")){           
809                 for(; d && d->typ == 'l'; d = d->next){
810                         Dict *di;
811
812                         if((s = dstr(dlook(d->val, "length"))) == nil)
813                                 continue;
814                         f = mallocz(sizeof(*f), 1);
815                         f->len = atoll(s);
816                         f->name = dstr(dlook(info, "name"));
817                         for(di = dlook(d->val, "path"); di && di->typ == 'l'; di = di->next)
818                                 if(s = dstr(di->val))
819                                         f->name = f->name ? smprint("%s/%s", f->name, s) : s;
820                         *fp = f;
821                         fp = &f->next;
822                 }
823         } else if(s = dstr(dlook(info, "length"))){
824                 f = mallocz(sizeof(*f), 1);
825                 f->len = atoll(s);
826                 f->name = dstr(dlook(info, "name"));
827                 *fp = f;
828         }
829         len = 0;
830         for(f = files; f; f = f->next){
831                 if(f->name == nil || f->len <= 0)
832                         sysfatal("bogus file entry in meta info");
833                 if(vflag) fprint(pflag ? 2 : 1, "%s\n", f->name);
834                 if((f->fd = open(f->name, ORDWR)) < 0)
835                         if((f->fd = create(f->name, ORDWR, 0666)) < 0)
836                                 sysfatal("create: %r");
837                 f->off = len;
838                 len += f->len;
839         }
840         if(len <= 0)
841                 sysfatal("no files in torrent");
842
843         if((s = dstr(dlook(info, "piece length"))) == nil)
844                 sysfatal("missing piece length in meta info");
845         if((blocksize = atoi(s)) <= 0)
846                 sysfatal("bogus piece length in meta info");
847         d = dlook(info, "pieces");
848         if(d == nil || d->typ != 's' || d->len <= 0 || d->len % 20)
849                 sysfatal("bad or no pices in meta info");
850         npieces = d->len / 20;
851         pieces = mallocz(sizeof(Piece) * npieces, 1);
852         nhavemap = (npieces+7) / 8;
853         havemap = mallocz(nhavemap, 1);
854         for(i = 0; i<npieces; i++){
855                 pieces[i].hash = (uchar*)d->str + i*20;
856                 if(len < blocksize)
857                         pieces[i].len = len;
858                 else
859                         pieces[i].len = blocksize;
860                 len -= pieces[i].len;
861                 stats.left += pieces[i].len;
862         }
863         if(len)
864                 sysfatal("pieces do not match file length");
865
866         for(i = 0; i<npieces; i++)
867                 havepiece(i);
868
869         srand(time(0));
870         atnotify(killnote, 1);
871         switch(i = rfork(RFPROC|RFMEM|RFNOTEG)){
872         case -1:
873                 sysfatal("fork: %r");
874         case 0:
875                 memmove(peerid, "-NF9001-", 8);
876                 for(i=8; i<sizeof(peerid); i++)
877                         peerid[i] = nrand(10)+'0';
878                 server();
879                 tracker(dstr(dlook(torrent, "announce")));
880                 for(d = dlook(torrent, "announce-list"); d && d->typ == 'l'; d = d->next)
881                         if(d->val && d->val->typ == 'l')
882                                 tracker(dstr(d->val->val));
883                 while(waitpid() != -1)
884                         ;
885                 break;
886         default:
887                 killgroup = i;
888                 while((nhavepieces < npieces) || sflag){
889                         if(pflag)
890                                 print("%d %d\n", nhavepieces, npieces);
891                         sleep(1000);
892                 }
893         }
894         postnote(PNGROUP, killgroup, "kill");
895         exits(0);
896 }