mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
p2p: add DialRatio for configuration of inbound vs. dialed connections
This commit is contained in:
parent
4e7c220e39
commit
02be17884b
1 changed files with 41 additions and 22 deletions
|
|
@ -40,11 +40,10 @@ const (
|
||||||
refreshPeersInterval = 30 * time.Second
|
refreshPeersInterval = 30 * time.Second
|
||||||
staticPeerCheckInterval = 15 * time.Second
|
staticPeerCheckInterval = 15 * time.Second
|
||||||
|
|
||||||
// Maximum number of concurrently handshaking inbound connections.
|
// Connectivity defaults.
|
||||||
maxAcceptConns = 50
|
maxActiveDialTasks = 16
|
||||||
|
defaultMaxPendingPeers = 50
|
||||||
// Maximum number of concurrently dialing outbound connections.
|
defaultDialRatio = 3
|
||||||
maxActiveDialTasks = 16
|
|
||||||
|
|
||||||
// Maximum time allowed for reading a complete message.
|
// Maximum time allowed for reading a complete message.
|
||||||
// This is effectively the amount of time a connection can be idle.
|
// This is effectively the amount of time a connection can be idle.
|
||||||
|
|
@ -70,6 +69,11 @@ type Config struct {
|
||||||
// Zero defaults to preset values.
|
// Zero defaults to preset values.
|
||||||
MaxPendingPeers int `toml:",omitempty"`
|
MaxPendingPeers int `toml:",omitempty"`
|
||||||
|
|
||||||
|
// DialRatio controls the ratio of inbound to dialed connections.
|
||||||
|
// Example: a DialRatio of 2 allows 1/2 of connections to be dialed.
|
||||||
|
// Setting DialRatio to zero defaults it to 3.
|
||||||
|
DialRatio int `toml:",omitempty"`
|
||||||
|
|
||||||
// NoDiscovery can be used to disable the peer discovery mechanism.
|
// NoDiscovery can be used to disable the peer discovery mechanism.
|
||||||
// Disabling is useful for protocol debugging (manual topology).
|
// Disabling is useful for protocol debugging (manual topology).
|
||||||
NoDiscovery bool
|
NoDiscovery bool
|
||||||
|
|
@ -476,10 +480,7 @@ func (srv *Server) Start() (err error) {
|
||||||
srv.DiscV5 = ntab
|
srv.DiscV5 = ntab
|
||||||
}
|
}
|
||||||
|
|
||||||
dynPeers := (srv.MaxPeers + 1) / 2
|
dynPeers := srv.maxDialedConns()
|
||||||
if srv.NoDiscovery {
|
|
||||||
dynPeers = 0
|
|
||||||
}
|
|
||||||
dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)
|
dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)
|
||||||
|
|
||||||
// handshake
|
// handshake
|
||||||
|
|
@ -536,6 +537,7 @@ func (srv *Server) run(dialstate dialer) {
|
||||||
defer srv.loopWG.Done()
|
defer srv.loopWG.Done()
|
||||||
var (
|
var (
|
||||||
peers = make(map[discover.NodeID]*Peer)
|
peers = make(map[discover.NodeID]*Peer)
|
||||||
|
inboundCount = 0
|
||||||
trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes))
|
trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes))
|
||||||
taskdone = make(chan task, maxActiveDialTasks)
|
taskdone = make(chan task, maxActiveDialTasks)
|
||||||
runningTasks []task
|
runningTasks []task
|
||||||
|
|
@ -621,14 +623,14 @@ running:
|
||||||
}
|
}
|
||||||
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
|
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
|
||||||
select {
|
select {
|
||||||
case c.cont <- srv.encHandshakeChecks(peers, c):
|
case c.cont <- srv.encHandshakeChecks(peers, inboundCount, c):
|
||||||
case <-srv.quit:
|
case <-srv.quit:
|
||||||
break running
|
break running
|
||||||
}
|
}
|
||||||
case c := <-srv.addpeer:
|
case c := <-srv.addpeer:
|
||||||
// At this point the connection is past the protocol handshake.
|
// At this point the connection is past the protocol handshake.
|
||||||
// Its capabilities are known and the remote identity is verified.
|
// Its capabilities are known and the remote identity is verified.
|
||||||
err := srv.protoHandshakeChecks(peers, c)
|
err := srv.protoHandshakeChecks(peers, inboundCount, c)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// The handshakes are done and it passed all checks.
|
// The handshakes are done and it passed all checks.
|
||||||
p := newPeer(c, srv.Protocols)
|
p := newPeer(c, srv.Protocols)
|
||||||
|
|
@ -639,8 +641,11 @@ running:
|
||||||
}
|
}
|
||||||
name := truncateName(c.name)
|
name := truncateName(c.name)
|
||||||
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
|
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
|
||||||
peers[c.id] = p
|
|
||||||
go srv.runPeer(p)
|
go srv.runPeer(p)
|
||||||
|
peers[c.id] = p
|
||||||
|
if p.Inbound() {
|
||||||
|
inboundCount++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// The dialer logic relies on the assumption that
|
// The dialer logic relies on the assumption that
|
||||||
// dial tasks complete after the peer has been added or
|
// dial tasks complete after the peer has been added or
|
||||||
|
|
@ -655,6 +660,9 @@ running:
|
||||||
d := common.PrettyDuration(mclock.Now() - pd.created)
|
d := common.PrettyDuration(mclock.Now() - pd.created)
|
||||||
pd.log.Debug("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err)
|
pd.log.Debug("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err)
|
||||||
delete(peers, pd.ID())
|
delete(peers, pd.ID())
|
||||||
|
if pd.Inbound() {
|
||||||
|
inboundCount--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -681,20 +689,22 @@ running:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error {
|
func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCount int, c *conn) error {
|
||||||
// Drop connections with no matching protocols.
|
// Drop connections with no matching protocols.
|
||||||
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
|
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
|
||||||
return DiscUselessPeer
|
return DiscUselessPeer
|
||||||
}
|
}
|
||||||
// Repeat the encryption handshake checks because the
|
// Repeat the encryption handshake checks because the
|
||||||
// peer set might have changed between the handshakes.
|
// peer set might have changed between the handshakes.
|
||||||
return srv.encHandshakeChecks(peers, c)
|
return srv.encHandshakeChecks(peers, inboundCount, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error {
|
func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCount int, c *conn) error {
|
||||||
switch {
|
switch {
|
||||||
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
|
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
|
||||||
return DiscTooManyPeers
|
return DiscTooManyPeers
|
||||||
|
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
|
||||||
|
return DiscTooManyPeers
|
||||||
case peers[c.id] != nil:
|
case peers[c.id] != nil:
|
||||||
return DiscAlreadyConnected
|
return DiscAlreadyConnected
|
||||||
case c.id == srv.Self().ID:
|
case c.id == srv.Self().ID:
|
||||||
|
|
@ -704,6 +714,21 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srv *Server) maxInboundConns() int {
|
||||||
|
return srv.MaxPeers - srv.maxDialedConns()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) maxDialedConns() int {
|
||||||
|
if srv.NoDiscovery || srv.NoDial {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
r := srv.DialRatio
|
||||||
|
if r == 0 {
|
||||||
|
r = defaultDialRatio
|
||||||
|
}
|
||||||
|
return srv.MaxPeers / r
|
||||||
|
}
|
||||||
|
|
||||||
type tempError interface {
|
type tempError interface {
|
||||||
Temporary() bool
|
Temporary() bool
|
||||||
}
|
}
|
||||||
|
|
@ -714,10 +739,7 @@ func (srv *Server) listenLoop() {
|
||||||
defer srv.loopWG.Done()
|
defer srv.loopWG.Done()
|
||||||
srv.log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab))
|
srv.log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab))
|
||||||
|
|
||||||
// This channel acts as a semaphore limiting
|
tokens := defaultMaxPendingPeers
|
||||||
// active inbound connections that are lingering pre-handshake.
|
|
||||||
// If all slots are taken, no further connections are accepted.
|
|
||||||
tokens := maxAcceptConns
|
|
||||||
if srv.MaxPendingPeers > 0 {
|
if srv.MaxPendingPeers > 0 {
|
||||||
tokens = srv.MaxPendingPeers
|
tokens = srv.MaxPendingPeers
|
||||||
}
|
}
|
||||||
|
|
@ -758,9 +780,6 @@ func (srv *Server) listenLoop() {
|
||||||
|
|
||||||
fd = newMeteredConn(fd, true)
|
fd = newMeteredConn(fd, true)
|
||||||
srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr())
|
srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr())
|
||||||
|
|
||||||
// Spawn the handler. It will give the slot back when the connection
|
|
||||||
// has been established.
|
|
||||||
go func() {
|
go func() {
|
||||||
srv.SetupConn(fd, inboundConn, nil)
|
srv.SetupConn(fd, inboundConn, nil)
|
||||||
slots <- struct{}{}
|
slots <- struct{}{}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue