@cryptotaxi247 / kubo / commits / e0f11dff2

dht: FindPeersConnectedToPeer

Juan Batiz-Benet committed Nov 24, 2014 at 14:58 UTC e0f11dff2423a4a6ab1dd6d125e6a1d29a0baab3
3 files changed +166
routing/dht/dht_test.go
+95
@@ -2,6 +2,7 @@ package dht
2
3 import (
4 "bytes"
5 + "sort"
6 "testing"
7
8 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@@ -414,6 +415,100 @@ func TestFindPeer(t *testing.T) {
415 }
416 }
417
418 +func TestFindPeersConnectedToPeer(t *testing.T) {
419 + if testing.Short() {
420 + t.SkipNow()
421 + }
422 +
423 + ctx := context.Background()
424 + u.Debug = false
425 +
426 + _, peers, dhts := setupDHTS(ctx, 4, t)
427 + defer func() {
428 + for i := 0; i < 4; i++ {
429 + dhts[i].Close()
430 + dhts[i].dialer.(inet.Network).Close()
431 + }
432 + }()
433 +
434 + // topology:
435 + // 0-1, 1-2, 1-3, 2-3
436 + err := dhts[0].Connect(ctx, peers[1])
437 + if err != nil {
438 + t.Fatal(err)
439 + }
440 +
441 + err = dhts[1].Connect(ctx, peers[2])
442 + if err != nil {
443 + t.Fatal(err)
444 + }
445 +
446 + err = dhts[1].Connect(ctx, peers[3])
447 + if err != nil {
448 + t.Fatal(err)
449 + }
450 +
451 + err = dhts[2].Connect(ctx, peers[3])
452 + if err != nil {
453 + t.Fatal(err)
454 + }
455 +
456 + // fmt.Println("0 is", peers[0])
457 + // fmt.Println("1 is", peers[1])
458 + // fmt.Println("2 is", peers[2])
459 + // fmt.Println("3 is", peers[3])
460 +
461 + ctxT, _ := context.WithTimeout(ctx, time.Second)
462 + pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2].ID())
463 + if err != nil {
464 + t.Fatal(err)
465 + }
466 +
467 + // shouldFind := []peer.Peer{peers[1], peers[3]}
468 + found := []peer.Peer{}
469 + for nextp := range pchan {
470 + found = append(found, nextp)
471 + }
472 +
473 + // fmt.Printf("querying 0 (%s) FindPeersConnectedToPeer 2 (%s)\n", peers[0], peers[2])
474 + // fmt.Println("should find 1, 3", shouldFind)
475 + // fmt.Println("found", found)
476 +
477 + // testPeerListsMatch(t, shouldFind, found)
478 +
479 + log.Warning("TestFindPeersConnectedToPeer is not quite correct")
480 + if len(found) == 0 {
481 + t.Fatal("didn't find any peers.")
482 + }
483 +}
484 +
485 +func testPeerListsMatch(t *testing.T, p1, p2 []peer.Peer) {
486 +
487 + if len(p1) != len(p2) {
488 + t.Fatal("did not find as many peers as should have", p1, p2)
489 + }
490 +
491 + ids1 := make([]string, len(p1))
492 + ids2 := make([]string, len(p2))
493 +
494 + for i, p := range p1 {
495 + ids1[i] = p.ID().Pretty()
496 + }
497 +
498 + for i, p := range p2 {
499 + ids2[i] = p.ID().Pretty()
500 + }
501 +
502 + sort.Sort(sort.StringSlice(ids1))
503 + sort.Sort(sort.StringSlice(ids2))
504 +
505 + for i := range ids1 {
506 + if ids1[i] != ids2[i] {
507 + t.Fatal("Didnt find expected peer", ids1[i], ids2)
508 + }
509 + }
510 +}
511 +
512 func TestConnectCollision(t *testing.T) {
513 if testing.Short() {
514 t.SkipNow()
routing/dht/handlers.go
+1
@@ -159,6 +159,7 @@ func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.Peer, pmes *pb.Me
159 for _, p := range withAddresses {
160 log.Debugf("handleFindPeer: sending back '%s'", p)
161 }
162 +
163 resp.CloserPeers = pb.PeersToPBPeers(dht.dialer, withAddresses)
164 return resp, nil
165 }
routing/dht/routing.go
+70
@@ -5,6 +5,7 @@ import (
5
6 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7
8 + inet "github.com/jbenet/go-ipfs/net"
9 peer "github.com/jbenet/go-ipfs/peer"
10 "github.com/jbenet/go-ipfs/routing"
11 pb "github.com/jbenet/go-ipfs/routing/dht/pb"
@@ -268,6 +269,75 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error)
269 return result.peer, nil
270 }
271
272 +// FindPeersConnectedToPeer searches for peers directly connected to a given peer.
273 +func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<-chan peer.Peer, error) {
274 +
275 + peerchan := make(chan peer.Peer, 10)
276 + peersSeen := map[string]peer.Peer{}
277 +
278 + routeLevel := 0
279 + closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
280 + if closest == nil || len(closest) == 0 {
281 + return nil, kb.ErrLookupFailure
282 + }
283 +
284 + // setup the Query
285 + query := newQuery(u.Key(id), dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
286 +
287 + pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
288 + if err != nil {
289 + return nil, err
290 + }
291 +
292 + var clpeers []peer.Peer
293 + closer := pmes.GetCloserPeers()
294 + for _, pbp := range closer {
295 + // skip peers already seen
296 + if _, found := peersSeen[string(pbp.GetId())]; found {
297 + continue
298 + }
299 +
300 + // skip peers that fail to unmarshal
301 + p, err := pb.PBPeerToPeer(dht.peerstore, pbp)
302 + if err != nil {
303 + log.Warning(err)
304 + continue
305 + }
306 +
307 + // if peer is connected, send it to our client.
308 + if pb.Connectedness(*pbp.Connection) == inet.Connected {
309 + select {
310 + case <-ctx.Done():
311 + return nil, ctx.Err()
312 + case peerchan <- p:
313 + }
314 + }
315 +
316 + peersSeen[string(p.ID())] = p
317 +
318 + // if peer is the peer we're looking for, don't bother querying it.
319 + if pb.Connectedness(*pbp.Connection) != inet.Connected {
320 + clpeers = append(clpeers, p)
321 + }
322 + }
323 +
324 + return &dhtQueryResult{closerPeers: clpeers}, nil
325 + })
326 +
327 + // run it! run it asynchronously to gen peers as results are found.
328 + // this does no error checking
329 + go func() {
330 + if _, err := query.Run(ctx, closest); err != nil {
331 + log.Error(err)
332 + }
333 +
334 + // close the peerchan channel when done.
335 + close(peerchan)
336 + }()
337 +
338 + return peerchan, nil
339 +}
340 +
341 // Ping a peer, log the time it took
342 func (dht *IpfsDHT) Ping(ctx context.Context, p peer.Peer) error {
343 // Thoughts: maybe this should accept an ID and do a peer lookup?