more work implementing coral type lookups
Jeromy committed
Aug 10, 2014 at 21:02 UTC
a43886245e7e5ada38acda3d8815111e57d8c9d3
6 files changed
+336
-183
routing/dht/dht.go
+113
-98
@@ -2,7 +2,6 @@ package dht
2
3
import (
4
"bytes"
5
- "encoding/json"
5
"errors"
6
"sync"
7
"time"
@@ -28,7 +27,7 @@ type IpfsDHT struct {
27
// NOTE: (currently, only a single table is used)
28
routes []*kb.RoutingTable
29
31
- network *swarm.Swarm
30
+ network swarm.Network
31
32
// Local peer (yourself)
33
self *peer.Peer
@@ -95,7 +94,7 @@ func (dht *IpfsDHT) Start() {
94
go dht.handleMessages()
95
}
96
98
-// Connect to a new peer at the given address
97
+// Connect to a new peer at the given address, ping and add to the routing table
98
func (dht *IpfsDHT) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
99
maddrstr, _ := addr.String()
100
u.DOut("Connect to new peer: %s", maddrstr)
@@ -104,8 +103,6 @@ func (dht *IpfsDHT) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
103
return nil, err
104
}
105
107
- dht.Update(npeer)
108
-
106
// Ping new peer to register in their routing table
107
// NOTE: this should be done better...
108
err = dht.Ping(npeer, time.Second*2)
@@ -113,6 +110,8 @@ func (dht *IpfsDHT) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
110
return nil, errors.New("failed to ping newly connected peer")
111
}
112
113
+ dht.Update(npeer)
114
+
115
return npeer, nil
116
}
117
@@ -122,9 +121,10 @@ func (dht *IpfsDHT) handleMessages() {
121
u.DOut("Begin message handling routine")
122
123
checkTimeouts := time.NewTicker(time.Minute * 5)
124
+ ch := dht.network.GetChan()
125
for {
126
select {
127
- case mes, ok := <-dht.network.Chan.Incoming:
127
+ case mes, ok := <-ch.Incoming:
128
if !ok {
129
u.DOut("handleMessages closing, bad recv on incoming")
130
return
@@ -184,8 +184,8 @@ func (dht *IpfsDHT) handleMessages() {
184
dht.handleDiagnostic(mes.Peer, pmes)
185
}
186
187
- case err := <-dht.network.Chan.Errors:
188
- u.DErr("dht err: %s", err)
187
+ case err := <-ch.Errors:
188
+ u.PErr("dht err: %s", err)
189
case <-dht.shutdown:
190
checkTimeouts.Stop()
191
return
@@ -235,7 +235,7 @@ func (dht *IpfsDHT) putValueToNetwork(p *peer.Peer, key string, value []byte) er
235
}
236
237
mes := swarm.NewMessage(p, pmes.ToProtobuf())
238
- dht.network.Chan.Outgoing <- mes
238
+ dht.network.Send(mes)
239
return nil
240
}
241
@@ -260,17 +260,26 @@ func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *PBDHTMessage) {
260
resp.Success = true
261
} else {
262
// No providers?
263
- // Find closest peer(s) to desired key and reply with that info
264
- closer := dht.routes[0].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
265
- resp.Peers = []*peer.Peer{closer}
263
+ // Find closest peer on given cluster to desired key and reply with that info
264
+
265
+ level := pmes.GetValue()[0] // Using value field to specify cluster level
266
+
267
+ closer := dht.routes[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
268
+
269
+ // If this peer is closer than the one from the table, return nil
270
+ if kb.Closer(dht.self.ID, closer.ID, u.Key(pmes.GetKey())) {
271
+ resp.Peers = nil
272
+ } else {
273
+ resp.Peers = []*peer.Peer{closer}
274
+ }
275
}
276
} else {
268
- //temp: what other errors can a datastore throw?
277
+ //temp: what other errors can a datastore return?
278
panic(err)
279
}
280
281
mes := swarm.NewMessage(p, resp.ToProtobuf())
273
- dht.network.Chan.Outgoing <- mes
282
+ dht.network.Send(mes)
283
}
284
285
// Store a value in this peer local storage
@@ -290,84 +299,66 @@ func (dht *IpfsDHT) handlePing(p *peer.Peer, pmes *PBDHTMessage) {
299
Id: pmes.GetId(),
300
}
301
293
- dht.network.Chan.Outgoing <- swarm.NewMessage(p, resp.ToProtobuf())
302
+ dht.network.Send(swarm.NewMessage(p, resp.ToProtobuf()))
303
}
304
305
func (dht *IpfsDHT) handleFindPeer(p *peer.Peer, pmes *PBDHTMessage) {
297
- success := true
298
- u.POut("handleFindPeer: searching for '%s'", peer.ID(pmes.GetKey()).Pretty())
299
- closest := dht.routes[0].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
306
+ resp := DHTMessage{
307
+ Type: pmes.GetType(),
308
+ Id: pmes.GetId(),
309
+ Response: true,
310
+ }
311
+ defer func() {
312
+ mes := swarm.NewMessage(p, resp.ToProtobuf())
313
+ dht.network.Send(mes)
314
+ }()
315
+ level := pmes.GetValue()[0]
316
+ u.DOut("handleFindPeer: searching for '%s'", peer.ID(pmes.GetKey()).Pretty())
317
+ closest := dht.routes[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
318
if closest == nil {
319
u.PErr("handleFindPeer: could not find anything.")
302
- success = false
320
+ return
321
}
322
323
if len(closest.Addresses) == 0 {
324
u.PErr("handleFindPeer: no addresses for connected peer...")
307
- success = false
325
+ return
326
}
327
310
- u.POut("handleFindPeer: sending back '%s'", closest.ID.Pretty())
311
-
312
- addr, err := closest.Addresses[0].String()
313
- if err != nil {
314
- u.PErr(err.Error())
315
- success = false
328
+ // If the found peer further away than this peer...
329
+ if kb.Closer(dht.self.ID, closest.ID, u.Key(pmes.GetKey())) {
330
+ return
331
}
332
333
+ u.DOut("handleFindPeer: sending back '%s'", closest.ID.Pretty())
334
+ resp.Peers = []*peer.Peer{closest}
335
+ resp.Success = true
336
+}
337
+
338
+func (dht *IpfsDHT) handleGetProviders(p *peer.Peer, pmes *PBDHTMessage) {
339
resp := DHTMessage{
319
- Type: pmes.GetType(),
320
- Response: true,
340
+ Type: PBDHTMessage_GET_PROVIDERS,
341
+ Key: pmes.GetKey(),
342
Id: pmes.GetId(),
322
- Value: []byte(addr),
323
- Success: success,
343
+ Response: true,
344
}
345
326
- mes := swarm.NewMessage(p, resp.ToProtobuf())
327
- dht.network.Chan.Outgoing <- mes
328
-}
329
-
330
-func (dht *IpfsDHT) handleGetProviders(p *peer.Peer, pmes *PBDHTMessage) {
346
dht.providerLock.RLock()
347
providers := dht.providers[u.Key(pmes.GetKey())]
348
dht.providerLock.RUnlock()
349
if providers == nil || len(providers) == 0 {
335
- // ?????
336
- u.DOut("No known providers for requested key.")
337
- }
338
-
339
- // This is just a quick hack, formalize method of sending addrs later
340
- addrs := make(map[u.Key]string)
341
- for _, prov := range providers {
342
- ma := prov.Value.NetAddress("tcp")
343
- str, err := ma.String()
344
- if err != nil {
345
- u.PErr("Error: %s", err)
346
- continue
350
+ // TODO: work on tiering this
351
+ closer := dht.routes[0].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
352
+ resp.Peers = []*peer.Peer{closer}
353
+ } else {
354
+ for _, prov := range providers {
355
+ resp.Peers = append(resp.Peers, prov.Value)
356
}
348
-
349
- addrs[prov.Value.Key()] = str
350
- }
351
-
352
- success := true
353
- data, err := json.Marshal(addrs)
354
- if err != nil {
355
- u.POut("handleGetProviders: error marshalling struct to JSON: %s", err)
356
- data = nil
357
- success = false
358
- }
359
-
360
- resp := DHTMessage{
361
- Type: PBDHTMessage_GET_PROVIDERS,
362
- Key: pmes.GetKey(),
363
- Value: data,
364
- Id: pmes.GetId(),
365
- Response: true,
366
- Success: success,
357
+ resp.Success = true
358
}
359
360
mes := swarm.NewMessage(p, resp.ToProtobuf())
370
- dht.network.Chan.Outgoing <- mes
361
+ dht.network.Send(mes)
362
}
363
364
type providerInfo struct {
@@ -445,7 +436,7 @@ func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
436
437
for _, ps := range seq {
438
mes := swarm.NewMessage(ps, pmes)
448
- dht.network.Chan.Outgoing <- mes
439
+ dht.network.Send(mes)
440
}
441
442
buf := new(bytes.Buffer)
@@ -481,19 +472,21 @@ out:
472
}
473
474
mes := swarm.NewMessage(p, resp.ToProtobuf())
484
- dht.network.Chan.Outgoing <- mes
475
+ dht.network.Send(mes)
476
}
477
487
-func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duration) ([]byte, error) {
478
+// getValueSingle simply performs the get value RPC with the given parameters
479
+func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duration, level int) (*PBDHTMessage, error) {
480
pmes := DHTMessage{
489
- Type: PBDHTMessage_GET_VALUE,
490
- Key: string(key),
491
- Id: GenerateMessageID(),
481
+ Type: PBDHTMessage_GET_VALUE,
482
+ Key: string(key),
483
+ Value: []byte{byte(level)},
484
+ Id: GenerateMessageID(),
485
}
486
response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
487
488
mes := swarm.NewMessage(p, pmes.ToProtobuf())
496
- dht.network.Chan.Outgoing <- mes
489
+ dht.network.Send(mes)
490
491
// Wait for either the response or a timeout
492
timeup := time.After(timeout)
@@ -511,46 +504,41 @@ func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duratio
504
if err != nil {
505
return nil, err
506
}
514
- // TODO: debate moving this logic out of this function to be handled by the caller
515
- if pmes_out.GetSuccess() {
516
- if pmes_out.Value == nil {
517
- // We were given provider[s]
518
- return dht.getFromProviderList(key, timeout, pmes_out.GetPeers())
519
- }
520
- // We were given the value
521
- return pmes_out.GetValue(), nil
522
- } else {
523
- return pmes_out.GetValue(), u.ErrSearchIncomplete
524
- }
507
+ return pmes_out, nil
508
}
509
}
510
528
-// TODO: Im not certain on this implementation, we get a list of providers from someone
529
-// what do we do with it? Connect to each of them? randomly pick one to get the value from?
530
-// Or just connect to one at a time until we get a successful connection and request the
531
-// value from it?
532
-func (dht *IpfsDHT) getFromProviderList(key u.Key, timeout time.Duration, provlist []*PBDHTMessage_PBPeer) ([]byte, error) {
533
- for _, prov := range provlist {
534
- prov_p, _ := dht.Find(peer.ID(prov.GetId()))
535
- if prov_p == nil {
536
- maddr, err := ma.NewMultiaddr(prov.GetAddr())
511
+// TODO: Im not certain on this implementation, we get a list of peers/providers
512
+// from someone what do we do with it? Connect to each of them? randomly pick
513
+// one to get the value from? Or just connect to one at a time until we get a
514
+// successful connection and request the value from it?
515
+func (dht *IpfsDHT) getFromPeerList(key u.Key, timeout time.Duration,
516
+ peerlist []*PBDHTMessage_PBPeer, level int) ([]byte, error) {
517
+ for _, pinfo := range peerlist {
518
+ p, _ := dht.Find(peer.ID(pinfo.GetId()))
519
+ if p == nil {
520
+ maddr, err := ma.NewMultiaddr(pinfo.GetAddr())
521
if err != nil {
522
u.PErr("getValue error: %s", err)
523
continue
524
}
541
- prov_p, err = dht.Connect(maddr)
525
+ p, err = dht.Connect(maddr)
526
if err != nil {
527
u.PErr("getValue error: %s", err)
528
continue
529
}
530
}
547
- data, err := dht.getValueSingle(prov_p, key, timeout)
531
+ pmes, err := dht.getValueSingle(p, key, timeout, level)
532
if err != nil {
549
- u.DErr("getFromProvs error: %s", err)
533
+ u.DErr("getFromPeers error: %s", err)
534
continue
535
}
536
+ dht.addProviderEntry(key, p)
537
553
- return data, nil
538
+ // Make sure it was a successful get
539
+ if pmes.GetSuccess() && pmes.Value != nil {
540
+ return pmes.GetValue(), nil
541
+ }
542
}
543
return nil, u.ErrNotFound
544
}
@@ -584,3 +572,30 @@ func (dht *IpfsDHT) Find(id peer.ID) (*peer.Peer, *kb.RoutingTable) {
572
}
573
return nil, nil
574
}
575
+
576
+func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Duration, level int) (*PBDHTMessage, error) {
577
+ pmes := DHTMessage{
578
+ Type: PBDHTMessage_FIND_NODE,
579
+ Key: string(id),
580
+ Id: GenerateMessageID(),
581
+ Value: []byte{byte(level)},
582
+ }
583
+
584
+ mes := swarm.NewMessage(p, pmes.ToProtobuf())
585
+ listenChan := dht.ListenFor(pmes.Id, 1, time.Minute)
586
+ dht.network.Send(mes)
587
+ after := time.After(timeout)
588
+ select {
589
+ case <-after:
590
+ dht.Unlisten(pmes.Id)
591
+ return nil, u.ErrTimeout
592
+ case resp := <-listenChan:
593
+ pmes_out := new(PBDHTMessage)
594
+ err := proto.Unmarshal(resp.Data, pmes_out)
595
+ if err != nil {
596
+ return nil, err
597
+ }
598
+
599
+ return pmes_out, nil
600
+ }
601
+}
routing/dht/dht_test.go
+91
-20
@@ -11,6 +11,37 @@ import (
11
"time"
12
)
13
14
+func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) {
15
+ var addrs []*ma.Multiaddr
16
+ for i := 0; i < 4; i++ {
17
+ a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
18
+ if err != nil {
19
+ t.Fatal(err)
20
+ }
21
+ addrs = append(addrs, a)
22
+ }
23
+
24
+ var peers []*peer.Peer
25
+ for i := 0; i < 4; i++ {
26
+ p := new(peer.Peer)
27
+ p.AddAddress(addrs[i])
28
+ p.ID = peer.ID([]byte(fmt.Sprintf("peer_%d", i)))
29
+ peers = append(peers, p)
30
+ }
31
+
32
+ var dhts []*IpfsDHT
33
+ for i := 0; i < 4; i++ {
34
+ d, err := NewDHT(peers[i])
35
+ if err != nil {
36
+ t.Fatal(err)
37
+ }
38
+ dhts = append(dhts, d)
39
+ d.Start()
40
+ }
41
+
42
+ return addrs, peers, dhts
43
+}
44
+
45
func TestPing(t *testing.T) {
46
u.Debug = false
47
addr_a, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
@@ -90,11 +121,13 @@ func TestValueGetSet(t *testing.T) {
121
dht_a.Start()
122
dht_b.Start()
123
124
+ errsa := dht_a.network.GetChan().Errors
125
+ errsb := dht_b.network.GetChan().Errors
126
go func() {
127
select {
95
- case err := <-dht_a.network.Chan.Errors:
128
+ case err := <-errsa:
129
t.Fatal(err)
97
- case err := <-dht_b.network.Chan.Errors:
130
+ case err := <-errsb:
131
t.Fatal(err)
132
}
133
}()
@@ -118,6 +151,52 @@ func TestValueGetSet(t *testing.T) {
151
152
func TestProvides(t *testing.T) {
153
u.Debug = false
154
+
155
+ addrs, _, dhts := setupDHTS(4, t)
156
+
157
+ _, err := dhts[0].Connect(addrs[1])
158
+ if err != nil {
159
+ t.Fatal(err)
160
+ }
161
+
162
+ _, err = dhts[1].Connect(addrs[2])
163
+ if err != nil {
164
+ t.Fatal(err)
165
+ }
166
+
167
+ _, err = dhts[1].Connect(addrs[3])
168
+ if err != nil {
169
+ t.Fatal(err)
170
+ }
171
+
172
+ err = dhts[3].PutLocal(u.Key("hello"), []byte("world"))
173
+ if err != nil {
174
+ t.Fatal(err)
175
+ }
176
+
177
+ err = dhts[3].Provide(u.Key("hello"))
178
+ if err != nil {
179
+ t.Fatal(err)
180
+ }
181
+
182
+ time.Sleep(time.Millisecond * 60)
183
+
184
+ provs, err := dhts[0].FindProviders(u.Key("hello"), time.Second)
185
+ if err != nil {
186
+ t.Fatal(err)
187
+ }
188
+
189
+ if len(provs) != 1 {
190
+ t.Fatal("Didnt get back providers")
191
+ }
192
+
193
+ for i := 0; i < 4; i++ {
194
+ dhts[i].Halt()
195
+ }
196
+}
197
+
198
+func TestLayeredGet(t *testing.T) {
199
+ u.Debug = false
200
var addrs []*ma.Multiaddr
201
for i := 0; i < 4; i++ {
202
a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
@@ -147,7 +226,7 @@ func TestProvides(t *testing.T) {
226
227
_, err := dhts[0].Connect(addrs[1])
228
if err != nil {
150
- t.Fatal(err)
229
+ t.Fatalf("Failed to connect: %s", err)
230
}
231
232
_, err = dhts[1].Connect(addrs[2])
@@ -172,13 +251,13 @@ func TestProvides(t *testing.T) {
251
252
time.Sleep(time.Millisecond * 60)
253
175
- provs, err := dhts[0].FindProviders(u.Key("hello"), time.Second)
254
+ val, err := dhts[0].GetValue(u.Key("hello"), time.Second)
255
if err != nil {
256
t.Fatal(err)
257
}
258
180
- if len(provs) != 1 {
181
- t.Fatal("Didnt get back providers")
259
+ if string(val) != "world" {
260
+ t.Fatal("Got incorrect value.")
261
}
262
263
for i := 0; i < 4; i++ {
@@ -186,7 +265,7 @@ func TestProvides(t *testing.T) {
265
}
266
}
267
189
-func TestLayeredGet(t *testing.T) {
268
+func TestFindPeer(t *testing.T) {
269
u.Debug = false
270
var addrs []*ma.Multiaddr
271
for i := 0; i < 4; i++ {
@@ -230,25 +309,17 @@ func TestLayeredGet(t *testing.T) {
309
t.Fatal(err)
310
}
311
233
- err = dhts[3].PutLocal(u.Key("hello"), []byte("world"))
312
+ p, err := dhts[0].FindPeer(peers[2].ID, time.Second)
313
if err != nil {
314
t.Fatal(err)
315
}
316
238
- err = dhts[3].Provide(u.Key("hello"))
239
- if err != nil {
240
- t.Fatal(err)
317
+ if p == nil {
318
+ t.Fatal("Failed to find peer.")
319
}
320
243
- time.Sleep(time.Millisecond * 60)
244
-
245
- val, err := dhts[0].GetValue(u.Key("hello"), time.Second)
246
- if err != nil {
247
- t.Fatal(err)
248
- }
249
-
250
- if string(val) != "world" {
251
- t.Fatal("Got incorrect value.")
321
+ if !p.ID.Equal(peers[2].ID) {
322
+ t.Fatal("Didnt find expected peer.")
323
}
324
325
for i := 0; i < 4; i++ {
routing/dht/routing.go
+74
-63
@@ -3,8 +3,6 @@ package dht
3
import (
4
"bytes"
5
"encoding/json"
6
- "errors"
7
- "fmt"
6
"math/rand"
7
"time"
8
@@ -35,19 +33,19 @@ func GenerateMessageID() uint64 {
33
// This is the top level "Store" operation of the DHT
34
func (s *IpfsDHT) PutValue(key u.Key, value []byte) {
35
complete := make(chan struct{})
38
- for i, route := range s.routes {
36
+ for _, route := range s.routes {
37
p := route.NearestPeer(kb.ConvertKey(key))
38
if p == nil {
41
- s.network.Chan.Errors <- fmt.Errorf("No peer found on level %d", i)
42
- continue
39
+ s.network.Error(kb.ErrLookupFailure)
40
go func() {
41
complete <- struct{}{}
42
}()
43
+ continue
44
}
45
go func() {
46
err := s.putValueToNetwork(p, string(key), value)
47
if err != nil {
50
- s.network.Chan.Errors <- err
48
+ s.network.Error(err)
49
}
50
complete <- struct{}{}
51
}()
@@ -61,19 +59,46 @@ func (s *IpfsDHT) PutValue(key u.Key, value []byte) {
59
// If the search does not succeed, a multiaddr string of a closer peer is
60
// returned along with util.ErrSearchIncomplete
61
func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
64
- for _, route := range s.routes {
65
- var p *peer.Peer
66
- p = route.NearestPeer(kb.ConvertKey(key))
67
- if p == nil {
68
- return nil, errors.New("Table returned nil peer!")
69
- }
62
+ route_level := 0
63
71
- b, err := s.getValueSingle(p, key, timeout)
72
- if err == nil {
73
- return b, nil
64
+ p := s.routes[route_level].NearestPeer(kb.ConvertKey(key))
65
+ if p == nil {
66
+ return nil, kb.ErrLookupFailure
67
+ }
68
+
69
+ for route_level < len(s.routes) && p != nil {
70
+ pmes, err := s.getValueSingle(p, key, timeout, route_level)
71
+ if err != nil {
72
+ return nil, u.WrapError(err, "getValue Error")
73
}
75
- if err != u.ErrSearchIncomplete {
76
- return nil, err
74
+
75
+ if pmes.GetSuccess() {
76
+ if pmes.Value == nil { // We were given provider[s]
77
+ return s.getFromPeerList(key, timeout, pmes.GetPeers(), route_level)
78
+ }
79
+
80
+ // Success! We were given the value
81
+ return pmes.GetValue(), nil
82
+ } else {
83
+ // We were given a closer node
84
+ closers := pmes.GetPeers()
85
+ if len(closers) > 0 {
86
+ maddr, err := ma.NewMultiaddr(closers[0].GetAddr())
87
+ if err != nil {
88
+ // ??? Move up route level???
89
+ panic("not yet implemented")
90
+ }
91
+
92
+ // TODO: dht.Connect has overhead due to an internal
93
+ // ping to the target. Use something else
94
+ p, err = s.Connect(maddr)
95
+ if err != nil {
96
+ // Move up route level
97
+ panic("not yet implemented.")
98
+ }
99
+ } else {
100
+ route_level++
101
+ }
102
}
103
}
104
return nil, u.ErrNotFound
@@ -86,7 +111,7 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
111
func (s *IpfsDHT) Provide(key u.Key) error {
112
peers := s.routes[0].NearestPeers(kb.ConvertKey(key), PoolSize)
113
if len(peers) == 0 {
89
- //return an error
114
+ return kb.ErrLookupFailure
115
}
116
117
pmes := DHTMessage{
@@ -97,7 +122,7 @@ func (s *IpfsDHT) Provide(key u.Key) error {
122
123
for _, p := range peers {
124
mes := swarm.NewMessage(p, pbmes)
100
- s.network.Chan.Outgoing <- mes
125
+ s.network.Send(mes)
126
}
127
return nil
128
}
@@ -105,6 +130,9 @@ func (s *IpfsDHT) Provide(key u.Key) error {
130
// FindProviders searches for peers who can provide the value for given key.
131
func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer, error) {
132
p := s.routes[0].NearestPeer(kb.ConvertKey(key))
133
+ if p == nil {
134
+ return nil, kb.ErrLookupFailure
135
+ }
136
137
pmes := DHTMessage{
138
Type: PBDHTMessage_GET_PROVIDERS,
@@ -116,7 +144,7 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
144
145
listenChan := s.ListenFor(pmes.Id, 1, time.Minute)
146
u.DOut("Find providers for: '%s'", key)
119
- s.network.Chan.Outgoing <- mes
147
+ s.network.Send(mes)
148
after := time.After(timeout)
149
select {
150
case <-after:
@@ -129,17 +157,12 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
157
if err != nil {
158
return nil, err
159
}
132
- var addrs map[u.Key]string
133
- err = json.Unmarshal(pmes_out.GetValue(), &addrs)
134
- if err != nil {
135
- return nil, err
136
- }
160
161
var prov_arr []*peer.Peer
139
- for pid, addr := range addrs {
140
- p := s.network.Find(pid)
162
+ for _, prov := range pmes_out.GetPeers() {
163
+ p := s.network.Find(u.Key(prov.GetId()))
164
if p == nil {
142
- maddr, err := ma.NewMultiaddr(addr)
165
+ maddr, err := ma.NewMultiaddr(prov.GetAddr())
166
if err != nil {
167
u.PErr("error connecting to new peer: %s", err)
168
continue
@@ -162,48 +185,36 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
185
186
// FindPeer searches for a peer with given ID.
187
func (s *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, error) {
165
- p := s.routes[0].NearestPeer(kb.ConvertPeerID(id))
166
-
167
- pmes := DHTMessage{
168
- Type: PBDHTMessage_FIND_NODE,
169
- Key: string(id),
170
- Id: GenerateMessageID(),
188
+ route_level := 0
189
+ p := s.routes[route_level].NearestPeer(kb.ConvertPeerID(id))
190
+ if p == nil {
191
+ return nil, kb.ErrLookupFailure
192
}
193
173
- mes := swarm.NewMessage(p, pmes.ToProtobuf())
174
-
175
- listenChan := s.ListenFor(pmes.Id, 1, time.Minute)
176
- s.network.Chan.Outgoing <- mes
177
- after := time.After(timeout)
178
- select {
179
- case <-after:
180
- s.Unlisten(pmes.Id)
181
- return nil, u.ErrTimeout
182
- case resp := <-listenChan:
183
- pmes_out := new(PBDHTMessage)
184
- err := proto.Unmarshal(resp.Data, pmes_out)
185
- if err != nil {
186
- return nil, err
194
+ for route_level < len(s.routes) {
195
+ pmes, err := s.findPeerSingle(p, id, timeout, route_level)
196
+ plist := pmes.GetPeers()
197
+ if len(plist) == 0 {
198
+ route_level++
199
}
188
- addr := string(pmes_out.GetValue())
189
- maddr, err := ma.NewMultiaddr(addr)
200
+ found := plist[0]
201
+
202
+ addr, err := ma.NewMultiaddr(found.GetAddr())
203
if err != nil {
191
- return nil, err
204
+ return nil, u.WrapError(err, "FindPeer received bad info")
205
}
206
194
- found_peer, err := s.Connect(maddr)
207
+ nxtPeer, err := s.Connect(addr)
208
if err != nil {
196
- u.POut("Found peer but couldnt connect.")
197
- return nil, err
209
+ return nil, u.WrapError(err, "FindPeer failed to connect to new peer.")
210
}
199
-
200
- if !found_peer.ID.Equal(id) {
201
- u.POut("FindPeer: searching for '%s' but found '%s'", id.Pretty(), found_peer.ID.Pretty())
202
- return found_peer, u.ErrSearchIncomplete
211
+ if pmes.GetSuccess() {
212
+ return nxtPeer, nil
213
+ } else {
214
+ p = nxtPeer
215
}
204
-
205
- return found_peer, nil
216
}
217
+ return nil, u.ErrNotFound
218
}
219
220
// Ping a peer, log the time it took
@@ -216,14 +227,14 @@ func (dht *IpfsDHT) Ping(p *peer.Peer, timeout time.Duration) error {
227
228
before := time.Now()
229
response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
219
- dht.network.Chan.Outgoing <- mes
230
+ dht.network.Send(mes)
231
232
tout := time.After(timeout)
233
select {
234
case <-response_chan:
235
roundtrip := time.Since(before)
236
p.SetLatency(roundtrip)
226
- u.POut("Ping took %s.", roundtrip.String())
237
+ u.DOut("Ping took %s.", roundtrip.String())
238
return nil
239
case <-tout:
240
// Timed out, think about removing peer from network
@@ -249,7 +260,7 @@ func (dht *IpfsDHT) GetDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
260
pbmes := pmes.ToProtobuf()
261
for _, p := range targets {
262
mes := swarm.NewMessage(p, pbmes)
252
- dht.network.Chan.Outgoing <- mes
263
+ dht.network.Send(mes)
264
}
265
266
var out []*diagInfo
routing/kbucket/util.go
+18
-2
@@ -3,11 +3,16 @@ package dht
3
import (
4
"bytes"
5
"crypto/sha256"
6
+ "errors"
7
8
peer "github.com/jbenet/go-ipfs/peer"
9
u "github.com/jbenet/go-ipfs/util"
10
)
11
12
+// Returned if a routing table query returns no results. This is NOT expected
13
+// behaviour
14
+var ErrLookupFailure = errors.New("failed to find any peer in table")
15
+
16
// ID for IpfsDHT should be a byte slice, to allow for simpler operations
17
// (xor). DHT ids are based on the peer.IDs.
18
//
@@ -19,8 +24,8 @@ func (id ID) Equal(other ID) bool {
24
return bytes.Equal(id, other)
25
}
26
22
-func (id ID) Less(other interface{}) bool {
23
- a, b := equalizeSizes(id, other.(ID))
27
+func (id ID) Less(other ID) bool {
28
+ a, b := equalizeSizes(id, other)
29
for i := 0; i < len(a); i++ {
30
if a[i] != b[i] {
31
return a[i] < b[i]
@@ -80,3 +85,14 @@ func ConvertKey(id u.Key) ID {
85
hash := sha256.Sum256([]byte(id))
86
return hash[:]
87
}
88
+
89
+// Returns true if a is closer to key than b is
90
+func Closer(a, b peer.ID, key u.Key) bool {
91
+ aid := ConvertPeerID(a)
92
+ bid := ConvertPeerID(b)
93
+ tgt := ConvertKey(key)
94
+ adist := xor(aid, tgt)
95
+ bdist := xor(bid, tgt)
96
+
97
+ return adist.Less(bdist)
98
+}
swarm/swarm.go
+14
@@ -355,3 +355,17 @@ func (s *Swarm) Drop(p *peer.Peer) error {
355
356
return conn.Close()
357
}
358
+
359
+func (s *Swarm) Send(mes *Message) {
360
+ s.Chan.Outgoing <- mes
361
+}
362
+
363
+func (s *Swarm) Error(e error) {
364
+ s.Chan.Errors <- e
365
+}
366
+
367
+func (s *Swarm) GetChan() *Chan {
368
+ return s.Chan
369
+}
370
+
371
+var _ Network = &Swarm{}
util/util.go
+26
@@ -1,10 +1,12 @@
1
package util
2
3
import (
4
+ "bytes"
5
"errors"
6
"fmt"
7
"os"
8
"os/user"
9
+ "runtime"
10
"strings"
11
12
b58 "github.com/jbenet/go-base58"
@@ -34,6 +36,30 @@ func (k Key) Pretty() string {
36
return b58.Encode([]byte(k))
37
}
38
39
+type IpfsError struct {
40
+ Inner error
41
+ Note string
42
+ Stack string
43
+}
44
+
45
+func (ie *IpfsError) Error() string {
46
+ buf := new(bytes.Buffer)
47
+ fmt.Fprintln(buf, ie.Inner)
48
+ fmt.Fprintln(buf, ie.Note)
49
+ fmt.Fprintln(buf, ie.Stack)
50
+ return buf.String()
51
+}
52
+
53
+func WrapError(err error, note string) error {
54
+ ie := new(IpfsError)
55
+ ie.Inner = err
56
+ ie.Note = note
57
+ stack := make([]byte, 2048)
58
+ n := runtime.Stack(stack, false)
59
+ ie.Stack = string(stack[:n])
60
+ return ie
61
+}
62
+
63
// Hash is the global IPFS hash function. uses multihash SHA2_256, 256 bits
64
func Hash(data []byte) (mh.Multihash, error) {
65
return mh.Sum(data, mh.SHA2_256, -1)