mirror of https://github.com/libp2p/go-libp2p.git
Browse Source
- time them out (already was doing that with addrbook) - keep count to counter symmetric natspull/2/head
Juan Batiz-Benet
10 years ago
4 changed files with 173 additions and 4 deletions
@ -0,0 +1,96 @@ |
|||||
|
package identify |
||||
|
|
||||
|
import ( |
||||
|
"sync" |
||||
|
"time" |
||||
|
|
||||
|
peer "github.com/jbenet/go-ipfs/p2p/peer" |
||||
|
|
||||
|
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" |
||||
|
) |
||||
|
|
||||
|
// ObservedAddr is an entry for an address reported by our peers.
|
||||
|
// We only use addresses that:
|
||||
|
// - have been observed more than once. (counter symmetric nats)
|
||||
|
// - have been observed recently (10min), because our position in the
|
||||
|
// network, or network port mapppings, may have changed.
|
||||
|
type ObservedAddr struct { |
||||
|
Addr ma.Multiaddr |
||||
|
LastSeen time.Time |
||||
|
TimesSeen int |
||||
|
} |
||||
|
|
||||
|
// ObservedAddrSet keeps track of a set of ObservedAddrs
|
||||
|
// the zero-value is ready to be used.
|
||||
|
type ObservedAddrSet struct { |
||||
|
sync.Mutex // guards whole datastruct.
|
||||
|
|
||||
|
addrs map[string]ObservedAddr |
||||
|
ttl time.Duration |
||||
|
} |
||||
|
|
||||
|
func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr { |
||||
|
oas.Lock() |
||||
|
defer oas.Unlock() |
||||
|
|
||||
|
// for zero-value.
|
||||
|
if oas.addrs == nil { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
now := time.Now() |
||||
|
addrs := make([]ma.Multiaddr, 0, len(oas.addrs)) |
||||
|
for s, a := range oas.addrs { |
||||
|
// remove timed out addresses.
|
||||
|
if now.Sub(a.LastSeen) > oas.ttl { |
||||
|
delete(oas.addrs, s) |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// we only use an address if we've seen it more than once
|
||||
|
// because symmetric nats may cause all our peers to see
|
||||
|
// different port numbers and thus report always different
|
||||
|
// addresses (different ports) for us. These wouldn't be
|
||||
|
// very useful. We make the assumption that if we've
|
||||
|
// connected to two different peers, and they both have
|
||||
|
// reported seeing the same address, it is probably useful.
|
||||
|
if a.TimesSeen > 1 { |
||||
|
addrs = append(addrs, a.Addr) |
||||
|
} |
||||
|
} |
||||
|
return addrs |
||||
|
} |
||||
|
|
||||
|
func (oas *ObservedAddrSet) Add(addr ma.Multiaddr) { |
||||
|
oas.Lock() |
||||
|
defer oas.Unlock() |
||||
|
|
||||
|
// for zero-value.
|
||||
|
if oas.addrs == nil { |
||||
|
oas.addrs = make(map[string]ObservedAddr) |
||||
|
oas.ttl = peer.OwnObservedAddrTTL |
||||
|
} |
||||
|
|
||||
|
s := addr.String() |
||||
|
oas.addrs[s] = ObservedAddr{ |
||||
|
Addr: addr, |
||||
|
TimesSeen: oas.addrs[s].TimesSeen + 1, |
||||
|
LastSeen: time.Now(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) { |
||||
|
oas.Lock() |
||||
|
defer oas.Unlock() |
||||
|
oas.ttl = ttl |
||||
|
} |
||||
|
|
||||
|
func (oas *ObservedAddrSet) TTL() time.Duration { |
||||
|
oas.Lock() |
||||
|
defer oas.Unlock() |
||||
|
// for zero-value.
|
||||
|
if oas.addrs == nil { |
||||
|
oas.ttl = peer.OwnObservedAddrTTL |
||||
|
} |
||||
|
return oas.ttl |
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
package identify |
||||
|
|
||||
|
import ( |
||||
|
"testing" |
||||
|
"time" |
||||
|
|
||||
|
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" |
||||
|
) |
||||
|
|
||||
|
// TestObsAddrSet
|
||||
|
func TestObsAddrSet(t *testing.T) { |
||||
|
m := func(s string) ma.Multiaddr { |
||||
|
m, err := ma.NewMultiaddr(s) |
||||
|
if err != nil { |
||||
|
t.Error(err) |
||||
|
} |
||||
|
return m |
||||
|
} |
||||
|
|
||||
|
addrsMarch := func(a, b []ma.Multiaddr) bool { |
||||
|
for _, aa := range a { |
||||
|
found := false |
||||
|
for _, bb := range b { |
||||
|
if aa.Equal(bb) { |
||||
|
found = true |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
if !found { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
a1 := m("/ip4/1.2.3.4/tcp/1231") |
||||
|
a2 := m("/ip4/1.2.3.4/tcp/1232") |
||||
|
a3 := m("/ip4/1.2.3.4/tcp/1233") |
||||
|
|
||||
|
oas := ObservedAddrSet{} |
||||
|
|
||||
|
if !addrsMarch(oas.Addrs(), nil) { |
||||
|
t.Error("addrs should be empty") |
||||
|
} |
||||
|
|
||||
|
oas.Add(a1) |
||||
|
oas.Add(a2) |
||||
|
oas.Add(a3) |
||||
|
|
||||
|
// these are all different so we should not yet get them.
|
||||
|
if !addrsMarch(oas.Addrs(), nil) { |
||||
|
t.Error("addrs should _still_ be empty (once)") |
||||
|
} |
||||
|
|
||||
|
oas.Add(a1) |
||||
|
if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1}) { |
||||
|
t.Error("addrs should only have a1") |
||||
|
} |
||||
|
|
||||
|
oas.Add(a2) |
||||
|
oas.Add(a1) |
||||
|
oas.Add(a1) |
||||
|
if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1, a2}) { |
||||
|
t.Error("addrs should only have a1, a2") |
||||
|
} |
||||
|
|
||||
|
// change the timeout constant so we can time it out.
|
||||
|
oas.SetTTL(time.Millisecond * 200) |
||||
|
<-time.After(time.Millisecond * 210) |
||||
|
if !addrsMarch(oas.Addrs(), []ma.Multiaddr{nil}) { |
||||
|
t.Error("addrs should have timed out") |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue