dial.go 2.86 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package conn

import (
	"fmt"
	"strings"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"

	peer "github.com/jbenet/go-ipfs/p2p/peer"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {

25
	_, _, err := manet.DialArgs(raddr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
26
27
28
29
30
31
32
33
34
	if err != nil {
		return nil, err
	}

	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	if len(d.LocalAddrs) > 0 {
35
36
37
		laddrs := manet.AddrMatch(raddr, d.LocalAddrs)
		if len(laddrs) < 1 {
			return nil, debugerror.Errorf("No local address matches %s %s", raddr, d.LocalAddrs)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38
39
		}

40
41
42
43
44
45
46
47
		// TODO pick with a good heuristic
		// we use a random one for now to prevent bad addresses from making nodes unreachable
		// with a random selection, multiple tries may work.
		// laddr := laddrs[rand.Intn(len(laddrs))]

		// TODO: try to get reusing addr/ports to work.
		// d.Dialer.LocalAddr = laddr
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48
49

	log.Debugf("%s dialing %s %s", d.LocalPeer, remote, raddr)
50
	maconn, err := d.Dialer.Dial(raddr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	if err != nil {
		return nil, err
	}

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() { done <- struct{}{} }()

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			errOut = err
			return
		}

		if d.PrivateKey == nil {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}
		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		maconn.Close()
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	return connOut, errOut
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
105
		if api.Code != bp[i].Code {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}