+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);
+}
+