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