order addresses to give certain address types priority
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
Oct 14, 2015 at 12:37 UTC
49733f4da1cde68f92e93f87de6e431c105d74cb
2 files changed
+91
-5
p2p/net/swarm/dial_test.go
+36
@@ -2,6 +2,7 @@ package swarm
2
3
import (
4
"net"
5
+ "sort"
6
"sync"
7
"testing"
8
"time"
@@ -438,3 +439,38 @@ func TestDialBackoffClears(t *testing.T) {
439
t.Log("correctly cleared backoff")
440
}
441
}
442
+
443
+func mkAddr(t *testing.T, s string) ma.Multiaddr {
444
+ a, err := ma.NewMultiaddr(s)
445
+ if err != nil {
446
+ t.Fatal(err)
447
+ }
448
+
449
+ return a
450
+}
451
+
452
+func TestAddressSorting(t *testing.T) {
453
+ u1 := mkAddr(t, "/ip4/152.12.23.53/udp/1234/utp")
454
+ u2l := mkAddr(t, "/ip4/127.0.0.1/udp/1234/utp")
455
+ local := mkAddr(t, "/ip4/127.0.0.1/tcp/1234")
456
+ norm := mkAddr(t, "/ip4/6.5.4.3/tcp/1234")
457
+
458
+ l := AddrList{local, u1, u2l, norm}
459
+ sort.Sort(l)
460
+
461
+ if !l[0].Equal(u2l) {
462
+ t.Fatal("expected utp local addr to be sorted first: ", l[0])
463
+ }
464
+
465
+ if !l[1].Equal(u1) {
466
+ t.Fatal("expected utp addr to be sorted second")
467
+ }
468
+
469
+ if !l[2].Equal(local) {
470
+ t.Fatal("expected tcp localhost addr thid")
471
+ }
472
+
473
+ if !l[3].Equal(norm) {
474
+ t.Fatal("expected normal addr last")
475
+ }
476
+}
p2p/net/swarm/swarm_dial.go
+55
-5
@@ -1,10 +1,11 @@
1
package swarm
2
3
import (
4
+ "bytes"
5
"errors"
6
"fmt"
6
- "math/rand"
7
"net"
8
+ "sort"
9
"sync"
10
"time"
11
@@ -358,6 +359,9 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
359
360
func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {
361
362
+ // sort addresses so preferred addresses are dialed sooner
363
+ sort.Sort(AddrList(remoteAddrs))
364
+
365
// try to connect to one of the peer's known addresses.
366
// we dial concurrently to each of the addresses, which:
367
// * makes the process faster overall
@@ -404,10 +408,7 @@ func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remote
408
// to end early.
409
go func() {
410
limiter := make(chan struct{}, 8)
407
- // permute addrs so we try different sets first each time.
408
- for _, i := range rand.Perm(len(remoteAddrs)) {
409
-
410
- addr := remoteAddrs[i]
411
+ for _, addr := range remoteAddrs {
412
// returns whatever ratelimiting is acceptable for workerAddr.
413
// may not rate limit at all.
414
rl := s.addrDialRateLimit(addr)
@@ -526,3 +527,52 @@ func isTCPMultiaddr(a ma.Multiaddr) bool {
527
p := a.Protocols()
528
return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp"
529
}
530
+
531
+type AddrList []ma.Multiaddr
532
+
533
+func (al AddrList) Len() int {
534
+ return len(al)
535
+}
536
+
537
+func (al AddrList) Swap(i, j int) {
538
+ al[i], al[j] = al[j], al[i]
539
+}
540
+
541
+func (al AddrList) Less(i, j int) bool {
542
+ a := al[i]
543
+ b := al[j]
544
+
545
+ // dial localhost addresses next, they should fail immediately
546
+ lba := manet.IsIPLoopback(a)
547
+ lbb := manet.IsIPLoopback(b)
548
+ if lba {
549
+ if !lbb {
550
+ return true
551
+ }
552
+ }
553
+
554
+ // dial utp and similar 'non-fd-consuming' addresses first
555
+ fda := isFDCostlyTransport(a)
556
+ fdb := isFDCostlyTransport(b)
557
+ if !fda {
558
+ if fdb {
559
+ return true
560
+ }
561
+
562
+ // if neither consume fd's, assume equal ordering
563
+ return false
564
+ }
565
+
566
+ // if 'b' doesnt take a file descriptor
567
+ if !fdb {
568
+ return false
569
+ }
570
+
571
+ // if 'b' is loopback and both take file descriptors
572
+ if lbb {
573
+ return false
574
+ }
575
+
576
+ // for the rest, just sort by bytes
577
+ return bytes.Compare(a.Bytes(), b.Bytes()) > 0
578
+}