rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/dial.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import ( 8 "errors" 9 "time" 10 ) 11 12 // A Dialer contains options for connecting to an address. 13 // 14 // The zero value for each field is equivalent to dialing 15 // without that option. Dialing with the zero value of Dialer 16 // is therefore equivalent to just calling the Dial function. 17 type Dialer struct { 18 // Timeout is the maximum amount of time a dial will wait for 19 // a connect to complete. If Deadline is also set, it may fail 20 // earlier. 21 // 22 // The default is no timeout. 23 // 24 // With or without a timeout, the operating system may impose 25 // its own earlier timeout. For instance, TCP timeouts are 26 // often around 3 minutes. 27 Timeout time.Duration 28 29 // Deadline is the absolute point in time after which dials 30 // will fail. If Timeout is set, it may fail earlier. 31 // Zero means no deadline, or dependent on the operating system 32 // as with the Timeout option. 33 Deadline time.Time 34 35 // LocalAddr is the local address to use when dialing an 36 // address. The address must be of a compatible type for the 37 // network being dialed. 38 // If nil, a local address is automatically chosen. 39 LocalAddr Addr 40 41 // DualStack allows a single dial to attempt to establish 42 // multiple IPv4 and IPv6 connections and to return the first 43 // established connection when the network is "tcp" and the 44 // destination is a host name that has multiple address family 45 // DNS records. 46 DualStack bool 47 48 // KeepAlive specifies the keep-alive period for an active 49 // network connection. 50 // If zero, keep-alives are not enabled. Network protocols 51 // that do not support keep-alives ignore this field. 52 KeepAlive time.Duration 53 } 54 55 // Return either now+Timeout or Deadline, whichever comes first. 56 // Or zero, if neither is set. 57 func (d *Dialer) deadline() time.Time { 58 if d.Timeout == 0 { 59 return d.Deadline 60 } 61 timeoutDeadline := time.Now().Add(d.Timeout) 62 if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) { 63 return timeoutDeadline 64 } else { 65 return d.Deadline 66 } 67 } 68 69 func parseNetwork(net string) (afnet string, proto int, err error) { 70 i := last(net, ':') 71 if i < 0 { // no colon 72 switch net { 73 case "tcp", "tcp4", "tcp6": 74 case "udp", "udp4", "udp6": 75 case "ip", "ip4", "ip6": 76 case "unix", "unixgram", "unixpacket": 77 default: 78 return "", 0, UnknownNetworkError(net) 79 } 80 return net, 0, nil 81 } 82 afnet = net[:i] 83 switch afnet { 84 case "ip", "ip4", "ip6": 85 protostr := net[i+1:] 86 proto, i, ok := dtoi(protostr, 0) 87 if !ok || i != len(protostr) { 88 proto, err = lookupProtocol(protostr) 89 if err != nil { 90 return "", 0, err 91 } 92 } 93 return afnet, proto, nil 94 } 95 return "", 0, UnknownNetworkError(net) 96 } 97 98 func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) { 99 afnet, _, err := parseNetwork(net) 100 if err != nil { 101 return nil, err 102 } 103 if op == "dial" && addr == "" { 104 return nil, errMissingAddress 105 } 106 switch afnet { 107 case "unix", "unixgram", "unixpacket": 108 addr, err := ResolveUnixAddr(afnet, addr) 109 if err != nil { 110 return nil, err 111 } 112 return addrList{addr}, nil 113 } 114 return internetAddrList(afnet, addr, deadline) 115 } 116 117 // Dial connects to the address on the named network. 118 // 119 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), 120 // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" 121 // (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and 122 // "unixpacket". 123 // 124 // For TCP and UDP networks, addresses have the form host:port. 125 // If host is a literal IPv6 address it must be enclosed 126 // in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80". 127 // The functions JoinHostPort and SplitHostPort manipulate addresses 128 // in this form. 129 // 130 // Examples: 131 // Dial("tcp", "12.34.56.78:80") 132 // Dial("tcp", "google.com:http") 133 // Dial("tcp", "[2001:db8::1]:http") 134 // Dial("tcp", "[fe80::1%lo0]:80") 135 // 136 // For IP networks, the network must be "ip", "ip4" or "ip6" followed 137 // by a colon and a protocol number or name and the addr must be a 138 // literal IP address. 139 // 140 // Examples: 141 // Dial("ip4:1", "127.0.0.1") 142 // Dial("ip6:ospf", "::1") 143 // 144 // For Unix networks, the address must be a file system path. 145 func Dial(network, address string) (Conn, error) { 146 var d Dialer 147 return d.Dial(network, address) 148 } 149 150 // DialTimeout acts like Dial but takes a timeout. 151 // The timeout includes name resolution, if required. 152 func DialTimeout(network, address string, timeout time.Duration) (Conn, error) { 153 d := Dialer{Timeout: timeout} 154 return d.Dial(network, address) 155 } 156 157 // Dial connects to the address on the named network. 158 // 159 // See func Dial for a description of the network and address 160 // parameters. 161 func (d *Dialer) Dial(network, address string) (Conn, error) { 162 addrs, err := resolveAddrList("dial", network, address, d.deadline()) 163 if err != nil { 164 return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err} 165 } 166 var dialer func(deadline time.Time) (Conn, error) 167 if d.DualStack && network == "tcp" { 168 primaries, fallbacks := addrs.partition(isIPv4) 169 if len(fallbacks) > 0 { 170 dialer = func(deadline time.Time) (Conn, error) { 171 return dialMulti(network, address, d.LocalAddr, addrList{primaries[0], fallbacks[0]}, deadline) 172 } 173 } 174 } 175 if dialer == nil { 176 dialer = func(deadline time.Time) (Conn, error) { 177 return dialSingle(network, address, d.LocalAddr, addrs.first(isIPv4), deadline) 178 } 179 } 180 c, err := dial(network, addrs.first(isIPv4), dialer, d.deadline()) 181 if d.KeepAlive > 0 && err == nil { 182 if tc, ok := c.(*TCPConn); ok { 183 tc.SetKeepAlive(true) 184 tc.SetKeepAlivePeriod(d.KeepAlive) 185 testHookSetKeepAlive() 186 } 187 } 188 return c, err 189 } 190 191 // dialMulti attempts to establish connections to each destination of 192 // the list of addresses. It will return the first established 193 // connection and close the other connections. Otherwise it returns 194 // error on the last attempt. 195 func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) { 196 type racer struct { 197 Conn 198 error 199 } 200 // Sig controls the flow of dial results on lane. It passes a 201 // token to the next racer and also indicates the end of flow 202 // by using closed channel. 203 sig := make(chan bool, 1) 204 lane := make(chan racer, 1) 205 for _, ra := range ras { 206 go func(ra Addr) { 207 c, err := dialSingle(net, addr, la, ra, deadline) 208 if _, ok := <-sig; ok { 209 lane <- racer{c, err} 210 } else if err == nil { 211 // We have to return the resources 212 // that belong to the other 213 // connections here for avoiding 214 // unnecessary resource starvation. 215 c.Close() 216 } 217 }(ra) 218 } 219 defer close(sig) 220 lastErr := errTimeout 221 nracers := len(ras) 222 for nracers > 0 { 223 sig <- true 224 racer := <-lane 225 if racer.error == nil { 226 return racer.Conn, nil 227 } 228 lastErr = racer.error 229 nracers-- 230 } 231 return nil, lastErr 232 } 233 234 // dialSingle attempts to establish and returns a single connection to 235 // the destination address. 236 func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) { 237 if la != nil && la.Network() != ra.Network() { 238 return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())} 239 } 240 switch ra := ra.(type) { 241 case *TCPAddr: 242 la, _ := la.(*TCPAddr) 243 c, err = dialTCP(net, la, ra, deadline) 244 case *UDPAddr: 245 la, _ := la.(*UDPAddr) 246 c, err = dialUDP(net, la, ra, deadline) 247 case *IPAddr: 248 la, _ := la.(*IPAddr) 249 c, err = dialIP(net, la, ra, deadline) 250 case *UnixAddr: 251 la, _ := la.(*UnixAddr) 252 c, err = dialUnix(net, la, ra, deadline) 253 default: 254 return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}} 255 } 256 if err != nil { 257 return nil, err // c is non-nil interface containing nil pointer 258 } 259 return c, nil 260 } 261 262 // Listen announces on the local network address laddr. 263 // The network net must be a stream-oriented network: "tcp", "tcp4", 264 // "tcp6", "unix" or "unixpacket". 265 // See Dial for the syntax of laddr. 266 func Listen(net, laddr string) (Listener, error) { 267 addrs, err := resolveAddrList("listen", net, laddr, noDeadline) 268 if err != nil { 269 return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err} 270 } 271 var l Listener 272 switch la := addrs.first(isIPv4).(type) { 273 case *TCPAddr: 274 l, err = ListenTCP(net, la) 275 case *UnixAddr: 276 l, err = ListenUnix(net, la) 277 default: 278 return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 279 } 280 if err != nil { 281 return nil, err // l is non-nil interface containing nil pointer 282 } 283 return l, nil 284 } 285 286 // ListenPacket announces on the local network address laddr. 287 // The network net must be a packet-oriented network: "udp", "udp4", 288 // "udp6", "ip", "ip4", "ip6" or "unixgram". 289 // See Dial for the syntax of laddr. 290 func ListenPacket(net, laddr string) (PacketConn, error) { 291 addrs, err := resolveAddrList("listen", net, laddr, noDeadline) 292 if err != nil { 293 return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err} 294 } 295 var l PacketConn 296 switch la := addrs.first(isIPv4).(type) { 297 case *UDPAddr: 298 l, err = ListenUDP(net, la) 299 case *IPAddr: 300 l, err = ListenIP(net, la) 301 case *UnixAddr: 302 l, err = ListenUnixgram(net, la) 303 default: 304 return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 305 } 306 if err != nil { 307 return nil, err // l is non-nil interface containing nil pointer 308 } 309 return l, nil 310 }