From e97f487d2ec24b0b684366e5cb1b3fc92c20aa7c Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sat, 16 Jun 2018 16:30:04 +1000 Subject: [PATCH] Rename Config->ClientConfig and change how defaults work This is a very breaking change. --- client.go | 27 ++++----------- client_test.go | 44 ++++++++++++++++-------- config.go | 86 ++++++++++++++++------------------------------ connection.go | 2 +- connection_test.go | 8 +++-- 5 files changed, 71 insertions(+), 96 deletions(-) diff --git a/client.go b/client.go index 49142431..038762a8 100644 --- a/client.go +++ b/client.go @@ -27,7 +27,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/dustin/go-humanize" "github.com/google/btree" - "golang.org/x/time/rate" "github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/iplist" @@ -44,7 +43,7 @@ type Client struct { event sync.Cond closed missinggo.Event - config Config + config *ClientConfig logger *log.Logger halfOpenLimit int @@ -56,8 +55,6 @@ type Client struct { ipBlockList iplist.Ranger // Our BitTorrent protocol extension bytes, sent in our BT handshakes. extensionBytes peerExtensionBytes - uploadLimit *rate.Limiter - downloadLimit *rate.Limiter // Set of addresses that have our client ID. This intentionally will // include ourselves if we end up trying to connect to our own address @@ -173,12 +170,10 @@ func (cl *Client) announceKey() int32 { return int32(binary.BigEndian.Uint32(cl.peerID[16:20])) } -func NewClient(cfg *Config) (cl *Client, err error) { +func NewClient(cfg *ClientConfig) (cl *Client, err error) { if cfg == nil { - cfg = &Config{} + cfg = NewDefaultClientConfig() } - cfg.setDefaults() - defer func() { if err != nil { cl = nil @@ -186,7 +181,7 @@ func NewClient(cfg *Config) (cl *Client, err error) { }() cl = &Client{ halfOpenLimit: cfg.HalfOpenConnsPerTorrent, - config: *cfg, + config: cfg, dopplegangerAddrs: make(map[string]struct{}), torrents: make(map[metainfo.Hash]*Torrent), } @@ -198,16 +193,6 @@ func NewClient(cfg *Config) (cl *Client, err error) { } cl.Close() }() - if cfg.UploadRateLimiter == nil { - cl.uploadLimit = unlimited - } else { - cl.uploadLimit = cfg.UploadRateLimiter - } - if cfg.DownloadRateLimiter == nil { - cl.downloadLimit = unlimited - } else { - cl.downloadLimit = cfg.DownloadRateLimiter - } cl.extensionBytes = defaultPeerExtensionBytes() cl.event.L = &cl.mu storageImpl := cfg.DefaultStorage @@ -492,7 +477,7 @@ func dialUTP(ctx context.Context, addr string, sock utpSocket) (c net.Conn, err var allPeerNetworks = []string{"tcp4", "tcp6", "udp4", "udp6"} -func peerNetworkEnabled(network string, cfg Config) bool { +func peerNetworkEnabled(network string, cfg *ClientConfig) bool { c := func(s string) bool { return strings.Contains(network, s) } @@ -1178,7 +1163,7 @@ func (cl *Client) newConnection(nc net.Conn, outgoing bool) (c *connection) { c.writerCond.L = &cl.mu c.setRW(connStatsReadWriter{nc, c}) c.r = &rateLimitedReader{ - l: cl.downloadLimit, + l: cl.config.DownloadRateLimiter, r: c.r, } return diff --git a/client_test.go b/client_test.go index 4d9c56ca..e374cb5d 100644 --- a/client_test.go +++ b/client_test.go @@ -30,15 +30,14 @@ import ( "github.com/anacrolix/torrent/storage" ) -func TestingConfig() *Config { - return &Config{ - ListenHost: LoopbackListenHost, - NoDHT: true, - DataDir: tempDir(), - DisableTrackers: true, - NoDefaultPortForwarding: true, - // Debug: true, - } +func TestingConfig() *ClientConfig { + cfg := NewDefaultClientConfig() + cfg.ListenHost = LoopbackListenHost + cfg.NoDHT = true + cfg.DataDir = tempDir() + cfg.DisableTrackers = true + cfg.NoDefaultPortForwarding = true + return cfg } func TestClientDefault(t *testing.T) { @@ -105,7 +104,9 @@ func TestPieceHashSize(t *testing.T) { func TestTorrentInitialState(t *testing.T) { dir, mi := testutil.GreetingTestTorrent() defer os.RemoveAll(dir) - cl := &Client{} + cl := &Client{ + config: &ClientConfig{}, + } cl.initLogger() tor := cl.newTorrent( mi.HashInfoBytes(), @@ -138,8 +139,7 @@ func TestUnmarshalPEXMsg(t *testing.T) { } func TestReducedDialTimeout(t *testing.T) { - cfg := &Config{} - cfg.setDefaults() + cfg := NewDefaultClientConfig() for _, _case := range []struct { Max time.Duration HalfOpenLimit int @@ -357,7 +357,9 @@ func testClientTransfer(t *testing.T, ps testClientTransferParams) { // Create seeder and a Torrent. cfg := TestingConfig() cfg.Seed = true - cfg.UploadRateLimiter = ps.SeederUploadRateLimiter + if ps.SeederUploadRateLimiter != nil { + cfg.UploadRateLimiter = ps.SeederUploadRateLimiter + } // cfg.ListenAddr = "localhost:4000" if ps.SeederStorage != nil { cfg.DefaultStorage = ps.SeederStorage(greetingTempDir) @@ -380,12 +382,15 @@ func testClientTransfer(t *testing.T, ps testClientTransferParams) { leecherDataDir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(leecherDataDir) + cfg = TestingConfig() if ps.LeecherStorage == nil { cfg.DataDir = leecherDataDir } else { cfg.DefaultStorage = ps.LeecherStorage(leecherDataDir) } - cfg.DownloadRateLimiter = ps.LeecherDownloadRateLimiter + if ps.LeecherDownloadRateLimiter != nil { + cfg.DownloadRateLimiter = ps.LeecherDownloadRateLimiter + } cfg.Seed = false leecher, err := NewClient(cfg) require.NoError(t, err) @@ -443,6 +448,7 @@ func assertReadAllGreeting(t *testing.T, r io.ReadSeeker) { func TestSeedAfterDownloading(t *testing.T) { greetingTempDir, mi := testutil.GreetingTestTorrent() defer os.RemoveAll(greetingTempDir) + cfg := TestingConfig() cfg.Seed = true cfg.DataDir = greetingTempDir @@ -454,6 +460,9 @@ func TestSeedAfterDownloading(t *testing.T) { require.NoError(t, err) assert.True(t, ok) seederTorrent.VerifyData() + + cfg = TestingConfig() + cfg.Seed = true cfg.DataDir, err = ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(cfg.DataDir) @@ -461,6 +470,8 @@ func TestSeedAfterDownloading(t *testing.T) { require.NoError(t, err) defer leecher.Close() testutil.ExportStatusWriter(leecher, "l") + + cfg = TestingConfig() cfg.Seed = false cfg.DataDir, err = ioutil.TempDir("", "") require.NoError(t, err) @@ -982,8 +993,11 @@ func TestSetMaxEstablishedConn(t *testing.T) { defer ss.Close() var tts []*Torrent ih := testutil.GreetingMetaInfo().HashInfoBytes() + cfg := TestingConfig() + cfg.DisableAcceptRateLimiting = true + cfg.dropDuplicatePeerIds = true for i := range iter.N(3) { - cl, err := NewClient(TestingConfig()) + cl, err := NewClient(cfg) require.NoError(t, err) defer cl.Close() tt, _ := cl.AddTorrentInfoHash(ih) diff --git a/config.go b/config.go index f45a1e02..25dee996 100644 --- a/config.go +++ b/config.go @@ -16,20 +16,10 @@ import ( "github.com/anacrolix/torrent/storage" ) -var DefaultHTTPClient = &http.Client{ - Timeout: time.Second * 15, - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 15 * time.Second, - }).Dial, - TLSHandshakeTimeout: 15 * time.Second, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }, -} var DefaultHTTPUserAgent = "Go-Torrent/1.0" -// Override Client defaults. -type Config struct { +// Probably not safe to modify this after it's given to a Client. +type ClientConfig struct { // Store torrent file data in this directory unless .DefaultStorage is // specified. DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"` @@ -120,7 +110,7 @@ type Config struct { PublicIp6 net.IP } -func (cfg *Config) SetListenAddr(addr string) *Config { +func (cfg *ClientConfig) SetListenAddr(addr string) *ClientConfig { host, port, err := missinggo.ParseHostPort(addr) expect.Nil(err) cfg.ListenHost = func(string) string { return host } @@ -128,53 +118,35 @@ func (cfg *Config) SetListenAddr(addr string) *Config { return cfg } -func (cfg *Config) setDefaults() { - if cfg.HTTP == nil { - cfg.HTTP = DefaultHTTPClient - if cfg.ProxyURL != "" { - cfg.setProxyURL() - } - } - if cfg.HTTPUserAgent == "" { - cfg.HTTPUserAgent = DefaultHTTPUserAgent - } - if cfg.ExtendedHandshakeClientVersion == "" { - cfg.ExtendedHandshakeClientVersion = "go.torrent dev 20150624" - } - if cfg.Bep20 == "" { - cfg.Bep20 = "-GT0001-" - } - if cfg.NominalDialTimeout == 0 { - cfg.NominalDialTimeout = 30 * time.Second - } - if cfg.MinDialTimeout == 0 { - cfg.MinDialTimeout = 5 * time.Second - } - if cfg.EstablishedConnsPerTorrent == 0 { - cfg.EstablishedConnsPerTorrent = 50 - } - if cfg.HalfOpenConnsPerTorrent == 0 { - cfg.HalfOpenConnsPerTorrent = (cfg.EstablishedConnsPerTorrent + 1) / 2 - } - if cfg.TorrentPeersHighWater == 0 { - // Memory and freshness are the concern here. - cfg.TorrentPeersHighWater = 500 - } - if cfg.TorrentPeersLowWater == 0 { - cfg.TorrentPeersLowWater = 2 * cfg.HalfOpenConnsPerTorrent - } - if cfg.HandshakesTimeout == 0 { - cfg.HandshakesTimeout = 20 * time.Second - } - if cfg.DhtStartingNodes == nil { - cfg.DhtStartingNodes = dht.GlobalBootstrapAddrs - } - if cfg.ListenHost == nil { - cfg.ListenHost = func(string) string { return "" } +func NewDefaultClientConfig() *ClientConfig { + return &ClientConfig{ + HTTP: &http.Client{ + Timeout: time.Second * 15, + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 15 * time.Second, + }).Dial, + TLSHandshakeTimeout: 15 * time.Second, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }}, + HTTPUserAgent: DefaultHTTPUserAgent, + ExtendedHandshakeClientVersion: "go.torrent dev 20150624", + Bep20: "-GT0001-", + NominalDialTimeout: 30 * time.Second, + MinDialTimeout: 5 * time.Second, + EstablishedConnsPerTorrent: 50, + HalfOpenConnsPerTorrent: 25, + TorrentPeersHighWater: 500, + TorrentPeersLowWater: 50, + HandshakesTimeout: 20 * time.Second, + DhtStartingNodes: dht.GlobalBootstrapAddrs, + ListenHost: func(string) string { return "" }, + UploadRateLimiter: unlimited, + DownloadRateLimiter: unlimited, } } -func (cfg *Config) setProxyURL() { +func (cfg *ClientConfig) setProxyURL() { fixedURL, err := url.Parse(cfg.ProxyURL) if err != nil { return diff --git a/connection.go b/connection.go index 70aa1ccb..2f9b5494 100644 --- a/connection.go +++ b/connection.go @@ -1308,7 +1308,7 @@ another: return false } for r := range c.PeerRequests { - res := c.t.cl.uploadLimit.ReserveN(time.Now(), int(r.Length)) + res := c.t.cl.config.UploadRateLimiter.ReserveN(time.Now(), int(r.Length)) if !res.OK() { panic(fmt.Sprintf("upload rate limiter burst size < %d", r.Length)) } diff --git a/connection_test.go b/connection_test.go index f741ac25..58a92a61 100644 --- a/connection_test.go +++ b/connection_test.go @@ -21,7 +21,9 @@ import ( // Have that would potentially alter it. func TestSendBitfieldThenHave(t *testing.T) { r, w := io.Pipe() - var cl Client + cl := Client{ + config: &ClientConfig{DownloadRateLimiter: unlimited}, + } cl.initLogger() c := cl.newConnection(nil, false) c.setTorrent(cl.newTorrent(metainfo.Hash{}, nil)) @@ -87,7 +89,9 @@ func (me *torrentStorage) WriteAt(b []byte, _ int64) (int, error) { func BenchmarkConnectionMainReadLoop(b *testing.B) { cl := &Client{ - downloadLimit: unlimited, + config: &ClientConfig{ + DownloadRateLimiter: unlimited, + }, } ts := &torrentStorage{} t := &Torrent{