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 }