Skip to content

Commit

Permalink
Announce to both v1 and v2 swarms
Browse files Browse the repository at this point in the history
  • Loading branch information
anacrolix committed Mar 2, 2024
1 parent 13b339c commit 80b1560
Show file tree
Hide file tree
Showing 27 changed files with 227 additions and 87 deletions.
46 changes: 32 additions & 14 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ import (
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/mse"
pp "github.com/anacrolix/torrent/peer_protocol"
infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
request_strategy "github.com/anacrolix/torrent/request-strategy"
"github.com/anacrolix/torrent/storage"
"github.com/anacrolix/torrent/tracker"
"github.com/anacrolix/torrent/types/infohash"
infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
"github.com/anacrolix/torrent/webtorrent"
)

Expand Down Expand Up @@ -156,7 +156,7 @@ func (cl *Client) WriteStatus(_w io.Writer) {
fmt.Fprintf(w, "# Torrents: %d\n", len(torrentsSlice))
fmt.Fprintln(w)
sort.Slice(torrentsSlice, func(l, r int) bool {
return torrentsSlice[l].infoHash.AsString() < torrentsSlice[r].infoHash.AsString()
return torrentsSlice[l].canonicalShortInfohash().AsString() < torrentsSlice[r].canonicalShortInfohash().AsString()
})
for _, t := range torrentsSlice {
if t.name() == "" {
Expand Down Expand Up @@ -306,14 +306,18 @@ func NewClient(cfg *ClientConfig) (cl *Client, err error) {
cl.websocketTrackers = websocketTrackers{
PeerId: cl.peerID,
Logger: cl.logger,
GetAnnounceRequest: func(event tracker.AnnounceEvent, infoHash [20]byte) (tracker.AnnounceRequest, error) {
GetAnnounceRequest: func(
event tracker.AnnounceEvent, infoHash [20]byte,
) (
tracker.AnnounceRequest, error,
) {
cl.lock()
defer cl.unlock()
t, ok := cl.torrents[infoHash]
if !ok {
return tracker.AnnounceRequest{}, errors.New("torrent not tracked by client")
}
return t.announceRequest(event), nil
return t.announceRequest(event, infoHash), nil
},
Proxy: cl.config.HTTPProxy,
WebsocketTrackerHttpHeader: cl.config.WebsocketTrackerHttpHeader,
Expand Down Expand Up @@ -903,16 +907,15 @@ func (cl *Client) incomingPeerPort() int {
return cl.LocalPort()
}

func (cl *Client) initiateHandshakes(c *PeerConn, t *Torrent) error {
func (cl *Client) initiateHandshakes(c *PeerConn, t *Torrent) (err error) {
if c.headerEncrypted {
var rw io.ReadWriter
var err error
rw, c.cryptoMethod, err = mse.InitiateHandshake(
struct {
io.Reader
io.Writer
}{c.r, c.w},
t.infoHash[:],
t.canonicalShortInfohash().Bytes(),
nil,
cl.config.CryptoProvides,
)
Expand All @@ -921,14 +924,19 @@ func (cl *Client) initiateHandshakes(c *PeerConn, t *Torrent) error {
return fmt.Errorf("header obfuscation handshake: %w", err)
}
}
ih, err := cl.connBtHandshake(c, &t.infoHash)
ih, err := cl.connBtHandshake(c, t.canonicalShortInfohash())
if err != nil {
return fmt.Errorf("bittorrent protocol handshake: %w", err)
}
if ih != t.infoHash {
return errors.New("bittorrent protocol handshake: peer infohash didn't match")
if g.Some(ih) == t.infoHash {
return nil
}
return nil
if t.infoHashV2.Ok && *t.infoHashV2.Value.ToShort() == ih {
c.v2 = true
return nil
}
err = errors.New("bittorrent protocol handshake: peer infohash didn't match")
return
}

// Calls f with any secret keys. Note that it takes the Client lock, and so must be used from code
Expand Down Expand Up @@ -1285,6 +1293,13 @@ func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (

// Return a Torrent ready for insertion into a Client.
func (cl *Client) newTorrentOpt(opts AddTorrentOpts) (t *Torrent) {
var v1InfoHash g.Option[infohash.T]
if !opts.InfoHash.IsZero() {
v1InfoHash.Set(opts.InfoHash)
}
if !v1InfoHash.Ok && !opts.InfoHashV2.Ok {
panic("v1 infohash must be nonzero or v2 infohash must be set")
}
// use provided storage, if provided
storageClient := cl.defaultStorage
if opts.Storage != nil {
Expand All @@ -1293,7 +1308,7 @@ func (cl *Client) newTorrentOpt(opts AddTorrentOpts) (t *Torrent) {

t = &Torrent{
cl: cl,
infoHash: opts.InfoHash,
infoHash: v1InfoHash,
infoHashV2: opts.InfoHashV2,
peers: prioritizedPeers{
om: gbtree.New(32),
Expand Down Expand Up @@ -1344,10 +1359,13 @@ func (cl *Client) AddTorrentInfoHash(infoHash metainfo.Hash) (t *Torrent, new bo
return cl.AddTorrentInfoHashWithStorage(infoHash, nil)
}

// Adds a torrent by InfoHash with a custom Storage implementation.
// Deprecated. Adds a torrent by InfoHash with a custom Storage implementation.
// If the torrent already exists then this Storage is ignored and the
// existing torrent returned with `new` set to `false`
func (cl *Client) AddTorrentInfoHashWithStorage(infoHash metainfo.Hash, specStorage storage.ClientImpl) (t *Torrent, new bool) {
func (cl *Client) AddTorrentInfoHashWithStorage(
infoHash metainfo.Hash,
specStorage storage.ClientImpl,
) (t *Torrent, new bool) {
cl.lock()
defer cl.unlock()
t, ok := cl.torrents[infoHash]
Expand Down
12 changes: 9 additions & 3 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"fmt"
"io"
"math/rand"
"net"
"net/netip"
"os"
Expand Down Expand Up @@ -131,9 +132,9 @@ func TestAddDropManyTorrents(t *testing.T) {
cl, err := NewClient(TestingConfig(t))
require.NoError(t, err)
defer cl.Close()
for i := 0; i < 1000; i += 1 {
for i := range 1000 {
var spec TorrentSpec
binary.PutVarint(spec.InfoHash[:], int64(i))
binary.PutVarint(spec.InfoHash[:], int64(i+1))
tt, new, err := cl.AddTorrentSpec(&spec)
assert.NoError(t, err)
assert.True(t, new)
Expand All @@ -155,6 +156,7 @@ func TestMergingTrackersByAddingSpecs(t *testing.T) {
require.NoError(t, err)
defer cl.Close()
spec := TorrentSpec{}
rand.Read(spec.InfoHash[:])
T, new, _ := cl.AddTorrentSpec(&spec)
if !new {
t.FailNow()
Expand Down Expand Up @@ -587,16 +589,20 @@ func TestPeerInvalidHave(t *testing.T) {
}

func TestPieceCompletedInStorageButNotClient(t *testing.T) {
c := qt.New(t)
greetingTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
defer os.RemoveAll(greetingTempDir)
cfg := TestingConfig(t)
cfg.DataDir = greetingTempDir
seeder, err := NewClient(TestingConfig(t))
require.NoError(t, err)
defer seeder.Close()
seeder.AddTorrentSpec(&TorrentSpec{
_, new, err := seeder.AddTorrentSpec(&TorrentSpec{
InfoBytes: greetingMetainfo.InfoBytes,
InfoHash: greetingMetainfo.HashInfoBytes(),
})
c.Check(err, qt.IsNil)
c.Check(new, qt.IsTrue)
}

// Check that when the listen port is 0, all the protocols listened on have
Expand Down
3 changes: 2 additions & 1 deletion cmd/torrent2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
package main

import (
"github.com/anacrolix/torrent/metainfo"
"os"

"github.com/anacrolix/torrent/metainfo"
)

type argError struct {
Expand Down
1 change: 1 addition & 0 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package torrent

import (
"crypto/sha256"

"github.com/RoaringBitmap/roaring"
g "github.com/anacrolix/generics"
"github.com/anacrolix/missinggo/v2/bitmap"
Expand Down
2 changes: 2 additions & 0 deletions issue97_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func TestHashPieceAfterStorageClosed(t *testing.T) {
logger: log.Default,
chunkSize: defaultChunkSize,
}
tt.infoHash.Ok = true
tt.infoHash.Value[0] = 1
mi := testutil.GreetingMetaInfo()
info, err := mi.UnmarshalInfo()
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions ltep_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package torrent_test

import (
"math/rand"
"strconv"
"testing"

Expand Down Expand Up @@ -113,6 +114,7 @@ func TestUserLtep(t *testing.T) {
c.Assert(err, qt.IsNil)
defer cl2.Close()
addOpts := AddTorrentOpts{}
rand.Read(addOpts.InfoHash[:])
t1, _ := cl1.AddTorrentOpt(addOpts)
t2, _ := cl2.AddTorrentOpt(addOpts)
defer testutil.ExportStatusWriter(cl1, "cl1", t)()
Expand Down
3 changes: 2 additions & 1 deletion merkle/merkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package merkle
import (
"crypto/sha256"
"fmt"
g "github.com/anacrolix/generics"
"math/bits"

g "github.com/anacrolix/generics"
)

// The leaf block size for BitTorrent v2 Merkle trees.
Expand Down
1 change: 1 addition & 0 deletions metainfo/bep52.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package metainfo

import (
"fmt"

"github.com/anacrolix/torrent/merkle"
)

Expand Down
6 changes: 4 additions & 2 deletions metainfo/file-tree.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package metainfo

import (
"sort"

g "github.com/anacrolix/generics"
"github.com/anacrolix/torrent/bencode"
"golang.org/x/exp/maps"
"sort"

"github.com/anacrolix/torrent/bencode"
)

const FileTreePropertiesKey = ""
Expand Down
3 changes: 2 additions & 1 deletion metainfo/fileinfo.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package metainfo

import (
g "github.com/anacrolix/generics"
"strings"

g "github.com/anacrolix/generics"
)

// Information specific to a single file inside the MetaInfo structure.
Expand Down
2 changes: 1 addition & 1 deletion metainfo/magnet-v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"net/url"
"strings"

g "github.com/anacrolix/generics"
"github.com/multiformats/go-multihash"

g "github.com/anacrolix/generics"
infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
)

Expand Down
4 changes: 2 additions & 2 deletions metainfo/magnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package metainfo

import (
"encoding/hex"
"github.com/davecgh/go-spew/spew"
qt "github.com/frankban/quicktest"
"testing"

"github.com/davecgh/go-spew/spew"
qt "github.com/frankban/quicktest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down
2 changes: 1 addition & 1 deletion metainfo/metainfo_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package metainfo

import (
"github.com/davecgh/go-spew/spew"
"io"
"os"
"path"
Expand All @@ -10,6 +9,7 @@ import (
"testing"

"github.com/anacrolix/missinggo/v2"
"github.com/davecgh/go-spew/spew"
qt "github.com/frankban/quicktest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down
3 changes: 3 additions & 0 deletions peerconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ import (
type PeerConn struct {
Peer

// BEP 52
v2 bool

// A string that should identify the PeerConn's net.Conn endpoints. The net.Conn could
// be wrapping WebRTC, uTP, or TCP etc. Used in writing the conn status for peers.
connString string
Expand Down
4 changes: 2 additions & 2 deletions peerconn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestSendBitfieldThenHave(t *testing.T) {
cl.initLogger()
qtc := qt.New(t)
c := cl.newConnection(nil, newConnectionOpts{network: "io.Pipe"})
c.setTorrent(cl.newTorrent(metainfo.Hash{}, nil))
c.setTorrent(cl.newTorrentForTesting())
err := c.t.setInfo(&metainfo.Info{Pieces: make([]byte, metainfo.HashSize*3)})
qtc.Assert(err, qt.IsNil)
r, w := io.Pipe()
Expand Down Expand Up @@ -98,7 +98,7 @@ func BenchmarkConnectionMainReadLoop(b *testing.B) {
})
cl.initLogger()
ts := &torrentStorage{}
t := cl.newTorrent(metainfo.Hash{}, nil)
t := cl.newTorrentForTesting()
t.initialPieceCheckDisabled = true
require.NoError(b, t.setInfo(&metainfo.Info{
Pieces: make([]byte, 20),
Expand Down
3 changes: 1 addition & 2 deletions pexconn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ import (
"github.com/anacrolix/dht/v2/krpc"
"github.com/stretchr/testify/require"

"github.com/anacrolix/torrent/metainfo"
pp "github.com/anacrolix/torrent/peer_protocol"
)

func TestPexConnState(t *testing.T) {
var cl Client
cl.init(TestingConfig(t))
cl.initLogger()
torrent := cl.newTorrent(metainfo.Hash{}, nil)
torrent := cl.newTorrentForTesting()
addr := &net.TCPAddr{IP: net.IPv6loopback, Port: 4747}
c := cl.newConnection(nil, newConnectionOpts{
remoteAddr: addr,
Expand Down
6 changes: 3 additions & 3 deletions piece.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package torrent

import (
"fmt"
g "github.com/anacrolix/generics"
infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
"sync"

"github.com/anacrolix/chansync"
g "github.com/anacrolix/generics"
"github.com/anacrolix/missinggo/v2/bitmap"

"github.com/anacrolix/torrent/metainfo"
pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/storage"
infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
)

type Piece struct {
Expand Down Expand Up @@ -48,7 +48,7 @@ type Piece struct {
}

func (p *Piece) String() string {
return fmt.Sprintf("%s/%d", p.t.infoHash.HexString(), p.index)
return fmt.Sprintf("%s/%d", p.t.canonicalShortInfohash().HexString(), p.index)
}

func (p *Piece) Info() metainfo.Piece {
Expand Down
4 changes: 2 additions & 2 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ func (r *reader) readOnceAt(ctx context.Context, b []byte, pos int64) (n int, er
}
// TODO: Just reset pieces in the readahead window. This might help
// prevent thrashing with small caches and file and piece priorities.
r.log(log.Fstr("error reading torrent %s piece %d offset %d, %d bytes: %v",
r.t.infoHash.HexString(), firstPieceIndex, firstPieceOffset, len(b1), err))
r.log(log.Fstr("error reading piece %d offset %d, %d bytes: %v",
firstPieceIndex, firstPieceOffset, len(b1), err))
if !r.t.updatePieceCompletion(firstPieceIndex) {
r.log(log.Fstr("piece %d completion unchanged", firstPieceIndex))
}
Expand Down
2 changes: 1 addition & 1 deletion requesting.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func (p *Peer) getDesiredRequestState() (desired desiredRequestState) {
input,
t.getPieceRequestOrder(),
func(ih InfoHash, pieceIndex int, pieceExtra requestStrategy.PieceRequestOrderState) {
if ih != t.infoHash {
if ih != *t.canonicalShortInfohash() {
return
}
if !p.peerHasPiece(pieceIndex) {
Expand Down
Loading

0 comments on commit 80b1560

Please sign in to comment.