From 834e584f2d78cd06f9749889e2f8644eaf643ce0 Mon Sep 17 00:00:00 2001
From: Jimmy Zelinskie <jimmyzelinskie@gmail.com>
Date: Mon, 30 Jun 2014 14:59:31 -0400
Subject: [PATCH] fix null ptrs, misuse of bencode

---
 config/config.go              |   2 +-
 models/models.go              |   6 +-
 server/serve_announce.go      | 104 ++++++++++++++++------------------
 server/serve_announce_test.go |  21 ++++++-
 server/serve_scrape.go        |   7 ++-
 5 files changed, 74 insertions(+), 66 deletions(-)

diff --git a/config/config.go b/config/config.go
index ded01ff..8b0f3b1 100644
--- a/config/config.go
+++ b/config/config.go
@@ -74,7 +74,7 @@ func New() *Config {
 		Backend: DriverConfig{
 			Driver: "mock",
 		},
-		Private:         true,
+		Private:         false,
 		Freeleech:       false,
 		Announce:        Duration{30 * time.Minute},
 		MinAnnounce:     Duration{15 * time.Minute},
diff --git a/models/models.go b/models/models.go
index 24cf67e..957f36c 100644
--- a/models/models.go
+++ b/models/models.go
@@ -49,13 +49,13 @@ func NewPeer(a *Announce, u *User, t *Torrent) *Peer {
 	}
 
 	var userID uint64
-	if u == nil {
+	if u != nil {
 		userID = u.ID
 	}
 
 	var torrentID uint64
-	if t == nil {
-		torrentID = u.ID
+	if t != nil {
+		torrentID = t.ID
 	}
 
 	return &Peer{
diff --git a/server/serve_announce.go b/server/serve_announce.go
index 45253a5..09d5741 100644
--- a/server/serve_announce.go
+++ b/server/serve_announce.go
@@ -5,9 +5,9 @@
 package server
 
 import (
+	"fmt"
 	"io"
 	"net/http"
-	"strconv"
 
 	log "github.com/golang/glog"
 
@@ -73,12 +73,21 @@ func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) {
 
 	w.(http.Flusher).Flush()
 
-	log.V(5).Infof(
-		"announce: ip: %s, user: %s, torrent: %s",
-		announce.IP,
-		user.ID,
-		torrent.ID,
-	)
+	if s.conf.Private {
+
+		log.V(5).Infof(
+			"announce: ip: %s user: %s torrent: %s",
+			announce.IP,
+			user.ID,
+			torrent.ID,
+		)
+	} else {
+		log.V(5).Infof(
+			"announce: ip: %s torrent: %s",
+			announce.IP,
+			torrent.ID,
+		)
+	}
 }
 
 func updateTorrent(c tracker.Conn, a *models.Announce, p *models.Peer, t *models.Torrent) (created bool, err error) {
@@ -173,7 +182,7 @@ func writeAnnounceResponse(w io.Writer, a *models.Announce, u *models.User, t *m
 	}
 
 	bencoder := bencode.NewEncoder(w)
-	bencoder.Encode("d")
+	fmt.Fprintf(w, "d")
 	bencoder.Encode("complete")
 	bencoder.Encode(seedCount)
 	bencoder.Encode("incomplete")
@@ -191,18 +200,16 @@ func writeAnnounceResponse(w io.Writer, a *models.Announce, u *models.User, t *m
 		}
 	}
 
-	bencoder.Encode("e")
+	fmt.Fprintf(w, "e")
 }
 
 func writePeersCompact(w io.Writer, a *models.Announce, u *models.User, t *models.Torrent, peerCount int) {
 	ipv4s, ipv6s := getPeers(a, u, t, peerCount)
-	bencoder := bencode.NewEncoder(w)
 
 	if len(ipv4s) > 0 {
 		// 6 is the number of bytes that represents 1 compact IPv4 address.
-		bencoder.Encode("peers")
-		bencoder.Encode(strconv.Itoa(len(ipv4s) * 6))
-		bencoder.Encode(":")
+		fmt.Fprintf(w, "peers%d:", len(ipv4s)*6)
+
 		for _, peer := range ipv4s {
 			if ip := peer.IP.To4(); ip != nil {
 				w.Write(ip)
@@ -213,8 +220,8 @@ func writePeersCompact(w io.Writer, a *models.Announce, u *models.User, t *model
 
 	if len(ipv6s) > 0 {
 		// 18 is the number of bytes that represents 1 compact IPv6 address.
-		bencoder.Encode("peers6")
-		bencoder.Encode(strconv.Itoa(len(ipv6s) * 18))
+		fmt.Fprintf(w, "peers6%d:", len(ipv6s)*18)
+
 		for _, peer := range ipv6s {
 			if ip := peer.IP.To16(); ip != nil {
 				w.Write(ip)
@@ -227,29 +234,29 @@ func writePeersCompact(w io.Writer, a *models.Announce, u *models.User, t *model
 func getPeers(a *models.Announce, u *models.User, t *models.Torrent, peerCount int) (ipv4s, ipv6s []*models.Peer) {
 	if a.Left == 0 {
 		// If they're seeding, give them only leechers.
-		splitPeers(&ipv4s, &ipv6s, u, t.Leechers, peerCount)
+		splitPeers(&ipv4s, &ipv6s, a, u, t.Leechers, peerCount)
 	} else {
 		// If they're leeching, prioritize giving them seeders.
-		count := splitPeers(&ipv4s, &ipv6s, u, t.Seeders, peerCount)
-		splitPeers(&ipv4s, &ipv6s, u, t.Leechers, peerCount-count)
+		count := splitPeers(&ipv4s, &ipv6s, a, u, t.Seeders, peerCount)
+		splitPeers(&ipv4s, &ipv6s, a, u, t.Leechers, peerCount-count)
 	}
 
 	return
 }
 
-func splitPeers(ipv4s, ipv6s *[]*models.Peer, u *models.User, peers map[string]models.Peer, peerCount int) (count int) {
+func splitPeers(ipv4s, ipv6s *[]*models.Peer, a *models.Announce, u *models.User, peers map[string]models.Peer, peerCount int) (count int) {
 	for _, peer := range peers {
 		if count >= peerCount {
 			break
 		}
 
-		if peer.UserID == u.ID {
+		if a.Config.Private && peer.UserID == u.ID {
 			continue
 		}
 
-		if ip := peer.IP.To4(); ip != nil {
+		if ip := peer.IP.To4(); len(ip) == 4 {
 			*ipv4s = append(*ipv4s, &peer)
-		} else {
+		} else if ip := peer.IP.To16(); len(ip) == 16 {
 			*ipv6s = append(*ipv6s, &peer)
 		}
 
@@ -261,46 +268,31 @@ func splitPeers(ipv4s, ipv6s *[]*models.Peer, u *models.User, peers map[string]m
 
 func writePeersList(w io.Writer, a *models.Announce, u *models.User, t *models.Torrent, peerCount int) {
 	bencoder := bencode.NewEncoder(w)
-	bencoder.Encode("peers")
-	bencoder.Encode("l")
+	ipv4s, ipv6s := getPeers(a, u, t, peerCount)
 
-	if a.Left == 0 {
-		// If they're seeding, give them only leechers
-		writePeerDicts(w, u, t.Leechers, peerCount)
-	} else {
-		// If they're leeching, prioritize giving them seeders
-		count := writePeerDicts(w, u, t.Seeders, peerCount)
-		writePeerDicts(w, u, t.Leechers, peerCount-count)
+	bencoder.Encode("peers")
+	fmt.Fprintf(w, "l")
+
+	for _, peer := range ipv4s {
+		writePeerDict(w, peer)
+	}
+	for _, peer := range ipv6s {
+		writePeerDict(w, peer)
 	}
 
-	bencoder.Encode("e")
+	fmt.Fprintf(w, "e")
 }
 
-func writePeerDicts(w io.Writer, u *models.User, peers map[string]models.Peer, peerCount int) (count int) {
+func writePeerDict(w io.Writer, peer *models.Peer) {
 	bencoder := bencode.NewEncoder(w)
-
-	for _, peer := range peers {
-		if count >= peerCount {
-			break
-		}
-
-		if peer.UserID == u.ID {
-			continue
-		}
-
-		bencoder.Encode("d")
-		bencoder.Encode("ip")
-		bencoder.Encode(peer.IP)
-		bencoder.Encode("peer id")
-		bencoder.Encode(peer.ID)
-		bencoder.Encode("port")
-		bencoder.Encode(peer.Port)
-		bencoder.Encode("e")
-
-		count++
-	}
-
-	return count
+	fmt.Fprintf(w, "d")
+	bencoder.Encode("ip")
+	bencoder.Encode(peer.IP.String())
+	bencoder.Encode("peer id")
+	bencoder.Encode(peer.ID)
+	bencoder.Encode("port")
+	bencoder.Encode(peer.Port)
+	fmt.Fprintf(w, "e")
 }
 
 func minInt(a, b int) int {
diff --git a/server/serve_announce_test.go b/server/serve_announce_test.go
index b28c25c..4974f7b 100644
--- a/server/serve_announce_test.go
+++ b/server/serve_announce_test.go
@@ -5,6 +5,7 @@
 package server
 
 import (
+	"net"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -42,11 +43,25 @@ func TestAnnounce(t *testing.T) {
 			return
 		}
 
-		err = conn.AddTorrent(&models.Torrent{
+		torrent := &models.Torrent{
 			ID:       1,
 			Infohash: string([]byte{0x89, 0xd4, 0xbc, 0x52, 0x11, 0x16, 0xca, 0x1d, 0x42, 0xa2, 0xf3, 0x0d, 0x1f, 0x27, 0x4d, 0x94, 0xe4, 0x68, 0x1d, 0xaf}),
 			Seeders:  make(map[string]models.Peer),
 			Leechers: make(map[string]models.Peer),
+		}
+
+		err = conn.AddTorrent(torrent)
+		if err != nil {
+			return
+		}
+
+		err = conn.AddLeecher(torrent, &models.Peer{
+			ID:        "-TR2820-l71jtqkl898b",
+			UserID:    1,
+			TorrentID: torrent.ID,
+			IP:        net.ParseIP("127.0.0.1"),
+			Port:      34000,
+			Left:      0,
 		})
 
 		return
@@ -55,7 +70,7 @@ func TestAnnounce(t *testing.T) {
 		t.Error(err)
 	}
 
-	url := "http://localhost:34000/yby47f04riwpndba456rqxtmifenq5h6/announce?info_hash=%89%d4%bcR%11%16%ca%1dB%a2%f3%0d%1f%27M%94%e4h%1d%af&peer_id=-TR2820-l71jtqkl898b&port=51413&uploaded=0&downloaded=0&left=0&numwant=0&key=3c8e3319&compact=1&supportcrypto=1&event=stopped"
+	url := "http://localhost:6881/yby47f04riwpndba456rqxtmifenq5h6/announce?info_hash=%89%d4%bcR%11%16%ca%1dB%a2%f3%0d%1f%27M%94%e4h%1d%af&peer_id=-TR2820-l71jtqkl898b&port=51413&uploaded=0&downloaded=0&left=0&numwant=1&key=3c8e3319&compact=0&supportcrypto=1"
 	r, err := http.NewRequest("GET", url, nil)
 	if err != nil {
 		t.Error(err)
@@ -64,7 +79,7 @@ func TestAnnounce(t *testing.T) {
 	w := httptest.NewRecorder()
 	s.serveAnnounce(w, r)
 
-	if w.Body.String() != "1:d8:completei0e10:incompletei0e8:intervali1800e12:min intervali900e1:e" {
+	if w.Body.String() != "d8:completei1e10:incompletei1e8:intervali1800e12:min intervali900e5:peersld2:ip9:127.0.0.17:peer id20:-TR2820-l71jtqkl898b4:porti34000eeee" {
 		t.Errorf("improper response from server:\n%s", w.Body.String())
 	}
 
diff --git a/server/serve_scrape.go b/server/serve_scrape.go
index 78d3857..93ed05b 100644
--- a/server/serve_scrape.go
+++ b/server/serve_scrape.go
@@ -5,6 +5,7 @@
 package server
 
 import (
+	"fmt"
 	"io"
 	"net/http"
 	"strings"
@@ -70,13 +71,13 @@ func (s *Server) serveScrape(w http.ResponseWriter, r *http.Request) {
 
 func writeTorrentStatus(w io.Writer, t *models.Torrent) {
 	bencoder := bencode.NewEncoder(w)
-	bencoder.Encode("t.Infohash")
-	bencoder.Encode("d")
+	bencoder.Encode(t.Infohash)
+	fmt.Fprintf(w, "d")
 	bencoder.Encode("complete")
 	bencoder.Encode(len(t.Seeders))
 	bencoder.Encode("downloaded")
 	bencoder.Encode(t.Snatches)
 	bencoder.Encode("incomplete")
 	bencoder.Encode(len(t.Leechers))
-	bencoder.Encode("e")
+	fmt.Fprintf(w, "e")
 }