github.com/klaytn/klaytn@v1.12.1/networks/p2p/peer.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2014 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from p2p/peer.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package p2p
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"net"
    28  	"sort"
    29  	"sync"
    30  	"sync/atomic"
    31  	"time"
    32  
    33  	"github.com/klaytn/klaytn/common"
    34  	"github.com/klaytn/klaytn/common/mclock"
    35  	"github.com/klaytn/klaytn/event"
    36  	"github.com/klaytn/klaytn/log"
    37  	"github.com/klaytn/klaytn/networks/p2p/discover"
    38  	"github.com/klaytn/klaytn/rlp"
    39  )
    40  
    41  var logger = log.NewModuleLogger(log.NetworksP2P)
    42  
    43  const (
    44  	baseProtocolVersion    = 5
    45  	baseProtocolLength     = uint64(16)
    46  	baseProtocolMaxMsgSize = 2 * 1024
    47  
    48  	snappyProtocolVersion = 5
    49  
    50  	pingInterval = 15 * time.Second
    51  )
    52  
    53  const (
    54  	// devp2p message codes
    55  	handshakeMsg = 0x00
    56  	discMsg      = 0x01
    57  	pingMsg      = 0x02
    58  	pongMsg      = 0x03
    59  )
    60  
    61  const (
    62  	ConnDefault = iota
    63  	ConnTxMsg
    64  )
    65  
    66  // protoHandshake is the RLP structure of the protocol handshake.
    67  type protoHandshake struct {
    68  	Version      uint64
    69  	Name         string
    70  	Caps         []Cap
    71  	ListenPort   []uint64
    72  	ID           discover.NodeID
    73  	Multichannel bool
    74  
    75  	// Ignore additional fields (for forward compatibility).
    76  	Rest []rlp.RawValue `rlp:"tail"`
    77  }
    78  
    79  // PeerEventType is the type of peer events emitted by a p2p.Server
    80  type PeerEventType string
    81  
    82  const (
    83  	// PeerEventTypeAdd is the type of event emitted when a peer is added
    84  	// to a p2p.Server
    85  	PeerEventTypeAdd PeerEventType = "add"
    86  
    87  	// PeerEventTypeDrop is the type of event emitted when a peer is
    88  	// dropped from a p2p.Server
    89  	PeerEventTypeDrop PeerEventType = "drop"
    90  
    91  	// PeerEventTypeMsgSend is the type of event emitted when a
    92  	// message is successfully sent to a peer
    93  	PeerEventTypeMsgSend PeerEventType = "msgsend"
    94  
    95  	// PeerEventTypeMsgRecv is the type of event emitted when a
    96  	// message is received from a peer
    97  	PeerEventTypeMsgRecv PeerEventType = "msgrecv"
    98  )
    99  
   100  // PeerEvent is an event emitted when peers are either added or dropped from
   101  // a p2p.Server or when a message is sent or received on a peer connection
   102  type PeerEvent struct {
   103  	Type     PeerEventType   `json:"type"`
   104  	Peer     discover.NodeID `json:"peer"`
   105  	Error    string          `json:"error,omitempty"`
   106  	Protocol string          `json:"protocol,omitempty"`
   107  	MsgCode  *uint64         `json:"msg_code,omitempty"`
   108  	MsgSize  *uint32         `json:"msg_size,omitempty"`
   109  }
   110  
   111  // Peer represents a connected remote node.
   112  type Peer struct {
   113  	rws     []*conn
   114  	running map[string][]*protoRW
   115  	logger  log.Logger
   116  	created mclock.AbsTime
   117  
   118  	wg       sync.WaitGroup
   119  	protoErr chan error
   120  	closed   chan struct{}
   121  	disc     chan DiscReason
   122  
   123  	// events receives message send / receive events if set
   124  	events *event.Feed
   125  }
   126  
   127  // NewPeer returns a peer for testing purposes.
   128  func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer {
   129  	pipe, _ := net.Pipe()
   130  	conn := []*conn{{fd: pipe, transport: nil, id: id, caps: caps, name: name}}
   131  	peer, _ := newPeer(conn, nil, defaultRWTimerConfig)
   132  	close(peer.closed) // ensures Disconnect doesn't block
   133  	return peer
   134  }
   135  
   136  // ID returns the node's public key.
   137  func (p *Peer) ID() discover.NodeID {
   138  	return p.rws[ConnDefault].id
   139  }
   140  
   141  // Name returns the node name that the remote node advertised.
   142  func (p *Peer) Name() string {
   143  	return p.rws[ConnDefault].name
   144  }
   145  
   146  // RunningCap returns true if the peer is actively connected using any of the
   147  // enumerated versions of a specific protocol, meaning that at least one of the
   148  // versions is supported by both this node and the peer p.
   149  func (p *Peer) RunningCap(protocol string, versions []uint) bool {
   150  	if protos, ok := p.running[protocol]; ok {
   151  		for _, ver := range versions {
   152  			if protos[ConnDefault].Version == ver {
   153  				return true
   154  			}
   155  		}
   156  	}
   157  	return false
   158  }
   159  
   160  // Caps returns the capabilities (supported subprotocols) of the remote peer.
   161  func (p *Peer) Caps() []Cap {
   162  	// TODO: maybe return copy
   163  	return p.rws[ConnDefault].caps
   164  }
   165  
   166  // RemoteAddr returns the remote address of the network connection.
   167  func (p *Peer) RemoteAddr() net.Addr {
   168  	return p.rws[ConnDefault].fd.RemoteAddr()
   169  }
   170  
   171  // LocalAddr returns the local address of the network connection.
   172  func (p *Peer) LocalAddr() net.Addr {
   173  	return p.rws[ConnDefault].fd.LocalAddr()
   174  }
   175  
   176  // Disconnect terminates the peer connection with the given reason.
   177  // It returns immediately and does not wait until the connection is closed.
   178  func (p *Peer) Disconnect(reason DiscReason) {
   179  	select {
   180  	case p.disc <- reason:
   181  	case <-p.closed:
   182  	}
   183  }
   184  
   185  // String implements fmt.Stringer.
   186  func (p *Peer) String() string {
   187  	return fmt.Sprintf("Peer %x %v", p.rws[ConnDefault].id[:8], p.RemoteAddr())
   188  }
   189  
   190  // Inbound returns true if the peer is an inbound connection
   191  func (p *Peer) Inbound() bool {
   192  	return p.rws[ConnDefault].flags&inboundConn != 0
   193  }
   194  
   195  // GetNumberInboundAndOutbound returns the number of
   196  // inbound and outbound connections connected to the peer.
   197  func (p *Peer) GetNumberInboundAndOutbound() (int, int) {
   198  	inbound, outbound := 0, 0
   199  	for _, rw := range p.rws {
   200  		if rw.flags&inboundConn != 0 {
   201  			inbound++
   202  		} else {
   203  			outbound++
   204  		}
   205  	}
   206  	return inbound, outbound
   207  }
   208  
   209  // newPeer should be called to create a peer.
   210  func newPeer(conns []*conn, protocols []Protocol, tc RWTimerConfig) (*Peer, error) {
   211  	if conns == nil || len(conns) < 1 || conns[ConnDefault] == nil {
   212  		return nil, errors.New("conn is invalid")
   213  	}
   214  	msgReadWriters := make([]MsgReadWriter, len(conns))
   215  	for i, c := range conns {
   216  		msgReadWriters[i] = c
   217  	}
   218  	protomap := matchProtocols(protocols, conns[ConnDefault].caps, msgReadWriters, tc)
   219  	p := &Peer{
   220  		rws:      conns,
   221  		running:  protomap,
   222  		created:  mclock.Now(),
   223  		disc:     make(chan DiscReason),
   224  		protoErr: make(chan error, len(protomap)+len(conns)), // protocols + pingLoop
   225  		closed:   make(chan struct{}),
   226  		logger:   logger.NewWith("id", conns[ConnDefault].id, "conn", conns[ConnDefault].flags),
   227  	}
   228  	return p, nil
   229  }
   230  
   231  func (p *Peer) Log() log.Logger {
   232  	return p.logger
   233  }
   234  
   235  func (p *Peer) run() (remoteRequested bool, err error) {
   236  	var (
   237  		writeStart = make(chan struct{}, 1)
   238  		writeErr   = make(chan error, 1)
   239  		readErr    = make(chan error, 1)
   240  		reason     DiscReason // sent to the peer
   241  	)
   242  	if len(p.rws) != 1 {
   243  		return false, errors.New("The size of rws should be 1")
   244  	}
   245  	p.wg.Add(2)
   246  	go p.readLoop(ConnDefault, p.rws[ConnDefault], readErr)
   247  	go p.pingLoop(p.rws[ConnDefault])
   248  
   249  	// Start all protocol handlers.
   250  	writeStart <- struct{}{}
   251  	p.startProtocols(writeStart, writeErr)
   252  
   253  	// Wait for an error or disconnect.
   254  loop:
   255  	for {
   256  		select {
   257  		case err = <-writeErr:
   258  			// A write finished. Allow the next write to start if
   259  			// there was no error.
   260  			if err != nil {
   261  				reason = DiscNetworkError
   262  				break loop
   263  			}
   264  			writeStart <- struct{}{}
   265  		case err = <-readErr:
   266  			if r, ok := err.(DiscReason); ok {
   267  				remoteRequested = true
   268  				reason = r
   269  			} else {
   270  				reason = DiscNetworkError
   271  			}
   272  			break loop
   273  		case err = <-p.protoErr:
   274  			reason = discReasonForError(err)
   275  			break loop
   276  		case err = <-p.disc:
   277  			reason = discReasonForError(err)
   278  			break loop
   279  		}
   280  	}
   281  
   282  	close(p.closed)
   283  	for _, rw := range p.rws {
   284  		rw.close(reason)
   285  	}
   286  	p.wg.Wait()
   287  	logger.Debug(fmt.Sprintf("run stopped, peer: %v", p.ID()))
   288  	return remoteRequested, err
   289  }
   290  
   291  // ErrorPeer is a peer error
   292  type ErrorPeer struct {
   293  	remoteRequested bool
   294  	err             error
   295  }
   296  
   297  // runWithRWs Runs peer
   298  func (p *Peer) runWithRWs() (remoteRequested bool, err error) {
   299  	resultErr := make(chan ErrorPeer, len(p.rws))
   300  	var errs ErrorPeer
   301  
   302  	var (
   303  		writeStarts = make([]chan struct{}, 0, len(p.rws))
   304  		writeErr    = make([]chan error, 0, 1)
   305  		readErr     = make([]chan error, 0, 1)
   306  	)
   307  
   308  	for range p.rws {
   309  		writeStarts = append(writeStarts, make(chan struct{}, 1))
   310  		writeErr = append(writeErr, make(chan error, 1))
   311  		readErr = append(readErr, make(chan error, 1))
   312  	}
   313  
   314  	for i, rw := range p.rws {
   315  		p.wg.Add(2)
   316  		go p.readLoop(i, rw, readErr[i])
   317  		go p.pingLoop(rw)
   318  		writeStarts[i] <- struct{}{}
   319  	}
   320  
   321  	// Start all protocol handlers.
   322  	p.startProtocolsWithRWs(writeStarts, writeErr)
   323  
   324  	for i, rw := range p.rws {
   325  		p.wg.Add(1)
   326  		go p.handleError(rw, resultErr, writeErr[i], writeStarts[i], readErr[i])
   327  	}
   328  
   329  	select {
   330  	case errs = <-resultErr:
   331  		close(p.closed)
   332  	}
   333  	p.wg.Wait()
   334  	logger.Debug(fmt.Sprintf("run stopped, peer: %v", p.ID()))
   335  	return errs.remoteRequested, errs.err
   336  }
   337  
   338  // handleError handles read, write, and protocol errors on rw
   339  func (p *Peer) handleError(rw *conn, errCh chan<- ErrorPeer, writeErr <-chan error, writeStart chan<- struct{}, readErr <-chan error) {
   340  	defer p.wg.Done()
   341  	var errRW ErrorPeer
   342  	var reason DiscReason // sent to the peer
   343  
   344  	// Wait for an error or disconnect.
   345  loop:
   346  	for {
   347  		select {
   348  		case errRW.err = <-writeErr:
   349  			// A write finished. Allow the next write to start if
   350  			// there was no error.
   351  			if errRW.err != nil {
   352  				reason = DiscNetworkError
   353  				break loop
   354  			}
   355  			writeStart <- struct{}{}
   356  		case errRW.err = <-readErr:
   357  			if r, ok := errRW.err.(DiscReason); ok {
   358  				errRW.remoteRequested = true
   359  				reason = r
   360  			} else {
   361  				reason = DiscNetworkError
   362  			}
   363  			break loop
   364  		case errRW.err = <-p.protoErr:
   365  			reason = discReasonForError(errRW.err)
   366  			break loop
   367  		case errRW.err = <-p.disc:
   368  			reason = discReasonForError(errRW.err)
   369  			break loop
   370  		case <-p.closed:
   371  			reason = DiscQuitting
   372  			break loop
   373  		}
   374  	}
   375  
   376  	rw.close(reason)
   377  	errCh <- errRW
   378  }
   379  
   380  func (p *Peer) pingLoop(rw *conn) {
   381  	ping := time.NewTimer(pingInterval)
   382  	defer p.wg.Done()
   383  	defer ping.Stop()
   384  	for {
   385  		select {
   386  		case <-ping.C:
   387  			if err := SendItems(rw, pingMsg); err != nil {
   388  				p.protoErr <- err
   389  				logger.Debug(fmt.Sprintf("pingLoop stopped, peer: %v", p.ID()))
   390  				return
   391  			}
   392  			ping.Reset(pingInterval)
   393  		case <-p.closed:
   394  			logger.Debug(fmt.Sprintf("pingLoop stopped, peer: %v", p.ID()))
   395  			return
   396  		}
   397  	}
   398  }
   399  
   400  func (p *Peer) readLoop(connectionOrder int, rw *conn, errc chan<- error) {
   401  	defer p.wg.Done()
   402  	for {
   403  		msg, err := rw.ReadMsg()
   404  		if err != nil {
   405  			errc <- err
   406  			logger.Debug(fmt.Sprintf("readLoop stopped, peer: %v", p.ID()))
   407  			return
   408  		}
   409  		msg.ReceivedAt = time.Now()
   410  		if err = p.handle(connectionOrder, rw, msg); err != nil {
   411  			errc <- err
   412  			logger.Debug(fmt.Sprintf("readLoop stopped, peer: %v", p.ID()))
   413  			return
   414  		}
   415  	}
   416  }
   417  
   418  func (p *Peer) handle(connectionOrder int, rw *conn, msg Msg) error {
   419  	switch {
   420  	case msg.Code == pingMsg:
   421  		msg.Discard()
   422  		go SendItems(rw, pongMsg)
   423  	case msg.Code == discMsg:
   424  		// This is the last message. We don't need to discard or
   425  		// check errors because, the connection will be closed after it.
   426  		var m struct{ R DiscReason }
   427  		rlp.Decode(msg.Payload, &m)
   428  		return m.R
   429  	case msg.Code < baseProtocolLength:
   430  		// ignore other base protocol messages
   431  		return msg.Discard()
   432  	default:
   433  		// it's a subprotocol message
   434  		proto, err := p.getProto(connectionOrder, msg.Code)
   435  		if err != nil {
   436  			return fmt.Errorf("msg code out of range: %v", msg.Code)
   437  		}
   438  		select {
   439  		case proto.in <- msg:
   440  			return nil
   441  		case <-p.closed:
   442  			return io.EOF
   443  		}
   444  	}
   445  	return nil
   446  }
   447  
   448  func countMatchingProtocols(protocols []Protocol, caps []Cap) int {
   449  	n := 0
   450  	for _, cap := range caps {
   451  		for _, proto := range protocols {
   452  			if proto.Name == cap.Name && proto.Version == cap.Version {
   453  				n++
   454  			}
   455  		}
   456  	}
   457  	return n
   458  }
   459  
   460  // matchProtocols creates structures for matching named subprotocols.
   461  func matchProtocols(protocols []Protocol, caps []Cap, rws []MsgReadWriter, tc RWTimerConfig) map[string][]*protoRW {
   462  	sort.Sort(capsByNameAndVersion(caps))
   463  	offset := baseProtocolLength
   464  	result := make(map[string][]*protoRW)
   465  
   466  outer:
   467  	for _, cap := range caps {
   468  		for _, proto := range protocols {
   469  			if proto.Name == cap.Name && proto.Version == cap.Version {
   470  				// If an old protocol version matched, revert it
   471  				if old := result[cap.Name]; old != nil {
   472  					offset -= old[ConnDefault].Length
   473  				}
   474  				// Assign the new match
   475  				protoRWs := make([]*protoRW, 0, len(rws))
   476  				if rws == nil || len(rws) == 0 {
   477  					protoRWs = []*protoRW{{Protocol: proto, offset: offset, in: make(chan Msg), w: nil, tc: tc}}
   478  				} else {
   479  					for _, rw := range rws {
   480  						protoRWs = append(protoRWs, &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw, tc: tc})
   481  					}
   482  				}
   483  				result[cap.Name] = protoRWs
   484  				offset += proto.Length
   485  
   486  				continue outer
   487  			}
   488  		}
   489  	}
   490  	return result
   491  }
   492  
   493  func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) {
   494  	p.wg.Add(len(p.running))
   495  	for _, protos := range p.running {
   496  		if len(protos) != 1 {
   497  			p.logger.Error("The size of protos should be 1", "size", len(protos))
   498  			p.protoErr <- errProtocolReturned
   499  			return
   500  		}
   501  		proto := protos[ConnDefault]
   502  		proto.closed = p.closed
   503  		proto.wstart = writeStart
   504  		proto.werr = writeErr
   505  		proto.tc = defaultRWTimerConfig
   506  		var rw MsgReadWriter = proto
   507  		if p.events != nil {
   508  			rw = newMsgEventer(rw, p.events, p.ID(), proto.Name)
   509  		}
   510  		p.logger.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version))
   511  		go func() {
   512  			// p.wg.Add(1)
   513  			defer p.wg.Done()
   514  			err := proto.Run(p, rw)
   515  			if err == nil {
   516  				p.logger.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version))
   517  				err = errProtocolReturned
   518  			} else if err != io.EOF {
   519  				p.logger.Error(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
   520  			}
   521  			p.protoErr <- err
   522  			p.logger.Debug(fmt.Sprintf("Protocol go routine stopped, peer: %v", p.ID()))
   523  			// p.wg.Done()
   524  		}()
   525  	}
   526  }
   527  
   528  // startProtocolsWithRWs run the protocol using several RWs.
   529  func (p *Peer) startProtocolsWithRWs(writeStarts []chan struct{}, writeErrs []chan error) {
   530  	p.wg.Add(len(p.running))
   531  
   532  	for _, protos := range p.running {
   533  		rws := make([]MsgReadWriter, 0, len(protos))
   534  		protos := protos
   535  		for i, proto := range protos {
   536  			proto.closed = p.closed
   537  			if len(writeStarts) > i {
   538  				proto.wstart = writeStarts[i]
   539  			} else {
   540  				writeErrs[i] <- errors.New("WriteStartsChannelSize")
   541  			}
   542  			proto.werr = writeErrs[i]
   543  
   544  			var rw MsgReadWriter = proto
   545  			if p.events != nil {
   546  				rw = newMsgEventer(rw, p.events, p.ID(), proto.Name)
   547  			}
   548  			rws = append(rws, rw)
   549  		}
   550  
   551  		p.logger.Trace(fmt.Sprintf("Starting protocol %s/%d", protos[ConnDefault].Name, protos[ConnDefault].Version))
   552  		go func() {
   553  			// p.wg.Add(1)
   554  			defer p.wg.Done()
   555  			err := protos[ConnDefault].RunWithRWs(p, rws)
   556  			if err == nil {
   557  				p.logger.Trace(fmt.Sprintf("Protocol %s/%d returned", protos[ConnDefault].Name, protos[ConnDefault].Version))
   558  				err = errProtocolReturned
   559  			} else if err != io.EOF {
   560  				p.logger.Error(fmt.Sprintf("Protocol %s/%d failed", protos[ConnDefault].Name, protos[ConnDefault].Version), "err", err)
   561  			}
   562  			p.protoErr <- err
   563  			p.logger.Debug(fmt.Sprintf("Protocol go routine stopped, peer: %v", p.ID()))
   564  			// p.wg.Done()
   565  		}()
   566  	}
   567  }
   568  
   569  // getProto finds the protocol responsible for handling
   570  // the given message code.
   571  func (p *Peer) getProto(connectionOrder int, code uint64) (*protoRW, error) {
   572  	for _, proto := range p.running {
   573  		if code >= proto[connectionOrder].offset && code < proto[connectionOrder].offset+proto[connectionOrder].Length {
   574  			return proto[connectionOrder], nil
   575  		}
   576  	}
   577  	return nil, newPeerError(errInvalidMsgCode, "%d", code)
   578  }
   579  
   580  type RWTimerConfig struct {
   581  	Interval uint64
   582  	WaitTime time.Duration
   583  }
   584  
   585  var defaultRWTimerConfig = RWTimerConfig{1000, 15 * time.Second}
   586  
   587  type protoRW struct {
   588  	Protocol
   589  	in     chan Msg        // receices read messages
   590  	closed <-chan struct{} // receives when peer is shutting down
   591  	wstart <-chan struct{} // receives when write may start
   592  	werr   chan<- error    // for write results
   593  	offset uint64
   594  	w      MsgWriter
   595  	count  uint64 // count the number of WriteMsg calls
   596  	tc     RWTimerConfig
   597  }
   598  
   599  func (rw *protoRW) WriteMsg(msg Msg) (err error) {
   600  	if msg.Code >= rw.Length {
   601  		return newPeerError(errInvalidMsgCode, "not handled, (code %x) (size %d)", msg.Code, msg.Size)
   602  	}
   603  	msg.Code += rw.offset
   604  	rwCount := atomic.AddUint64(&rw.count, 1)
   605  	if rwCount%rw.tc.Interval == 0 {
   606  		timer := time.NewTimer(rw.tc.WaitTime)
   607  		defer timer.Stop()
   608  		select {
   609  		case <-rw.wstart:
   610  			err = rw.w.WriteMsg(msg)
   611  			// Report write status back to Peer.run. It will initiate
   612  			// shutdown if the error is non-nil and unblock the next write
   613  			// otherwise. The calling protocol code should exit for errors
   614  			// as well but we don't want to rely on that.
   615  		case <-rw.closed:
   616  			err = fmt.Errorf("shutting down")
   617  			return err
   618  		case <-timer.C:
   619  			writeMsgTimeOutCounter.Inc(1)
   620  			err = fmt.Errorf("failed to write message for %v", rw.tc.WaitTime)
   621  		}
   622  	} else {
   623  		select {
   624  		case <-rw.wstart:
   625  			err = rw.w.WriteMsg(msg)
   626  		case <-rw.closed:
   627  			err = fmt.Errorf("shutting down")
   628  			return err
   629  		}
   630  	}
   631  	select {
   632  	case rw.werr <- err:
   633  	default:
   634  	}
   635  	return err
   636  }
   637  
   638  func (rw *protoRW) ReadMsg() (Msg, error) {
   639  	select {
   640  	case msg := <-rw.in:
   641  		msg.Code -= rw.offset
   642  		return msg, nil
   643  	case <-rw.closed:
   644  		return Msg{}, io.EOF
   645  	}
   646  }
   647  
   648  // NetworkInfo represents the connection information with the peer.
   649  type NetworkInfo struct {
   650  	LocalAddress  string `json:"localAddress"`  // Local endpoint of the TCP data connection
   651  	RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection
   652  	Inbound       bool   `json:"inbound"`
   653  	Trusted       bool   `json:"trusted"`
   654  	Static        bool   `json:"static"`
   655  	NodeType      string `json:"nodeType"`
   656  }
   657  
   658  // PeerInfo represents a short summary of the information known about a connected
   659  // peer. Sub-protocol independent fields are contained and initialized here, with
   660  // protocol specifics delegated to all connected sub-protocols.
   661  type PeerInfo struct {
   662  	ID        string                 `json:"id"`        // Unique node identifier (also the encryption key)
   663  	Name      string                 `json:"name"`      // Name of the node, including client type, version, OS, custom data
   664  	Caps      []string               `json:"caps"`      // Sum-protocols advertised by this particular peer
   665  	Networks  []NetworkInfo          `json:"networks"`  // Networks is all the NetworkInfo associated with the peer
   666  	Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields
   667  }
   668  
   669  // Info gathers and returns a collection of metadata known about a peer.
   670  func (p *Peer) Info() *PeerInfo {
   671  	// Gather the protocol capabilities
   672  	var caps []string
   673  	for _, cap := range p.Caps() {
   674  		caps = append(caps, cap.String())
   675  	}
   676  	// Assemble the generic peer metadata
   677  	info := &PeerInfo{
   678  		ID:        p.ID().String(),
   679  		Name:      p.Name(),
   680  		Caps:      caps,
   681  		Protocols: make(map[string]interface{}),
   682  	}
   683  
   684  	for _, rw := range p.rws {
   685  		var network NetworkInfo
   686  		network.LocalAddress = rw.fd.LocalAddr().String()
   687  		network.RemoteAddress = rw.fd.RemoteAddr().String()
   688  		network.Inbound = rw.is(inboundConn)
   689  		network.Trusted = rw.is(trustedConn)
   690  		network.Static = rw.is(staticDialedConn)
   691  		switch rw.conntype {
   692  		case common.CONSENSUSNODE:
   693  			network.NodeType = "cn"
   694  		case common.ENDPOINTNODE:
   695  			network.NodeType = "en"
   696  		case common.PROXYNODE:
   697  			network.NodeType = "pn"
   698  		case common.BOOTNODE:
   699  			network.NodeType = "bn"
   700  		default:
   701  			network.NodeType = "unknown"
   702  		}
   703  		info.Networks = append(info.Networks, network)
   704  	}
   705  
   706  	// Gather all the running protocol infos
   707  	for _, proto := range p.running {
   708  		protoInfo := interface{}("unknown")
   709  		if query := proto[ConnDefault].Protocol.PeerInfo; query != nil {
   710  			if metadata := query(p.ID()); metadata != nil {
   711  				protoInfo = metadata
   712  			} else {
   713  				protoInfo = "handshake"
   714  			}
   715  		}
   716  		info.Protocols[proto[ConnDefault].Name] = protoInfo
   717  	}
   718  	return info
   719  }
   720  
   721  func (p *Peer) ConnType() common.ConnType {
   722  	return p.rws[ConnDefault].conntype
   723  }
   724  
   725  type PeerTypeValidator interface {
   726  	// ValidatePeerType returns nil if successful. Otherwise, it returns an error object.
   727  	ValidatePeerType(addr common.Address) error
   728  }