From b529666a82f4da878e3d7520e672297cde70d9cd Mon Sep 17 00:00:00 2001
From: Richard Nyberg <rnyberg@murmeldjur.se>
Date: Sun, 3 Jul 2005 13:02:43 +0000
Subject: [PATCH] Use compact mode for tracker requests.

---
 btpd/btpd.h        |  1 +
 btpd/net.c         | 50 +++++++++++++++++++++++++---------------------
 btpd/net.h         |  1 +
 btpd/peer.c        | 23 ++++++++++++++++++++-
 btpd/peer.h        |  2 +-
 btpd/tracker_req.c | 36 +++++++++++++++++++++++----------
 6 files changed, 78 insertions(+), 35 deletions(-)

diff --git a/btpd/btpd.h b/btpd/btpd.h
index d3cf990..e5d102d 100644
--- a/btpd/btpd.h
+++ b/btpd/btpd.h
@@ -2,6 +2,7 @@
 #define BTPD_H
 
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 
 #include <assert.h>
diff --git a/btpd/net.c b/btpd/net.c
index a7a9023..cc908c6 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -872,12 +872,11 @@ net_shake_read(struct peer *p, unsigned long rmax)
 	if (in->buf_off < 68)
 	    break;
 	else {
-	    if (!hs->incoming && bcmp(in->buf + 48, p->id, 20) != 0)
-		goto bad_shake;
-	    else if (hs->incoming && torrent_has_peer(p->tp, in->buf + 48))
-		goto bad_shake; // Not really, but we are already connected
-	    if (hs->incoming)
-		bcopy(in->buf + 48, p->id, 20);
+	    if (torrent_has_peer(p->tp, in->buf + 48))
+		goto bad_shake; // Not really, but we're already connected.
+	    else if (bcmp(in->buf + 48, btpd.peer_id, 20) == 0)
+		goto bad_shake; // Connection from myself.
+	    bcopy(in->buf + 48, p->id, 20);
 	    hs->state = SHAKE_ID;
 	}
     default:
@@ -922,6 +921,22 @@ net_handshake(struct peer *p, int incoming)
 	net_send_shake(p);
 }
 
+int
+net_connect2(struct sockaddr *sa, socklen_t salen, int *sd)
+{
+    if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 
+	return errno;
+    
+    set_nonblocking(*sd);
+
+    if (connect(*sd, sa, salen) == -1 && errno != EINPROGRESS) {
+	btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno));
+	close(*sd);
+	return errno;
+    }
+    return 0;
+}
+
 int
 net_connect(const char *ip, int port, int *sd)
 {
@@ -939,25 +954,14 @@ net_connect(const char *ip, int port, int *sd)
     if (getaddrinfo(ip, portstr, &hints, &res) != 0)
 	return errno;
 
-    if (res) {
-	if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
-	    btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno));
-	    freeaddrinfo(res);
-	    return errno;
-	}
-	set_nonblocking(*sd);
-	if (connect(*sd, res->ai_addr, res->ai_addrlen) == -1 &&
-	    errno != EINPROGRESS) {
-	    btpd_log(BTPD_L_CONN, "Botched connection %s.", strerror(errno));
-	    close(*sd);
-	    freeaddrinfo(res);
-	    return errno;
-	}
-    }
+    int error = net_connect2(res->ai_addr, res->ai_addrlen, sd);
 	
     freeaddrinfo(res);
-    btpd.npeers++;
-    return 0;
+    
+    if (error == 0)
+	btpd.npeers++;
+
+    return error;
 }
 
 void
diff --git a/btpd/net.h b/btpd/net.h
index 33137dd..5a2c704 100644
--- a/btpd/net.h
+++ b/btpd/net.h
@@ -99,6 +99,7 @@ void net_handshake(struct peer *p, int incoming);
 
 void net_read_cb(int sd, short type, void *arg);
 void net_write_cb(int sd, short type, void *arg);
