From: Matt Joiner <anacrolix@gmail.com>
Date: Wed, 8 Nov 2017 04:00:18 +0000 (+1100)
Subject: Move some code around
X-Git-Tag: v1.0.0~340
X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=7eb62eec0df0f58b192e96f90470a890287da4dd;p=btrtrc.git

Move some code around
---

diff --git a/client.go b/client.go
index 47d3b54b..1779c289 100644
--- a/client.go
+++ b/client.go
@@ -2,10 +2,8 @@ package torrent
 
 import (
 	"bufio"
-	"bytes"
 	"context"
 	"crypto/rand"
-	"encoding/hex"
 	"errors"
 	"expvar"
 	"fmt"
@@ -711,187 +709,6 @@ func (cl *Client) incomingPeerPort() int {
 	return port
 }
 
-// Convert a net.Addr to its compact IP representation. Either 4 or 16 bytes
-// per "yourip" field of http://www.bittorrent.org/beps/bep_0010.html.
-func addrCompactIP(addr net.Addr) (string, error) {
-	host, _, err := net.SplitHostPort(addr.String())
-	if err != nil {
-		return "", err
-	}
-	ip := net.ParseIP(host)
-	if v4 := ip.To4(); v4 != nil {
-		if len(v4) != 4 {
-			panic(v4)
-		}
-		return string(v4), nil
-	}
-	return string(ip.To16()), nil
-}
-
-func handshakeWriter(w io.Writer, bb <-chan []byte, done chan<- error) {
-	var err error
-	for b := range bb {
-		_, err = w.Write(b)
-		if err != nil {
-			break
-		}
-	}
-	done <- err
-}
-
-type (
-	peerExtensionBytes [8]byte
-	peerID             [20]byte
-)
-
-func (pex *peerExtensionBytes) SupportsExtended() bool {
-	return pex[5]&0x10 != 0
-}
-
-func (pex *peerExtensionBytes) SupportsDHT() bool {
-	return pex[7]&0x01 != 0
-}
-
-func (pex *peerExtensionBytes) SupportsFast() bool {
-	return pex[7]&0x04 != 0
-}
-
-type handshakeResult struct {
-	peerExtensionBytes
-	peerID
-	metainfo.Hash
-}
-
-// ih is nil if we expect the peer to declare the InfoHash, such as when the
-// peer initiated the connection. Returns ok if the handshake was successful,
-// and err if there was an unexpected condition other than the peer simply
-// abandoning the handshake.
-func handshake(sock io.ReadWriter, ih *metainfo.Hash, peerID [20]byte, extensions peerExtensionBytes) (res handshakeResult, ok bool, err error) {
-	// Bytes to be sent to the peer. Should never block the sender.
-	postCh := make(chan []byte, 4)
-	// A single error value sent when the writer completes.
-	writeDone := make(chan error, 1)
-	// Performs writes to the socket and ensures posts don't block.
-	go handshakeWriter(sock, postCh, writeDone)
-
-	defer func() {
-		close(postCh) // Done writing.
-		if !ok {
-			return
-		}
-		if err != nil {
-			panic(err)
-		}
-		// Wait until writes complete before returning from handshake.
-		err = <-writeDone
-		if err != nil {
-			err = fmt.Errorf("error writing: %s", err)
-		}
-	}()
-
-	post := func(bb []byte) {
-		select {
-		case postCh <- bb:
-		default:
-			panic("mustn't block while posting")
-		}
-	}
-
-	post([]byte(pp.Protocol))
-	post(extensions[:])
-	if ih != nil { // We already know what we want.
-		post(ih[:])
-		post(peerID[:])
-	}
-	var b [68]byte
-	_, err = io.ReadFull(sock, b[:68])
-	if err != nil {
-		err = nil
-		return
-	}
-	if string(b[:20]) != pp.Protocol {
-		return
-	}
-	missinggo.CopyExact(&res.peerExtensionBytes, b[20:28])
-	missinggo.CopyExact(&res.Hash, b[28:48])
-	missinggo.CopyExact(&res.peerID, b[48:68])
-	peerExtensions.Add(hex.EncodeToString(res.peerExtensionBytes[:]), 1)
-
-	// TODO: Maybe we can just drop peers here if we're not interested. This
-	// could prevent them trying to reconnect, falsely believing there was
-	// just a problem.
-	if ih == nil { // We were waiting for the peer to tell us what they wanted.
-		post(res.Hash[:])
-		post(peerID[:])
-	}
-
-	ok = true
-	return
-}
-
-// Wraps a raw connection and provides the interface we want for using the
-// connection in the message loop.
-type deadlineReader struct {
-	nc net.Conn
-	r  io.Reader
-}
-
-func (r deadlineReader) Read(b []byte) (int, error) {
-	// Keep-alives should be received every 2 mins. Give a bit of gracetime.
-	err := r.nc.SetReadDeadline(time.Now().Add(150 * time.Second))
-	if err != nil {
-		return 0, fmt.Errorf("error setting read deadline: %s", err)
-	}
-	return r.r.Read(b)
-}
-
-func handleEncryption(
-	rw io.ReadWriter,
-	skeys mse.SecretKeyIter,
-	policy EncryptionPolicy,
-) (
-	ret io.ReadWriter,
-	headerEncrypted bool,
-	cryptoMethod uint32,
-	err error,
-) {
-	if !policy.ForceEncryption {
-		var protocol [len(pp.Protocol)]byte
-		_, err = io.ReadFull(rw, protocol[:])
-		if err != nil {
-			return
-		}
-		rw = struct {
-			io.Reader
-			io.Writer
-		}{
-			io.MultiReader(bytes.NewReader(protocol[:]), rw),
-			rw,
-		}
-		if string(protocol[:]) == pp.Protocol {
-			ret = rw
-			return
-		}
-	}
-	headerEncrypted = true
-	ret, err = mse.ReceiveHandshake(rw, skeys, func(provides uint32) uint32 {
-		cryptoMethod = func() uint32 {
-			switch {
-			case policy.ForceEncryption:
-				return mse.CryptoMethodRC4
-			case policy.DisableEncryption:
-				return mse.CryptoMethodPlaintext
-			case policy.PreferNoEncryption && provides&mse.CryptoMethodPlaintext != 0:
-				return mse.CryptoMethodPlaintext
-			default:
-				return mse.DefaultCryptoSelector(provides)
-			}
-		}()
-		return cryptoMethod
-	})
-	return
-}
-
 func (cl *Client) initiateHandshakes(c *connection, t *Torrent) (ok bool, err error) {
 	if c.headerEncrypted {
 		var rw io.ReadWriter
diff --git a/handshake.go b/handshake.go
new file mode 100644
index 00000000..b79b5fd6
--- /dev/null
+++ b/handshake.go
@@ -0,0 +1,180 @@
+package torrent
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"io"
+	"net"
+	"time"
+
+	pp "github.com/anacrolix/torrent/peer_protocol"
+
+	"github.com/anacrolix/missinggo"
+	"github.com/anacrolix/torrent/metainfo"
+	"github.com/anacrolix/torrent/mse"
+)
+
+func handshakeWriter(w io.Writer, bb <-chan []byte, done chan<- error) {
+	var err error
+	for b := range bb {
+		_, err = w.Write(b)
+		if err != nil {
+			break
+		}
+	}
+	done <- err
+}
+
+type (
+	peerExtensionBytes [8]byte
+	peerID             [20]byte
+)
+
+func (pex *peerExtensionBytes) SupportsExtended() bool {
+	return pex[5]&0x10 != 0
+}
+
+func (pex *peerExtensionBytes) SupportsDHT() bool {
+	return pex[7]&0x01 != 0
+}
+
+func (pex *peerExtensionBytes) SupportsFast() bool {
+	return pex[7]&0x04 != 0
+}
+
+type handshakeResult struct {
+	peerExtensionBytes
+	peerID
+	metainfo.Hash
+}
+
+// ih is nil if we expect the peer to declare the InfoHash, such as when the
+// peer initiated the connection. Returns ok if the handshake was successful,
+// and err if there was an unexpected condition other than the peer simply
+// abandoning the handshake.
+func handshake(sock io.ReadWriter, ih *metainfo.Hash, peerID [20]byte, extensions peerExtensionBytes) (res handshakeResult, ok bool, err error) {
+	// Bytes to be sent to the peer. Should never block the sender.
+	postCh := make(chan []byte, 4)
+	// A single error value sent when the writer completes.
+	writeDone := make(chan error, 1)
+	// Performs writes to the socket and ensures posts don't block.
+	go handshakeWriter(sock, postCh, writeDone)
+
+	defer func() {
+		close(postCh) // Done writing.
+		if !ok {
+			return
+		}
+		if err != nil {
+			panic(err)
+		}
+		// Wait until writes complete before returning from handshake.
+		err = <-writeDone
+		if err != nil {
+			err = fmt.Errorf("error writing: %s", err)
+		}
+	}()
+
+	post := func(bb []byte) {
+		select {
+		case postCh <- bb:
+		default:
+			panic("mustn't block while posting")
+		}
+	}
+
+	post([]byte(pp.Protocol))
+	post(extensions[:])
+	if ih != nil { // We already know what we want.
+		post(ih[:])
+		post(peerID[:])
+	}
+	var b [68]byte
+	_, err = io.ReadFull(sock, b[:68])
+	if err != nil {
+		err = nil
+		return
+	}
+	if string(b[:20]) != pp.Protocol {
+		return
+	}
+	missinggo.CopyExact(&res.peerExtensionBytes, b[20:28])
+	missinggo.CopyExact(&res.Hash, b[28:48])
+	missinggo.CopyExact(&res.peerID, b[48:68])
+	peerExtensions.Add(hex.EncodeToString(res.peerExtensionBytes[:]), 1)
+
+	// TODO: Maybe we can just drop peers here if we're not interested. This
+	// could prevent them trying to reconnect, falsely believing there was
+	// just a problem.
+	if ih == nil { // We were waiting for the peer to tell us what they wanted.
+		post(res.Hash[:])
+		post(peerID[:])
+	}
+
+	ok = true
+	return
+}
+
+// Wraps a raw connection and provides the interface we want for using the
+// connection in the message loop.
+type deadlineReader struct {
+	nc net.Conn
+	r  io.Reader
+}
+
+func (r deadlineReader) Read(b []byte) (int, error) {
+	// Keep-alives should be received every 2 mins. Give a bit of gracetime.
+	err := r.nc.SetReadDeadline(time.Now().Add(150 * time.Second))
+	if err != nil {
+		return 0, fmt.Errorf("error setting read deadline: %s", err)
+	}
+	return r.r.Read(b)
+}
+
+func handleEncryption(
+	rw io.ReadWriter,
+	skeys mse.SecretKeyIter,
+	policy EncryptionPolicy,
+) (
+	ret io.ReadWriter,
+	headerEncrypted bool,
+	cryptoMethod uint32,
+	err error,
+) {
+	if !policy.ForceEncryption {
+		var protocol [len(pp.Protocol)]byte
+		_, err = io.ReadFull(rw, protocol[:])
+		if err != nil {
+			return
+		}
+		rw = struct {
+			io.Reader
+			io.Writer
+		}{
+			io.MultiReader(bytes.NewReader(protocol[:]), rw),
+			rw,
+		}
+		if string(protocol[:]) == pp.Protocol {
+			ret = rw
+			return
+		}
+	}
+	headerEncrypted = true
+	ret, err = mse.ReceiveHandshake(rw, skeys, func(provides uint32) uint32 {
+		cryptoMethod = func() uint32 {
+			switch {
+			case policy.ForceEncryption:
+				return mse.CryptoMethodRC4
+			case policy.DisableEncryption:
+				return mse.CryptoMethodPlaintext
+			case policy.PreferNoEncryption && provides&mse.CryptoMethodPlaintext != 0:
+				return mse.CryptoMethodPlaintext
+			default:
+				return mse.DefaultCryptoSelector(provides)
+			}
+		}()
+		return cryptoMethod
+	})
+	return
+}
diff --git a/misc.go b/misc.go
index 9d26738c..6ff47775 100644
--- a/misc.go
+++ b/misc.go
@@ -2,6 +2,7 @@ package torrent
 
 import (
 	"errors"
+	"net"
 
 	"github.com/anacrolix/torrent/metainfo"
 	pp "github.com/anacrolix/torrent/peer_protocol"
@@ -85,3 +86,20 @@ func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
 func connLessTrusted(l, r *connection) bool {
 	return l.netGoodPiecesDirtied() < r.netGoodPiecesDirtied()
 }
+
+// Convert a net.Addr to its compact IP representation. Either 4 or 16 bytes
+// per "yourip" field of http://www.bittorrent.org/beps/bep_0010.html.
+func addrCompactIP(addr net.Addr) (string, error) {
+	host, _, err := net.SplitHostPort(addr.String())
+	if err != nil {
+		return "", err
+	}
+	ip := net.ParseIP(host)
+	if v4 := ip.To4(); v4 != nil {
+		if len(v4) != 4 {
+			panic(v4)
+		}
+		return string(v4), nil
+	}
+	return string(ip.To16()), nil
+}