@cryptotaxi247 / kubo / commits / a43886245

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)