peerconn.go | 2 +- prioritized_peers.go | 3 +++ torrent.go | 14 +++++++++----- torrent_test.go | 36 ++++++++++++++++++++++++++++++++++++ diff --git a/peerconn.go b/peerconn.go index af9c084410e758f562fe4eaa236ab621d6952a1f..5b580bd695dd1959822eab23c0c4116904e1f8ca 100644 --- a/peerconn.go +++ b/peerconn.go @@ -899,7 +899,7 @@ return nil } func (cn *PeerConn) peerSentHaveNone() error { - if cn.peerSentHaveAll { + if !cn.peerSentHaveAll { cn.t.decPeerPieceAvailability(&cn.Peer) } cn._peerPieces.Clear() diff --git a/prioritized_peers.go b/prioritized_peers.go index d0ef43edbb6d9bed2c89ea8f9bfbaa2152fc3a74..443d72072188aec5398e8953a4283c1aff6de9dd 100644 --- a/prioritized_peers.go +++ b/prioritized_peers.go @@ -45,6 +45,9 @@ }) } func (me *prioritizedPeers) Len() int { + if me == nil || me.om == nil { + return 0 + } return me.om.Len() } diff --git a/torrent.go b/torrent.go index f19deb7587aa07b26c18d779025779e16c2e88b7..637a9897b67761d602028cf02e4c4df97936abcd 100644 --- a/torrent.go +++ b/torrent.go @@ -894,17 +894,21 @@ }) if t.storage != nil { t.deletePieceRequestOrder() } + t.assertAllPiecesRelativeAvailabilityZero() + t.pex.Reset() + t.cl.event.Broadcast() + t.pieceStateChanges.Close() + t.updateWantPeersEvent() + return +} + +func (t *Torrent) assertAllPiecesRelativeAvailabilityZero() { for i := range t.pieces { p := t.piece(i) if p.relativeAvailability != 0 { panic(fmt.Sprintf("piece %v has relative availability %v", i, p.relativeAvailability)) } } - t.pex.Reset() - t.cl.event.Broadcast() - t.pieceStateChanges.Close() - t.updateWantPeersEvent() - return } func (t *Torrent) requestOffset(r Request) int64 { diff --git a/torrent_test.go b/torrent_test.go index ce0af9f4e7693a47fee41b18503a6581ce1d4d09..d2c7ba72057ac0af9d0f22eb94a30894c4cfb9f6 100644 --- a/torrent_test.go +++ b/torrent_test.go @@ -6,10 +6,14 @@ "io" "net" "os" "path/filepath" + "sync" "testing" + "github.com/anacrolix/generics" + "github.com/anacrolix/log" "github.com/anacrolix/missinggo/v2" "github.com/anacrolix/missinggo/v2/bitmap" + qt "github.com/frankban/quicktest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -215,3 +219,35 @@ assert.Equal(t, make([]byte, len(mi.InfoBytes)), tt.metadataBytes) assert.False(t, tt.haveAllMetadataPieces()) assert.Nil(t, tt.Metainfo().InfoBytes) } + +func TestRelativeAvailabilityHaveNone(t *testing.T) { + c := qt.New(t) + var err error + cl := Client{ + config: TestingConfig(t), + } + tt := Torrent{ + cl: &cl, + logger: log.Default, + gotMetainfoC: make(chan struct{}), + } + tt.setChunkSize(2) + generics.MakeMapIfNil(&tt.conns) + pc := PeerConn{} + pc.t = &tt + pc.peerImpl = &pc + pc.initRequestState() + generics.InitNew(&pc.callbacks) + tt.conns[&pc] = struct{}{} + err = pc.peerSentHave(0) + c.Assert(err, qt.IsNil) + info := testutil.Greeting.Info(5) + err = tt.setInfo(&info) + c.Assert(err, qt.IsNil) + tt.onSetInfo() + err = pc.peerSentHaveNone() + c.Assert(err, qt.IsNil) + var wg sync.WaitGroup + tt.close(&wg) + tt.assertAllPiecesRelativeAvailabilityZero() +}