github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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 // When dialing a name with multiple IP addresses, the timeout 25 // may be divided between them. 26 // 27 // With or without a timeout, the operating system may impose 28 // its own earlier timeout. For instance, TCP timeouts are 29 // often around 3 minutes. 30 Timeout time.Duration 31 32 // Deadline is the absolute point in time after which dials 33 // will fail. If Timeout is set, it may fail earlier. 34 // Zero means no deadline, or dependent on the operating system 35 // as with the Timeout option. 36 Deadline time.Time 37 38 // LocalAddr is the local address to use when dialing an 39 // address. The address must be of a compatible type for the 40 // network being dialed. 41 // If nil, a local address is automatically chosen. 42 LocalAddr Addr 43 44 // DualStack enables RFC 6555-compliant "Happy Eyeballs" dialing 45 // when the network is "tcp" and the destination is a host name 46 // with both IPv4 and IPv6 addresses. This allows a client to 47 // tolerate networks where one address family is silently broken. 48 DualStack bool 49 50 // FallbackDelay specifies the length of time to wait before 51 // spawning a fallback connection, when DualStack is enabled. 52 // If zero, a default delay of 300ms is used. 53 FallbackDelay time.Duration 54 55 // KeepAlive specifies the keep-alive period for an active 56 // network connection. 57 // If zero, keep-alives are not enabled. Network protocols 58 // that do not support keep-alives ignore this field. 59 KeepAlive time.Duration 60 } 61 62 // Return either now+Timeout or Deadline, whichever comes first. 63 // Or zero, if neither is set. 64 func (d *Dialer) deadline(now time.Time) time.Time { 65 if d.Timeout == 0 { 66 return d.Deadline 67 } 68 timeoutDeadline := now.Add(d.Timeout) 69 if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) { 70 return timeoutDeadline 71 } else { 72 return d.Deadline 73 } 74 } 75 76 // partialDeadline returns the deadline to use for a single address, 77 // when multiple addresses are pending. 78 func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) { 79 if deadline.IsZero() { 80 return deadline, nil 81 } 82 timeRemaining := deadline.Sub(now) 83 if timeRemaining <= 0 { 84 return time.Time{}, errTimeout 85 } 86 // Tentatively allocate equal time to each remaining address. 87 timeout := timeRemaining / time.Duration(addrsRemaining) 88 // If the time per address is too short, steal from the end of the list. 89 const saneMinimum = 2 * time.Second 90 if timeout < saneMinimum { 91 if timeRemaining < saneMinimum { 92 timeout = timeRemaining 93 } else { 94 timeout = saneMinimum 95 } 96 } 97 return now.Add(timeout), nil 98 } 99 100 func (d *Dialer) fallbackDelay() time.Duration { 101 if d.FallbackDelay > 0 { 102 return d.FallbackDelay 103 } else { 104 return 300 * time.Millisecond 105 } 106 } 107 108 func parseNetwork(net string) (afnet string, proto int, err error) { 109 i := last(net, ':') 110 if i < 0 { // no colon 111 switch net { 112 case "tcp", "tcp4", "tcp6": 113 case "udp", "udp4", "udp6": 114 case "ip", "ip4", "ip6": 115 case "unix", "unixgram", "unixpacket": 116 default: 117 return "", 0, UnknownNetworkError(net) 118 } 119 return net, 0, nil 120 } 121 afnet = net[:i] 122 switch afnet { 123 case "ip", "ip4", "ip6": 124 protostr := net[i+1:] 125 proto, i, ok := dtoi(protostr, 0) 126 if !ok || i != len(protostr) { 127 proto, err = lookupProtocol(protostr) 128 if err != nil { 129 return "", 0, err 130 } 131 } 132 return afnet, proto, nil 133 } 134 return "", 0, UnknownNetworkError(net) 135 } 136 137 func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) { 138 afnet, _, err := parseNetwork(net) 139 if err != nil { 140 return nil, err 141 } 142 if op == "dial" && addr == "" { 143 return nil, errMissingAddress 144 } 145 switch afnet { 146 case "unix", "unixgram", "unixpacket": 147 addr, err := ResolveUnixAddr(afnet, addr) 148 if err != nil { 149 return nil, err 150 } 151 return addrList{addr}, nil 152 } 153 return internetAddrList(afnet, addr, deadline) 154 } 155 156 // Dial connects to the address on the named network. 157 // 158 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), 159 // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" 160 // (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and 161 // "unixpacket". 162 // 163 // For TCP and UDP networks, addresses have the form host:port. 164 // If host is a literal IPv6 address it must be enclosed 165 // in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80". 166 // The functions JoinHostPort and SplitHostPort manipulate addresses 167 // in this form. 168 // 169 // Examples: 170 // Dial("tcp", "12.34.56.78:80") 171 // Dial("tcp", "google.com:http") 172 // Dial("tcp", "[2001:db8::1]:http") 173 // Dial("tcp", "[fe80::1%lo0]:80") 174 // 175 // For IP networks, the network must be "ip", "ip4" or "ip6" followed 176 // by a colon and a protocol number or name and the addr must be a 177 // literal IP address. 178 // 179 // Examples: 180 // Dial("ip4:1", "127.0.0.1") 181 // Dial("ip6:ospf", "::1") 182 // 183 // For Unix networks, the address must be a file system path. 184 func Dial(network, address string) (Conn, error) { 185 var d Dialer 186 return d.Dial(network, address) 187 } 188 189 // DialTimeout acts like Dial but takes a timeout. 190 // The timeout includes name resolution, if required. 191 func DialTimeout(network, address string, timeout time.Duration) (Conn, error) { 192 d := Dialer{Timeout: timeout} 193 return d.Dial(network, address) 194 } 195 196 // dialContext holds common state for all dial operations. 197 type dialContext struct { 198 Dialer 199 network, address string 200 finalDeadline time.Time 201 } 202 203 // Dial connects to the address on the named network. 204 // 205 // See func Dial for a description of the network and address 206 // parameters. 207 func (d *Dialer) Dial(network, address string) (Conn, error) { 208 finalDeadline := d.deadline(time.Now()) 209 addrs, err := resolveAddrList("dial", network, address, finalDeadline) 210 if err != nil { 211 return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err} 212 } 213 214 ctx := &dialContext{ 215 Dialer: *d, 216 network: network, 217 address: address, 218 finalDeadline: finalDeadline, 219 } 220 221 var primaries, fallbacks addrList 222 if d.DualStack && network == "tcp" { 223 primaries, fallbacks = addrs.partition(isIPv4) 224 } else { 225 primaries = addrs 226 } 227 228 var c Conn 229 if len(fallbacks) == 0 { 230 // dialParallel can accept an empty fallbacks list, 231 // but this shortcut avoids the goroutine/channel overhead. 232 c, err = dialSerial(ctx, primaries, nil) 233 } else { 234 c, err = dialParallel(ctx, primaries, fallbacks) 235 } 236 237 if d.KeepAlive > 0 && err == nil { 238 if tc, ok := c.(*TCPConn); ok { 239 setKeepAlive(tc.fd, true) 240 setKeepAlivePeriod(tc.fd, d.KeepAlive) 241 testHookSetKeepAlive() 242 } 243 } 244 return c, err 245 } 246 247 // dialParallel races two copies of dialSerial, giving the first a 248 // head start. It returns the first established connection and 249 // closes the others. Otherwise it returns an error from the first 250 // primary address. 251 func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) { 252 results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup 253 cancel := make(chan struct{}) 254 defer close(cancel) 255 256 // Spawn the primary racer. 257 go dialSerialAsync(ctx, primaries, nil, cancel, results) 258 259 // Spawn the fallback racer. 260 fallbackTimer := time.NewTimer(ctx.fallbackDelay()) 261 go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results) 262 263 var primaryErr error 264 for nracers := 2; nracers > 0; nracers-- { 265 res := <-results 266 // If we're still waiting for a connection, then hasten the delay. 267 // Otherwise, disable the Timer and let cancel take over. 268 if fallbackTimer.Stop() && res.error != nil { 269 fallbackTimer.Reset(0) 270 } 271 if res.error == nil { 272 return res.Conn, nil 273 } 274 if res.primary { 275 primaryErr = res.error 276 } 277 } 278 return nil, primaryErr 279 } 280 281 type dialResult struct { 282 Conn 283 error 284 primary bool 285 } 286 287 // dialSerialAsync runs dialSerial after some delay, and returns the 288 // resulting connection through a channel. When racing two connections, 289 // the primary goroutine uses a nil timer to omit the delay. 290 func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <-chan struct{}, results chan<- dialResult) { 291 if timer != nil { 292 // We're in the fallback goroutine; sleep before connecting. 293 select { 294 case <-timer.C: 295 case <-cancel: 296 return 297 } 298 } 299 c, err := dialSerial(ctx, ras, cancel) 300 select { 301 case results <- dialResult{c, err, timer == nil}: 302 // We won the race. 303 case <-cancel: 304 // The other goroutine won the race. 305 if c != nil { 306 c.Close() 307 } 308 } 309 } 310 311 // dialSerial connects to a list of addresses in sequence, returning 312 // either the first successful connection, or the first error. 313 func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, error) { 314 var firstErr error // The error from the first address is most relevant. 315 316 for i, ra := range ras { 317 select { 318 case <-cancel: 319 return nil, &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: errCanceled} 320 default: 321 } 322 323 partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i) 324 if err != nil { 325 // Ran out of time. 326 if firstErr == nil { 327 firstErr = &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: err} 328 } 329 break 330 } 331 332 // dialTCP does not support cancelation (see golang.org/issue/11225), 333 // so if cancel fires, we'll continue trying to connect until the next 334 // timeout, or return a spurious connection for the caller to close. 335 dialer := func(d time.Time) (Conn, error) { 336 return dialSingle(ctx, ra, d) 337 } 338 c, err := dial(ctx.network, ra, dialer, partialDeadline) 339 if err == nil { 340 return c, nil 341 } 342 if firstErr == nil { 343 firstErr = err 344 } 345 } 346 347 if firstErr == nil { 348 firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress} 349 } 350 return nil, firstErr 351 } 352 353 // dialSingle attempts to establish and returns a single connection to 354 // the destination address. This must be called through the OS-specific 355 // dial function, because some OSes don't implement the deadline feature. 356 func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) { 357 la := ctx.LocalAddr 358 if la != nil && la.Network() != ra.Network() { 359 return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())} 360 } 361 switch ra := ra.(type) { 362 case *TCPAddr: 363 la, _ := la.(*TCPAddr) 364 c, err = testHookDialTCP(ctx.network, la, ra, deadline) 365 case *UDPAddr: 366 la, _ := la.(*UDPAddr) 367 c, err = dialUDP(ctx.network, la, ra, deadline) 368 case *IPAddr: 369 la, _ := la.(*IPAddr) 370 c, err = dialIP(ctx.network, la, ra, deadline) 371 case *UnixAddr: 372 la, _ := la.(*UnixAddr) 373 c, err = dialUnix(ctx.network, la, ra, deadline) 374 default: 375 return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}} 376 } 377 if err != nil { 378 return nil, err // c is non-nil interface containing nil pointer 379 } 380 return c, nil 381 } 382 383 // Listen announces on the local network address laddr. 384 // The network net must be a stream-oriented network: "tcp", "tcp4", 385 // "tcp6", "unix" or "unixpacket". 386 // See Dial for the syntax of laddr. 387 func Listen(net, laddr string) (Listener, error) { 388 addrs, err := resolveAddrList("listen", net, laddr, noDeadline) 389 if err != nil { 390 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} 391 } 392 var l Listener 393 switch la := addrs.first(isIPv4).(type) { 394 case *TCPAddr: 395 l, err = ListenTCP(net, la) 396 case *UnixAddr: 397 l, err = ListenUnix(net, la) 398 default: 399 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 400 } 401 if err != nil { 402 return nil, err // l is non-nil interface containing nil pointer 403 } 404 return l, nil 405 } 406 407 // ListenPacket announces on the local network address laddr. 408 // The network net must be a packet-oriented network: "udp", "udp4", 409 // "udp6", "ip", "ip4", "ip6" or "unixgram". 410 // See Dial for the syntax of laddr. 411 func ListenPacket(net, laddr string) (PacketConn, error) { 412 addrs, err := resolveAddrList("listen", net, laddr, noDeadline) 413 if err != nil { 414 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} 415 } 416 var l PacketConn 417 switch la := addrs.first(isIPv4).(type) { 418 case *UDPAddr: 419 l, err = ListenUDP(net, la) 420 case *IPAddr: 421 l, err = ListenIP(net, la) 422 case *UnixAddr: 423 l, err = ListenUnixgram(net, la) 424 default: 425 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 426 } 427 if err != nil { 428 return nil, err // l is non-nil interface containing nil pointer 429 } 430 return l, nil 431 }