github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/p2p/peer.go (about)

     1  package p2p
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"reflect"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/btcsuite/go-socks/socks"
    11  	"github.com/pkg/errors"
    12  	log "github.com/sirupsen/logrus"
    13  	"github.com/tendermint/go-crypto"
    14  	"github.com/tendermint/go-wire"
    15  	cmn "github.com/tendermint/tmlibs/common"
    16  	"github.com/tendermint/tmlibs/flowrate"
    17  
    18  	cfg "github.com/bytom/bytom/config"
    19  	"github.com/bytom/bytom/consensus"
    20  	"github.com/bytom/bytom/p2p/connection"
    21  )
    22  
    23  // peerConn contains the raw connection and its config.
    24  type peerConn struct {
    25  	outbound bool
    26  	config   *PeerConfig
    27  	conn     net.Conn // source connection
    28  }
    29  
    30  // PeerConfig is a Peer configuration.
    31  type PeerConfig struct {
    32  	HandshakeTimeout time.Duration           `mapstructure:"handshake_timeout"` // times are in seconds
    33  	DialTimeout      time.Duration           `mapstructure:"dial_timeout"`
    34  	ProxyAddress     string                  `mapstructure:"proxy_address"`
    35  	ProxyUsername    string                  `mapstructure:"proxy_username"`
    36  	ProxyPassword    string                  `mapstructure:"proxy_password"`
    37  	MConfig          *connection.MConnConfig `mapstructure:"connection"`
    38  }
    39  
    40  // DefaultPeerConfig returns the default config.
    41  func DefaultPeerConfig(config *cfg.P2PConfig) *PeerConfig {
    42  	return &PeerConfig{
    43  		HandshakeTimeout: time.Duration(config.HandshakeTimeout) * time.Second, // * time.Second,
    44  		DialTimeout:      time.Duration(config.DialTimeout) * time.Second,      // * time.Second,
    45  		ProxyAddress:     config.ProxyAddress,
    46  		ProxyUsername:    config.ProxyUsername,
    47  		ProxyPassword:    config.ProxyPassword,
    48  		MConfig:          connection.DefaultMConnConfig(),
    49  	}
    50  }
    51  
    52  // Peer represent a bytom network node
    53  type Peer struct {
    54  	cmn.BaseService
    55  	*NodeInfo
    56  	*peerConn
    57  	mconn *connection.MConnection // multiplex connection
    58  	Key   string
    59  	isLAN bool
    60  }
    61  
    62  // OnStart implements BaseService.
    63  func (p *Peer) OnStart() error {
    64  	p.BaseService.OnStart()
    65  	_, err := p.mconn.Start()
    66  	return err
    67  }
    68  
    69  // OnStop implements BaseService.
    70  func (p *Peer) OnStop() {
    71  	p.BaseService.OnStop()
    72  	p.mconn.Stop()
    73  }
    74  
    75  func newPeer(pc *peerConn, nodeInfo *NodeInfo, reactorsByCh map[byte]Reactor, chDescs []*connection.ChannelDescriptor, onPeerError func(*Peer, interface{}), isLAN bool) *Peer {
    76  	// Key and NodeInfo are set after Handshake
    77  	p := &Peer{
    78  		peerConn: pc,
    79  		NodeInfo: nodeInfo,
    80  		Key:      nodeInfo.PubKey.KeyString(),
    81  		isLAN:    isLAN,
    82  	}
    83  	p.mconn = createMConnection(pc.conn, p, reactorsByCh, chDescs, onPeerError, pc.config.MConfig)
    84  	p.BaseService = *cmn.NewBaseService(nil, "Peer", p)
    85  	return p
    86  }
    87  
    88  func newOutboundPeerConn(addr *NetAddress, ourNodePrivKey crypto.PrivKeyEd25519, config *PeerConfig) (*peerConn, error) {
    89  	conn, err := dial(addr, config)
    90  	if err != nil {
    91  		return nil, errors.Wrap(err, "Error dial peer")
    92  	}
    93  
    94  	pc, err := newPeerConn(conn, true, ourNodePrivKey, config)
    95  	if err != nil {
    96  		conn.Close()
    97  		return nil, err
    98  	}
    99  	return pc, nil
   100  }
   101  
   102  func newInboundPeerConn(conn net.Conn, ourNodePrivKey crypto.PrivKeyEd25519, config *cfg.P2PConfig) (*peerConn, error) {
   103  	return newPeerConn(conn, false, ourNodePrivKey, DefaultPeerConfig(config))
   104  }
   105  
   106  func newPeerConn(rawConn net.Conn, outbound bool, ourNodePrivKey crypto.PrivKeyEd25519, config *PeerConfig) (*peerConn, error) {
   107  	rawConn.SetDeadline(time.Now().Add(config.HandshakeTimeout))
   108  	conn, err := connection.MakeSecretConnection(rawConn, ourNodePrivKey)
   109  	if err != nil {
   110  		return nil, errors.Wrap(err, "Error creating peer")
   111  	}
   112  
   113  	return &peerConn{
   114  		config:   config,
   115  		outbound: outbound,
   116  		conn:     conn,
   117  	}, nil
   118  }
   119  
   120  // Addr returns peer's remote network address.
   121  func (p *Peer) Addr() net.Addr {
   122  	return p.conn.RemoteAddr()
   123  }
   124  
   125  // CanSend returns true if the send queue is not full, false otherwise.
   126  func (p *Peer) CanSend(chID byte) bool {
   127  	if !p.IsRunning() {
   128  		return false
   129  	}
   130  	return p.mconn.CanSend(chID)
   131  }
   132  
   133  // CloseConn should be used when the peer was created, but never started.
   134  func (pc *peerConn) CloseConn() {
   135  	pc.conn.Close()
   136  }
   137  
   138  // Equals reports whenever 2 peers are actually represent the same node.
   139  func (p *Peer) Equals(other *Peer) bool {
   140  	return p.Key == other.Key
   141  }
   142  
   143  // HandshakeTimeout performs a handshake between a given node and the peer.
   144  // NOTE: blocking
   145  func (pc *peerConn) HandshakeTimeout(ourNodeInfo *NodeInfo, timeout time.Duration) (*NodeInfo, error) {
   146  	// Set deadline for handshake so we don't block forever on conn.ReadFull
   147  	if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	var peerNodeInfo = new(NodeInfo)
   152  	var err1, err2 error
   153  	cmn.Parallel(
   154  		func() {
   155  			var n int
   156  			wire.WriteBinary(ourNodeInfo, pc.conn, &n, &err1)
   157  		},
   158  		func() {
   159  			var n int
   160  			wire.ReadBinary(peerNodeInfo, pc.conn, maxNodeInfoSize, &n, &err2)
   161  			log.WithFields(log.Fields{"module": logModule, "address": pc.conn.RemoteAddr().String()}).Info("Peer handshake")
   162  		})
   163  	if err1 != nil {
   164  		return peerNodeInfo, errors.Wrap(err1, "Error during handshake/write")
   165  	}
   166  	if err2 != nil {
   167  		return peerNodeInfo, errors.Wrap(err2, "Error during handshake/read")
   168  	}
   169  
   170  	// Remove deadline
   171  	if err := pc.conn.SetDeadline(time.Time{}); err != nil {
   172  		return nil, err
   173  	}
   174  	peerNodeInfo.RemoteAddr = pc.conn.RemoteAddr().String()
   175  	return peerNodeInfo, nil
   176  }
   177  
   178  // ID return the uuid of the peer
   179  func (p *Peer) ID() string {
   180  	return p.Key
   181  }
   182  
   183  // IsOutbound returns true if the connection is outbound, false otherwise.
   184  func (p *Peer) IsOutbound() bool {
   185  	return p.outbound
   186  }
   187  
   188  // IsLAN returns true if peer is LAN peer, false otherwise.
   189  func (p *Peer) IsLAN() bool {
   190  	return p.isLAN
   191  }
   192  
   193  // PubKey returns peer's public key.
   194  func (p *Peer) PubKey() crypto.PubKeyEd25519 {
   195  	return p.conn.(*connection.SecretConnection).RemotePubKey()
   196  }
   197  
   198  // Send msg to the channel identified by chID byte. Returns false if the send
   199  // queue is full after timeout, specified by MConnection.
   200  func (p *Peer) Send(chID byte, msg interface{}) bool {
   201  	if !p.IsRunning() {
   202  		return false
   203  	}
   204  	return p.mconn.Send(chID, msg)
   205  }
   206  
   207  // ServiceFlag return the ServiceFlag of this peer
   208  func (p *Peer) ServiceFlag() consensus.ServiceFlag {
   209  	services := consensus.SFFullNode
   210  	if len(p.Other) == 0 {
   211  		return services
   212  	}
   213  
   214  	if serviceFlag, err := strconv.ParseUint(p.Other[0], 10, 64); err == nil {
   215  		services = consensus.ServiceFlag(serviceFlag)
   216  	}
   217  	return services
   218  }
   219  
   220  // String representation.
   221  func (p *Peer) String() string {
   222  	if p.outbound {
   223  		return fmt.Sprintf("Peer{%v %v out}", p.mconn, p.Key[:12])
   224  	}
   225  	return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.Key[:12])
   226  }
   227  
   228  // TrafficStatus return the in and out traffic status
   229  func (p *Peer) TrafficStatus() (*flowrate.Status, *flowrate.Status) {
   230  	return p.mconn.TrafficStatus()
   231  }
   232  
   233  // TrySend msg to the channel identified by chID byte. Immediately returns
   234  // false if the send queue is full.
   235  func (p *Peer) TrySend(chID byte, msg interface{}) bool {
   236  	if !p.IsRunning() {
   237  		return false
   238  	}
   239  
   240  	log.WithFields(log.Fields{
   241  		"module": logModule,
   242  		"peer":   p.Addr(),
   243  		"msg":    msg,
   244  		"type":   reflect.TypeOf(msg),
   245  	}).Info("send message to peer")
   246  	return p.mconn.TrySend(chID, msg)
   247  }
   248  
   249  func createMConnection(conn net.Conn, p *Peer, reactorsByCh map[byte]Reactor, chDescs []*connection.ChannelDescriptor, onPeerError func(*Peer, interface{}), config *connection.MConnConfig) *connection.MConnection {
   250  	onReceive := func(chID byte, msgBytes []byte) {
   251  		reactor := reactorsByCh[chID]
   252  		if reactor == nil {
   253  			cmn.PanicSanity(cmn.Fmt("Unknown channel %X", chID))
   254  		}
   255  		reactor.Receive(chID, p, msgBytes)
   256  	}
   257  
   258  	onError := func(r interface{}) {
   259  		onPeerError(p, r)
   260  	}
   261  	return connection.NewMConnectionWithConfig(conn, chDescs, onReceive, onError, config)
   262  }
   263  
   264  func dial(addr *NetAddress, config *PeerConfig) (net.Conn, error) {
   265  	var conn net.Conn
   266  	var err error
   267  	if config.ProxyAddress == "" {
   268  		conn, err = addr.DialTimeout(config.DialTimeout)
   269  	} else {
   270  		proxy := &socks.Proxy{
   271  			Addr:         config.ProxyAddress,
   272  			Username:     config.ProxyUsername,
   273  			Password:     config.ProxyPassword,
   274  			TorIsolation: false,
   275  		}
   276  		conn, err = addr.DialTimeoutWithProxy(proxy, config.DialTimeout)
   277  	}
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	return conn, nil
   282  }