From 0d13293d71e468222dfa4a4f82b1b9d7775cfa5a Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Fri, 15 May 2015 08:39:53 +1000 Subject: [PATCH] Support seeding --- client.go | 27 +++++++++++++++------------ cmd/torrent/main.go | 3 +-- config.go | 5 ++++- connection.go | 8 ++++++-- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/client.go b/client.go index f5ecac7c..1e8755f1 100644 --- a/client.go +++ b/client.go @@ -1167,14 +1167,7 @@ func (me *Client) sendInitialMessages(conn *connection, torrent *torrent) { }(), "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 @@ func (me *Client) connectionLoop(t *torrent, c *connection) error { 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 @@ func (me *Client) connectionLoop(t *torrent, c *connection) error { Piece: p, }) uploadChunksPosted.Add(1) + c.chunksSent++ case pp.Cancel: req := newRequest(msg.Index, msg.Begin, msg.Length) if !c.PeerCancel(req) { @@ -2196,9 +2190,13 @@ func (cl *Client) waitWantPeers(t *torrent) bool { 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() @@ -2207,6 +2205,11 @@ func (cl *Client) waitWantPeers(t *torrent) bool { } } +// 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) { for cl.waitWantPeers(t) { log.Printf("getting peers for %q from DHT", t) diff --git a/cmd/torrent/main.go b/cmd/torrent/main.go index d81d219e..8f8b67ec 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 @@ waitDone: os.Stdout.WriteString(progressLine(client)) } } - if rootGroup.Seed { + if rootGroup.Client.Seed { select {} } } diff --git a/config.go b/config.go index 56081998..b6921182 100644 --- a/config.go +++ b/config.go @@ -20,8 +20,11 @@ type Config struct { 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 1913298d..ed94626f 100644 --- a/connection.go +++ b/connection.go @@ -46,6 +46,7 @@ type connection struct { UnwantedChunksReceived int UsefulChunksReceived int + chunksSent int lastMessageReceived time.Time completedHandshake time.Time @@ -237,13 +238,16 @@ func (cn *connection) WriteStatus(w io.Writer, t *torrent) { 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() { -- 2.48.1