torrent.go | 2 +- tracker/tracker.go | 3 ++- tracker_scraper.go | 21 ++++++++++++++------- diff --git a/torrent.go b/torrent.go index 3c0bcb09275282a509aac7e8cccd21dc53eba1c4..1849dbcf3cb456934a9501f6aa6b08e09b36c371 100644 --- a/torrent.go +++ b/torrent.go @@ -1431,7 +1431,7 @@ } } cl.activeAnnounces[urlString] = struct{}{} }, - done: func() { + done: func(slowdown bool) { cl.lock() defer cl.unlock() delete(cl.activeAnnounces, urlString) diff --git a/tracker/tracker.go b/tracker/tracker.go index 5497037f5acb07d79302b867269875c419fa1775..65cad803c25caf39355bc5e5d3cb4e13b6832987 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -73,7 +73,8 @@ return } if me.Context == nil { // This is just to maintain the old behaviour that should be a timeout of 15s. Users can - // override it by providing their own Context. + // override it by providing their own Context. See comments elsewhere about longer timeouts + // acting as rate limiting overloaded trackers. ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() me.Context = ctx diff --git a/tracker_scraper.go b/tracker_scraper.go index 62ca426167eb74ec29556294419c843b7ff51a3e..27018398e9733e761f009604386a80a8d026234f 100644 --- a/tracker_scraper.go +++ b/tracker_scraper.go @@ -2,7 +2,6 @@ package torrent import ( "bytes" - "context" "errors" "fmt" "net" @@ -21,7 +20,10 @@ type trackerScraper struct { u url.URL t *Torrent lastAnnounce trackerAnnounceResult - allow, done func() + allow func() + // The slowdown argument lets us indicate if we think there should be some backpressure on + // access to the tracker. It doesn't necessarily have to be used. + done func(slowdown bool) } type torrentTrackerAnnouncer interface { @@ -111,7 +113,10 @@ ret.Completed = time.Now() }() ret.Interval = time.Minute me.allow() - defer me.done() + // We might pass true if we got an error. Currently we don't because timing out with a + // reasonably long timeout is its own form of backpressure (it remains to be seen if it's + // enough). + defer me.done(false) ip, err := me.getIp() if err != nil { ret.Err = fmt.Errorf("error getting ip: %s", err) @@ -120,11 +125,13 @@ } me.t.cl.rLock() req := me.t.announceRequest(event) me.t.cl.rUnlock() - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() + // The default timeout is currently 15s, and that works well as backpressure on concurrent + // access to the tracker. + //ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + //defer cancel() me.t.logger.WithDefaultLevel(log.Debug).Printf("announcing to %q: %#v", me.u.String(), req) res, err := tracker.Announce{ - Context: ctx, + //Context: ctx, HTTPProxy: me.t.cl.config.HTTPProxy, UserAgent: me.t.cl.config.HTTPUserAgent, TrackerUrl: me.trackerUrl(ip), @@ -136,7 +143,7 @@ ClientIp4: krpc.NodeAddr{IP: me.t.cl.config.PublicIp4}, ClientIp6: krpc.NodeAddr{IP: me.t.cl.config.PublicIp6}, }.Do() if err != nil { - ret.Err = fmt.Errorf("error announcing: %s", err) + ret.Err = fmt.Errorf("announcing: %w", err) return } me.t.AddPeers(peerInfos(nil).AppendFromTracker(res.Peers))