github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 "context" 9 "internal/nettrace" 10 "time" 11 ) 12 13 // A Dialer contains options for connecting to an address. 14 // 15 // The zero value for each field is equivalent to dialing 16 // without that option. Dialing with the zero value of Dialer 17 // is therefore equivalent to just calling the Dial function. 18 type Dialer struct { 19 // Timeout is the maximum amount of time a dial will wait for 20 // a connect to complete. If Deadline is also set, it may fail 21 // earlier. 22 // 23 // The default is no timeout. 24 // 25 // When dialing a name with multiple IP addresses, the timeout 26 // may be divided between them. 27 // 28 // With or without a timeout, the operating system may impose 29 // its own earlier timeout. For instance, TCP timeouts are 30 // often around 3 minutes. 31 Timeout time.Duration 32 33 // Deadline is the absolute point in time after which dials 34 // will fail. If Timeout is set, it may fail earlier. 35 // Zero means no deadline, or dependent on the operating system 36 // as with the Timeout option. 37 Deadline time.Time 38 39 // LocalAddr is the local address to use when dialing an 40 // address. The address must be of a compatible type for the 41 // network being dialed. 42 // If nil, a local address is automatically chosen. 43 LocalAddr Addr 44 45 // DualStack enables RFC 6555-compliant "Happy Eyeballs" dialing 46 // when the network is "tcp" and the destination is a host name 47 // with both IPv4 and IPv6 addresses. This allows a client to 48 // tolerate networks where one address family is silently broken. 49 DualStack bool 50 51 // FallbackDelay specifies the length of time to wait before 52 // spawning a fallback connection, when DualStack is enabled. 53 // If zero, a default delay of 300ms is used. 54 FallbackDelay time.Duration 55 56 // KeepAlive specifies the keep-alive period for an active 57 // network connection. 58 // If zero, keep-alives are not enabled. Network protocols 59 // that do not support keep-alives ignore this field. 60 KeepAlive time.Duration 61 62 // Cancel is an optional channel whose closure indicates that 63 // the dial should be canceled. Not all types of dials support 64 // cancelation. 65 // 66 // Deprecated: Use DialContext instead. 67 Cancel <-chan struct{} 68 } 69 70 func minNonzeroTime(a, b time.Time) time.Time { 71 if a.IsZero() { 72 return b 73 } 74 if b.IsZero() || a.Before(b) { 75 return a 76 } 77 return b 78 } 79 80 // deadline returns the earliest of: 81 // - now+Timeout 82 // - d.Deadline 83 // - the context's deadline 84 // Or zero, if none of Timeout, Deadline, or context's deadline is set. 85 func (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Time) { 86 if d.Timeout != 0 { // including negative, for historical reasons 87 earliest = now.Add(d.Timeout) 88 } 89 if d, ok := ctx.Deadline(); ok { 90 earliest = minNonzeroTime(earliest, d) 91 } 92 return minNonzeroTime(earliest, d.Deadline) 93 } 94 95 // partialDeadline returns the deadline to use for a single address, 96 // when multiple addresses are pending. 97 func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) { 98 if deadline.IsZero() { 99 return deadline, nil 100 } 101 timeRemaining := deadline.Sub(now) 102 if timeRemaining <= 0 { 103 return time.Time{}, errTimeout 104 } 105 // Tentatively allocate equal time to each remaining address. 106 timeout := timeRemaining / time.Duration(addrsRemaining) 107 // If the time per address is too short, steal from the end of the list. 108 const saneMinimum = 2 * time.Second 109 if timeout < saneMinimum { 110 if timeRemaining < saneMinimum { 111 timeout = timeRemaining 112 } else { 113 timeout = saneMinimum 114 } 115 } 116 return now.Add(timeout), nil 117 } 118 119 func (d *Dialer) fallbackDelay() time.Duration { 120 if d.FallbackDelay > 0 { 121 return d.FallbackDelay 122 } else { 123 return 300 * time.Millisecond 124 } 125 } 126 127 func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err error) { 128 i := last(net, ':') 129 if i < 0 { // no colon 130 switch net { 131 case "tcp", "tcp4", "tcp6": 132 case "udp", "udp4", "udp6": 133 case "ip", "ip4", "ip6": 134 case "unix", "unixgram", "unixpacket": 135 default: 136 return "", 0, UnknownNetworkError(net) 137 } 138 return net, 0, nil 139 } 140 afnet = net[:i] 141 switch afnet { 142 case "ip", "ip4", "ip6": 143 protostr := net[i+1:] 144 proto, i, ok := dtoi(protostr, 0) 145 if !ok || i != len(protostr) { 146 proto, err = lookupProtocol(ctx, protostr) 147 if err != nil { 148 return "", 0, err 149 } 150 } 151 return afnet, proto, nil 152 } 153 return "", 0, UnknownNetworkError(net) 154 } 155 156 // resolverAddrList resolves addr using hint and returns a list of 157 // addresses. The result contains at least one address when error is 158 // nil. 159 func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) { 160 afnet, _, err := parseNetwork(ctx, network) 161 if err != nil { 162 return nil, err 163 } 164 if op == "dial" && addr == "" { 165 return nil, errMissingAddress 166 } 167 switch afnet { 168 case "unix", "unixgram", "unixpacket": 169 // TODO(bradfitz): push down context 170 addr, err := ResolveUnixAddr(afnet, addr) 171 if err != nil { 172 return nil, err 173 } 174 if op == "dial" && hint != nil && addr.Network() != hint.Network() { 175 return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()} 176 } 177 return addrList{addr}, nil 178 } 179 addrs, err := internetAddrList(ctx, afnet, addr) 180 if err != nil || op != "dial" || hint == nil { 181 return addrs, err 182 } 183 var ( 184 tcp *TCPAddr 185 udp *UDPAddr 186 ip *IPAddr 187 wildcard bool 188 ) 189 switch hint := hint.(type) { 190 case *TCPAddr: 191 tcp = hint 192 wildcard = tcp.isWildcard() 193 case *UDPAddr: 194 udp = hint 195 wildcard = udp.isWildcard() 196 case *IPAddr: 197 ip = hint 198 wildcard = ip.isWildcard() 199 } 200 naddrs := addrs[:0] 201 for _, addr := range addrs { 202 if addr.Network() != hint.Network() { 203 return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()} 204 } 205 switch addr := addr.(type) { 206 case *TCPAddr: 207 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(tcp.IP) { 208 continue 209 } 210 naddrs = append(naddrs, addr) 211 case *UDPAddr: 212 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(udp.IP) { 213 continue 214 } 215 naddrs = append(naddrs, addr) 216 case *IPAddr: 217 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(ip.IP) { 218 continue 219 } 220 naddrs = append(naddrs, addr) 221 } 222 } 223 if len(naddrs) == 0 { 224 return nil, errNoSuitableAddress 225 } 226 return naddrs, nil 227 } 228 229 // Dial connects to the address on the named network. 230 // 231 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), 232 // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" 233 // (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and 234 // "unixpacket". 235 // 236 // For TCP and UDP networks, addresses have the form host:port. 237 // If host is a literal IPv6 address it must be enclosed 238 // in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80". 239 // The functions JoinHostPort and SplitHostPort manipulate addresses 240 // in this form. 241 // If the host is empty, as in ":80", the local system is assumed. 242 // 243 // Examples: 244 // Dial("tcp", "192.0.2.1:80") 245 // Dial("tcp", "golang.org:http") 246 // Dial("tcp", "[2001:db8::1]:http") 247 // Dial("tcp", "[fe80::1%lo0]:80") 248 // Dial("tcp", ":80") 249 // 250 // For IP networks, the network must be "ip", "ip4" or "ip6" followed 251 // by a colon and a protocol number or name and the addr must be a 252 // literal IP address. 253 // 254 // Examples: 255 // Dial("ip4:1", "192.0.2.1") 256 // Dial("ip6:ipv6-icmp", "2001:db8::1") 257 // 258 // For Unix networks, the address must be a file system path. 259 func Dial(network, address string) (Conn, error) { 260 var d Dialer 261 return d.Dial(network, address) 262 } 263 264 // DialTimeout acts like Dial but takes a timeout. 265 // The timeout includes name resolution, if required. 266 func DialTimeout(network, address string, timeout time.Duration) (Conn, error) { 267 d := Dialer{Timeout: timeout} 268 return d.Dial(network, address) 269 } 270 271 // dialParam contains a Dial's parameters and configuration. 272 type dialParam struct { 273 Dialer 274 network, address string 275 } 276 277 // Dial connects to the address on the named network. 278 // 279 // See func Dial for a description of the network and address 280 // parameters. 281 func (d *Dialer) Dial(network, address string) (Conn, error) { 282 return d.DialContext(context.Background(), network, address) 283 } 284 285 // DialContext connects to the address on the named network using 286 // the provided context. 287 // 288 // The provided Context must be non-nil. If the context expires before 289 // the connection is complete, an error is returned. Once successfully 290 // connected, any expiration of the context will not affect the 291 // connection. 292 // 293 // See func Dial for a description of the network and address 294 // parameters. 295 func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) { 296 if ctx == nil { 297 panic("nil context") 298 } 299 deadline := d.deadline(ctx, time.Now()) 300 if !deadline.IsZero() { 301 if d, ok := ctx.Deadline(); !ok || deadline.Before(d) { 302 subCtx, cancel := context.WithDeadline(ctx, deadline) 303 defer cancel() 304 ctx = subCtx 305 } 306 } 307 if oldCancel := d.Cancel; oldCancel != nil { 308 subCtx, cancel := context.WithCancel(ctx) 309 defer cancel() 310 go func() { 311 select { 312 case <-oldCancel: 313 cancel() 314 case <-subCtx.Done(): 315 } 316 }() 317 ctx = subCtx 318 } 319 320 // Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups. 321 resolveCtx := ctx 322 if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil { 323 shadow := *trace 324 shadow.ConnectStart = nil 325 shadow.ConnectDone = nil 326 resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow) 327 } 328 329 addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr) 330 if err != nil { 331 return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err} 332 } 333 334 dp := &dialParam{ 335 Dialer: *d, 336 network: network, 337 address: address, 338 } 339 340 var primaries, fallbacks addrList 341 if d.DualStack && network == "tcp" { 342 primaries, fallbacks = addrs.partition(isIPv4) 343 } else { 344 primaries = addrs 345 } 346 347 var c Conn 348 if len(fallbacks) > 0 { 349 c, err = dialParallel(ctx, dp, primaries, fallbacks) 350 } else { 351 c, err = dialSerial(ctx, dp, primaries) 352 } 353 if err != nil { 354 return nil, err 355 } 356 357 if tc, ok := c.(*TCPConn); ok && d.KeepAlive > 0 { 358 setKeepAlive(tc.fd, true) 359 setKeepAlivePeriod(tc.fd, d.KeepAlive) 360 testHookSetKeepAlive() 361 } 362 return c, nil 363 } 364 365 // dialParallel races two copies of dialSerial, giving the first a 366 // head start. It returns the first established connection and 367 // closes the others. Otherwise it returns an error from the first 368 // primary address. 369 func dialParallel(ctx context.Context, dp *dialParam, primaries, fallbacks addrList) (Conn, error) { 370 if len(fallbacks) == 0 { 371 return dialSerial(ctx, dp, primaries) 372 } 373 374 returned := make(chan struct{}) 375 defer close(returned) 376 377 type dialResult struct { 378 Conn 379 error 380 primary bool 381 done bool 382 } 383 results := make(chan dialResult) // unbuffered 384 385 startRacer := func(ctx context.Context, primary bool) { 386 ras := primaries 387 if !primary { 388 ras = fallbacks 389 } 390 c, err := dialSerial(ctx, dp, ras) 391 select { 392 case results <- dialResult{Conn: c, error: err, primary: primary, done: true}: 393 case <-returned: 394 if c != nil { 395 c.Close() 396 } 397 } 398 } 399 400 var primary, fallback dialResult 401 402 // Start the main racer. 403 primaryCtx, primaryCancel := context.WithCancel(ctx) 404 defer primaryCancel() 405 go startRacer(primaryCtx, true) 406 407 // Start the timer for the fallback racer. 408 fallbackTimer := time.NewTimer(dp.fallbackDelay()) 409 defer fallbackTimer.Stop() 410 411 for { 412 select { 413 case <-fallbackTimer.C: 414 fallbackCtx, fallbackCancel := context.WithCancel(ctx) 415 defer fallbackCancel() 416 go startRacer(fallbackCtx, false) 417 418 case res := <-results: 419 if res.error == nil { 420 return res.Conn, nil 421 } 422 if res.primary { 423 primary = res 424 } else { 425 fallback = res 426 } 427 if primary.done && fallback.done { 428 return nil, primary.error 429 } 430 if res.primary && fallbackTimer.Stop() { 431 // If we were able to stop the timer, that means it 432 // was running (hadn't yet started the fallback), but 433 // we just got an error on the primary path, so start 434 // the fallback immediately (in 0 nanoseconds). 435 fallbackTimer.Reset(0) 436 } 437 } 438 } 439 } 440 441 // dialSerial connects to a list of addresses in sequence, returning 442 // either the first successful connection, or the first error. 443 func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (Conn, error) { 444 var firstErr error // The error from the first address is most relevant. 445 446 for i, ra := range ras { 447 select { 448 case <-ctx.Done(): 449 return nil, &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())} 450 default: 451 } 452 453 deadline, _ := ctx.Deadline() 454 partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i) 455 if err != nil { 456 // Ran out of time. 457 if firstErr == nil { 458 firstErr = &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: err} 459 } 460 break 461 } 462 dialCtx := ctx 463 if partialDeadline.Before(deadline) { 464 var cancel context.CancelFunc 465 dialCtx, cancel = context.WithDeadline(ctx, partialDeadline) 466 defer cancel() 467 } 468 469 c, err := dialSingle(dialCtx, dp, ra) 470 if err == nil { 471 return c, nil 472 } 473 if firstErr == nil { 474 firstErr = err 475 } 476 } 477 478 if firstErr == nil { 479 firstErr = &OpError{Op: "dial", Net: dp.network, Source: nil, Addr: nil, Err: errMissingAddress} 480 } 481 return nil, firstErr 482 } 483 484 // dialSingle attempts to establish and returns a single connection to 485 // the destination address. 486 func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) { 487 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 488 if trace != nil { 489 raStr := ra.String() 490 if trace.ConnectStart != nil { 491 trace.ConnectStart(dp.network, raStr) 492 } 493 if trace.ConnectDone != nil { 494 defer func() { trace.ConnectDone(dp.network, raStr, err) }() 495 } 496 } 497 la := dp.LocalAddr 498 switch ra := ra.(type) { 499 case *TCPAddr: 500 la, _ := la.(*TCPAddr) 501 c, err = dialTCP(ctx, dp.network, la, ra) 502 case *UDPAddr: 503 la, _ := la.(*UDPAddr) 504 c, err = dialUDP(ctx, dp.network, la, ra) 505 case *IPAddr: 506 la, _ := la.(*IPAddr) 507 c, err = dialIP(ctx, dp.network, la, ra) 508 case *UnixAddr: 509 la, _ := la.(*UnixAddr) 510 c, err = dialUnix(ctx, dp.network, la, ra) 511 default: 512 return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: dp.address}} 513 } 514 if err != nil { 515 return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: err} // c is non-nil interface containing nil pointer 516 } 517 return c, nil 518 } 519 520 // Listen announces on the local network address laddr. 521 // The network net must be a stream-oriented network: "tcp", "tcp4", 522 // "tcp6", "unix" or "unixpacket". 523 // For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080". 524 // If host is omitted, as in ":8080", Listen listens on all available interfaces 525 // instead of just the interface with the given host address. 526 // See Dial for more details about address syntax. 527 func Listen(net, laddr string) (Listener, error) { 528 addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil) 529 if err != nil { 530 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} 531 } 532 var l Listener 533 switch la := addrs.first(isIPv4).(type) { 534 case *TCPAddr: 535 l, err = ListenTCP(net, la) 536 case *UnixAddr: 537 l, err = ListenUnix(net, la) 538 default: 539 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 540 } 541 if err != nil { 542 return nil, err // l is non-nil interface containing nil pointer 543 } 544 return l, nil 545 } 546 547 // ListenPacket announces on the local network address laddr. 548 // The network net must be a packet-oriented network: "udp", "udp4", 549 // "udp6", "ip", "ip4", "ip6" or "unixgram". 550 // For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080". 551 // If host is omitted, as in ":8080", ListenPacket listens on all available interfaces 552 // instead of just the interface with the given host address. 553 // See Dial for the syntax of laddr. 554 func ListenPacket(net, laddr string) (PacketConn, error) { 555 addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil) 556 if err != nil { 557 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} 558 } 559 var l PacketConn 560 switch la := addrs.first(isIPv4).(type) { 561 case *UDPAddr: 562 l, err = ListenUDP(net, la) 563 case *IPAddr: 564 l, err = ListenIP(net, la) 565 case *UnixAddr: 566 l, err = ListenUnixgram(net, la) 567 default: 568 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} 569 } 570 if err != nil { 571 return nil, err // l is non-nil interface containing nil pointer 572 } 573 return l, nil 574 }