@cryptotaxi247 / kubo / commits / 983822f33

p2p/peer: addresses expire after an hour

Juan Batiz-Benet committed Jan 26, 2015 at 12:43 UTC 983822f335e574fe9bf9afe8b6614cea8ca59580
2 files changed +131 -8
p2p/peer/peerstore.go
+44 -8
@@ -3,6 +3,7 @@ package peer
3 import (
4 "errors"
5 "sync"
6 + "time"
7
8 ic "github.com/jbenet/go-ipfs/p2p/crypto"
9
@@ -11,6 +12,11 @@ import (
12 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 )
14
15 +const (
16 + // AddressTTL is the expiration time of addresses.
17 + AddressTTL = time.Hour
18 +)
19 +
20 // Peerstore provides a threadsafe store of Peer related
21 // information.
22 type Peerstore interface {
@@ -44,15 +50,28 @@ type AddressBook interface {
50 SetAddresses(ID, []ma.Multiaddr) // Sets given addrs for ID (clears previously stored)
51 }
52
47 -type addressMap map[string]ma.Multiaddr
53 +type expiringAddr struct {
54 + Addr ma.Multiaddr
55 + TTL time.Time
56 +}
57 +
58 +func (e *expiringAddr) Expired() bool {
59 + return time.Now().After(e.TTL)
60 +}
61 +
62 +type addressMap map[string]expiringAddr
63
64 type addressbook struct {
65 addrs map[ID]addressMap
66 + ttl time.Duration // initial ttl
67 sync.RWMutex
68 }
69
70 func newAddressbook() *addressbook {
55 - return &addressbook{addrs: map[ID]addressMap{}}
71 + return &addressbook{
72 + addrs: map[ID]addressMap{},
73 + ttl: AddressTTL,
74 + }
75 }
76
77 func (ab *addressbook) Peers() []ID {
@@ -74,11 +93,21 @@ func (ab *addressbook) Addresses(p ID) []ma.Multiaddr {
93 return nil
94 }
95
77 - maddrs2 := make([]ma.Multiaddr, 0, len(maddrs))
78 - for _, m := range maddrs {
79 - maddrs2 = append(maddrs2, m)
96 + good := make([]ma.Multiaddr, 0, len(maddrs))
97 + var expired []string
98 + for s, m := range maddrs {
99 + if m.Expired() {
100 + expired = append(expired, s)
101 + } else {
102 + good = append(good, m.Addr)
103 + }
104 + }
105 +
106 + // clean up the expired ones.
107 + for _, s := range expired {
108 + delete(ab.addrs[p], s)
109 }
81 - return maddrs2
110 + return good
111 }
112
113 func (ab *addressbook) AddAddress(p ID, m ma.Multiaddr) {
@@ -94,8 +123,14 @@ func (ab *addressbook) AddAddresses(p ID, ms []ma.Multiaddr) {
123 amap = addressMap{}
124 ab.addrs[p] = amap
125 }
126 +
127 + ttl := time.Now().Add(ab.ttl)
128 for _, m := range ms {
98 - amap[m.String()] = m
129 + // re-set all of them for new ttl.
130 + amap[m.String()] = expiringAddr{
131 + Addr: m,
132 + TTL: ttl,
133 + }
134 }
135 }
136
@@ -104,8 +139,9 @@ func (ab *addressbook) SetAddresses(p ID, ms []ma.Multiaddr) {
139 defer ab.Unlock()
140
141 amap := addressMap{}
142 + ttl := time.Now().Add(ab.ttl)
143 for _, m := range ms {
108 - amap[m.String()] = m
144 + amap[m.String()] = expiringAddr{Addr: m, TTL: ttl}
145 }
146 ab.addrs[p] = amap // clear what was there before
147 }
p2p/peer/peerstore_test.go
+87
@@ -2,6 +2,7 @@ package peer
2
3 import (
4 "testing"
5 + "time"
6
7 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 )
@@ -96,3 +97,89 @@ func TestAddresses(t *testing.T) {
97 test([]ma.Multiaddr{ma41, ma42, ma43, ma44}, ps.PeerInfo(id4).Addrs)
98 test([]ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ps.PeerInfo(id5).Addrs)
99 }
100 +
101 +func TestAddressTTL(t *testing.T) {
102 +
103 + ps := NewPeerstore()
104 + id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
105 + ma1 := MA(t, "/ip4/1.2.3.1/tcp/1111")
106 + ma2 := MA(t, "/ip4/2.2.3.2/tcp/2222")
107 + ma3 := MA(t, "/ip4/3.2.3.3/tcp/3333")
108 + ma4 := MA(t, "/ip4/4.2.3.3/tcp/4444")
109 + ma5 := MA(t, "/ip4/5.2.3.3/tcp/5555")
110 +
111 + ps.AddAddress(id1, ma1)
112 + ps.AddAddress(id1, ma2)
113 + ps.AddAddress(id1, ma3)
114 + ps.AddAddress(id1, ma4)
115 + ps.AddAddress(id1, ma5)
116 +
117 + test := func(exp, act []ma.Multiaddr) {
118 + if len(exp) != len(act) {
119 + t.Fatal("lengths not the same")
120 + }
121 +
122 + for _, a := range exp {
123 + found := false
124 +
125 + for _, b := range act {
126 + if a.Equal(b) {
127 + found = true
128 + break
129 + }
130 + }
131 +
132 + if !found {
133 + t.Fatal("expected address %s not found", a)
134 + }
135 + }
136 + }
137 +
138 + testTTL := func(ttle time.Duration, id ID, addr ma.Multiaddr) {
139 + ab := ps.(*peerstore).addressbook
140 + ttlat := ab.addrs[id][addr.String()].TTL
141 + ttla := ttlat.Sub(time.Now())
142 + if ttla > ttle {
143 + t.Error("ttl is greater than expected", ttle, ttla)
144 + }
145 + if ttla < (ttle / 2) {
146 + t.Error("ttl is smaller than expected", ttle/2, ttla)
147 + }
148 + }
149 +
150 + // should they are there
151 + ab := ps.(*peerstore).addressbook
152 + if len(ab.addrs[id1]) != 5 {
153 + t.Error("incorrect addr count", len(ab.addrs[id1]), ab.addrs[id1])
154 + }
155 +
156 + // test the Addresses return value
157 + test([]ma.Multiaddr{ma1, ma2, ma3, ma4, ma5}, ps.Addresses(id1))
158 + test([]ma.Multiaddr{ma1, ma2, ma3, ma4, ma5}, ps.PeerInfo(id1).Addrs)
159 +
160 + // check the addr TTL is a bit smaller than the init TTL
161 + testTTL(AddressTTL, id1, ma1)
162 + testTTL(AddressTTL, id1, ma2)
163 + testTTL(AddressTTL, id1, ma3)
164 + testTTL(AddressTTL, id1, ma4)
165 + testTTL(AddressTTL, id1, ma5)
166 +
167 + // change the TTL
168 + setTTL := func(id ID, addr ma.Multiaddr, ttl time.Time) {
169 + a := ab.addrs[id][addr.String()]
170 + a.TTL = ttl
171 + ab.addrs[id][addr.String()] = a
172 + }
173 + setTTL(id1, ma1, time.Now().Add(-1*time.Second))
174 + setTTL(id1, ma2, time.Now().Add(-1*time.Hour))
175 + setTTL(id1, ma3, time.Now().Add(-1*AddressTTL))
176 +
177 + // should no longer list those
178 + test([]ma.Multiaddr{ma4, ma5}, ps.Addresses(id1))
179 + test([]ma.Multiaddr{ma4, ma5}, ps.PeerInfo(id1).Addrs)
180 +
181 + // should no longer be there
182 + if len(ab.addrs[id1]) != 2 {
183 + t.Error("incorrect addr count", len(ab.addrs[id1]), ab.addrs[id1])
184 + }
185 +}