}(),
})
}
- if torrent.haveAnyPieces() {
- conn.Bitfield(torrent.bitfield())
- } else if cl.extensionBytes.SupportsFast() && conn.PeerExtensionBytes.SupportsFast() {
- conn.Post(pp.Message{
- Type: pp.HaveNone,
- })
- }
+ func() {
+ if conn.fastEnabled() {
+ if torrent.haveAllPieces() {
+ conn.Post(pp.Message{Type: pp.HaveAll})
+ conn.sentHaves.AddRange(0, conn.t.NumPieces())
+ return
+ } else if !torrent.haveAnyPieces() {
+ conn.Post(pp.Message{Type: pp.HaveNone})
+ conn.sentHaves.Clear()
+ return
+ }
+ }
+ conn.PostBitfield()
+ }()
if conn.PeerExtensionBytes.SupportsDHT() && cl.extensionBytes.SupportsDHT() && cl.dHT != nil {
conn.Post(pp.Message{
Type: pp.Port,
if !t.haveInfo() {
return false
}
- if t.numPiecesCompleted() != t.numPieces() {
+ if !t.haveAllPieces() {
return false
}
}
// Indexed by metadata piece, set to true if posted and pending a
// response.
metadataRequests []bool
- sentHaves []bool
+ sentHaves bitmap.Bitmap
// Stuff controlled by the remote peer.
PeerID PeerID
// invalid, such as by receiving badly sized BITFIELD, or invalid HAVE
// messages.
func (cn *connection) setNumPieces(num int) error {
- cn.peerPieces.RemoveRange(num, -1)
+ cn.peerPieces.RemoveRange(num, bitmap.ToEnd)
cn.peerPiecesChanged()
return nil
}
}
func (cn *connection) Have(piece int) {
- for piece >= len(cn.sentHaves) {
- cn.sentHaves = append(cn.sentHaves, false)
- }
- if cn.sentHaves[piece] {
+ if cn.sentHaves.Get(piece) {
return
}
cn.Post(pp.Message{
Type: pp.Have,
Index: pp.Integer(piece),
})
- cn.sentHaves[piece] = true
+ cn.sentHaves.Add(piece)
}
-func (cn *connection) Bitfield(haves []bool) {
- if cn.sentHaves != nil {
+func (cn *connection) PostBitfield() {
+ if cn.sentHaves.Len() != 0 {
panic("bitfield must be first have-related message sent")
}
+ if !cn.t.haveAnyPieces() {
+ return
+ }
cn.Post(pp.Message{
Type: pp.Bitfield,
- Bitfield: haves,
+ Bitfield: cn.t.bitfield(),
})
- // Make a copy of haves, as that's read when the message is marshalled
- // without the lock. Also it obviously shouldn't change in the Msg due to
- // changes in .sentHaves.
- cn.sentHaves = append([]bool(nil), haves...)
+ cn.sentHaves = cn.t.completedPieces.Copy()
}
// Determines interest and requests to send to a connected peer.
func (cn *connection) unbiasedPieceRequestOrder() iter.Func {
now, readahead := cn.t.readerPiecePriorities()
- // Pieces to skip include pieces the peer doesn't have
- skip := bitmap.Flip(cn.peerPieces, 0, cn.t.numPieces())
+ var skip bitmap.Bitmap
+ if !cn.peerSentHaveAll {
+ // Pieces to skip include pieces the peer doesn't have
+ skip = bitmap.Flip(cn.peerPieces, 0, cn.t.numPieces())
+ }
// And pieces that we already have.
skip.Union(cn.t.completedPieces)
// Return an iterator over the different priority classes, minus the skip
cl.initLogger()
c := cl.newConnection(nil)
c.setTorrent(cl.newTorrent(metainfo.Hash{}, nil))
+ c.t.setInfo(&metainfo.Info{
+ Pieces: make([]byte, metainfo.HashSize*3),
+ })
c.r = r
c.w = w
go c.writer(time.Minute)
c.mu().Lock()
- c.Bitfield([]bool{false, true, false})
+ c.t.completedPieces.Add(1)
+ c.PostBitfield( /*[]bool{false, true, false}*/ )
c.mu().Unlock()
c.mu().Lock()
c.Have(2)
}
func (t *Torrent) pieceLength(piece int) pp.Integer {
+ if t.info.PieceLength == 0 {
+ // There will be no variance amongst pieces. Only pain.
+ return 0
+ }
if piece == t.numPieces()-1 {
ret := pp.Integer(*t.length % t.info.PieceLength)
if ret != 0 {
}
func (t *Torrent) haveAnyPieces() bool {
- for i := range t.pieces {
- if t.pieceComplete(i) {
- return true
- }
+ return t.completedPieces.Len() != 0
+}
+
+func (t *Torrent) haveAllPieces() bool {
+ if !t.haveInfo() {
+ return false
}
- return false
+ return t.completedPieces.Len() == t.numPieces()
}
func (t *Torrent) havePiece(index int) bool {