github.com/gnattishness/bazel-go-ethereum@v0.0.0-20190929123618-7022a154f56d/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 "errors" 21 "fmt" 22 "net" 23 "time" 24 25 "github.com/ethereum/go-ethereum/log" 26 "github.com/ethereum/go-ethereum/p2p/enode" 27 "github.com/ethereum/go-ethereum/p2p/netutil" 28 ) 29 30 const ( 31 // This is the amount of time spent waiting in between redialing a certain node. The 32 // limit is a bit higher than inboundThrottleTime to prevent failing dials in small 33 // private networks. 34 dialHistoryExpiration = inboundThrottleTime + 5*time.Second 35 36 // Discovery lookups are throttled and can only run 37 // once every few seconds. 38 lookupInterval = 4 * time.Second 39 40 // If no peers are found for this amount of time, the initial bootnodes are 41 // attempted to be connected. 42 fallbackInterval = 20 * time.Second 43 44 // Endpoint resolution is throttled with bounded backoff. 45 initialResolveDelay = 60 * time.Second 46 maxResolveDelay = time.Hour 47 ) 48 49 // NodeDialer is used to connect to nodes in the network, typically by using 50 // an underlying net.Dialer but also using net.Pipe in tests 51 type NodeDialer interface { 52 Dial(*enode.Node) (net.Conn, error) 53 } 54 55 // TCPDialer implements the NodeDialer interface by using a net.Dialer to 56 // create TCP connections to nodes in the network 57 type TCPDialer struct { 58 *net.Dialer 59 } 60 61 // Dial creates a TCP connection to the node 62 func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) { 63 addr := &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()} 64 return t.Dialer.Dial("tcp", addr.String()) 65 } 66 67 // dialstate schedules dials and discovery lookups. 68 // It gets a chance to compute new tasks on every iteration 69 // of the main loop in Server.run. 70 type dialstate struct { 71 maxDynDials int 72 ntab discoverTable 73 netrestrict *netutil.Netlist 74 self enode.ID 75 bootnodes []*enode.Node // default dials when there are no peers 76 log log.Logger 77 78 start time.Time // time when the dialer was first used 79 lookupRunning bool 80 dialing map[enode.ID]connFlag 81 lookupBuf []*enode.Node // current discovery lookup results 82 randomNodes []*enode.Node // filled from Table 83 static map[enode.ID]*dialTask 84 hist expHeap 85 } 86 87 type discoverTable interface { 88 Close() 89 Resolve(*enode.Node) *enode.Node 90 LookupRandom() []*enode.Node 91 ReadRandomNodes([]*enode.Node) int 92 } 93 94 type task interface { 95 Do(*Server) 96 } 97 98 // A dialTask is generated for each node that is dialed. Its 99 // fields cannot be accessed while the task is running. 100 type dialTask struct { 101 flags connFlag 102 dest *enode.Node 103 lastResolved time.Time 104 resolveDelay time.Duration 105 } 106 107 // discoverTask runs discovery table operations. 108 // Only one discoverTask is active at any time. 109 // discoverTask.Do performs a random lookup. 110 type discoverTask struct { 111 results []*enode.Node 112 } 113 114 // A waitExpireTask is generated if there are no other tasks 115 // to keep the loop in Server.run ticking. 116 type waitExpireTask struct { 117 time.Duration 118 } 119 120 func newDialState(self enode.ID, ntab discoverTable, maxdyn int, cfg *Config) *dialstate { 121 s := &dialstate{ 122 maxDynDials: maxdyn, 123 ntab: ntab, 124 self: self, 125 netrestrict: cfg.NetRestrict, 126 log: cfg.Logger, 127 static: make(map[enode.ID]*dialTask), 128 dialing: make(map[enode.ID]connFlag), 129 bootnodes: make([]*enode.Node, len(cfg.BootstrapNodes)), 130 randomNodes: make([]*enode.Node, maxdyn/2), 131 } 132 copy(s.bootnodes, cfg.BootstrapNodes) 133 if s.log == nil { 134 s.log = log.Root() 135 } 136 for _, n := range cfg.StaticNodes { 137 s.addStatic(n) 138 } 139 return s 140 } 141 142 func (s *dialstate) addStatic(n *enode.Node) { 143 // This overwrites the task instead of updating an existing 144 // entry, giving users the opportunity to force a resolve operation. 145 s.static[n.ID()] = &dialTask{flags: staticDialedConn, dest: n} 146 } 147 148 func (s *dialstate) removeStatic(n *enode.Node) { 149 // This removes a task so future attempts to connect will not be made. 150 delete(s.static, n.ID()) 151 } 152 153 func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Time) []task { 154 if s.start.IsZero() { 155 s.start = now 156 } 157 158 var newtasks []task 159 addDial := func(flag connFlag, n *enode.Node) bool { 160 if err := s.checkDial(n, peers); err != nil { 161 s.log.Trace("Skipping dial candidate", "id", n.ID(), "addr", &net.TCPAddr{IP: n.IP(), Port: n.TCP()}, "err", err) 162 return false 163 } 164 s.dialing[n.ID()] = flag 165 newtasks = append(newtasks, &dialTask{flags: flag, dest: n}) 166 return true 167 } 168 169 // Compute number of dynamic dials necessary at this point. 170 needDynDials := s.maxDynDials 171 for _, p := range peers { 172 if p.rw.is(dynDialedConn) { 173 needDynDials-- 174 } 175 } 176 for _, flag := range s.dialing { 177 if flag&dynDialedConn != 0 { 178 needDynDials-- 179 } 180 } 181 182 // Expire the dial history on every invocation. 183 s.hist.expire(now) 184 185 // Create dials for static nodes if they are not connected. 186 for id, t := range s.static { 187 err := s.checkDial(t.dest, peers) 188 switch err { 189 case errNotWhitelisted, errSelf: 190 s.log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}, "err", err) 191 delete(s.static, t.dest.ID()) 192 case nil: 193 s.dialing[id] = t.flags 194 newtasks = append(newtasks, t) 195 } 196 } 197 // If we don't have any peers whatsoever, try to dial a random bootnode. This 198 // scenario is useful for the testnet (and private networks) where the discovery 199 // table might be full of mostly bad peers, making it hard to find good ones. 200 if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval { 201 bootnode := s.bootnodes[0] 202 s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...) 203 s.bootnodes = append(s.bootnodes, bootnode) 204 205 if addDial(dynDialedConn, bootnode) { 206 needDynDials-- 207 } 208 } 209 // Use random nodes from the table for half of the necessary 210 // dynamic dials. 211 randomCandidates := needDynDials / 2 212 if randomCandidates > 0 { 213 n := s.ntab.ReadRandomNodes(s.randomNodes) 214 for i := 0; i < randomCandidates && i < n; i++ { 215 if addDial(dynDialedConn, s.randomNodes[i]) { 216 needDynDials-- 217 } 218 } 219 } 220 // Create dynamic dials from random lookup results, removing tried 221 // items from the result buffer. 222 i := 0 223 for ; i < len(s.lookupBuf) && needDynDials > 0; i++ { 224 if addDial(dynDialedConn, s.lookupBuf[i]) { 225 needDynDials-- 226 } 227 } 228 s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])] 229 // Launch a discovery lookup if more candidates are needed. 230 if len(s.lookupBuf) < needDynDials && !s.lookupRunning { 231 s.lookupRunning = true 232 newtasks = append(newtasks, &discoverTask{}) 233 } 234 235 // Launch a timer to wait for the next node to expire if all 236 // candidates have been tried and no task is currently active. 237 // This should prevent cases where the dialer logic is not ticked 238 // because there are no pending events. 239 if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 { 240 t := &waitExpireTask{s.hist.nextExpiry().Sub(now)} 241 newtasks = append(newtasks, t) 242 } 243 return newtasks 244 } 245 246 var ( 247 errSelf = errors.New("is self") 248 errAlreadyDialing = errors.New("already dialing") 249 errAlreadyConnected = errors.New("already connected") 250 errRecentlyDialed = errors.New("recently dialed") 251 errNotWhitelisted = errors.New("not contained in netrestrict whitelist") 252 ) 253 254 func (s *dialstate) checkDial(n *enode.Node, peers map[enode.ID]*Peer) error { 255 _, dialing := s.dialing[n.ID()] 256 switch { 257 case dialing: 258 return errAlreadyDialing 259 case peers[n.ID()] != nil: 260 return errAlreadyConnected 261 case n.ID() == s.self: 262 return errSelf 263 case s.netrestrict != nil && !s.netrestrict.Contains(n.IP()): 264 return errNotWhitelisted 265 case s.hist.contains(string(n.ID().Bytes())): 266 return errRecentlyDialed 267 } 268 return nil 269 } 270 271 func (s *dialstate) taskDone(t task, now time.Time) { 272 switch t := t.(type) { 273 case *dialTask: 274 s.hist.add(string(t.dest.ID().Bytes()), now.Add(dialHistoryExpiration)) 275 delete(s.dialing, t.dest.ID()) 276 case *discoverTask: 277 s.lookupRunning = false 278 s.lookupBuf = append(s.lookupBuf, t.results...) 279 } 280 } 281 282 func (t *dialTask) Do(srv *Server) { 283 if t.dest.Incomplete() { 284 if !t.resolve(srv) { 285 return 286 } 287 } 288 err := t.dial(srv, t.dest) 289 if err != nil { 290 srv.log.Trace("Dial error", "task", t, "err", err) 291 // Try resolving the ID of static nodes if dialing failed. 292 if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { 293 if t.resolve(srv) { 294 t.dial(srv, t.dest) 295 } 296 } 297 } 298 } 299 300 // resolve attempts to find the current endpoint for the destination 301 // using discovery. 302 // 303 // Resolve operations are throttled with backoff to avoid flooding the 304 // discovery network with useless queries for nodes that don't exist. 305 // The backoff delay resets when the node is found. 306 func (t *dialTask) resolve(srv *Server) bool { 307 if srv.ntab == nil { 308 srv.log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled") 309 return false 310 } 311 if t.resolveDelay == 0 { 312 t.resolveDelay = initialResolveDelay 313 } 314 if time.Since(t.lastResolved) < t.resolveDelay { 315 return false 316 } 317 resolved := srv.ntab.Resolve(t.dest) 318 t.lastResolved = time.Now() 319 if resolved == nil { 320 t.resolveDelay *= 2 321 if t.resolveDelay > maxResolveDelay { 322 t.resolveDelay = maxResolveDelay 323 } 324 srv.log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay) 325 return false 326 } 327 // The node was found. 328 t.resolveDelay = initialResolveDelay 329 t.dest = resolved 330 srv.log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}) 331 return true 332 } 333 334 type dialError struct { 335 error 336 } 337 338 // dial performs the actual connection attempt. 339 func (t *dialTask) dial(srv *Server, dest *enode.Node) error { 340 fd, err := srv.Dialer.Dial(dest) 341 if err != nil { 342 return &dialError{err} 343 } 344 mfd := newMeteredConn(fd, false, dest.IP()) 345 return srv.SetupConn(mfd, t.flags, dest) 346 } 347 348 func (t *dialTask) String() string { 349 id := t.dest.ID() 350 return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP()) 351 } 352 353 func (t *discoverTask) Do(srv *Server) { 354 // newTasks generates a lookup task whenever dynamic dials are 355 // necessary. Lookups need to take some time, otherwise the 356 // event loop spins too fast. 357 next := srv.lastLookup.Add(lookupInterval) 358 if now := time.Now(); now.Before(next) { 359 time.Sleep(next.Sub(now)) 360 } 361 srv.lastLookup = time.Now() 362 t.results = srv.ntab.LookupRandom() 363 } 364 365 func (t *discoverTask) String() string { 366 s := "discovery lookup" 367 if len(t.results) > 0 { 368 s += fmt.Sprintf(" (%d results)", len(t.results)) 369 } 370 return s 371 } 372 373 func (t waitExpireTask) Do(*Server) { 374 time.Sleep(t.Duration) 375 } 376 func (t waitExpireTask) String() string { 377 return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration) 378 }