Skip to content

Commit

Permalink
order addresses to give certain address types priority
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Jeromy <jeromyj@gmail.com>
  • Loading branch information
whyrusleeping committed Oct 17, 2015
1 parent 4de5eaa commit 71474c4
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 5 deletions.
49 changes: 49 additions & 0 deletions p2p/net/swarm/dial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package swarm

import (
"net"
"sort"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -438,3 +439,51 @@ func TestDialBackoffClears(t *testing.T) {
t.Log("correctly cleared backoff")
}
}

func mkAddr(t *testing.T, s string) ma.Multiaddr {
a, err := ma.NewMultiaddr(s)
if err != nil {
t.Fatal(err)
}

return a
}

func TestDockerAddrCheck(t *testing.T) {
a := mkAddr(t, "/ip4/172.17.2.65/tcp/3124")

if !isDefaultDockerRange(a) {
t.Fatal("expected to be in docker range check")
}
}

func TestAddressSorting(t *testing.T) {
u1 := mkAddr(t, "/ip4/152.12.23.53/udp/1234/utp")
u2l := mkAddr(t, "/ip4/127.0.0.1/udp/1234/utp")
local := mkAddr(t, "/ip4/127.0.0.1/tcp/1234")
norm := mkAddr(t, "/ip4/6.5.4.3/tcp/1234")
docker := mkAddr(t, "/ip4/172.17.4.3/tcp/1234")

l := AddrList{local, docker, u1, u2l, norm}
sort.Sort(l)

if !l[0].Equal(u2l) {
t.Fatal("expected utp local addr to be sorted first")
}

if !l[1].Equal(u1) {
t.Fatal("expected utp addr to be sorted second")
}

if !l[2].Equal(local) {
t.Fatal("expected tcp localhost addr thid")
}

if !l[3].Equal(norm) {
t.Fatal("expected normal addr before docker addr")
}

if !l[4].Equal(docker) {
t.Fatal("expected docker addr last")
}
}
72 changes: 67 additions & 5 deletions p2p/net/swarm/swarm_dial.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package swarm

import (
"bytes"
"errors"
"fmt"
"math/rand"
"net"
"sort"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -358,6 +360,9 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {

func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {

// sort addresses so preferred addresses are dialed sooner
sort.Sort(AddrList(remoteAddrs))

// try to connect to one of the peer's known addresses.
// we dial concurrently to each of the addresses, which:
// * makes the process faster overall
Expand Down Expand Up @@ -404,10 +409,7 @@ func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remote
// to end early.
go func() {
limiter := make(chan struct{}, 8)
// permute addrs so we try different sets first each time.
for _, i := range rand.Perm(len(remoteAddrs)) {

addr := remoteAddrs[i]
for _, addr := range remoteAddrs {
// returns whatever ratelimiting is acceptable for workerAddr.
// may not rate limit at all.
rl := s.addrDialRateLimit(addr)
Expand Down Expand Up @@ -526,3 +528,63 @@ func isTCPMultiaddr(a ma.Multiaddr) bool {
p := a.Protocols()
return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp"
}

func isDefaultDockerRange(a ma.Multiaddr) bool {
parts := strings.Split(a.String(), "/")
if len(parts) != 5 {
return false
}

if parts[1] == "ip4" && strings.HasPrefix(parts[2], "172.17.") {
return true
}

return false
}

type AddrList []ma.Multiaddr

func (al AddrList) Len() int {
return len(al)
}

func (al AddrList) Swap(i, j int) {
al[i], al[j] = al[j], al[i]
}

func (al AddrList) Less(i, j int) bool {
a := al[i]
b := al[j]

// dial localhost addresses next, they should fail immediately
if manet.IsIPLoopback(a) {
if !manet.IsIPLoopback(b) {
return true
}

// both local? equal
return false
}

// dial utp and similar 'non-fd-consuming' addresses first
if !isFDCostlyTransport(a) {
if isFDCostlyTransport(b) {
return true
}

// if neither consume fd's, assume equal ordering
return false
}

// docker addresses should be tried last. they very rarely work.
if isDefaultDockerRange(a) {
return false
}

if isDefaultDockerRange(b) {
return true
}

// for the rest, just sort by bytes
return bytes.Compare(a.Bytes(), b.Bytes()) > 0
}

0 comments on commit 71474c4

Please sign in to comment.