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
+}