4
4
5
5
package net
6
6
7
+ import (
8
+ "time"
9
+ )
10
+
7
11
func resolveNetAddr (op , net , addr string ) (a Addr , err error ) {
8
12
if addr == "" {
9
13
return nil , & OpError {op , net , nil , errMissingAddress }
@@ -42,11 +46,15 @@ func resolveNetAddr(op, net, addr string) (a Addr, err error) {
42
46
// Dial("tcp", "google.com:80")
43
47
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
44
48
//
45
- func Dial (net , addr string ) (c Conn , err error ) {
49
+ func Dial (net , addr string ) (Conn , error ) {
46
50
addri , err := resolveNetAddr ("dial" , net , addr )
47
51
if err != nil {
48
52
return nil , err
49
53
}
54
+ return dialAddr (net , addr , addri )
55
+ }
56
+
57
+ func dialAddr (net , addr string , addri Addr ) (c Conn , err error ) {
50
58
switch ra := addri .(type ) {
51
59
case * TCPAddr :
52
60
c , err = DialTCP (net , nil , ra )
@@ -65,6 +73,62 @@ func Dial(net, addr string) (c Conn, err error) {
65
73
return
66
74
}
67
75
76
+ // DialTimeout acts like Dial but takes a timeout.
77
+ // The timeout includes name resolution, if required.
78
+ func DialTimeout (net , addr string , timeout time.Duration ) (Conn , error ) {
79
+ // TODO(bradfitz): the timeout should be pushed down into the
80
+ // net package's event loop, so on timeout to dead hosts we
81
+ // don't have a goroutine sticking around for the default of
82
+ // ~3 minutes.
83
+ t := time .NewTimer (timeout )
84
+ defer t .Stop ()
85
+ type pair struct {
86
+ Conn
87
+ error
88
+ }
89
+ ch := make (chan pair , 1 )
90
+ resolvedAddr := make (chan Addr , 1 )
91
+ go func () {
92
+ addri , err := resolveNetAddr ("dial" , net , addr )
93
+ if err != nil {
94
+ ch <- pair {nil , err }
95
+ return
96
+ }
97
+ resolvedAddr <- addri // in case we need it for OpError
98
+ c , err := dialAddr (net , addr , addri )
99
+ ch <- pair {c , err }
100
+ }()
101
+ select {
102
+ case <- t .C :
103
+ // Try to use the real Addr in our OpError, if we resolved it
104
+ // before the timeout. Otherwise we just use stringAddr.
105
+ var addri Addr
106
+ select {
107
+ case a := <- resolvedAddr :
108
+ addri = a
109
+ default :
110
+ addri = & stringAddr {net , addr }
111
+ }
112
+ err := & OpError {
113
+ Op : "dial" ,
114
+ Net : net ,
115
+ Addr : addri ,
116
+ Err : & timeoutError {},
117
+ }
118
+ return nil , err
119
+ case p := <- ch :
120
+ return p .Conn , p .error
121
+ }
122
+ panic ("unreachable" )
123
+ }
124
+
125
+ type stringAddr struct {
126
+ net , addr string
127
+ }
128
+
129
+ func (a stringAddr ) Network () string { return a .net }
130
+ func (a stringAddr ) String () string { return a .addr }
131
+
68
132
// Listen announces on the local network address laddr.
69
133
// The network string net must be a stream-oriented
70
134
// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
0 commit comments