shithub: riscv

Download patch

ref: d899f9cfc6ef5bb88aa537601d420d1524bcf370
parent: caa6d7701d7ce8fa09be5717d4095d0c81c4f50a
author: cinap_lenrek <[email protected]>
date: Thu Apr 26 23:05:16 EDT 2012

ip/torrent: udp tracker support

--- a/sys/src/cmd/ip/torrent.c
+++ b/sys/src/cmd/ip/torrent.c
@@ -275,11 +275,29 @@
 			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+4 > 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);
@@ -294,6 +312,7 @@
 {
 	va_list arg;
 	uchar *b, *e;
+	vlong v;
 	int i;
 
 	b = s;
@@ -310,6 +329,12 @@
 			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;
@@ -318,10 +343,22 @@
 			*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;
 		}
@@ -727,38 +764,15 @@
 }
 
 void
-tracker(char *url)
+webtracker(char *url)
 {
-	static Dict *trackers;
-	static QLock trackerslk;
-
 	char *event, *p;
 	Dict *d, *l;
 	int n, fd;
 
-	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(debug) fprint(2, "tracker %s\n", url);
-
 	if(rfork(RFPROC|RFMEM))
 		return;
+	if(debug) fprint(2, "webtracker %s\n", url);
 
 	event = "&event=started";
 	for(;;){
@@ -808,6 +822,143 @@
 }
 
 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", (int)(x-url), url, port);
+	return 0;
+}
+
+void
+udptracker(char *url)
+{
+	uchar buf[MAXIO], *p, *e;
+	int fd, event, n, a, i;
+	int transid, interval;
+	vlong connid;
+	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;
+			e = buf+n;
+			if((n = unpack(buf, n, "lll________", &a, &i, &interval)) < 0)
+				continue;
+			if(a == 1 && i == transid){
+				for(p = buf+n; p+6 <= e; p += 6){
+					char ip[16], port[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]);
+					client(ip, port);
+				}
+				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)
 {
 	uchar *s, *e;
@@ -946,8 +1097,10 @@
 }
 
 int
-killnote(void *, char *)
+catch(void *, char *msg)
 {
+	if(strstr(msg, "alarm"))
+		return 1;
 	postnote(PNGROUP, killgroup, "kill");
 	return 0;
 }
@@ -1125,7 +1278,7 @@
 		havepiece(i);
 
 	srand(time(0));
-	atnotify(killnote, 1);
+	atnotify(catch, 1);
 	switch(i = rfork(RFPROC|RFMEM|RFNOTEG)){
 	case -1:
 		sysfatal("fork: %r");