c.PeerPieces[piece] = true
}
if t.wantPiece(piece) {
- me.replenishConnRequests(t, c)
+ c.updateRequests()
}
return nil
}
func (me *Client) peerUnchoked(torrent *torrent, conn *connection) {
- me.replenishConnRequests(torrent, conn)
+ conn.updateRequests()
}
func (cl *Client) connCancel(t *torrent, cn *connection, r request) (ok bool) {
me.connDeleteRequest(t, c, r)
}
// We can then reset our interest.
- me.replenishConnRequests(t, c)
+ c.updateRequests()
case pp.Reject:
me.connDeleteRequest(t, c, newRequest(msg.Index, msg.Begin, msg.Length))
- me.replenishConnRequests(t, c)
+ c.updateRequests()
case pp.Unchoke:
c.PeerChoked = false
me.peerUnchoked(t, c)
panic(len(t.Conns))
}
t.Conns = append(t.Conns, c)
+ c.t = t
return true
}
return true
}
-func (me *Client) replenishConnRequests(t *torrent, c *connection) {
- if !t.haveInfo() {
- return
- }
- t.fillRequests(c)
- if len(c.Requests) == 0 && !c.PeerChoked {
- // So we're not choked, but we don't want anything right now. We may
- // have completed readahead, and the readahead window has not rolled
- // over to the next piece. Better to stay interested in case we're
- // going to want data in the near future.
- c.SetInterested(!t.haveAllPieces())
- }
-}
-
// Handle a received chunk from a peer.
func (me *Client) downloadedChunk(t *torrent, c *connection, msg *pp.Message) error {
chunksReceived.Add(1)
// Request has been satisfied.
if me.connDeleteRequest(t, c, req) {
- defer me.replenishConnRequests(t, c)
+ defer c.updateRequests()
} else {
unexpectedChunksReceived.Add(1)
}
// Cancel pending requests for this chunk.
for _, c := range t.Conns {
if me.connCancel(t, c, req) {
- me.replenishConnRequests(t, c)
+ c.updateRequests()
}
}
me.openNewConns(t)
for _, conn := range t.Conns {
if conn.PeerHasPiece(piece) {
- me.replenishConnRequests(t, conn)
+ conn.updateRequests()
}
}
}
// Maintains the state of a connection with a peer.
type connection struct {
+ t *torrent
conn net.Conn
rw io.ReadWriter // The real slim shady
encrypted bool
})
cn.sentHaves = haves
}
+
+func (c *connection) updateRequests() {
+ if !c.t.haveInfo() {
+ return
+ }
+ if c.Interested {
+ if c.PeerChoked {
+ return
+ }
+ if len(c.Requests) > c.requestsLowWater {
+ return
+ }
+ }
+ c.fillRequests()
+ if len(c.Requests) == 0 && !c.PeerChoked {
+ // So we're not choked, but we don't want anything right now. We may
+ // have completed readahead, and the readahead window has not rolled
+ // over to the next piece. Better to stay interested in case we're
+ // going to want data in the near future.
+ c.SetInterested(!c.t.haveAllPieces())
+ }
+}
+
+func (c *connection) fillRequests() {
+ if !c.t.forUrgentPieces(func(piece int) (again bool) {
+ return c.t.connRequestPiecePendingChunks(c, piece)
+ }) {
+ return
+ }
+ c.t.forReaderWantedRegionPieces(func(begin, end int) (again bool) {
+ for i := begin + 1; i < end; i++ {
+ if !c.t.connRequestPiecePendingChunks(c, i) {
+ return false
+ }
+ }
+ return true
+ })
+ for i := range c.t.pendingPieces {
+ if !c.t.connRequestPiecePendingChunks(c, i) {
+ return
+ }
+ }
+}
}
func (t *torrent) haveInfo() bool {
- return t != nil && t.Info != nil
+ return t.Info != nil
}
// TODO: Include URIs that weren't converted to tracker clients.
func (t *torrent) readersChanged(cl *Client) {
for _, c := range t.Conns {
- cl.replenishConnRequests(t, c)
+ c.updateRequests()
}
cl.openNewConns(t)
}
if !c.PeerHasPiece(piece) {
continue
}
-
+ c.updateRequests()
}
+ cl.openNewConns(t)
+ cl.pieceChanged(t, piece)
}
func (t *torrent) connRequestPiecePendingChunks(c *connection, piece int) (more bool) {
}
return true
}
-
-func (t *torrent) fillRequests(c *connection) {
- if c.Interested {
- if c.PeerChoked {
- return
- }
- if len(c.Requests) > c.requestsLowWater {
- return
- }
- }
- if !t.forUrgentPieces(func(piece int) (again bool) {
- return t.connRequestPiecePendingChunks(c, piece)
- }) {
- return
- }
- t.forReaderWantedRegionPieces(func(begin, end int) (again bool) {
- for i := begin + 1; i < end; i++ {
- if !t.connRequestPiecePendingChunks(c, i) {
- return false
- }
- }
- return true
- })
- for i := range t.pendingPieces {
- if !t.connRequestPiecePendingChunks(c, i) {
- return
- }
- }
-}