@cryptotaxi247 / kubo / commits / ee4a9a271

p2p/protocol/identity: smarter tracking observed addrs

- time them out (already was doing that with addrbook) - keep count to counter symmetric nats

Juan Batiz-Benet committed Feb 5, 2015 at 10:15 UTC ee4a9a27113169209a13288fd5ad1b010ee11204
4 files changed +173 -4
p2p/peer/addr_manager.go
+1 -1
@@ -22,7 +22,7 @@ const (
22 RecentlyConnectedAddrTTL = time.Minute * 10
23
24 // OwnObservedAddrTTL is used for our own external addresses observed by peers.
25 - OwnObservedAddrTTL = time.Minute * 20
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
p2p/protocol/identify/id.go
+3 -3
@@ -47,7 +47,7 @@ type IDService struct {
47
48 // our own observed addresses.
49 // TODO: instead of expiring, remove these when we disconnect
50 - addrs peer.AddrManager
50 + observedAddrs ObservedAddrSet
51 }
52
53 func NewIDService(h host.Host) *IDService {
@@ -61,7 +61,7 @@ func NewIDService(h host.Host) *IDService {
61
62 // OwnObservedAddrs returns the addresses peers have reported we've dialed from
63 func (ids *IDService) OwnObservedAddrs() []ma.Multiaddr {
64 - return ids.addrs.Addrs(ids.Host.ID())
64 + return ids.observedAddrs.Addrs()
65 }
66
67 func (ids *IDService) IdentifyConn(c inet.Conn) {
@@ -250,7 +250,7 @@ func (ids *IDService) consumeObservedAddress(observed []byte, c inet.Conn) {
250
251 // ok! we have the observed version of one of our ListenAddresses!
252 log.Debugf("added own observed listen addr: %s --> %s", c.LocalMultiaddr(), maddr)
253 - ids.addrs.AddAddr(ids.Host.ID(), maddr, peer.OwnObservedAddrTTL)
253 + ids.observedAddrs.Add(maddr)
254 }
255
256 func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool {
p2p/protocol/identify/obsaddr.go new
+96
@@ -0,0 +1,96 @@
1 +package identify
2 +
3 +import (
4 + "sync"
5 + "time"
6 +
7 + peer "github.com/jbenet/go-ipfs/p2p/peer"
8 +
9 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 +)
11 +
12 +// ObservedAddr is an entry for an address reported by our peers.
13 +// We only use addresses that:
14 +// - have been observed more than once. (counter symmetric nats)
15 +// - have been observed recently (10min), because our position in the
16 +// network, or network port mapppings, may have changed.
17 +type ObservedAddr struct {
18 + Addr ma.Multiaddr
19 + LastSeen time.Time
20 + TimesSeen int
21 +}
22 +
23 +// ObservedAddrSet keeps track of a set of ObservedAddrs
24 +// the zero-value is ready to be used.
25 +type ObservedAddrSet struct {
26 + sync.Mutex // guards whole datastruct.
27 +
28 + addrs map[string]ObservedAddr
29 + ttl time.Duration
30 +}
31 +
32 +func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr {
33 + oas.Lock()
34 + defer oas.Unlock()
35 +
36 + // for zero-value.
37 + if oas.addrs == nil {
38 + return nil
39 + }
40 +
41 + now := time.Now()
42 + addrs := make([]ma.Multiaddr, 0, len(oas.addrs))
43 + for s, a := range oas.addrs {
44 + // remove timed out addresses.
45 + if now.Sub(a.LastSeen) > oas.ttl {
46 + delete(oas.addrs, s)
47 + continue
48 + }
49 +
50 + // we only use an address if we've seen it more than once
51 + // because symmetric nats may cause all our peers to see
52 + // different port numbers and thus report always different
53 + // addresses (different ports) for us. These wouldn't be
54 + // very useful. We make the assumption that if we've
55 + // connected to two different peers, and they both have
56 + // reported seeing the same address, it is probably useful.
57 + if a.TimesSeen > 1 {
58 + addrs = append(addrs, a.Addr)
59 + }
60 + }
61 + return addrs
62 +}
63 +
64 +func (oas *ObservedAddrSet) Add(addr ma.Multiaddr) {
65 + oas.Lock()
66 + defer oas.Unlock()
67 +
68 + // for zero-value.
69 + if oas.addrs == nil {
70 + oas.addrs = make(map[string]ObservedAddr)
71 + oas.ttl = peer.OwnObservedAddrTTL
72 + }
73 +
74 + s := addr.String()
75 + oas.addrs[s] = ObservedAddr{
76 + Addr: addr,
77 + TimesSeen: oas.addrs[s].TimesSeen + 1,
78 + LastSeen: time.Now(),
79 + }
80 +}
81 +
82 +func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) {
83 + oas.Lock()
84 + defer oas.Unlock()
85 + oas.ttl = ttl
86 +}
87 +
88 +func (oas *ObservedAddrSet) TTL() time.Duration {
89 + oas.Lock()
90 + defer oas.Unlock()
91 + // for zero-value.
92 + if oas.addrs == nil {
93 + oas.ttl = peer.OwnObservedAddrTTL
94 + }
95 + return oas.ttl
96 +}
p2p/protocol/identify/obsaddr_test.go new
+73
@@ -0,0 +1,73 @@
1 +package identify
2 +
3 +import (
4 + "testing"
5 + "time"
6 +
7 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 +)
9 +
10 +// TestObsAddrSet
11 +func TestObsAddrSet(t *testing.T) {
12 + m := func(s string) ma.Multiaddr {
13 + m, err := ma.NewMultiaddr(s)
14 + if err != nil {
15 + t.Error(err)
16 + }
17 + return m
18 + }
19 +
20 + addrsMarch := func(a, b []ma.Multiaddr) bool {
21 + for _, aa := range a {
22 + found := false
23 + for _, bb := range b {
24 + if aa.Equal(bb) {
25 + found = true
26 + break
27 + }
28 + }
29 + if !found {
30 + return false
31 + }
32 + }
33 + return true
34 + }
35 +
36 + a1 := m("/ip4/1.2.3.4/tcp/1231")
37 + a2 := m("/ip4/1.2.3.4/tcp/1232")
38 + a3 := m("/ip4/1.2.3.4/tcp/1233")
39 +
40 + oas := ObservedAddrSet{}
41 +
42 + if !addrsMarch(oas.Addrs(), nil) {
43 + t.Error("addrs should be empty")
44 + }
45 +
46 + oas.Add(a1)
47 + oas.Add(a2)
48 + oas.Add(a3)
49 +
50 + // these are all different so we should not yet get them.
51 + if !addrsMarch(oas.Addrs(), nil) {
52 + t.Error("addrs should _still_ be empty (once)")
53 + }
54 +
55 + oas.Add(a1)
56 + if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1}) {
57 + t.Error("addrs should only have a1")
58 + }
59 +
60 + oas.Add(a2)
61 + oas.Add(a1)
62 + oas.Add(a1)
63 + if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1, a2}) {
64 + t.Error("addrs should only have a1, a2")
65 + }
66 +
67 + // change the timeout constant so we can time it out.
68 + oas.SetTTL(time.Millisecond * 200)
69 + <-time.After(time.Millisecond * 210)
70 + if !addrsMarch(oas.Addrs(), []ma.Multiaddr{nil}) {
71 + t.Error("addrs should have timed out")
72 + }
73 +}