github.com/okex/exchain@v1.8.0/libs/tendermint/p2p/peer.go (about)

     1  package p2p
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/go-kit/kit/metrics"
     9  
    10  	"github.com/okex/exchain/libs/tendermint/libs/cmap"
    11  	"github.com/okex/exchain/libs/tendermint/libs/log"
    12  	"github.com/okex/exchain/libs/tendermint/libs/service"
    13  
    14  	tmconn "github.com/okex/exchain/libs/tendermint/p2p/conn"
    15  )
    16  
    17  const metricsTickerDuration = 10 * time.Second
    18  
    19  var chIdStrTable = [256]string{
    20  	"0x0", "0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", "0x8", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
    21  	"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f",
    22  	"0x20", "0x21", "0x22", "0x23", "0x24", "0x25", "0x26", "0x27", "0x28", "0x29", "0x2a", "0x2b", "0x2c", "0x2d", "0x2e", "0x2f",
    23  	"0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "0x3f",
    24  	"0x40", "0x41", "0x42", "0x43", "0x44", "0x45", "0x46", "0x47", "0x48", "0x49", "0x4a", "0x4b", "0x4c", "0x4d", "0x4e", "0x4f",
    25  	"0x50", "0x51", "0x52", "0x53", "0x54", "0x55", "0x56", "0x57", "0x58", "0x59", "0x5a", "0x5b", "0x5c", "0x5d", "0x5e", "0x5f",
    26  	"0x60", "0x61", "0x62", "0x63", "0x64", "0x65", "0x66", "0x67", "0x68", "0x69", "0x6a", "0x6b", "0x6c", "0x6d", "0x6e", "0x6f",
    27  	"0x70", "0x71", "0x72", "0x73", "0x74", "0x75", "0x76", "0x77", "0x78", "0x79", "0x7a", "0x7b", "0x7c", "0x7d", "0x7e", "0x7f",
    28  	"0x80", "0x81", "0x82", "0x83", "0x84", "0x85", "0x86", "0x87", "0x88", "0x89", "0x8a", "0x8b", "0x8c", "0x8d", "0x8e", "0x8f",
    29  	"0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96", "0x97", "0x98", "0x99", "0x9a", "0x9b", "0x9c", "0x9d", "0x9e", "0x9f",
    30  	"0xa0", "0xa1", "0xa2", "0xa3", "0xa4", "0xa5", "0xa6", "0xa7", "0xa8", "0xa9", "0xaa", "0xab", "0xac", "0xad", "0xae", "0xaf",
    31  	"0xb0", "0xb1", "0xb2", "0xb3", "0xb4", "0xb5", "0xb6", "0xb7", "0xb8", "0xb9", "0xba", "0xbb", "0xbc", "0xbd", "0xbe", "0xbf",
    32  	"0xc0", "0xc1", "0xc2", "0xc3", "0xc4", "0xc5", "0xc6", "0xc7", "0xc8", "0xc9", "0xca", "0xcb", "0xcc", "0xcd", "0xce", "0xcf",
    33  	"0xd0", "0xd1", "0xd2", "0xd3", "0xd4", "0xd5", "0xd6", "0xd7", "0xd8", "0xd9", "0xda", "0xdb", "0xdc", "0xdd", "0xde", "0xdf",
    34  	"0xe0", "0xe1", "0xe2", "0xe3", "0xe4", "0xe5", "0xe6", "0xe7", "0xe8", "0xe9", "0xea", "0xeb", "0xec", "0xed", "0xee", "0xef",
    35  	"0xf0", "0xf1", "0xf2", "0xf3", "0xf4", "0xf5", "0xf6", "0xf7", "0xf8", "0xf9", "0xfa", "0xfb", "0xfc", "0xfd", "0xfe", "0xff",
    36  }
    37  
    38  func getChIdStr(chID byte) string {
    39  	// fmt.Sprintf("%#x", chID),
    40  	return chIdStrTable[chID]
    41  }
    42  
    43  // Peer is an interface representing a peer connected on a reactor.
    44  type Peer interface {
    45  	service.Service
    46  	FlushStop()
    47  
    48  	ID() ID               // peer's cryptographic ID
    49  	RemoteIP() net.IP     // remote IP of the connection
    50  	RemoteAddr() net.Addr // remote address of the connection
    51  
    52  	IsOutbound() bool   // did we dial the peer
    53  	IsPersistent() bool // do we redial this peer when we disconnect
    54  
    55  	CloseConn() error // close original connection
    56  
    57  	NodeInfo() NodeInfo // peer's info
    58  	Status() tmconn.ConnectionStatus
    59  	SocketAddr() *NetAddress // actual address of the socket
    60  
    61  	Send(byte, []byte) bool
    62  	TrySend(byte, []byte) bool
    63  
    64  	Set(string, interface{})
    65  	Get(string) interface{}
    66  }
    67  
    68  //----------------------------------------------------------
    69  
    70  // peerConn contains the raw connection and its config.
    71  type peerConn struct {
    72  	outbound   bool
    73  	persistent bool
    74  	conn       net.Conn // source connection
    75  
    76  	socketAddr *NetAddress
    77  
    78  	// cached RemoteIP()
    79  	ip net.IP
    80  }
    81  
    82  func newPeerConn(
    83  	outbound, persistent bool,
    84  	conn net.Conn,
    85  	socketAddr *NetAddress,
    86  ) peerConn {
    87  
    88  	return peerConn{
    89  		outbound:   outbound,
    90  		persistent: persistent,
    91  		conn:       conn,
    92  		socketAddr: socketAddr,
    93  	}
    94  }
    95  
    96  // ID only exists for SecretConnection.
    97  // NOTE: Will panic if conn is not *SecretConnection.
    98  func (pc peerConn) ID() ID {
    99  	return PubKeyToID(pc.conn.(*tmconn.SecretConnection).RemotePubKey())
   100  }
   101  
   102  // Return the IP from the connection RemoteAddr
   103  func (pc peerConn) RemoteIP() net.IP {
   104  	if pc.ip != nil {
   105  		return pc.ip
   106  	}
   107  
   108  	host, _, err := net.SplitHostPort(pc.conn.RemoteAddr().String())
   109  	if err != nil {
   110  		panic(err)
   111  	}
   112  
   113  	ips, err := net.LookupIP(host)
   114  	if err != nil {
   115  		panic(err)
   116  	}
   117  
   118  	pc.ip = ips[0]
   119  
   120  	return pc.ip
   121  }
   122  
   123  // peer implements Peer.
   124  //
   125  // Before using a peer, you will need to perform a handshake on connection.
   126  type peer struct {
   127  	service.BaseService
   128  
   129  	// raw peerConn and the multiplex connection
   130  	peerConn
   131  	mconn *tmconn.MConnection
   132  
   133  	// peer's node info and the channel it knows about
   134  	// channels = nodeInfo.Channels
   135  	// cached to avoid copying nodeInfo in hasChannel
   136  	nodeInfo NodeInfo
   137  	channels []byte
   138  
   139  	// User data
   140  	Data *cmap.CMap
   141  
   142  	metrics       *Metrics
   143  	metricsTicker *time.Ticker
   144  	chMetrics     peerChMetric
   145  }
   146  
   147  type PeerOption func(*peer)
   148  
   149  func newPeer(
   150  	pc peerConn,
   151  	mConfig tmconn.MConnConfig,
   152  	nodeInfo NodeInfo,
   153  	reactorsByCh map[byte]Reactor,
   154  	chDescs []*tmconn.ChannelDescriptor,
   155  	onPeerError func(Peer, interface{}),
   156  	options ...PeerOption,
   157  ) *peer {
   158  	p := &peer{
   159  		peerConn:      pc,
   160  		nodeInfo:      nodeInfo,
   161  		channels:      nodeInfo.(DefaultNodeInfo).Channels, // TODO
   162  		Data:          cmap.NewCMap(),
   163  		metricsTicker: time.NewTicker(metricsTickerDuration),
   164  		metrics:       NopMetrics(),
   165  	}
   166  
   167  	p.mconn = createMConnection(
   168  		pc.conn,
   169  		p,
   170  		reactorsByCh,
   171  		chDescs,
   172  		onPeerError,
   173  		mConfig,
   174  	)
   175  	p.BaseService = *service.NewBaseService(nil, "Peer", p)
   176  	for _, option := range options {
   177  		option(p)
   178  	}
   179  
   180  	p.chMetrics = peerChMetric{
   181  		PeerSendBytesTotal:    make(map[byte]metrics.Counter),
   182  		PeerReceiveBytesTotal: make(map[byte]metrics.Counter),
   183  	}
   184  
   185  	if p.metrics != nil {
   186  		pid := string(p.ID())
   187  		for _, ch := range p.channels {
   188  			p.chMetrics.PeerSendBytesTotal[ch] = p.metrics.PeerSendBytesTotal.With("peer_id", pid, "chID", getChIdStr(ch))
   189  			p.chMetrics.PeerReceiveBytesTotal[ch] = p.metrics.PeerReceiveBytesTotal.With("peer_id", pid, "chID", getChIdStr(ch))
   190  		}
   191  	}
   192  
   193  	return p
   194  }
   195  
   196  // String representation.
   197  func (p *peer) String() string {
   198  	if p.outbound {
   199  		return fmt.Sprintf("Peer{%v %v out}", p.mconn, p.ID())
   200  	}
   201  
   202  	return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.ID())
   203  }
   204  
   205  //---------------------------------------------------
   206  // Implements service.Service
   207  
   208  // SetLogger implements BaseService.
   209  func (p *peer) SetLogger(l log.Logger) {
   210  	p.Logger = l
   211  	p.mconn.SetLogger(l)
   212  }
   213  
   214  // OnStart implements BaseService.
   215  func (p *peer) OnStart() error {
   216  	if err := p.BaseService.OnStart(); err != nil {
   217  		return err
   218  	}
   219  
   220  	if err := p.mconn.Start(); err != nil {
   221  		return err
   222  	}
   223  
   224  	go p.metricsReporter()
   225  	return nil
   226  }
   227  
   228  // FlushStop mimics OnStop but additionally ensures that all successful
   229  // .Send() calls will get flushed before closing the connection.
   230  // NOTE: it is not safe to call this method more than once.
   231  func (p *peer) FlushStop() {
   232  	p.metricsTicker.Stop()
   233  	p.BaseService.OnStop()
   234  	p.mconn.FlushStop() // stop everything and close the conn
   235  }
   236  
   237  // OnStop implements BaseService.
   238  func (p *peer) OnStop() {
   239  	p.metricsTicker.Stop()
   240  	p.BaseService.OnStop()
   241  	p.mconn.Stop() // stop everything and close the conn
   242  }
   243  
   244  //---------------------------------------------------
   245  // Implements Peer
   246  
   247  // ID returns the peer's ID - the hex encoded hash of its pubkey.
   248  func (p *peer) ID() ID {
   249  	return p.nodeInfo.ID()
   250  }
   251  
   252  // IsOutbound returns true if the connection is outbound, false otherwise.
   253  func (p *peer) IsOutbound() bool {
   254  	return p.peerConn.outbound
   255  }
   256  
   257  // IsPersistent returns true if the peer is persitent, false otherwise.
   258  func (p *peer) IsPersistent() bool {
   259  	return p.peerConn.persistent
   260  }
   261  
   262  // NodeInfo returns a copy of the peer's NodeInfo.
   263  func (p *peer) NodeInfo() NodeInfo {
   264  	return p.nodeInfo
   265  }
   266  
   267  // SocketAddr returns the address of the socket.
   268  // For outbound peers, it's the address dialed (after DNS resolution).
   269  // For inbound peers, it's the address returned by the underlying connection
   270  // (not what's reported in the peer's NodeInfo).
   271  func (p *peer) SocketAddr() *NetAddress {
   272  	return p.peerConn.socketAddr
   273  }
   274  
   275  // Status returns the peer's ConnectionStatus.
   276  func (p *peer) Status() tmconn.ConnectionStatus {
   277  	return p.mconn.Status()
   278  }
   279  
   280  // Send msg bytes to the channel identified by chID byte. Returns false if the
   281  // send queue is full after timeout, specified by MConnection.
   282  func (p *peer) Send(chID byte, msgBytes []byte) bool {
   283  	if !p.IsRunning() {
   284  		// see Switch#Broadcast, where we fetch the list of peers and loop over
   285  		// them - while we're looping, one peer may be removed and stopped.
   286  		return false
   287  	} else if !p.hasChannel(chID) {
   288  		return false
   289  	}
   290  	res := p.mconn.Send(chID, msgBytes)
   291  	if res {
   292  		p.updateSendBytesTotalMetrics(chID, len(msgBytes))
   293  	}
   294  	return res
   295  }
   296  
   297  // TrySend msg bytes to the channel identified by chID byte. Immediately returns
   298  // false if the send queue is full.
   299  func (p *peer) TrySend(chID byte, msgBytes []byte) bool {
   300  	if !p.IsRunning() {
   301  		return false
   302  	} else if !p.hasChannel(chID) {
   303  		return false
   304  	}
   305  	res := p.mconn.TrySend(chID, msgBytes)
   306  	if res {
   307  		p.updateSendBytesTotalMetrics(chID, len(msgBytes))
   308  	}
   309  	return res
   310  }
   311  
   312  // Get the data for a given key.
   313  func (p *peer) Get(key string) interface{} {
   314  	return p.Data.Get(key)
   315  }
   316  
   317  // Set sets the data for the given key.
   318  func (p *peer) Set(key string, data interface{}) {
   319  	p.Data.Set(key, data)
   320  }
   321  
   322  // hasChannel returns true if the peer reported
   323  // knowing about the given chID.
   324  func (p *peer) hasChannel(chID byte) bool {
   325  	for _, ch := range p.channels {
   326  		if ch == chID {
   327  			return true
   328  		}
   329  	}
   330  	// NOTE: probably will want to remove this
   331  	// but could be helpful while the feature is new
   332  	p.Logger.Debug(
   333  		"Unknown channel for peer",
   334  		"channel",
   335  		chID,
   336  		"channels",
   337  		p.channels,
   338  	)
   339  	return false
   340  }
   341  
   342  // CloseConn closes original connection. Used for cleaning up in cases where the peer had not been started at all.
   343  func (p *peer) CloseConn() error {
   344  	return p.peerConn.conn.Close()
   345  }
   346  
   347  //---------------------------------------------------
   348  // methods only used for testing
   349  // TODO: can we remove these?
   350  
   351  // CloseConn closes the underlying connection
   352  func (pc *peerConn) CloseConn() {
   353  	pc.conn.Close() // nolint: errcheck
   354  }
   355  
   356  // RemoteAddr returns peer's remote network address.
   357  func (p *peer) RemoteAddr() net.Addr {
   358  	return p.peerConn.conn.RemoteAddr()
   359  }
   360  
   361  // CanSend returns true if the send queue is not full, false otherwise.
   362  func (p *peer) CanSend(chID byte) bool {
   363  	if !p.IsRunning() {
   364  		return false
   365  	}
   366  	return p.mconn.CanSend(chID)
   367  }
   368  
   369  //---------------------------------------------------
   370  
   371  func PeerMetrics(metrics *Metrics) PeerOption {
   372  	return func(p *peer) {
   373  		p.metrics = metrics
   374  	}
   375  }
   376  
   377  func (p *peer) metricsReporter() {
   378  	for {
   379  		select {
   380  		case <-p.metricsTicker.C:
   381  			status := p.mconn.Status()
   382  			var sendQueueSize float64
   383  			for _, chStatus := range status.Channels {
   384  				sendQueueSize += float64(chStatus.SendQueueSize)
   385  			}
   386  
   387  			p.metrics.PeerPendingSendBytes.With("peer_id", string(p.ID())).Set(sendQueueSize)
   388  		case <-p.Quit():
   389  			return
   390  		}
   391  	}
   392  }
   393  
   394  func (p *peer) updateSendBytesTotalMetrics(chID byte, msgBytesLen int) {
   395  	if counter, ok := p.chMetrics.PeerSendBytesTotal[chID]; ok {
   396  		counter.Add(float64(msgBytesLen))
   397  	} else {
   398  		labels := []string{
   399  			"peer_id", string(p.ID()),
   400  			"chID", getChIdStr(chID),
   401  		}
   402  		p.metrics.PeerSendBytesTotal.With(labels...).Add(float64(msgBytesLen))
   403  	}
   404  }
   405  
   406  func (p *peer) updateReceiveBytesTotalMetrics(chID byte, msgBytesLen int) {
   407  	if counter, ok := p.chMetrics.PeerReceiveBytesTotal[chID]; ok {
   408  		counter.Add(float64(msgBytesLen))
   409  	} else {
   410  		labels := []string{
   411  			"peer_id", string(p.ID()),
   412  			"chID", getChIdStr(chID),
   413  		}
   414  		p.metrics.PeerReceiveBytesTotal.With(labels...).Add(float64(msgBytesLen))
   415  	}
   416  }
   417  
   418  //------------------------------------------------------------------
   419  // helper funcs
   420  
   421  func createMConnection(
   422  	conn net.Conn,
   423  	p *peer,
   424  	reactorsByCh map[byte]Reactor,
   425  	chDescs []*tmconn.ChannelDescriptor,
   426  	onPeerError func(Peer, interface{}),
   427  	config tmconn.MConnConfig,
   428  ) *tmconn.MConnection {
   429  
   430  	onReceive := func(chID byte, msgBytes []byte) {
   431  		reactor := reactorsByCh[chID]
   432  		if reactor == nil {
   433  			// Note that its ok to panic here as it's caught in the conn._recover,
   434  			// which does onPeerError.
   435  			panic(fmt.Sprintf("Unknown channel %X", chID))
   436  		}
   437  		p.updateReceiveBytesTotalMetrics(chID, len(msgBytes))
   438  		reactor.Receive(chID, p, msgBytes)
   439  	}
   440  
   441  	onError := func(r interface{}) {
   442  		onPeerError(p, r)
   443  	}
   444  
   445  	return tmconn.NewMConnectionWithConfig(
   446  		conn,
   447  		chDescs,
   448  		onReceive,
   449  		onError,
   450  		config,
   451  	)
   452  }