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  }