@@ -9,37 +9,33 @@ import (
99
1010// Dial connects to the address on the named network.
1111func Dial (network , address string ) (net.Conn , error ) {
12+ return DialContext (context .Background (), network , address )
13+ }
14+
15+ // DialContext is a variant of Dial that accepts a context.
16+ func DialContext (ctx context.Context , network , address string ) (net.Conn , error ) {
1217 addr , err := lookupAddr ("dial" , network , address )
1318 if err != nil {
1419 addr := & netAddr {network , address }
1520 return nil , dialErr (addr , err )
1621 }
17- conn , err := dialAddr (addr )
22+ conn , err := dialAddr (ctx , addr )
1823 if err != nil {
1924 return nil , dialErr (addr , err )
2025 }
2126 return conn , nil
2227}
2328
24- // DialContext is a variant of Dial that accepts a context.
25- func DialContext (ctx context.Context , network , address string ) (net.Conn , error ) {
26- select {
27- case <- ctx .Done ():
28- addr := & netAddr {network , address }
29- return nil , dialErr (addr , context .Cause (ctx ))
30- default :
31- return Dial (network , address )
32- }
33- }
34-
3529func dialErr (addr net.Addr , err error ) error {
3630 return newOpError ("dial" , addr , err )
3731}
3832
39- func dialAddr (addr net.Addr ) (net.Conn , error ) {
33+ func dialAddr (ctx context. Context , addr net.Addr ) (net.Conn , error ) {
4034 proto := family (addr )
41- sotype := socketType (addr )
42-
35+ sotype , err := socketType (addr )
36+ if err != nil {
37+ return nil , os .NewSyscallError ("socket" , err )
38+ }
4339 fd , err := socket (proto , sotype , 0 )
4440 if err != nil {
4541 return nil , os .NewSyscallError ("socket" , err )
@@ -49,7 +45,6 @@ func dialAddr(addr net.Addr) (net.Conn, error) {
4945 syscall .Close (fd )
5046 return nil , os .NewSyscallError ("setnonblock" , err )
5147 }
52-
5348 if sotype == SOCK_DGRAM && proto != AF_UNIX {
5449 if err := setsockopt (fd , SOL_SOCKET , SO_BROADCAST , 1 ); err != nil {
5550 syscall .Close (fd )
@@ -61,7 +56,6 @@ func dialAddr(addr net.Addr) (net.Conn, error) {
6156 if err != nil {
6257 return nil , os .NewSyscallError ("connect" , err )
6358 }
64-
6559 var inProgress bool
6660 switch err := connect (fd , connectAddr ); err {
6761 case nil :
@@ -80,96 +74,56 @@ func dialAddr(addr net.Addr) (net.Conn, error) {
8074 if err != nil {
8175 return nil , err
8276 }
83- rawConnErr := rawConn .Write (func (fd uintptr ) bool {
84- var value int
85- value , err = getsockopt (int (fd ), SOL_SOCKET , SO_ERROR )
86- if err != nil {
87- return true // done
77+
78+ errch := make (chan error )
79+ go func () {
80+ var err error
81+ rawConnErr := rawConn .Write (func (fd uintptr ) bool {
82+ var value int
83+ value , err = getsockopt (int (fd ), SOL_SOCKET , SO_ERROR )
84+ if err != nil {
85+ return true // done
86+ }
87+ switch syscall .Errno (value ) {
88+ case syscall .EINPROGRESS , syscall .EINTR :
89+ return false // continue
90+ case syscall .EISCONN :
91+ err = nil
92+ return true
93+ case syscall .Errno (0 ):
94+ // The net poller can wake up spuriously. Check that we are
95+ // are really connected.
96+ _ , err := getpeername (int (fd ))
97+ return err == nil
98+ default :
99+ return true
100+ }
101+ })
102+ if err == nil {
103+ err = rawConnErr
88104 }
89- switch syscall .Errno (value ) {
90- case syscall .EINPROGRESS , syscall .EINTR :
91- return false // continue
92- case syscall .EISCONN :
93- err = nil
94- return true
95- case syscall .Errno (0 ):
96- // The net poller can wake up spuriously. Check that we are
97- // are really connected.
98- _ , err := getpeername (int (fd ))
99- return err == nil
100- default :
101- return true
105+ errch <- err
106+ }()
107+
108+ select {
109+ case err := <- errch :
110+ if err != nil {
111+ return nil , os .NewSyscallError ("connect" , err )
102112 }
103- })
104- if err == nil {
105- err = rawConnErr
106- }
107- if err != nil {
108- return nil , os .NewSyscallError ("connect" , err )
113+ case <- ctx .Done ():
114+ // This should interrupt the async connect operation handled by the
115+ // goroutine.
116+ f .Close ()
117+ // Wait for the goroutine to complete, we can safely discard the
118+ // error here because we don't care about the socket anymore.
119+ <- errch
120+ return nil , context .Cause (ctx )
109121 }
110122 }
111123
112124 c , err := net .FileConn (f )
113125 if err != nil {
114126 return nil , err
115127 }
116-
117- // TODO: get local+peer address; wrap FileConn to implement LocalAddr() and RemoteAddr()
118- return c , nil
119- }
120-
121- func family (addr net.Addr ) int {
122- var ip net.IP
123- switch a := addr .(type ) {
124- case * net.UnixAddr :
125- return AF_UNIX
126- case * net.TCPAddr :
127- ip = a .IP
128- case * net.UDPAddr :
129- ip = a .IP
130- case * net.IPAddr :
131- ip = a .IP
132- }
133- if ip .To4 () != nil {
134- return AF_INET
135- } else if len (ip ) == net .IPv6len {
136- return AF_INET6
137- }
138- return AF_INET
139- }
140-
141- func socketType (addr net.Addr ) int {
142- switch addr .Network () {
143- case "tcp" , "unix" :
144- return SOCK_STREAM
145- case "udp" , "unixgram" :
146- return SOCK_DGRAM
147- default :
148- panic ("not implemented" )
149- }
150- }
151-
152- func socketAddress (addr net.Addr ) (sockaddr , error ) {
153- var ip net.IP
154- var port int
155- switch a := addr .(type ) {
156- case * net.UnixAddr :
157- return & sockaddrUnix {name : a .Name }, nil
158- case * net.TCPAddr :
159- ip , port = a .IP , a .Port
160- case * net.UDPAddr :
161- ip , port = a .IP , a .Port
162- case * net.IPAddr :
163- ip = a .IP
164- }
165- if ipv4 := ip .To4 (); ipv4 != nil {
166- return & sockaddrInet4 {addr : ([4 ]byte )(ipv4 ), port : port }, nil
167- } else if len (ip ) == net .IPv6len {
168- return & sockaddrInet6 {addr : ([16 ]byte )(ip ), port : port }, nil
169- } else {
170- return nil , & net.AddrError {
171- Err : "unsupported address type" ,
172- Addr : addr .String (),
173- }
174- }
128+ return makeConn (c )
175129}
0 commit comments