client.go | 29 ++++++++--------------------- connection.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ torrent.go | 37 +++++-------------------------------- diff --git a/client.go b/client.go index fe1c6ae4c3b4ea4763f62c4dafa109c68cca72bf..d1dcd4a8f7c866442356dbd5774576c82ee00416 100644 --- a/client.go +++ b/client.go @@ -1185,13 +1185,13 @@ } 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) { @@ -1416,10 +1416,10 @@ for r := range c.Requests { 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) @@ -1671,6 +1671,7 @@ if len(t.Conns) >= socketsPerTorrent { panic(len(t.Conns)) } t.Conns = append(t.Conns, c) + c.t = t return true } @@ -2362,20 +2363,6 @@ } 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) @@ -2384,7 +2371,7 @@ req := newRequest(msg.Index, msg.Begin, pp.Integer(len(msg.Piece))) // Request has been satisfied. if me.connDeleteRequest(t, c, req) { - defer me.replenishConnRequests(t, c) + defer c.updateRequests() } else { unexpectedChunksReceived.Add(1) } @@ -2447,7 +2434,7 @@ // Cancel pending requests for this chunk. for _, c := range t.Conns { if me.connCancel(t, c, req) { - me.replenishConnRequests(t, c) + c.updateRequests() } } @@ -2520,7 +2507,7 @@ } me.openNewConns(t) for _, conn := range t.Conns { if conn.PeerHasPiece(piece) { - me.replenishConnRequests(t, conn) + conn.updateRequests() } } } diff --git a/connection.go b/connection.go index 9a88191845abfadd328e30fba8e3730f6d02e431..75c26d46ce653bfe7b93f2e96236595a3ab8f7fd 100644 --- a/connection.go +++ b/connection.go @@ -30,6 +30,7 @@ ) // 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 @@ -534,3 +535,46 @@ Bitfield: haves, }) 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 + } + } +} diff --git a/torrent.go b/torrent.go index cb1c3fa87435b90f61519e8ace78c8b13e9819df..eaa33aa03169c9895346fd8672e0f3352d7c446f 100644 --- a/torrent.go +++ b/torrent.go @@ -458,7 +458,7 @@ return s } 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. @@ -814,7 +814,7 @@ } func (t *torrent) readersChanged(cl *Client) { for _, c := range t.Conns { - cl.replenishConnRequests(t, c) + c.updateRequests() } cl.openNewConns(t) } @@ -897,8 +897,10 @@ for _, c := range t.Conns { if !c.PeerHasPiece(piece) { continue } - + c.updateRequests() } + cl.openNewConns(t) + cl.pieceChanged(t, piece) } func (t *torrent) connRequestPiecePendingChunks(c *connection, piece int) (more bool) { @@ -913,32 +915,3 @@ } } 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 - } - } -}