+int net_connect2(struct sockaddr *sa, socklen_t salen, int *sd);
 int net_connect(const char *ip, int port, int *sd);
 
 void net_unsend_piece(struct peer *p, struct piece_req *req);
diff --git a/btpd/peer.c b/btpd/peer.c
index 9c7720e..1ab125f 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -1,4 +1,6 @@
 #include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -173,6 +175,25 @@ peer_create_out(struct torrent *tp,
 
     p = peer_create_common(sd);
     p->tp = tp;
-    bcopy(id, p->id, 20);
+    //bcopy(id, p->id, 20);
+    net_handshake(p, 0);
+}
+
+void
+peer_create_out_compact(struct torrent *tp, const char *compact)
+{
+    int sd;
+    struct peer *p;
+    struct sockaddr_in addr;
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = *(long *)compact;
+    addr.sin_port = *(short *)(compact + 4);
+
+    if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0)
+	return;
+
+    p = peer_create_common(sd);
+    p->tp = tp;
     net_handshake(p, 0);
 }
diff --git a/btpd/peer.h b/btpd/peer.h
index 3bfbc04..c1e2f75 100644
--- a/btpd/peer.h
+++ b/btpd/peer.h
@@ -58,7 +58,7 @@ unsigned long peer_get_rate(unsigned long *rates);
 void peer_create_in(int sd);
 void peer_create_out(struct torrent *tp, const uint8_t *id,
 		     const char *ip, int port);
-
+void peer_create_out_compact(struct torrent *tp, const char *compact);
 void peer_kill(struct peer *p);
 
 #endif
diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c
index 0db0a6a..ad14c57 100644
--- a/btpd/tracker_req.c
+++ b/btpd/tracker_req.c
@@ -21,7 +21,7 @@
 #define PRIu64 "llu"
 #endif
 
-#define REQ_SIZE (getpagesize() * 2)
+#define REQ_SIZE (1024 + 6 * 50)
 
 struct tracker_req {
     enum tr_event tr_event;
@@ -102,16 +102,29 @@ tracker_done(struct child *child)
 
     tp->tracker_time = btpd.seconds + interval;
 
-    if ((benc_dget_lst(req->res->buf, "peers", &peers)) != 0) {
-	btpd_log(BTPD_L_TRACKER, "Bad data from tracker.\n");
-	failed = 1;
-	goto out;
+    int error = 0;
+    size_t length;
+
+    if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) {
+	for (peers = benc_first(peers);
+	     peers != NULL && btpd.npeers < btpd.maxpeers;
+	     peers = benc_next(peers))
+	    maybe_connect_to(tp, peers);
     }
 
-    for (peers = benc_first(peers);
-	 peers != NULL && btpd.npeers < btpd.maxpeers;
-	 peers = benc_next(peers))
-	maybe_connect_to(tp, peers);
+    if (error == EINVAL) {
+	error = benc_dget_str(req->res->buf, "peers", &peers, &length);
+	if (error == 0 && length % 6 == 0) {
+	    for (size_t i = 0; i < length; i += 6)
+		peer_create_out_compact(tp, peers + i * 6);
+	}
+    }
+
+    if (error != 0) {
+	btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
+	failed = 1;
+	goto out;	
+    }
 
 out:
     if (failed) {
@@ -165,10 +178,13 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url)
 
     left = torrent_bytes_left(tp);
 
-    i = asprintf(url, "%s%cinfo_hash=%s&peer_id=%s&port=%d"
+    i = asprintf(url, "%s%cinfo_hash=%s"
+		 "&peer_id=%s"
+		 "&port=%d"
 		 "&uploaded=%" PRIu64
 		 "&downloaded=%" PRIu64
 		 "&left=%" PRIu64
+		 "&compact=1"
 		 "%s%s",
 		 tp->meta.announce, qc, e_hash, e_id, btpd.port,
 		 tp->uploaded, tp->downloaded, left,