diff --git a/client.go b/client.go index fafb6e2d..6292d778 100644 --- a/client.go +++ b/client.go @@ -75,6 +75,7 @@ type Client struct { acceptLimiter map[ipStr]int dialRateLimiter *rate.Limiter + numHalfOpen int websocketTrackers websocketTrackers } @@ -658,7 +659,10 @@ func (cl *Client) noLongerHalfOpen(t *Torrent, addr string) { panic("invariant broken") } delete(t.halfOpen, addr) - t.openNewConns() + cl.numHalfOpen-- + for _, t := range cl.torrents { + t.openNewConns() + } } // Performs initiator handshakes and returns a connection. Returns nil *connection if no connection diff --git a/config.go b/config.go index c28ee124..4af86cf6 100644 --- a/config.go +++ b/config.go @@ -102,6 +102,7 @@ type ClientConfig struct { MinDialTimeout time.Duration EstablishedConnsPerTorrent int HalfOpenConnsPerTorrent int + TotalHalfOpenConns int // Maximum number of peer addresses in reserve. TorrentPeersHighWater int // Minumum number of peers before effort is made to obtain more peers. @@ -155,6 +156,7 @@ func NewDefaultClientConfig() *ClientConfig { MinDialTimeout: 3 * time.Second, EstablishedConnsPerTorrent: 50, HalfOpenConnsPerTorrent: 25, + TotalHalfOpenConns: 100, TorrentPeersHighWater: 500, TorrentPeersLowWater: 50, HandshakesTimeout: 4 * time.Second, diff --git a/torrent.go b/torrent.go index 639e330e..21069ec5 100644 --- a/torrent.go +++ b/torrent.go @@ -1075,7 +1075,7 @@ func (t *Torrent) maxHalfOpen() int { return int(min(max(5, extraIncoming)+establishedHeadroom, int64(t.cl.config.HalfOpenConnsPerTorrent))) } -func (t *Torrent) openNewConns() { +func (t *Torrent) openNewConns() (initiated int) { defer t.updateWantPeersEvent() for t.peers.Len() != 0 { if !t.wantConns() { @@ -1087,9 +1087,14 @@ func (t *Torrent) openNewConns() { if len(t.cl.dialers) == 0 { return } + if t.cl.numHalfOpen >= t.cl.config.TotalHalfOpenConns { + return + } p := t.peers.PopMax() t.initiateConn(p) + initiated++ } + return } func (t *Torrent) getConnPieceInclination() []int { @@ -1889,7 +1894,6 @@ func (t *Torrent) initiateConn(peer PeerInfo) { if peer.Id == t.cl.peerID { return } - if t.cl.badPeerAddr(peer.Addr) && !peer.Trusted { return } @@ -1897,6 +1901,7 @@ func (t *Torrent) initiateConn(peer PeerInfo) { if t.addrActive(addr.String()) { return } + t.cl.numHalfOpen++ t.halfOpen[addr.String()] = peer go t.cl.outgoingConnection(t, addr, peer.Source, peer.Trusted) }