github.com/phillinzzz/newBsc@v1.1.6/p2p/dial.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "context" 21 crand "crypto/rand" 22 "encoding/binary" 23 "errors" 24 "fmt" 25 mrand "math/rand" 26 "net" 27 "sync" 28 "time" 29 30 "github.com/phillinzzz/newBsc/common/gopool" 31 "github.com/phillinzzz/newBsc/common/mclock" 32 "github.com/phillinzzz/newBsc/log" 33 "github.com/phillinzzz/newBsc/p2p/enode" 34 "github.com/phillinzzz/newBsc/p2p/netutil" 35 ) 36 37 const ( 38 // This is the amount of time spent waiting in between redialing a certain node. The 39 // limit is a bit higher than inboundThrottleTime to prevent failing dials in small 40 // private networks. 41 dialHistoryExpiration = inboundThrottleTime + 5*time.Second 42 43 // Config for the "Looking for peers" message. 44 dialStatsLogInterval = 10 * time.Second // printed at most this often 45 dialStatsPeerLimit = 3 // but not if more than this many dialed peers 46 47 // Endpoint resolution is throttled with bounded backoff. 48 initialResolveDelay = 60 * time.Second 49 maxResolveDelay = time.Hour 50 ) 51 52 // NodeDialer is used to connect to nodes in the network, typically by using 53 // an underlying net.Dialer but also using net.Pipe in tests. 54 type NodeDialer interface { 55 Dial(context.Context, *enode.Node) (net.Conn, error) 56 } 57 58 type nodeResolver interface { 59 Resolve(*enode.Node) *enode.Node 60 } 61 62 // tcpDialer implements NodeDialer using real TCP connections. 63 type tcpDialer struct { 64 d *net.Dialer 65 } 66 67 func (t tcpDialer) Dial(ctx context.Context, dest *enode.Node) (net.Conn, error) { 68 return t.d.DialContext(ctx, "tcp", nodeAddr(dest).String()) 69 } 70 71 func nodeAddr(n *enode.Node) net.Addr { 72 return &net.TCPAddr{IP: n.IP(), Port: n.TCP()} 73 } 74 75 // checkDial errors: 76 var ( 77 errSelf = errors.New("is self") 78 errAlreadyDialing = errors.New("already dialing") 79 errAlreadyConnected = errors.New("already connected") 80 errRecentlyDialed = errors.New("recently dialed") 81 errNotWhitelisted = errors.New("not contained in netrestrict whitelist") 82 errNoPort = errors.New("node does not provide TCP port") 83 ) 84 85 // dialer creates outbound connections and submits them into Server. 86 // Two types of peer connections can be created: 87 // 88 // - static dials are pre-configured connections. The dialer attempts 89 // keep these nodes connected at all times. 90 // 91 // - dynamic dials are created from node discovery results. The dialer 92 // continuously reads candidate nodes from its input iterator and attempts 93 // to create peer connections to nodes arriving through the iterator. 94 // 95 type dialScheduler struct { 96 dialConfig 97 setupFunc dialSetupFunc 98 wg sync.WaitGroup 99 cancel context.CancelFunc 100 ctx context.Context 101 nodesIn chan *enode.Node 102 doneCh chan *dialTask 103 addStaticCh chan *enode.Node 104 remStaticCh chan *enode.Node 105 addPeerCh chan *conn 106 remPeerCh chan *conn 107 108 // Everything below here belongs to loop and 109 // should only be accessed by code on the loop goroutine. 110 dialing map[enode.ID]*dialTask // active tasks 111 peers map[enode.ID]connFlag // all connected peers 112 dialPeers int // current number of dialed peers 113 114 // The static map tracks all static dial tasks. The subset of usable static dial tasks 115 // (i.e. those passing checkDial) is kept in staticPool. The scheduler prefers 116 // launching random static tasks from the pool over launching dynamic dials from the 117 // iterator. 118 static map[enode.ID]*dialTask 119 staticPool []*dialTask 120 121 // The dial history keeps recently dialed nodes. Members of history are not dialed. 122 history expHeap 123 historyTimer mclock.Timer 124 historyTimerTime mclock.AbsTime 125 126 // for logStats 127 lastStatsLog mclock.AbsTime 128 doneSinceLastLog int 129 } 130 131 type dialSetupFunc func(net.Conn, connFlag, *enode.Node) error 132 133 type dialConfig struct { 134 self enode.ID // our own ID 135 maxDialPeers int // maximum number of dialed peers 136 maxActiveDials int // maximum number of active dials 137 netRestrict *netutil.Netlist // IP whitelist, disabled if nil 138 resolver nodeResolver 139 dialer NodeDialer 140 log log.Logger 141 clock mclock.Clock 142 rand *mrand.Rand 143 } 144 145 func (cfg dialConfig) withDefaults() dialConfig { 146 if cfg.maxActiveDials == 0 { 147 cfg.maxActiveDials = defaultMaxPendingPeers 148 } 149 if cfg.log == nil { 150 cfg.log = log.Root() 151 } 152 if cfg.clock == nil { 153 cfg.clock = mclock.System{} 154 } 155 if cfg.rand == nil { 156 seedb := make([]byte, 8) 157 crand.Read(seedb) 158 seed := int64(binary.BigEndian.Uint64(seedb)) 159 cfg.rand = mrand.New(mrand.NewSource(seed)) 160 } 161 return cfg 162 } 163 164 func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupFunc) *dialScheduler { 165 d := &dialScheduler{ 166 dialConfig: config.withDefaults(), 167 setupFunc: setupFunc, 168 dialing: make(map[enode.ID]*dialTask), 169 static: make(map[enode.ID]*dialTask), 170 peers: make(map[enode.ID]connFlag), 171 doneCh: make(chan *dialTask), 172 nodesIn: make(chan *enode.Node), 173 addStaticCh: make(chan *enode.Node), 174 remStaticCh: make(chan *enode.Node), 175 addPeerCh: make(chan *conn), 176 remPeerCh: make(chan *conn), 177 } 178 d.lastStatsLog = d.clock.Now() 179 d.ctx, d.cancel = context.WithCancel(context.Background()) 180 d.wg.Add(2) 181 gopool.Submit(func() { 182 d.readNodes(it) 183 }) 184 gopool.Submit( 185 func() { 186 d.loop(it) 187 }) 188 return d 189 } 190 191 // stop shuts down the dialer, canceling all current dial tasks. 192 func (d *dialScheduler) stop() { 193 d.cancel() 194 d.wg.Wait() 195 } 196 197 // addStatic adds a static dial candidate. 198 func (d *dialScheduler) addStatic(n *enode.Node) { 199 select { 200 case d.addStaticCh <- n: 201 case <-d.ctx.Done(): 202 } 203 } 204 205 // removeStatic removes a static dial candidate. 206 func (d *dialScheduler) removeStatic(n *enode.Node) { 207 select { 208 case d.remStaticCh <- n: 209 case <-d.ctx.Done(): 210 } 211 } 212 213 // peerAdded updates the peer set. 214 func (d *dialScheduler) peerAdded(c *conn) { 215 select { 216 case d.addPeerCh <- c: 217 case <-d.ctx.Done(): 218 } 219 } 220 221 // peerRemoved updates the peer set. 222 func (d *dialScheduler) peerRemoved(c *conn) { 223 select { 224 case d.remPeerCh <- c: 225 case <-d.ctx.Done(): 226 } 227 } 228 229 // loop is the main loop of the dialer. 230 func (d *dialScheduler) loop(it enode.Iterator) { 231 var ( 232 nodesCh chan *enode.Node 233 historyExp = make(chan struct{}, 1) 234 ) 235 236 loop: 237 for { 238 // Launch new dials if slots are available. 239 slots := d.freeDialSlots() 240 slots -= d.startStaticDials(slots) 241 if slots > 0 { 242 nodesCh = d.nodesIn 243 } else { 244 nodesCh = nil 245 } 246 d.rearmHistoryTimer(historyExp) 247 d.logStats() 248 249 select { 250 case node := <-nodesCh: 251 if err := d.checkDial(node); err != nil { 252 d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IP(), "reason", err) 253 } else { 254 d.startDial(newDialTask(node, dynDialedConn)) 255 } 256 257 case task := <-d.doneCh: 258 id := task.dest.ID() 259 delete(d.dialing, id) 260 d.updateStaticPool(id) 261 d.doneSinceLastLog++ 262 263 case c := <-d.addPeerCh: 264 if c.is(dynDialedConn) || c.is(staticDialedConn) { 265 d.dialPeers++ 266 } 267 id := c.node.ID() 268 d.peers[id] = c.flags 269 // Remove from static pool because the node is now connected. 270 task := d.static[id] 271 if task != nil && task.staticPoolIndex >= 0 { 272 d.removeFromStaticPool(task.staticPoolIndex) 273 } 274 // TODO: cancel dials to connected peers 275 276 case c := <-d.remPeerCh: 277 if c.is(dynDialedConn) || c.is(staticDialedConn) { 278 d.dialPeers-- 279 } 280 delete(d.peers, c.node.ID()) 281 d.updateStaticPool(c.node.ID()) 282 283 case node := <-d.addStaticCh: 284 id := node.ID() 285 _, exists := d.static[id] 286 d.log.Trace("Adding static node", "id", id, "ip", node.IP(), "added", !exists) 287 if exists { 288 continue loop 289 } 290 task := newDialTask(node, staticDialedConn) 291 d.static[id] = task 292 if d.checkDial(node) == nil { 293 d.addToStaticPool(task) 294 } 295 296 case node := <-d.remStaticCh: 297 id := node.ID() 298 task := d.static[id] 299 d.log.Trace("Removing static node", "id", id, "ok", task != nil) 300 if task != nil { 301 delete(d.static, id) 302 if task.staticPoolIndex >= 0 { 303 d.removeFromStaticPool(task.staticPoolIndex) 304 } 305 } 306 307 case <-historyExp: 308 d.expireHistory() 309 310 case <-d.ctx.Done(): 311 it.Close() 312 break loop 313 } 314 } 315 316 d.stopHistoryTimer(historyExp) 317 for range d.dialing { 318 <-d.doneCh 319 } 320 d.wg.Done() 321 } 322 323 // readNodes runs in its own goroutine and delivers nodes from 324 // the input iterator to the nodesIn channel. 325 func (d *dialScheduler) readNodes(it enode.Iterator) { 326 defer d.wg.Done() 327 328 for it.Next() { 329 select { 330 case d.nodesIn <- it.Node(): 331 case <-d.ctx.Done(): 332 } 333 } 334 } 335 336 // logStats prints dialer statistics to the log. The message is suppressed when enough 337 // peers are connected because users should only see it while their client is starting up 338 // or comes back online. 339 func (d *dialScheduler) logStats() { 340 now := d.clock.Now() 341 if d.lastStatsLog.Add(dialStatsLogInterval) > now { 342 return 343 } 344 if d.dialPeers < dialStatsPeerLimit && d.dialPeers < d.maxDialPeers { 345 d.log.Info("Looking for peers", "peercount", len(d.peers), "tried", d.doneSinceLastLog, "static", len(d.static)) 346 } 347 d.doneSinceLastLog = 0 348 d.lastStatsLog = now 349 } 350 351 // rearmHistoryTimer configures d.historyTimer to fire when the 352 // next item in d.history expires. 353 func (d *dialScheduler) rearmHistoryTimer(ch chan struct{}) { 354 if len(d.history) == 0 || d.historyTimerTime == d.history.nextExpiry() { 355 return 356 } 357 d.stopHistoryTimer(ch) 358 d.historyTimerTime = d.history.nextExpiry() 359 timeout := time.Duration(d.historyTimerTime - d.clock.Now()) 360 d.historyTimer = d.clock.AfterFunc(timeout, func() { ch <- struct{}{} }) 361 } 362 363 // stopHistoryTimer stops the timer and drains the channel it sends on. 364 func (d *dialScheduler) stopHistoryTimer(ch chan struct{}) { 365 if d.historyTimer != nil && !d.historyTimer.Stop() { 366 <-ch 367 } 368 } 369 370 // expireHistory removes expired items from d.history. 371 func (d *dialScheduler) expireHistory() { 372 d.historyTimer.Stop() 373 d.historyTimer = nil 374 d.historyTimerTime = 0 375 d.history.expire(d.clock.Now(), func(hkey string) { 376 var id enode.ID 377 copy(id[:], hkey) 378 d.updateStaticPool(id) 379 }) 380 } 381 382 // freeDialSlots returns the number of free dial slots. The result can be negative 383 // when peers are connected while their task is still running. 384 func (d *dialScheduler) freeDialSlots() int { 385 slots := (d.maxDialPeers - d.dialPeers) * 2 386 if slots > d.maxActiveDials { 387 slots = d.maxActiveDials 388 } 389 free := slots - len(d.dialing) 390 return free 391 } 392 393 // checkDial returns an error if node n should not be dialed. 394 func (d *dialScheduler) checkDial(n *enode.Node) error { 395 if n.ID() == d.self { 396 return errSelf 397 } 398 if n.IP() != nil && n.TCP() == 0 { 399 // This check can trigger if a non-TCP node is found 400 // by discovery. If there is no IP, the node is a static 401 // node and the actual endpoint will be resolved later in dialTask. 402 return errNoPort 403 } 404 if _, ok := d.dialing[n.ID()]; ok { 405 return errAlreadyDialing 406 } 407 if _, ok := d.peers[n.ID()]; ok { 408 return errAlreadyConnected 409 } 410 if d.netRestrict != nil && !d.netRestrict.Contains(n.IP()) { 411 return errNotWhitelisted 412 } 413 if d.history.contains(string(n.ID().Bytes())) { 414 return errRecentlyDialed 415 } 416 return nil 417 } 418 419 // startStaticDials starts n static dial tasks. 420 func (d *dialScheduler) startStaticDials(n int) (started int) { 421 for started = 0; started < n && len(d.staticPool) > 0; started++ { 422 idx := d.rand.Intn(len(d.staticPool)) 423 task := d.staticPool[idx] 424 d.startDial(task) 425 d.removeFromStaticPool(idx) 426 } 427 return started 428 } 429 430 // updateStaticPool attempts to move the given static dial back into staticPool. 431 func (d *dialScheduler) updateStaticPool(id enode.ID) { 432 task, ok := d.static[id] 433 if ok && task.staticPoolIndex < 0 && d.checkDial(task.dest) == nil { 434 d.addToStaticPool(task) 435 } 436 } 437 438 func (d *dialScheduler) addToStaticPool(task *dialTask) { 439 if task.staticPoolIndex >= 0 { 440 panic("attempt to add task to staticPool twice") 441 } 442 d.staticPool = append(d.staticPool, task) 443 task.staticPoolIndex = len(d.staticPool) - 1 444 } 445 446 // removeFromStaticPool removes the task at idx from staticPool. It does that by moving the 447 // current last element of the pool to idx and then shortening the pool by one. 448 func (d *dialScheduler) removeFromStaticPool(idx int) { 449 task := d.staticPool[idx] 450 end := len(d.staticPool) - 1 451 d.staticPool[idx] = d.staticPool[end] 452 d.staticPool[idx].staticPoolIndex = idx 453 d.staticPool[end] = nil 454 d.staticPool = d.staticPool[:end] 455 task.staticPoolIndex = -1 456 } 457 458 // startDial runs the given dial task in a separate goroutine. 459 func (d *dialScheduler) startDial(task *dialTask) { 460 d.log.Trace("Starting p2p dial", "id", task.dest.ID(), "ip", task.dest.IP(), "flag", task.flags) 461 hkey := string(task.dest.ID().Bytes()) 462 d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) 463 d.dialing[task.dest.ID()] = task 464 gopool.Submit(func() { 465 task.run(d) 466 d.doneCh <- task 467 }) 468 } 469 470 // A dialTask generated for each node that is dialed. 471 type dialTask struct { 472 staticPoolIndex int 473 flags connFlag 474 // These fields are private to the task and should not be 475 // accessed by dialScheduler while the task is running. 476 dest *enode.Node 477 lastResolved mclock.AbsTime 478 resolveDelay time.Duration 479 } 480 481 func newDialTask(dest *enode.Node, flags connFlag) *dialTask { 482 return &dialTask{dest: dest, flags: flags, staticPoolIndex: -1} 483 } 484 485 type dialError struct { 486 error 487 } 488 489 func (t *dialTask) run(d *dialScheduler) { 490 if t.needResolve() && !t.resolve(d) { 491 return 492 } 493 494 err := t.dial(d, t.dest) 495 if err != nil { 496 // For static nodes, resolve one more time if dialing fails. 497 if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { 498 if t.resolve(d) { 499 t.dial(d, t.dest) 500 } 501 } 502 } 503 } 504 505 func (t *dialTask) needResolve() bool { 506 return t.flags&staticDialedConn != 0 && t.dest.IP() == nil 507 } 508 509 // resolve attempts to find the current endpoint for the destination 510 // using discovery. 511 // 512 // Resolve operations are throttled with backoff to avoid flooding the 513 // discovery network with useless queries for nodes that don't exist. 514 // The backoff delay resets when the node is found. 515 func (t *dialTask) resolve(d *dialScheduler) bool { 516 if d.resolver == nil { 517 return false 518 } 519 if t.resolveDelay == 0 { 520 t.resolveDelay = initialResolveDelay 521 } 522 if t.lastResolved > 0 && time.Duration(d.clock.Now()-t.lastResolved) < t.resolveDelay { 523 return false 524 } 525 resolved := d.resolver.Resolve(t.dest) 526 t.lastResolved = d.clock.Now() 527 if resolved == nil { 528 t.resolveDelay *= 2 529 if t.resolveDelay > maxResolveDelay { 530 t.resolveDelay = maxResolveDelay 531 } 532 d.log.Debug("Resolving node failed", "id", t.dest.ID(), "newdelay", t.resolveDelay) 533 return false 534 } 535 // The node was found. 536 t.resolveDelay = initialResolveDelay 537 t.dest = resolved 538 d.log.Debug("Resolved node", "id", t.dest.ID(), "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}) 539 return true 540 } 541 542 // dial performs the actual connection attempt. 543 func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { 544 fd, err := d.dialer.Dial(d.ctx, t.dest) 545 if err != nil { 546 d.log.Trace("Dial error", "id", t.dest.ID(), "addr", nodeAddr(t.dest), "conn", t.flags, "err", cleanupDialErr(err)) 547 return &dialError{err} 548 } 549 mfd := newMeteredConn(fd, false, &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()}) 550 return d.setupFunc(mfd, t.flags, dest) 551 } 552 553 func (t *dialTask) String() string { 554 id := t.dest.ID() 555 return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP()) 556 } 557 558 func cleanupDialErr(err error) error { 559 if netErr, ok := err.(*net.OpError); ok && netErr.Op == "dial" { 560 return netErr.Err 561 } 562 return err 563 }