-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrrdialer.go
73 lines (61 loc) · 1.5 KB
/
rrdialer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package netutil
import (
"fmt"
"log"
"net"
"time"
"golang.org/x/net/context"
)
// RRDialer contains options for connection to an address with a specific IP.
//
// TODO: connection pool
type RRDialer struct {
dialer *net.Dialer
Sort func([]net.IP)
}
// DefaultRRDialer has a dialer that includes the same as
// DefaultTransport use
var DefaultRRDialer = &RRDialer{
dialer: &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
},
}
// Dial connects to the address with an specific IP
// on the named network.
func (d *RRDialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
}
// DialContext connects to the address with an specific IP
// on the named network using the provided context.
func (d *RRDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
addrs, err := net.LookupIP(host)
if err != nil {
return nil, err
}
if d.Sort == nil {
RandomSort(addrs)
} else {
d.Sort(addrs)
}
for _, addr := range addrs {
ip4 := addr.To4()
if ip4 == nil {
continue
}
ipStr := ip4.String()
name := net.JoinHostPort(ipStr, port)
pc, err := d.dialer.Dial(network, name)
if err != nil {
// retry connect with a next address
log.Printf("failed to net.Dial(%s, %s): %s", network, name, err)
continue
}
return pc, nil
}
return nil, fmt.Errorf("cannot get connection: %s://%s", network, addr)
}