From 62985139c4fec069efaea3cce43d7457596f387e Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sat, 28 Sep 2024 22:19:29 +1000 Subject: [PATCH] Rework handshake parsing --- go.mod | 2 +- go.sum | 4 ++-- peer_protocol/handshake.go | 43 +++++++++++++++++++------------------- peer_protocol/protocol.go | 10 +++++++++ 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index fe0f108eeb..35cc26b65c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 github.com/anacrolix/envpprof v1.3.0 github.com/anacrolix/fuse v0.2.0 - github.com/anacrolix/generics v0.0.2-0.20240227122613-f95486179cab + github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca github.com/anacrolix/go-libutp v1.3.1 github.com/anacrolix/gostdapp v0.1.0 github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 diff --git a/go.sum b/go.sum index 52a865de24..2de5eff7e5 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcer github.com/anacrolix/fuse v0.2.0 h1:pc+To78kI2d/WUjIyrsdqeJQAesuwpGxlI3h1nAv3Do= github.com/anacrolix/fuse v0.2.0/go.mod h1:Kfu02xBwnySDpH3N23BmrP3MDfwAQGRLUCj6XyeOvBQ= github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= -github.com/anacrolix/generics v0.0.2-0.20240227122613-f95486179cab h1:MvuAC/UJtcohN6xWc8zYXSZfllh1LVNepQ0R3BCX5I4= -github.com/anacrolix/generics v0.0.2-0.20240227122613-f95486179cab/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= +github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca h1:aiiGqSQWjtVNdi8zUMfA//IrM8fPkv2bWwZVPbDe0wg= +github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8= github.com/anacrolix/go-libutp v1.3.1 h1:idJzreNLl+hNjGC3ZnUOjujEaryeOGgkwHLqSGoige0= github.com/anacrolix/go-libutp v1.3.1/go.mod h1:heF41EC8kN0qCLMokLBVkB8NXiLwx3t8R8810MTNI5o= github.com/anacrolix/gostdapp v0.1.0 h1:sZC+gSLhA7Hdalak5rPCkhO0YSEl0tt/lsovxh6qka4= diff --git a/peer_protocol/handshake.go b/peer_protocol/handshake.go index a87b7c9215..162047f3aa 100644 --- a/peer_protocol/handshake.go +++ b/peer_protocol/handshake.go @@ -3,12 +3,11 @@ package peer_protocol import ( "context" "encoding/hex" - "errors" "fmt" + "github.com/anacrolix/missinggo/v2/panicif" "github.com/anacrolix/torrent/internal/ctxrw" "io" "math/bits" - "strconv" "strings" "unsafe" @@ -153,37 +152,39 @@ func Handshake( }() post := func(bb []byte) { - select { - case postCh <- bb: - default: - panic("mustn't block while posting") - } + panicif.SendBlocks(postCh, bb) } - post([]byte(Protocol)) + post(protocolBytes()) 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]) + + // Putting an array on the heap still escapes. + b := make([]byte, 68) + // Read in one hit to avoid potential overhead in underlying reader. + _, err = io.ReadFull(sock, b[:]) if err != nil { return res, fmt.Errorf("while reading: %w", err) } - if string(b[:20]) != Protocol { - return res, errors.New("unexpected protocol string") - } - copyExact := func(dst, src []byte) { - if dstLen, srcLen := uint64(len(dst)), uint64(len(src)); dstLen != srcLen { - panic("dst len " + strconv.FormatUint(dstLen, 10) + " != src len " + strconv.FormatUint(srcLen, 10)) - } - copy(dst, src) + p := b[:len(Protocol)] + // This gets optimized to runtime.memequal + if string(p) != Protocol { + return res, fmt.Errorf("unexpected protocol string %q", string(p)) + } + b = b[len(p):] + read := func(dst []byte) { + n := copy(dst, b) + panicif.NotEq(n, len(dst)) + b = b[n:] } - copyExact(res.PeerExtensionBits[:], b[20:28]) - copyExact(res.Hash[:], b[28:48]) - copyExact(res.PeerID[:], b[48:68]) + read(res.PeerExtensionBits[:]) + read(res.Hash[:]) + read(res.PeerID[:]) + panicif.NotEq(len(b), 0) // peerExtensions.Add(res.PeerExtensionBits.String(), 1) // TODO: Maybe we can just drop peers here if we're not interested. This diff --git a/peer_protocol/protocol.go b/peer_protocol/protocol.go index b1790d1c10..ebd0a7a17b 100644 --- a/peer_protocol/protocol.go +++ b/peer_protocol/protocol.go @@ -1,9 +1,19 @@ package peer_protocol +import ( + "unsafe" +) + const ( Protocol = "\x13BitTorrent protocol" ) +var protocolStr = Protocol + +func protocolBytes() []byte { + return unsafe.Slice(unsafe.StringData(Protocol), len(Protocol)) +} + type MessageType byte // golang.org/x/tools/cmd/stringer