client.go | 27 +++++++++++++++------------ cmd/torrent/main.go | 3 +-- config.go | 5 ++++- connection.go | 8 ++++++-- diff --git a/client.go b/client.go index f5ecac7cfb45282828ee6465a4ba5b82794e6a66..1e8755f10438d8ef78c6fd2835c64aebf7966e86 100644 --- a/client.go +++ b/client.go @@ -1167,14 +1167,7 @@ return }(), "v": extendedHandshakeClientVersion, // No upload queue is implemented yet. - "reqq": func() int { - if me.config.NoUpload { - // No need to look strange if it costs us nothing. - return 250 - } else { - return 1 - } - }(), + "reqq": 64, } if !me.config.DisableEncryption { d["e"] = 1 @@ -1454,13 +1447,13 @@ case pp.Request: if me.config.NoUpload { break } - if c.PeerRequests == nil { - c.PeerRequests = make(map[request]struct{}, maxRequests) - } request := newRequest(msg.Index, msg.Begin, msg.Length) // TODO: Requests should be satisfied from a dedicated upload // routine. // c.PeerRequests[request] = struct{}{} + // if c.PeerRequests == nil { + // c.PeerRequests = make(map[request]struct{}, maxRequests) + // } p := make([]byte, msg.Length) n, err := dataReadAt(t.data, p, int64(t.pieceLength(0))*int64(msg.Index)+int64(msg.Begin)) if err != nil { @@ -1476,6 +1469,7 @@ Begin: msg.Begin, Piece: p, }) uploadChunksPosted.Add(1) + c.chunksSent++ case pp.Cancel: req := newRequest(msg.Index, msg.Begin, msg.Length) if !c.PeerCancel(req) { @@ -2196,15 +2190,24 @@ case <-t.ceasingNetworking: return false default: } - if len(t.Peers) < torrentPeersLowWater && t.needData() { + if len(t.Peers) > torrentPeersLowWater { + goto wait + } + if t.needData() || cl.seeding(t) { return true } + wait: cl.mu.Unlock() t.wantPeers.Wait() t.stateMu.Unlock() cl.mu.Lock() t.stateMu.Lock() } +} + +// Returns whether the client should make effort to seed the torrent. +func (cl *Client) seeding(t *torrent) bool { + return cl.config.Seed && !cl.config.NoUpload } func (cl *Client) announceTorrentDHT(t *torrent, impliedPort bool) { diff --git a/cmd/torrent/main.go b/cmd/torrent/main.go index d81d219ed8ceb65cc13e0cf533c882b2146b9eb4..8f8b67ecd0859a148ae31f9557c127cb68f9943a 100644 --- a/cmd/torrent/main.go +++ b/cmd/torrent/main.go @@ -73,7 +73,6 @@ func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) var rootGroup struct { Client torrent.Config `group:"Client Options"` - Seed bool `long:"seed" description:"continue seeding torrents after completed"` TestPeers []string `long:"test-peer" description:"address of peer to inject to every torrent"` } // Don't pass flags.PrintError because it's inconsistent with printing. @@ -151,7 +150,7 @@ case <-ticker.C: os.Stdout.WriteString(progressLine(client)) } } - if rootGroup.Seed { + if rootGroup.Client.Seed { select {} } } diff --git a/config.go b/config.go index 56081998900b273dc867dd2e22e56ffedac23417..b6921182a2fd6416e05cbc44baa68646fe7aa446 100644 --- a/config.go +++ b/config.go @@ -20,8 +20,11 @@ // Don't create a DHT. NoDHT bool `long:"disable-dht"` // Overrides the default DHT configuration. DHTConfig *dht.ServerConfig - // Don't send chunks to peers. + // Don't ever send chunks to peers. NoUpload bool `long:"no-upload"` + // Upload even after there's nothing in it for us. By default uploading is + // not altruistic. + Seed bool `long:"seed"` // User-provided Client peer ID. If not present, one is generated automatically. PeerID string // For the bittorrent protocol. diff --git a/connection.go b/connection.go index 1913298d608245614f64bc64d9b0f87803eb9094..ed94626ff3a890b1b0d1242045374fa0708f548c 100644 --- a/connection.go +++ b/connection.go @@ -46,6 +46,7 @@ pieceRequestOrder *pieceordering.Instance UnwantedChunksReceived int UsefulChunksReceived int + chunksSent int lastMessageReceived time.Time completedHandshake time.Time @@ -237,13 +238,16 @@ fmt.Fprintf(w, " last msg: %s, connected: %s, last useful chunk: %s\n", eventAgeString(cn.lastMessageReceived), eventAgeString(cn.completedHandshake), eventAgeString(cn.lastUsefulChunkReceived)) - fmt.Fprintf(w, " %s completed, good chunks: %d/%d reqs: %d-%d, flags: %s\n", + fmt.Fprintf(w, + " %s completed, good chunks: %d/%d-%d reqq: %d-%d, flags: %s\n", cn.completedString(t), cn.UsefulChunksReceived, cn.UnwantedChunksReceived+cn.UsefulChunksReceived, + cn.chunksSent, len(cn.Requests), len(cn.PeerRequests), - cn.statusFlags()) + cn.statusFlags(), + ) } func (c *connection) Close() {