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