github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/peer/addr_manager.go (about) 1 package peer 2 3 import ( 4 "sync" 5 "time" 6 7 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 8 ) 9 10 const ( 11 12 // TempAddrTTL is the ttl used for a short lived address 13 TempAddrTTL = time.Second * 10 14 15 // ProviderAddrTTL is the TTL of an address we've received from a provider. 16 // This is also a temporary address, but lasts longer. After this expires, 17 // the records we return will require an extra lookup. 18 ProviderAddrTTL = time.Minute * 10 19 20 // RecentlyConnectedAddrTTL is used when we recently connected to a peer. 21 // It means that we are reasonably certain of the peer's address. 22 RecentlyConnectedAddrTTL = time.Minute * 10 23 24 // OwnObservedAddrTTL is used for our own external addresses observed by peers. 25 OwnObservedAddrTTL = time.Minute * 10 26 27 // PermanentAddrTTL is the ttl for a "permanent address" (e.g. bootstrap nodes) 28 // if we haven't shipped you an update to ipfs in 356 days 29 // we probably arent running the same bootstrap nodes... 30 PermanentAddrTTL = time.Hour * 24 * 356 31 32 // ConnectedAddrTTL is the ttl used for the addresses of a peer to whom 33 // we're connected directly. This is basically permanent, as we will 34 // clear them + re-add under a TempAddrTTL after disconnecting. 35 ConnectedAddrTTL = PermanentAddrTTL 36 ) 37 38 type expiringAddr struct { 39 Addr ma.Multiaddr 40 TTL time.Time 41 } 42 43 func (e *expiringAddr) ExpiredBy(t time.Time) bool { 44 return t.After(e.TTL) 45 } 46 47 type addrSet map[string]expiringAddr 48 49 // AddrManager manages addresses. 50 // The zero-value is ready to be used. 51 type AddrManager struct { 52 addrmu sync.Mutex // guards addrs 53 addrs map[ID]addrSet 54 } 55 56 // ensures the AddrManager is initialized. 57 // So we can use the zero value. 58 func (mgr *AddrManager) init() { 59 if mgr.addrs == nil { 60 mgr.addrs = make(map[ID]addrSet) 61 } 62 } 63 64 func (mgr *AddrManager) Peers() []ID { 65 mgr.addrmu.Lock() 66 defer mgr.addrmu.Unlock() 67 if mgr.addrs == nil { 68 return nil 69 } 70 71 pids := make([]ID, 0, len(mgr.addrs)) 72 for pid := range mgr.addrs { 73 pids = append(pids, pid) 74 } 75 return pids 76 } 77 78 // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl) 79 func (mgr *AddrManager) AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) { 80 mgr.AddAddrs(p, []ma.Multiaddr{addr}, ttl) 81 } 82 83 // AddAddrs gives AddrManager addresses to use, with a given ttl 84 // (time-to-live), after which the address is no longer valid. 85 // If the manager has a longer TTL, the operation is a no-op for that address 86 func (mgr *AddrManager) AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) { 87 mgr.addrmu.Lock() 88 defer mgr.addrmu.Unlock() 89 90 // if ttl is zero, exit. nothing to do. 91 if ttl <= 0 { 92 return 93 } 94 95 // so zero value can be used 96 mgr.init() 97 98 amap, found := mgr.addrs[p] 99 if !found { 100 amap = make(addrSet) 101 mgr.addrs[p] = amap 102 } 103 104 // only expand ttls 105 exp := time.Now().Add(ttl) 106 for _, addr := range addrs { 107 addrstr := addr.String() 108 a, found := amap[addrstr] 109 if !found || exp.After(a.TTL) { 110 amap[addrstr] = expiringAddr{Addr: addr, TTL: exp} 111 } 112 } 113 } 114 115 // SetAddr calls mgr.SetAddrs(p, addr, ttl) 116 func (mgr *AddrManager) SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) { 117 mgr.SetAddrs(p, []ma.Multiaddr{addr}, ttl) 118 } 119 120 // SetAddrs sets the ttl on addresses. This clears any TTL there previously. 121 // This is used when we receive the best estimate of the validity of an address. 122 func (mgr *AddrManager) SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) { 123 mgr.addrmu.Lock() 124 defer mgr.addrmu.Unlock() 125 126 // so zero value can be used 127 mgr.init() 128 129 amap, found := mgr.addrs[p] 130 if !found { 131 amap = make(addrSet) 132 mgr.addrs[p] = amap 133 } 134 135 exp := time.Now().Add(ttl) 136 for _, addr := range addrs { 137 // re-set all of them for new ttl. 138 addrs := addr.String() 139 140 if ttl > 0 { 141 amap[addrs] = expiringAddr{Addr: addr, TTL: exp} 142 } else { 143 delete(amap, addrs) 144 } 145 } 146 } 147 148 // Addresses returns all known (and valid) addresses for a given 149 func (mgr *AddrManager) Addrs(p ID) []ma.Multiaddr { 150 mgr.addrmu.Lock() 151 defer mgr.addrmu.Unlock() 152 153 // not initialized? nothing to give. 154 if mgr.addrs == nil { 155 return nil 156 } 157 158 maddrs, found := mgr.addrs[p] 159 if !found { 160 return nil 161 } 162 163 now := time.Now() 164 good := make([]ma.Multiaddr, 0, len(maddrs)) 165 var expired []string 166 for s, m := range maddrs { 167 if m.ExpiredBy(now) { 168 expired = append(expired, s) 169 } else { 170 good = append(good, m.Addr) 171 } 172 } 173 174 // clean up the expired ones. 175 for _, s := range expired { 176 delete(maddrs, s) 177 } 178 return good 179 } 180 181 // ClearAddresses removes all previously stored addresses 182 func (mgr *AddrManager) ClearAddrs(p ID) { 183 mgr.addrmu.Lock() 184 defer mgr.addrmu.Unlock() 185 mgr.init() 186 187 mgr.addrs[p] = make(addrSet) // clear what was there before 188 }