peerPieces bitmap.Bitmap
// The peer has everything. This can occur due to a special message, when
// we may not even know the number of pieces in the torrent yet.
- peerHasAll bool
+ peerSentHaveAll bool
// The highest possible number of pieces the torrent could have based on
// communication with the peer. Generally only useful until we have the
// torrent info.
writerCond sync.Cond
}
+func (cn *connection) peerHasAllPieces() (all bool, known bool) {
+ if cn.peerSentHaveAll {
+ return true, true
+ }
+ if !cn.t.haveInfo() {
+ return false, false
+ }
+ return bitmap.Flip(cn.peerPieces, 0, cn.t.numPieces()).IsEmpty(), true
+}
+
func (cn *connection) mu() sync.Locker {
return &cn.t.cl.mu
}
}
func (cn *connection) PeerHasPiece(piece int) bool {
- return cn.peerHasAll || cn.peerPieces.Contains(piece)
+ return cn.peerSentHaveAll || cn.peerPieces.Contains(piece)
}
func (cn *connection) Post(msg pp.Message) {
}
func (cn *connection) peerSentBitfield(bf []bool) error {
- cn.peerHasAll = false
+ cn.peerSentHaveAll = false
if len(bf)%8 != 0 {
panic("expected bitfield length divisible by 8")
}
return nil
}
-func (cn *connection) peerSentHaveAll() error {
- cn.peerHasAll = true
+func (cn *connection) onPeerSentHaveAll() error {
+ cn.peerSentHaveAll = true
cn.peerPieces.Clear()
cn.peerPiecesChanged()
return nil
func (cn *connection) peerSentHaveNone() error {
cn.peerPieces.Clear()
- cn.peerHasAll = false
+ cn.peerSentHaveAll = false
cn.peerPiecesChanged()
return nil
}
case pp.Bitfield:
err = c.peerSentBitfield(msg.Bitfield)
case pp.HaveAll:
- err = c.peerSentHaveAll()
+ err = c.onPeerSentHaveAll()
case pp.HaveNone:
err = c.peerSentHaveNone()
case pp.Piece:
t.stats.HalfOpenPeers = len(t.halfOpen)
t.stats.PendingPeers = len(t.peers)
t.stats.TotalPeers = t.numTotalPeers()
+ t.stats.ConnectedSeeders = 0
+ for c := range t.conns {
+ if all, ok := c.peerHasAllPieces(); all && ok {
+ t.stats.ConnectedSeeders++
+ }
+ }
return t.stats
}