p2p: revert node id change, add protocol handshake event

This commit is contained in:
Kurkó Mihály 2019-02-19 19:12:20 +02:00
parent 20a4756f73
commit 7070891ade
2 changed files with 49 additions and 29 deletions

View file

@ -19,6 +19,7 @@
package p2p package p2p
import ( import (
"fmt"
"net" "net"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -57,23 +58,28 @@ var (
type MeteredPeerEventType int type MeteredPeerEventType int
const ( const (
// PeerConnected is the type of event emitted when a peer successfully // PeerEncHandshakeSucceeded is the type of event emitted when a peer successfully
// made the handshake. // makes the encryption handshake.
PeerConnected MeteredPeerEventType = iota PeerEncHandshakeSucceeded MeteredPeerEventType = iota
// PeerEncHandshakeFailed is the type of event emitted when a peer fails to
// make the encryption handshake or disconnects before it.
PeerEncHandshakeFailed
// PeerProtoHandshakeSucceeded is the type of event emitted when a peer successfully
// makes the protocol handshake.
PeerProtoHandshakeSucceeded
// PeerDisconnected is the type of event emitted when a peer disconnects. // PeerDisconnected is the type of event emitted when a peer disconnects.
PeerDisconnected PeerDisconnected
// PeerHandshakeFailed is the type of event emitted when a peer fails to
// make the handshake or disconnects before the handshake.
PeerHandshakeFailed
) )
// MeteredPeerEvent is an event emitted when peers connect or disconnect. // MeteredPeerEvent is an event emitted when peers connect or disconnect.
type MeteredPeerEvent struct { type MeteredPeerEvent struct {
Type MeteredPeerEventType // Type of peer event Type MeteredPeerEventType // Type of peer event
Addr string // TCP address of the peer Addr string // TCP address of the peer
Node string // Host ID enode.ID // NodeID of the peer
Info *PeerInfo // Collection of metadata known about the peer
Elapsed time.Duration // Time elapsed between the connection and the handshake/disconnection Elapsed time.Duration // Time elapsed between the connection and the handshake/disconnection
Ingress uint64 // Ingress count at the moment of the event Ingress uint64 // Ingress count at the moment of the event
Egress uint64 // Egress count at the moment of the event Egress uint64 // Egress count at the moment of the event
@ -92,7 +98,7 @@ type meteredConn struct {
connected time.Time // Connection time of the peer connected time.Time // Connection time of the peer
addr *net.TCPAddr // TCP address of the peer addr *net.TCPAddr // TCP address of the peer
node *enode.Node // Host id enode.ID // NodeID of the peer
// trafficMetered denotes if the peer is registered in the traffic registries. // trafficMetered denotes if the peer is registered in the traffic registries.
// Its value is true if the metered peer count doesn't reach the limit in the // Its value is true if the metered peer count doesn't reach the limit in the
@ -156,56 +162,66 @@ func (c *meteredConn) Write(b []byte) (n int, err error) {
return n, err return n, err
} }
// handshakeDone is called when a peer handshake is done. Registers the peer to // encHandshakeDone is called after the connection passes the encryption
// the ingress and the egress traffic registries using the peer's IP and node ID, // handshake. Registers the peer to the ingress and the egress traffic
// also emits connect event. // registries using the peer's IP and node ID, also emits connect event.
func (c *meteredConn) handshakeDone(node *enode.Node) { func (c *meteredConn) encHandshakeDone(id enode.ID) {
if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit { if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit {
// Don't register the peer in the traffic registries. // Don't register the peer in the traffic registries.
atomic.AddInt32(&meteredPeerCount, -1) atomic.AddInt32(&meteredPeerCount, -1)
c.lock.Lock() c.lock.Lock()
c.node, c.trafficMetered = node, false c.id, c.trafficMetered = id, false
c.lock.Unlock() c.lock.Unlock()
log.Warn("Metered peer count reached the limit") log.Warn("Metered peer count reached the limit")
} else { } else {
key := node.String() key := fmt.Sprintf("%s/%s", c.addr.String(), id.String())
c.lock.Lock() c.lock.Lock()
c.node, c.trafficMetered = node, true c.id, c.trafficMetered = id, true
c.ingressMeter = metrics.NewRegisteredMeter(key, PeerIngressRegistry) c.ingressMeter = metrics.NewRegisteredMeter(key, PeerIngressRegistry)
c.egressMeter = metrics.NewRegisteredMeter(key, PeerEgressRegistry) c.egressMeter = metrics.NewRegisteredMeter(key, PeerEgressRegistry)
c.lock.Unlock() c.lock.Unlock()
} }
meteredPeerFeed.Send(MeteredPeerEvent{ meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerConnected, Type: PeerEncHandshakeSucceeded,
Addr: c.addr.String(), Addr: c.addr.String(),
Node: node.String(), ID: id,
Elapsed: time.Since(c.connected), Elapsed: time.Since(c.connected),
}) })
} }
// peerAdded is called after the connection passes the protocol handshake.
func (c *meteredConn) peerAdded(info *PeerInfo) {
meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerProtoHandshakeSucceeded,
Addr: c.addr.String(),
ID: c.id,
Info: info,
})
}
// Close delegates a close operation to the underlying connection, unregisters // Close delegates a close operation to the underlying connection, unregisters
// the peer from the traffic registries and emits close event. // the peer from the traffic registries and emits close event.
func (c *meteredConn) Close() error { func (c *meteredConn) Close() error {
err := c.Conn.Close() err := c.Conn.Close()
c.lock.RLock() c.lock.RLock()
if c.node == nil { if c.id == (enode.ID{}) {
// If the peer disconnects before the handshake. // If the peer disconnects before the encryption handshake.
c.lock.RUnlock() c.lock.RUnlock()
meteredPeerFeed.Send(MeteredPeerEvent{ meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerHandshakeFailed, Type: PeerEncHandshakeFailed,
Addr: c.addr.String(), Addr: c.addr.String(),
Elapsed: time.Since(c.connected), Elapsed: time.Since(c.connected),
}) })
return err return err
} }
node := c.node.String() id := c.id
if !c.trafficMetered { if !c.trafficMetered {
// If the peer isn't registered in the traffic registries. // If the peer isn't registered in the traffic registries.
c.lock.RUnlock() c.lock.RUnlock()
meteredPeerFeed.Send(MeteredPeerEvent{ meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerDisconnected, Type: PeerDisconnected,
Addr: c.addr.String(), Addr: c.addr.String(),
Node: node, ID: id,
}) })
return err return err
} }
@ -216,13 +232,14 @@ func (c *meteredConn) Close() error {
atomic.AddInt32(&meteredPeerCount, -1) atomic.AddInt32(&meteredPeerCount, -1)
// Unregister the peer from the traffic registries // Unregister the peer from the traffic registries
PeerIngressRegistry.Unregister(node) key := fmt.Sprintf("%s/%s", c.addr.String(), id)
PeerEgressRegistry.Unregister(node) PeerIngressRegistry.Unregister(key)
PeerEgressRegistry.Unregister(key)
meteredPeerFeed.Send(MeteredPeerEvent{ meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerDisconnected, Type: PeerDisconnected,
Addr: c.addr.String(), Addr: c.addr.String(),
Node: node, ID: id,
Ingress: ingress, Ingress: ingress,
Egress: egress, Egress: egress,
}) })

View file

@ -717,6 +717,9 @@ running:
case <-srv.quit: case <-srv.quit:
break running break running
} }
if conn, ok := c.fd.(*meteredConn); ok {
conn.encHandshakeDone(c.node.ID())
}
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.
@ -736,6 +739,9 @@ running:
if p.Inbound() { if p.Inbound() {
inboundCount++ inboundCount++
} }
if conn, ok := c.fd.(*meteredConn); ok {
conn.peerAdded(p.Info())
}
} }
// 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
@ -920,9 +926,6 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
} else { } else {
c.node = nodeFromConn(remotePubkey, c.fd) c.node = nodeFromConn(remotePubkey, c.fd)
} }
if conn, ok := c.fd.(*meteredConn); ok {
conn.handshakeDone(c.node)
}
clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags) clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
err = srv.checkpoint(c, srv.posthandshake) err = srv.checkpoint(c, srv.posthandshake)
if err != nil { if err != nil {