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
|
||||
staticPeerCheckInterval = 15 * time.Second
|
||||
|
||||
// Maximum number of concurrently handshaking inbound connections.
|
||||
maxAcceptConns = 50
|
||||
|
||||
// Maximum number of concurrently dialing outbound connections.
|
||||
maxActiveDialTasks = 16
|
||||
// Connectivity defaults.
|
||||
maxActiveDialTasks = 16
|
||||
defaultMaxPendingPeers = 50
|
||||
defaultDialRatio = 3
|
||||
|
||||
// Maximum time allowed for reading a complete message.
|
||||
// This is effectively the amount of time a connection can be idle.
|
||||
|
|
@ -70,6 +69,11 @@ type Config struct {
|
|||
// Zero defaults to preset values.
|
||||
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.
|
||||
// Disabling is useful for protocol debugging (manual topology).
|
||||
NoDiscovery bool
|
||||
|
|
@ -476,10 +480,7 @@ func (srv *Server) Start() (err error) {
|
|||
srv.DiscV5 = ntab
|
||||
}
|
||||
|
||||
dynPeers := (srv.MaxPeers + 1) / 2
|
||||
if srv.NoDiscovery {
|
||||
dynPeers = 0
|
||||
}
|
||||
dynPeers := srv.maxDialedConns()
|
||||
dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)
|
||||
|
||||
// handshake
|
||||
|
|
@ -536,6 +537,7 @@ func (srv *Server) run(dialstate dialer) {
|
|||
defer srv.loopWG.Done()
|
||||
var (
|
||||
peers = make(map[discover.NodeID]*Peer)
|
||||
inboundCount = 0
|
||||
trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes))
|
||||
taskdone = make(chan task, maxActiveDialTasks)
|
||||
runningTasks []task
|
||||
|
|
@ -621,14 +623,14 @@ running:
|
|||
}
|
||||
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
|
||||
select {
|
||||
case c.cont <- srv.encHandshakeChecks(peers, c):
|
||||
case c.cont <- srv.encHandshakeChecks(peers, inboundCount, c):
|
||||
case <-srv.quit:
|
||||
break running
|
||||
}
|
||||
case c := <-srv.addpeer:
|
||||
// At this point the connection is past the protocol handshake.
|
||||
// Its capabilities are known and the remote identity is verified.
|
||||
err := srv.protoHandshakeChecks(peers, c)
|
||||
err := srv.protoHandshakeChecks(peers, inboundCount, c)
|
||||
if err == nil {
|
||||
// The handshakes are done and it passed all checks.
|
||||
p := newPeer(c, srv.Protocols)
|
||||
|
|
@ -639,8 +641,11 @@ running:
|
|||
}
|
||||
name := truncateName(c.name)
|
||||
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
|
||||
peers[c.id] = p
|
||||
go srv.runPeer(p)
|
||||
peers[c.id] = p
|
||||
if p.Inbound() {
|
||||
inboundCount++
|
||||
}
|
||||
}
|
||||
// The dialer logic relies on the assumption that
|
||||
// dial tasks complete after the peer has been added or
|
||||
|
|
@ -655,6 +660,9 @@ running:
|
|||
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)
|
||||
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.
|
||||
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
|
||||
return DiscUselessPeer
|
||||
}
|
||||
// Repeat the encryption handshake checks because the
|
||||
// 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 {
|
||||
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
|
||||
return DiscTooManyPeers
|
||||
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
|
||||
return DiscTooManyPeers
|
||||
case peers[c.id] != nil:
|
||||
return DiscAlreadyConnected
|
||||
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 {
|
||||
Temporary() bool
|
||||
}
|
||||
|
|
@ -714,10 +739,7 @@ func (srv *Server) listenLoop() {
|
|||
defer srv.loopWG.Done()
|
||||
srv.log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab))
|
||||
|
||||
// This channel acts as a semaphore limiting
|
||||
// active inbound connections that are lingering pre-handshake.
|
||||
// If all slots are taken, no further connections are accepted.
|
||||
tokens := maxAcceptConns
|
||||
tokens := defaultMaxPendingPeers
|
||||
if srv.MaxPendingPeers > 0 {
|
||||
tokens = srv.MaxPendingPeers
|
||||
}
|
||||
|
|
@ -758,9 +780,6 @@ func (srv *Server) listenLoop() {
|
|||
|
||||
fd = newMeteredConn(fd, true)
|
||||
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() {
|
||||
srv.SetupConn(fd, inboundConn, nil)
|
||||
slots <- struct{}{}
|
||||
|
|
|
|||
Loading…
Reference in a new issue