@ -51,7 +51,6 @@ const (
discmixTimeout = 5 * time . Second
discmixTimeout = 5 * time . Second
// Connectivity defaults.
// Connectivity defaults.
maxActiveDialTasks = 16
defaultMaxPendingPeers = 50
defaultMaxPendingPeers = 50
defaultDialRatio = 3
defaultDialRatio = 3
@ -156,6 +155,8 @@ type Config struct {
// Logger is a custom logger to use with the p2p.Server.
// Logger is a custom logger to use with the p2p.Server.
Logger log . Logger ` toml:",omitempty" `
Logger log . Logger ` toml:",omitempty" `
clock mclock . Clock
}
}
// Server manages all peer connections.
// Server manages all peer connections.
@ -183,13 +184,10 @@ type Server struct {
ntab * discover . UDPv4
ntab * discover . UDPv4
DiscV5 * discv5 . Network
DiscV5 * discv5 . Network
discmix * enode . FairMix
discmix * enode . FairMix
dialsched * dialScheduler
staticNodeResolver nodeResolver
// Channels into the run loop.
// Channels into the run loop.
quit chan struct { }
quit chan struct { }
addstatic chan * enode . Node
removestatic chan * enode . Node
addtrusted chan * enode . Node
addtrusted chan * enode . Node
removetrusted chan * enode . Node
removetrusted chan * enode . Node
peerOp chan peerOpFunc
peerOp chan peerOpFunc
@ -302,47 +300,57 @@ func (srv *Server) LocalNode() *enode.LocalNode {
// Peers returns all connected peers.
// Peers returns all connected peers.
func ( srv * Server ) Peers ( ) [ ] * Peer {
func ( srv * Server ) Peers ( ) [ ] * Peer {
var ps [ ] * Peer
var ps [ ] * Peer
select {
srv . doPeerOp ( func ( peers map [ enode . ID ] * Peer ) {
// Note: We'd love to put this function into a variable but
// that seems to cause a weird compiler error in some
// environments.
case srv . peerOp <- func ( peers map [ enode . ID ] * Peer ) {
for _ , p := range peers {
for _ , p := range peers {
ps = append ( ps , p )
ps = append ( ps , p )
}
}
} :
} )
<- srv . peerOpDone
case <- srv . quit :
}
return ps
return ps
}
}
// PeerCount returns the number of connected peers.
// PeerCount returns the number of connected peers.
func ( srv * Server ) PeerCount ( ) int {
func ( srv * Server ) PeerCount ( ) int {
var count int
var count int
select {
srv . doPeerOp ( func ( ps map [ enode . ID ] * Peer ) {
case srv . peerOp <- func ( ps map [ enode . ID ] * Peer ) { count = len ( ps ) } :
count = len ( ps )
<- srv . peerOpDone
} )
case <- srv . quit :
}
return count
return count
}
}
// AddPeer connects to the given node and maintains the connection until the
// AddPeer adds the given node to the static node set. When there is room in the peer set,
// server is shut down . If the connection fails for any reason, the server will
// the server will connect to the node . If the connection fails for any reason, the server
// attempt to reconnect the peer.
// will attempt to reconnect the peer.
func ( srv * Server ) AddPeer ( node * enode . Node ) {
func ( srv * Server ) AddPeer ( node * enode . Node ) {
select {
srv . dialsched . addStatic ( node )
case srv . addstatic <- node :
case <- srv . quit :
}
}
}
// RemovePeer disconnects from the given node
// RemovePeer removes a node from the static node set. It also disconnects from the given
// node if it is currently connected as a peer.
//
// This method blocks until all protocols have exited and the peer is removed. Do not use
// RemovePeer in protocol implementations, call Disconnect on the Peer instead.
func ( srv * Server ) RemovePeer ( node * enode . Node ) {
func ( srv * Server ) RemovePeer ( node * enode . Node ) {
select {
var (
case srv . removestatic <- node :
ch chan * PeerEvent
case <- srv . quit :
sub event . Subscription
)
// Disconnect the peer on the main loop.
srv . doPeerOp ( func ( peers map [ enode . ID ] * Peer ) {
srv . dialsched . removeStatic ( node )
if peer := peers [ node . ID ( ) ] ; peer != nil {
ch = make ( chan * PeerEvent , 1 )
sub = srv . peerFeed . Subscribe ( ch )
peer . Disconnect ( DiscRequested )
}
} )
// Wait for the peer connection to end.
if ch != nil {
defer sub . Unsubscribe ( )
for ev := range ch {
if ev . Peer == node . ID ( ) && ev . Type == PeerEventTypeDrop {
return
}
}
}
}
}
}
@ -437,6 +445,9 @@ func (srv *Server) Start() (err error) {
if srv . log == nil {
if srv . log == nil {
srv . log = log . Root ( )
srv . log = log . Root ( )
}
}
if srv . clock == nil {
srv . clock = mclock . System { }
}
if srv . NoDial && srv . ListenAddr == "" {
if srv . NoDial && srv . ListenAddr == "" {
srv . log . Warn ( "P2P server will be useless, neither dialing nor listening" )
srv . log . Warn ( "P2P server will be useless, neither dialing nor listening" )
}
}
@ -451,15 +462,10 @@ func (srv *Server) Start() (err error) {
if srv . listenFunc == nil {
if srv . listenFunc == nil {
srv . listenFunc = net . Listen
srv . listenFunc = net . Listen
}
}
if srv . Dialer == nil {
srv . Dialer = TCPDialer { & net . Dialer { Timeout : defaultDialTimeout } }
}
srv . quit = make ( chan struct { } )
srv . quit = make ( chan struct { } )
srv . delpeer = make ( chan peerDrop )
srv . delpeer = make ( chan peerDrop )
srv . checkpointPostHandshake = make ( chan * conn )
srv . checkpointPostHandshake = make ( chan * conn )
srv . checkpointAddPeer = make ( chan * conn )
srv . checkpointAddPeer = make ( chan * conn )
srv . addstatic = make ( chan * enode . Node )
srv . removestatic = make ( chan * enode . Node )
srv . addtrusted = make ( chan * enode . Node )
srv . addtrusted = make ( chan * enode . Node )
srv . removetrusted = make ( chan * enode . Node )
srv . removetrusted = make ( chan * enode . Node )
srv . peerOp = make ( chan peerOpFunc )
srv . peerOp = make ( chan peerOpFunc )
@ -476,11 +482,10 @@ func (srv *Server) Start() (err error) {
if err := srv . setupDiscovery ( ) ; err != nil {
if err := srv . setupDiscovery ( ) ; err != nil {
return err
return err
}
}
srv . setupDialScheduler ( )
dynPeers := srv . maxDialedConns ( )
dialer := newDialState ( srv . localnode . ID ( ) , dynPeers , & srv . Config )
srv . loopWG . Add ( 1 )
srv . loopWG . Add ( 1 )
go srv . run ( dialer )
go srv . run ( )
return nil
return nil
}
}
@ -583,7 +588,6 @@ func (srv *Server) setupDiscovery() error {
}
}
srv . ntab = ntab
srv . ntab = ntab
srv . discmix . AddSource ( ntab . RandomNodes ( ) )
srv . discmix . AddSource ( ntab . RandomNodes ( ) )
srv . staticNodeResolver = ntab
}
}
// Discovery V5
// Discovery V5
@ -606,6 +610,47 @@ func (srv *Server) setupDiscovery() error {
return nil
return nil
}
}
func ( srv * Server ) setupDialScheduler ( ) {
config := dialConfig {
self : srv . localnode . ID ( ) ,
maxDialPeers : srv . maxDialedConns ( ) ,
maxActiveDials : srv . MaxPendingPeers ,
log : srv . Logger ,
netRestrict : srv . NetRestrict ,
dialer : srv . Dialer ,
clock : srv . clock ,
}
if srv . ntab != nil {
config . resolver = srv . ntab
}
if config . dialer == nil {
config . dialer = tcpDialer { & net . Dialer { Timeout : defaultDialTimeout } }
}
srv . dialsched = newDialScheduler ( config , srv . discmix , srv . SetupConn )
for _ , n := range srv . StaticNodes {
srv . dialsched . addStatic ( n )
}
}
func ( srv * Server ) maxInboundConns ( ) int {
return srv . MaxPeers - srv . maxDialedConns ( )
}
func ( srv * Server ) maxDialedConns ( ) ( limit int ) {
if srv . NoDial || srv . MaxPeers == 0 {
return 0
}
if srv . DialRatio == 0 {
limit = srv . MaxPeers / defaultDialRatio
} else {
limit = srv . MaxPeers / srv . DialRatio
}
if limit == 0 {
limit = 1
}
return limit
}
func ( srv * Server ) setupListening ( ) error {
func ( srv * Server ) setupListening ( ) error {
// Launch the listener.
// Launch the listener.
listener , err := srv . listenFunc ( "tcp" , srv . ListenAddr )
listener , err := srv . listenFunc ( "tcp" , srv . ListenAddr )
@ -632,112 +677,55 @@ func (srv *Server) setupListening() error {
return nil
return nil
}
}
type dialer interface {
// doPeerOp runs fn on the main loop.
newTasks ( running int , peers map [ enode . ID ] * Peer , now time . Time ) [ ] task
func ( srv * Server ) doPeerOp ( fn peerOpFunc ) {
taskDone ( task , time . Time )
select {
addStatic ( * enode . Node )
case srv . peerOp <- fn :
removeStatic ( * enode . Node )
<- srv . peerOpDone
case <- srv . quit :
}
}
}
func ( srv * Server ) run ( dialstate dialer ) {
// run is the main loop of the server.
func ( srv * Server ) run ( ) {
srv . log . Info ( "Started P2P networking" , "self" , srv . localnode . Node ( ) . URLv4 ( ) )
srv . log . Info ( "Started P2P networking" , "self" , srv . localnode . Node ( ) . URLv4 ( ) )
defer srv . loopWG . Done ( )
defer srv . loopWG . Done ( )
defer srv . nodedb . Close ( )
defer srv . nodedb . Close ( )
defer srv . discmix . Close ( )
defer srv . discmix . Close ( )
defer srv . dialsched . stop ( )
var (
var (
peers = make ( map [ enode . ID ] * Peer )
peers = make ( map [ enode . ID ] * Peer )
inboundCount = 0
inboundCount = 0
trusted = make ( map [ enode . ID ] bool , len ( srv . TrustedNodes ) )
trusted = make ( map [ enode . ID ] bool , len ( srv . TrustedNodes ) )
taskdone = make ( chan task , maxActiveDialTasks )
tick = time . NewTicker ( 30 * time . Second )
runningTasks [ ] task
queuedTasks [ ] task // tasks that can't run yet
)
)
defer tick . Stop ( )
// Put trusted nodes into a map to speed up checks.
// Put trusted nodes into a map to speed up checks.
// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
for _ , n := range srv . TrustedNodes {
for _ , n := range srv . TrustedNodes {
trusted [ n . ID ( ) ] = true
trusted [ n . ID ( ) ] = true
}
}
// removes t from runningTasks
delTask := func ( t task ) {
for i := range runningTasks {
if runningTasks [ i ] == t {
runningTasks = append ( runningTasks [ : i ] , runningTasks [ i + 1 : ] ... )
break
}
}
}
// starts until max number of active tasks is satisfied
startTasks := func ( ts [ ] task ) ( rest [ ] task ) {
i := 0
for ; len ( runningTasks ) < maxActiveDialTasks && i < len ( ts ) ; i ++ {
t := ts [ i ]
srv . log . Trace ( "New dial task" , "task" , t )
go func ( ) { t . Do ( srv ) ; taskdone <- t } ( )
runningTasks = append ( runningTasks , t )
}
return ts [ i : ]
}
scheduleTasks := func ( ) {
// Start from queue first.
queuedTasks = append ( queuedTasks [ : 0 ] , startTasks ( queuedTasks ) ... )
// Query dialer for new tasks and start as many as possible now.
if len ( runningTasks ) < maxActiveDialTasks {
nt := dialstate . newTasks ( len ( runningTasks ) + len ( queuedTasks ) , peers , time . Now ( ) )
queuedTasks = append ( queuedTasks , startTasks ( nt ) ... )
}
}
running :
running :
for {
for {
scheduleTasks ( )
select {
select {
case <- tick . C :
// This is just here to ensure the dial scheduler runs occasionally.
case <- srv . quit :
case <- srv . quit :
// The server was stopped. Run the cleanup logic.
// The server was stopped. Run the cleanup logic.
break running
break running
case n := <- srv . addstatic :
// This channel is used by AddPeer to add to the
// ephemeral static peer list. Add it to the dialer,
// it will keep the node connected.
srv . log . Trace ( "Adding static node" , "node" , n )
dialstate . addStatic ( n )
case n := <- srv . removestatic :
// This channel is used by RemovePeer to send a
// disconnect request to a peer and begin the
// stop keeping the node connected.
srv . log . Trace ( "Removing static node" , "node" , n )
dialstate . removeStatic ( n )
if p , ok := peers [ n . ID ( ) ] ; ok {
p . Disconnect ( DiscRequested )
}
case n := <- srv . addtrusted :
case n := <- srv . addtrusted :
// This channel is used by AddTrustedPeer to add an e node
// This channel is used by AddTrustedPeer to add a node
// to the trusted node set.
// to the trusted node set.
srv . log . Trace ( "Adding trusted node" , "node" , n )
srv . log . Trace ( "Adding trusted node" , "node" , n )
trusted [ n . ID ( ) ] = true
trusted [ n . ID ( ) ] = true
// Mark any already-connected peer as trusted
if p , ok := peers [ n . ID ( ) ] ; ok {
if p , ok := peers [ n . ID ( ) ] ; ok {
p . rw . set ( trustedConn , true )
p . rw . set ( trustedConn , true )
}
}
case n := <- srv . removetrusted :
case n := <- srv . removetrusted :
// This channel is used by RemoveTrustedPeer to remove an e node
// This channel is used by RemoveTrustedPeer to remove a node
// from the trusted node set.
// from the trusted node set.
srv . log . Trace ( "Removing trusted node" , "node" , n )
srv . log . Trace ( "Removing trusted node" , "node" , n )
delete ( trusted , n . ID ( ) )
delete ( trusted , n . ID ( ) )
// Unmark any already-connected peer as trusted
if p , ok := peers [ n . ID ( ) ] ; ok {
if p , ok := peers [ n . ID ( ) ] ; ok {
p . rw . set ( trustedConn , false )
p . rw . set ( trustedConn , false )
}
}
@ -747,14 +735,6 @@ running:
op ( peers )
op ( peers )
srv . peerOpDone <- struct { } { }
srv . peerOpDone <- struct { } { }
case t := <- taskdone :
// A task got done. Tell dialstate about it so it
// can update its state and remove it from the active
// tasks list.
srv . log . Trace ( "Dial task done" , "task" , t )
dialstate . taskDone ( t , time . Now ( ) )
delTask ( t )
case c := <- srv . checkpointPostHandshake :
case c := <- srv . checkpointPostHandshake :
// A connection has passed the encryption handshake so
// A connection has passed the encryption handshake so
// the remote identity is known (but hasn't been verified yet).
// the remote identity is known (but hasn't been verified yet).
@ -771,33 +751,25 @@ running:
err := srv . addPeerChecks ( peers , inboundCount , c )
err := srv . addPeerChecks ( 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 ( srv . log , c , srv . Protocols )
p := srv . launchPeer ( c )
// If message events are enabled, pass the peerFeed
// to the peer
if srv . EnableMsgEvents {
p . events = & srv . peerFeed
}
name := truncateName ( c . name )
p . log . Debug ( "Adding p2p peer" , "addr" , p . RemoteAddr ( ) , "peers" , len ( peers ) + 1 , "name" , name )
go srv . runPeer ( p )
peers [ c . node . ID ( ) ] = p
peers [ c . node . ID ( ) ] = p
if p . Inbound ( ) {
srv . log . Debug ( "Adding p2p peer" , "peercount" , len ( peers ) , "id" , p . ID ( ) , "conn" , c . flags , "addr" , p . RemoteAddr ( ) , "name" , truncateName ( c . name ) )
inboundCount ++
srv . dialsched . peerAdded ( c )
}
if conn , ok := c . fd . ( * meteredConn ) ; ok {
if conn , ok := c . fd . ( * meteredConn ) ; ok {
conn . handshakeDone ( p )
conn . handshakeDone ( p )
}
}
if p . Inbound ( ) {
inboundCount ++
}
}
}
// The dialer logic relies on the assumption that
// dial tasks complete after the peer has been added or
// discarded. Unblock the task last.
c . cont <- err
c . cont <- err
case pd := <- srv . delpeer :
case pd := <- srv . delpeer :
// A peer disconnected.
// A peer disconnected.
d := common . PrettyDuration ( mclock . Now ( ) - pd . created )
d := common . PrettyDuration ( mclock . Now ( ) - pd . created )
pd . log . Debug ( "Removing p2p peer" , "addr" , pd . RemoteAddr ( ) , "peers" , len ( peers ) - 1 , "duration" , d , "req" , pd . requested , "err" , pd . err )
delete ( peers , pd . ID ( ) )
delete ( peers , pd . ID ( ) )
srv . log . Debug ( "Removing p2p peer" , "peercount" , len ( peers ) , "id" , pd . ID ( ) , "duration" , d , "req" , pd . requested , "err" , pd . err )
srv . dialsched . peerRemoved ( pd . rw )
if pd . Inbound ( ) {
if pd . Inbound ( ) {
inboundCount --
inboundCount --
}
}
@ -822,14 +794,14 @@ running:
// is closed.
// is closed.
for len ( peers ) > 0 {
for len ( peers ) > 0 {
p := <- srv . delpeer
p := <- srv . delpeer
p . log . Trace ( "<-delpeer (spindown)" , "remainingTasks" , len ( runningTasks ) )
p . log . Trace ( "<-delpeer (spindown)" )
delete ( peers , p . ID ( ) )
delete ( peers , p . ID ( ) )
}
}
}
}
func ( srv * Server ) postHandshakeChecks ( peers map [ enode . ID ] * Peer , inboundCount int , c * conn ) error {
func ( srv * Server ) postHandshakeChecks ( peers map [ enode . ID ] * Peer , inboundCount int , c * conn ) error {
switch {
switch {
case ! c . is ( trustedConn | staticDialedConn ) && len ( peers ) >= srv . MaxPeers :
case ! c . is ( trustedConn ) && len ( peers ) >= srv . MaxPeers :
return DiscTooManyPeers
return DiscTooManyPeers
case ! c . is ( trustedConn ) && c . is ( inboundConn ) && inboundCount >= srv . maxInboundConns ( ) :
case ! c . is ( trustedConn ) && c . is ( inboundConn ) && inboundCount >= srv . maxInboundConns ( ) :
return DiscTooManyPeers
return DiscTooManyPeers
@ -852,21 +824,6 @@ func (srv *Server) addPeerChecks(peers map[enode.ID]*Peer, inboundCount int, c *
return srv . postHandshakeChecks ( peers , inboundCount , c )
return srv . postHandshakeChecks ( peers , inboundCount , c )
}
}
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
}
// listenLoop runs in its own goroutine and accepts
// listenLoop runs in its own goroutine and accepts
// inbound connections.
// inbound connections.
func ( srv * Server ) listenLoop ( ) {
func ( srv * Server ) listenLoop ( ) {
@ -935,18 +892,20 @@ func (srv *Server) listenLoop() {
}
}
func ( srv * Server ) checkInboundConn ( fd net . Conn , remoteIP net . IP ) error {
func ( srv * Server ) checkInboundConn ( fd net . Conn , remoteIP net . IP ) error {
if remoteIP != nil {
if remoteIP == nil {
// Reject connections that do not match NetRestrict.
return nil
if srv . NetRestrict != nil && ! srv . NetRestrict . Contains ( remoteIP ) {
}
return fmt . Errorf ( "not whitelisted in NetRestrict" )
// Reject connections that do not match NetRestrict.
}
if srv . NetRestrict != nil && ! srv . NetRestrict . Contains ( remoteIP ) {
// Reject Internet peers that try too often.
return fmt . Errorf ( "not whitelisted in NetRestrict" )
srv . inboundHistory . expire ( time . Now ( ) )
if ! netutil . IsLAN ( remoteIP ) && srv . inboundHistory . contains ( remoteIP . String ( ) ) {
return fmt . Errorf ( "too many attempts" )
}
srv . inboundHistory . add ( remoteIP . String ( ) , time . Now ( ) . Add ( inboundThrottleTime ) )
}
}
// Reject Internet peers that try too often.
now := srv . clock . Now ( )
srv . inboundHistory . expire ( now , nil )
if ! netutil . IsLAN ( remoteIP ) && srv . inboundHistory . contains ( remoteIP . String ( ) ) {
return fmt . Errorf ( "too many attempts" )
}
srv . inboundHistory . add ( remoteIP . String ( ) , now . Add ( inboundThrottleTime ) )
return nil
return nil
}
}
@ -958,7 +917,6 @@ func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node)
err := srv . setupConn ( c , flags , dialDest )
err := srv . setupConn ( c , flags , dialDest )
if err != nil {
if err != nil {
c . close ( err )
c . close ( err )
srv . log . Trace ( "Setting up connection failed" , "addr" , fd . RemoteAddr ( ) , "err" , err )
}
}
return err
return err
}
}
@ -977,7 +935,9 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
if dialDest != nil {
if dialDest != nil {
dialPubkey = new ( ecdsa . PublicKey )
dialPubkey = new ( ecdsa . PublicKey )
if err := dialDest . Load ( ( * enode . Secp256k1 ) ( dialPubkey ) ) ; err != nil {
if err := dialDest . Load ( ( * enode . Secp256k1 ) ( dialPubkey ) ) ; err != nil {
return errors . New ( "dial destination doesn't have a secp256k1 public key" )
err = errors . New ( "dial destination doesn't have a secp256k1 public key" )
srv . log . Trace ( "Setting up connection failed" , "addr" , c . fd . RemoteAddr ( ) , "conn" , c . flags , "err" , err )
return err
}
}
}
}
@ -1006,7 +966,7 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
// Run the capability negotiation handshake.
// Run the capability negotiation handshake.
phs , err := c . doProtoHandshake ( srv . ourHandshake )
phs , err := c . doProtoHandshake ( srv . ourHandshake )
if err != nil {
if err != nil {
clog . Trace ( "Failed proto handshake" , "err" , err )
clog . Trace ( "Failed p2p handshake" , "err" , err )
return err
return err
}
}
if id := c . node . ID ( ) ; ! bytes . Equal ( crypto . Keccak256 ( phs . ID ) , id [ : ] ) {
if id := c . node . ID ( ) ; ! bytes . Equal ( crypto . Keccak256 ( phs . ID ) , id [ : ] ) {
@ -1020,9 +980,6 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
return err
return err
}
}
// If the checks completed successfully, the connection has been added as a peer and
// runPeer has been launched.
clog . Trace ( "Connection set up" , "inbound" , dialDest == nil )
return nil
return nil
}
}
@ -1054,15 +1011,22 @@ func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error {
return <- c . cont
return <- c . cont
}
}
func ( srv * Server ) launchPeer ( c * conn ) * Peer {
p := newPeer ( srv . log , c , srv . Protocols )
if srv . EnableMsgEvents {
// If message events are enabled, pass the peerFeed
// to the peer.
p . events = & srv . peerFeed
}
go srv . runPeer ( p )
return p
}
// runPeer runs in its own goroutine for each peer.
// runPeer runs in its own goroutine for each peer.
// it waits until the Peer logic returns and removes
// the peer.
func ( srv * Server ) runPeer ( p * Peer ) {
func ( srv * Server ) runPeer ( p * Peer ) {
if srv . newPeerHook != nil {
if srv . newPeerHook != nil {
srv . newPeerHook ( p )
srv . newPeerHook ( p )
}
}
// broadcast peer add
srv . peerFeed . Send ( & PeerEvent {
srv . peerFeed . Send ( & PeerEvent {
Type : PeerEventTypeAdd ,
Type : PeerEventTypeAdd ,
Peer : p . ID ( ) ,
Peer : p . ID ( ) ,
@ -1070,10 +1034,18 @@ func (srv *Server) runPeer(p *Peer) {
LocalAddress : p . LocalAddr ( ) . String ( ) ,
LocalAddress : p . LocalAddr ( ) . String ( ) ,
} )
} )
// run the protocol
// Run the per-peer main loop.
remoteRequested , err := p . run ( )
remoteRequested , err := p . run ( )
// broadcast peer drop
// Announce disconnect on the main loop to update the peer set.
// The main loop waits for existing peers to be sent on srv.delpeer
// before returning, so this send should not select on srv.quit.
srv . delpeer <- peerDrop { p , err , remoteRequested }
// Broadcast peer drop to external subscribers. This needs to be
// after the send to delpeer so subscribers have a consistent view of
// the peer set (i.e. Server.Peers() doesn't include the peer when the
// event is received.
srv . peerFeed . Send ( & PeerEvent {
srv . peerFeed . Send ( & PeerEvent {
Type : PeerEventTypeDrop ,
Type : PeerEventTypeDrop ,
Peer : p . ID ( ) ,
Peer : p . ID ( ) ,
@ -1081,10 +1053,6 @@ func (srv *Server) runPeer(p *Peer) {
RemoteAddress : p . RemoteAddr ( ) . String ( ) ,
RemoteAddress : p . RemoteAddr ( ) . String ( ) ,
LocalAddress : p . LocalAddr ( ) . String ( ) ,
LocalAddress : p . LocalAddr ( ) . String ( ) ,
} )
} )
// Note: run waits for existing peers to be sent on srv.delpeer
// before returning, so this send should not select on srv.quit.
srv . delpeer <- peerDrop { p , err , remoteRequested }
}
}
// NodeInfo represents a short summary of the information known about the host.
// NodeInfo represents a short summary of the information known about the host.