From aec5074f3d5c33e63e440e9e383dd16b9f097e68 Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Sun, 29 Jun 2014 18:57:49 +1000
Subject: [PATCH] Add support for extended handshake "v", "reqq", and "p"
 fields

---
 client.go     | 29 +++++++++++++++++++++++++++++
 connection.go |  1 +
 2 files changed, 30 insertions(+)

diff --git a/client.go b/client.go
index ad1afff6..fe701146 100644
--- a/client.go
+++ b/client.go
@@ -291,6 +291,22 @@ func (me *Client) initiateConn(peer Peer, torrent *torrent) {
 	}()
 }
 
+func (cl *Client) incomingPeerPort() int {
+	if cl.Listener == nil {
+		return 0
+	}
+	_, p, err := net.SplitHostPort(cl.Listener.Addr().String())
+	if err != nil {
+		panic(err)
+	}
+	var i int
+	_, err = fmt.Sscanf(p, "%d", &i)
+	if err != nil {
+		panic(err)
+	}
+	return i
+}
+
 func (me *Client) runConnection(sock net.Conn, torrent *torrent) (err error) {
 	conn := &connection{
 		Socket:          sock,
@@ -364,10 +380,14 @@ func (me *Client) runConnection(sock net.Conn, torrent *torrent) (err error) {
 					"m": map[string]int{
 						"ut_metadata": 1,
 					},
+					"v": "go.torrent dev",
 				}
 				if torrent.metadataSizeKnown() {
 					d["metadata_size"] = torrent.metadataSize()
 				}
+				if p := me.incomingPeerPort(); p != 0 {
+					d["p"] = p
+				}
 				b, err := bencode.Marshal(d)
 				if err != nil {
 					panic(err)
@@ -599,12 +619,21 @@ func (me *Client) connectionLoop(t *torrent, c *connection) error {
 		case pp.Extended:
 			switch msg.ExtendedID {
 			case pp.HandshakeExtendedID:
+				// TODO: Create a bencode struct for this.
 				var d map[string]interface{}
 				err = bencode.Unmarshal(msg.ExtendedPayload, &d)
 				if err != nil {
 					err = fmt.Errorf("error decoding extended message payload: %s", err)
 					break
 				}
+				if reqq, ok := d["reqq"]; ok {
+					if i, ok := reqq.(int64); ok {
+						c.PeerMaxRequests = int(i)
+					}
+				}
+				if v, ok := d["v"]; ok {
+					c.PeerClientName = v.(string)
+				}
 				m, ok := d["m"]
 				if !ok {
 					err = errors.New("handshake missing m item")
diff --git a/connection.go b/connection.go
index ddd875d4..32f81480 100644
--- a/connection.go
+++ b/connection.go
@@ -35,6 +35,7 @@ type connection struct {
 	PeerPieces       []bool
 	PeerMaxRequests  int // Maximum pending requests the peer allows.
 	PeerExtensionIDs map[string]int64
+	PeerClientName   string
 }
 
 func (cn *connection) completedString() string {
-- 
2.51.0