From d19079e69899016c08c993d07431be9e2cd51f0a Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sun, 10 Oct 2021 11:22:29 +1100 Subject: [PATCH] Only allow chunk size to be set for new Torrents (cherry picked from commit 09e73e9fce139cd78da48c442e8610501b6fd26b) --- client.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++------ spec.go | 18 ++++++++++----- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/client.go b/client.go index dcf93628..3aa3ad25 100644 --- a/client.go +++ b/client.go @@ -1095,15 +1095,23 @@ func (cl *Client) badPeerIPPort(ip net.IP, port int) bool { // Return a Torrent ready for insertion into a Client. func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (t *Torrent) { + return cl.newTorrentOpt(addTorrentOpts{ + InfoHash: ih, + Storage: specStorage, + }) +} + +// Return a Torrent ready for insertion into a Client. +func (cl *Client) newTorrentOpt(opts addTorrentOpts) (t *Torrent) { // use provided storage, if provided storageClient := cl.defaultStorage - if specStorage != nil { - storageClient = storage.NewClient(specStorage) + if opts.Storage != nil { + storageClient = storage.NewClient(opts.Storage) } t = &Torrent{ cl: cl, - infoHash: ih, + infoHash: opts.InfoHash, peers: prioritizedPeers{ om: btree.New(32), getPrio: func(p PeerInfo) peerPriority { @@ -1128,7 +1136,10 @@ func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) ( t.networkingEnabled.Set() t._pendingPieces.NewSet = priorityBitmapStableNewSet t.logger = cl.logger.WithContextValue(t) - t.setChunkSize(defaultChunkSize) + if opts.ChunkSize == 0 { + opts.ChunkSize = defaultChunkSize + } + t.setChunkSize(opts.ChunkSize) return } @@ -1170,11 +1181,54 @@ func (cl *Client) AddTorrentInfoHashWithStorage(infoHash metainfo.Hash, specStor return } +// 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) AddTorrentOpt(opts addTorrentOpts) (t *Torrent, new bool) { + infoHash := opts.InfoHash + cl.lock() + defer cl.unlock() + t, ok := cl.torrents[infoHash] + if ok { + return + } + new = true + + t = cl.newTorrentOpt(opts) + cl.eachDhtServer(func(s DhtServer) { + if cl.config.PeriodicallyAnnounceTorrentsToDht { + go t.dhtAnnouncer(s) + } + }) + cl.torrents[infoHash] = t + cl.clearAcceptLimits() + t.updateWantPeersEvent() + // Tickle Client.waitAccept, new torrent may want conns. + cl.event.Broadcast() + return +} + +type addTorrentOpts struct { + InfoHash InfoHash + Storage storage.ClientImpl + ChunkSize pp.Integer +} + // Add or merge a torrent spec. Returns new if the torrent wasn't already in the client. See also // Torrent.MergeSpec. func (cl *Client) AddTorrentSpec(spec *TorrentSpec) (t *Torrent, new bool, err error) { - t, new = cl.AddTorrentInfoHashWithStorage(spec.InfoHash, spec.Storage) - err = t.MergeSpec(spec) + t, new = cl.AddTorrentOpt(addTorrentOpts{ + InfoHash: spec.InfoHash, + Storage: spec.Storage, + ChunkSize: spec.ChunkSize, + }) + modSpec := *spec + if new { + // ChunkSize was already applied by adding a new Torrent, and MergeSpec disallows changing + // it. + modSpec.ChunkSize = 0 + } + err = t.MergeSpec(&modSpec) if err != nil && new { t.Drop() } @@ -1218,7 +1272,7 @@ func (t *Torrent) MergeSpec(spec *TorrentSpec) error { }) } if spec.ChunkSize != 0 { - t.setChunkSize(pp.Integer(spec.ChunkSize)) + panic("chunk size cannot be changed for existing Torrent") } t.addTrackers(spec.Trackers) t.maybeNewConns() diff --git a/spec.go b/spec.go index 21058477..a69e2093 100644 --- a/spec.go +++ b/spec.go @@ -4,14 +4,17 @@ import ( "fmt" "github.com/anacrolix/torrent/metainfo" + pp "github.com/anacrolix/torrent/peer_protocol" "github.com/anacrolix/torrent/storage" ) -// Specifies a new torrent for adding to a client. There are helpers for magnet URIs and torrent -// metainfo files. +// Specifies a new torrent for adding to a client, or additions to an existing Torrent. There are +// constructor functions for magnet URIs and torrent metainfo files. TODO: This type should be +// dismantled into a new Torrent option type, and separate Torrent mutate method(s). type TorrentSpec struct { // The tiered tracker URIs. - Trackers [][]string + Trackers [][]string + // TODO: Move into a "new" Torrent opt type. InfoHash metainfo.Hash InfoBytes []byte // The name to use if the Name field from the Info isn't available. @@ -22,10 +25,13 @@ type TorrentSpec struct { // The combination of the "xs" and "as" fields in magnet links, for now. Sources []string - // The chunk size to use for outbound requests. Defaults to 16KiB if not set. - ChunkSize int + // The chunk size to use for outbound requests. Defaults to 16KiB if not set. Can only be set + // for new Torrents. TODO: Move into a "new" Torrent opt type. + ChunkSize pp.Integer + // TODO: Move into a "new" Torrent opt type. + Storage storage.ClientImpl + DisableInitialPieceCheck bool - Storage storage.ClientImpl // Whether to allow data download or upload DisallowDataUpload bool -- 2.44.0