@ -139,6 +139,9 @@ type Config struct {
// If EnableMsgEvents is set then the server will emit PeerEvents
// whenever a message is sent to or received from a peer
EnableMsgEvents bool
// Logger is a custom logger to use with the p2p.Server.
Logger log . Logger
}
// Server manages all peer connections.
@ -172,6 +175,7 @@ type Server struct {
delpeer chan peerDrop
loopWG sync . WaitGroup // loop, listenLoop
peerFeed event . Feed
log log . Logger
}
type peerOpFunc func ( map [ discover . NodeID ] * Peer )
@ -359,7 +363,11 @@ func (srv *Server) Start() (err error) {
return errors . New ( "server already running" )
}
srv . running = true
log . Info ( "Starting P2P networking" )
srv . log = srv . Config . Logger
if srv . log == nil {
srv . log = log . New ( )
}
srv . log . Info ( "Starting P2P networking" )
// static fields
if srv . PrivateKey == nil {
@ -421,7 +429,7 @@ func (srv *Server) Start() (err error) {
}
}
if srv . NoDial && srv . ListenAddr == "" {
log . Warn ( "P2P server will be useless, neither dialing nor listening" )
srv . log . Warn ( "P2P server will be useless, neither dialing nor listening" )
}
srv . loopWG . Add ( 1 )
@ -489,7 +497,7 @@ func (srv *Server) run(dialstate dialer) {
i := 0
for ; len ( runningTasks ) < maxActiveDialTasks && i < len ( ts ) ; i ++ {
t := ts [ i ]
log . Trace ( "New dial task" , "task" , t )
srv . log . Trace ( "New dial task" , "task" , t )
go func ( ) { t . Do ( srv ) ; taskdone <- t } ( )
runningTasks = append ( runningTasks , t )
}
@ -517,13 +525,13 @@ running:
// 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.
log . Debug ( "Adding static node" , "node" , n )
srv . log . Debug ( "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
log . Debug ( "Removing static node" , "node" , n )
srv . log . Debug ( "Removing static node" , "node" , n )
dialstate . removeStatic ( n )
if p , ok := peers [ n . ID ] ; ok {
p . Disconnect ( DiscRequested )
@ -536,7 +544,7 @@ running:
// A task got done. Tell dialstate about it so it
// can update its state and remove it from the active
// tasks list.
log . Trace ( "Dial task done" , "task" , t )
srv . log . Trace ( "Dial task done" , "task" , t )
dialstate . taskDone ( t , time . Now ( ) )
delTask ( t )
case c := <- srv . posthandshake :
@ -565,7 +573,7 @@ running:
p . events = & srv . peerFeed
}
name := truncateName ( c . name )
log . Debug ( "Adding p2p peer" , "id" , c . id , "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 )
}
@ -585,7 +593,7 @@ running:
}
}
log . Trace ( "P2P networking is spinning down" )
srv . log . Trace ( "P2P networking is spinning down" )
// Terminate discovery. If there is a running lookup it will terminate soon.
if srv . ntab != nil {
@ -639,7 +647,7 @@ type tempError interface {
// inbound connections.
func ( srv * Server ) listenLoop ( ) {
defer srv . loopWG . Done ( )
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
// active inbound connections that are lingering pre-handshake.
@ -664,10 +672,10 @@ func (srv *Server) listenLoop() {
for {
fd , err = srv . listener . Accept ( )
if tempErr , ok := err . ( tempError ) ; ok && tempErr . Temporary ( ) {
log . Debug ( "Temporary read error" , "err" , err )
srv . log . Debug ( "Temporary read error" , "err" , err )
continue
} else if err != nil {
log . Debug ( "Read error" , "err" , err )
srv . log . Debug ( "Read error" , "err" , err )
return
}
break
@ -676,7 +684,7 @@ func (srv *Server) listenLoop() {
// Reject connections that do not match NetRestrict.
if srv . NetRestrict != nil {
if tcp , ok := fd . RemoteAddr ( ) . ( * net . TCPAddr ) ; ok && ! srv . NetRestrict . Contains ( tcp . IP ) {
log . Debug ( "Rejected conn (not whitelisted in NetRestrict)" , "addr" , fd . RemoteAddr ( ) )
srv . log . Debug ( "Rejected conn (not whitelisted in NetRestrict)" , "addr" , fd . RemoteAddr ( ) )
fd . Close ( )
slots <- struct { } { }
continue
@ -684,7 +692,7 @@ func (srv *Server) listenLoop() {
}
fd = newMeteredConn ( fd , true )
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.
@ -698,55 +706,65 @@ func (srv *Server) listenLoop() {
// SetupConn runs the handshakes and attempts to add the connection
// as a peer. It returns when the connection has been added as a peer
// or the handshakes have failed.
func ( srv * Server ) SetupConn ( fd net . Conn , flags connFlag , dialDest * discover . Node ) {
func ( srv * Server ) SetupConn ( fd net . Conn , flags connFlag , dialDest * discover . Node ) error {
self := srv . Self ( )
if self == nil {
return errors . New ( "shutdown" )
}
c := & conn { fd : fd , transport : srv . newTransport ( fd ) , flags : flags , cont : make ( chan error ) }
err := srv . setupConn ( c , flags , dialDest )
if err != nil {
c . close ( err )
srv . log . Trace ( "Setting up connection failed" , "id" , c . id , "err" , err )
}
return err
}
func ( srv * Server ) setupConn ( c * conn , flags connFlag , dialDest * discover . Node ) error {
// Prevent leftover pending conns from entering the handshake.
srv . lock . Lock ( )
running := srv . running
srv . lock . Unlock ( )
c := & conn { fd : fd , transport : srv . newTransport ( fd ) , flags : flags , cont : make ( chan error ) }
if ! running {
c . close ( errServerStopped )
return
return errServerStopped
}
// Run the encryption handshake.
var err error
if c . id , err = c . doEncHandshake ( srv . PrivateKey , dialDest ) ; err != nil {
log . Trace ( "Failed RLPx handshake" , "addr" , c . fd . RemoteAddr ( ) , "conn" , c . flags , "err" , err )
c . close ( err )
return
srv . log . Trace ( "Failed RLPx handshake" , "addr" , c . fd . RemoteAddr ( ) , "conn" , c . flags , "err" , err )
return err
}
clog := log . New ( "id" , c . id , "addr" , c . fd . RemoteAddr ( ) , "conn" , c . flags )
clog := srv . log . New ( "id" , c . id , "addr" , c . fd . RemoteAddr ( ) , "conn" , c . flags )
// For dialed connections, check that the remote public key matches.
if dialDest != nil && c . id != dialDest . ID {
c . close ( DiscUnexpectedIdentity )
clog . Trace ( "Dialed identity mismatch" , "want" , c , dialDest . ID )
return
return DiscUnexpectedIdentity
}
if err := srv . checkpoint ( c , srv . posthandshake ) ; err != nil {
err = srv . checkpoint ( c , srv . posthandshake )
if err != nil {
clog . Trace ( "Rejected peer before protocol handshake" , "err" , err )
c . close ( err )
return
return err
}
// Run the protocol handshake
phs , err := c . doProtoHandshake ( srv . ourHandshake )
if err != nil {
clog . Trace ( "Failed proto handshake" , "err" , err )
c . close ( err )
return
return err
}
if phs . ID != c . id {
clog . Trace ( "Wrong devp2p handshake identity" , "err" , phs . ID )
c . close ( DiscUnexpectedIdentity )
return
return DiscUnexpectedIdentity
}
c . caps , c . name = phs . Caps , phs . Name
if err := srv . checkpoint ( c , srv . addpeer ) ; err != nil {
err = srv . checkpoint ( c , srv . addpeer )
if err != nil {
clog . Trace ( "Rejected peer" , "err" , err )
c . close ( err )
return
return err
}
// If the checks completed successfully, runPeer has now been
// launched by run.
clog . Trace ( "connection set up" , "inbound" , dialDest == nil )
return nil
}
func truncateName ( s string ) string {