1// Copyright 2011 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// +build !js 6 7package net 8 9import ( 10 "bufio" 11 "context" 12 "internal/testenv" 13 "io" 14 "os" 15 "runtime" 16 "strings" 17 "sync" 18 "testing" 19 "time" 20) 21 22var prohibitionaryDialArgTests = []struct { 23 network string 24 address string 25}{ 26 {"tcp6", "127.0.0.1"}, 27 {"tcp6", "::ffff:127.0.0.1"}, 28} 29 30func TestProhibitionaryDialArg(t *testing.T) { 31 testenv.MustHaveExternalNetwork(t) 32 33 switch runtime.GOOS { 34 case "plan9": 35 t.Skipf("not supported on %s", runtime.GOOS) 36 } 37 if !supportsIPv4map() { 38 t.Skip("mapping ipv4 address inside ipv6 address not supported") 39 } 40 41 ln, err := Listen("tcp", "[::]:0") 42 if err != nil { 43 t.Fatal(err) 44 } 45 defer ln.Close() 46 47 _, port, err := SplitHostPort(ln.Addr().String()) 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 for i, tt := range prohibitionaryDialArgTests { 53 c, err := Dial(tt.network, JoinHostPort(tt.address, port)) 54 if err == nil { 55 c.Close() 56 t.Errorf("#%d: %v", i, err) 57 } 58 } 59} 60 61func TestDialLocal(t *testing.T) { 62 ln, err := newLocalListener("tcp") 63 if err != nil { 64 t.Fatal(err) 65 } 66 defer ln.Close() 67 _, port, err := SplitHostPort(ln.Addr().String()) 68 if err != nil { 69 t.Fatal(err) 70 } 71 c, err := Dial("tcp", JoinHostPort("", port)) 72 if err != nil { 73 t.Fatal(err) 74 } 75 c.Close() 76} 77 78func TestDialerDualStackFDLeak(t *testing.T) { 79 switch runtime.GOOS { 80 case "plan9": 81 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 82 case "windows": 83 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) 84 case "openbsd": 85 testenv.SkipFlaky(t, 15157) 86 } 87 if !supportsIPv4() || !supportsIPv6() { 88 t.Skip("both IPv4 and IPv6 are required") 89 } 90 91 before := sw.Sockets() 92 origTestHookLookupIP := testHookLookupIP 93 defer func() { testHookLookupIP = origTestHookLookupIP }() 94 testHookLookupIP = lookupLocalhost 95 handler := func(dss *dualStackServer, ln Listener) { 96 for { 97 c, err := ln.Accept() 98 if err != nil { 99 return 100 } 101 c.Close() 102 } 103 } 104 dss, err := newDualStackServer() 105 if err != nil { 106 t.Fatal(err) 107 } 108 if err := dss.buildup(handler); err != nil { 109 dss.teardown() 110 t.Fatal(err) 111 } 112 113 const N = 10 114 var wg sync.WaitGroup 115 wg.Add(N) 116 d := &Dialer{DualStack: true, Timeout: 5 * time.Second} 117 for i := 0; i < N; i++ { 118 go func() { 119 defer wg.Done() 120 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 121 if err != nil { 122 t.Error(err) 123 return 124 } 125 c.Close() 126 }() 127 } 128 wg.Wait() 129 dss.teardown() 130 after := sw.Sockets() 131 if len(after) != len(before) { 132 t.Errorf("got %d; want %d", len(after), len(before)) 133 } 134} 135 136// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is 137// expected to hang until the timeout elapses. These addresses are reserved 138// for benchmarking by RFC 6890. 139const ( 140 slowDst4 = "198.18.0.254" 141 slowDst6 = "2001:2::254" 142) 143 144// In some environments, the slow IPs may be explicitly unreachable, and fail 145// more quickly than expected. This test hook prevents dialTCP from returning 146// before the deadline. 147func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) { 148 sd := &sysDialer{network: network, address: raddr.String()} 149 c, err := sd.doDialTCP(ctx, laddr, raddr) 150 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { 151 // Wait for the deadline, or indefinitely if none exists. 152 <-ctx.Done() 153 } 154 return c, err 155} 156 157func dialClosedPort(t *testing.T) (actual, expected time.Duration) { 158 // Estimate the expected time for this platform. 159 // On Windows, dialing a closed port takes roughly 1 second, 160 // but other platforms should be instantaneous. 161 if runtime.GOOS == "windows" { 162 expected = 1500 * time.Millisecond 163 } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 164 expected = 150 * time.Millisecond 165 } else { 166 expected = 95 * time.Millisecond 167 } 168 169 l, err := Listen("tcp", "127.0.0.1:0") 170 if err != nil { 171 t.Logf("dialClosedPort: Listen failed: %v", err) 172 return 999 * time.Hour, expected 173 } 174 addr := l.Addr().String() 175 l.Close() 176 // On OpenBSD, interference from TestTCPSelfConnect is mysteriously 177 // causing the first attempt to hang for a few seconds, so we throw 178 // away the first result and keep the second. 179 for i := 1; ; i++ { 180 startTime := time.Now() 181 c, err := Dial("tcp", addr) 182 if err == nil { 183 c.Close() 184 } 185 elapsed := time.Now().Sub(startTime) 186 if i == 2 { 187 t.Logf("dialClosedPort: measured delay %v", elapsed) 188 return elapsed, expected 189 } 190 } 191} 192 193func TestDialParallel(t *testing.T) { 194 testenv.MustHaveExternalNetwork(t) 195 196 if !supportsIPv4() || !supportsIPv6() { 197 t.Skip("both IPv4 and IPv6 are required") 198 } 199 200 closedPortDelay, expectClosedPortDelay := dialClosedPort(t) 201 if closedPortDelay > expectClosedPortDelay { 202 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) 203 } 204 205 const instant time.Duration = 0 206 const fallbackDelay = 200 * time.Millisecond 207 208 // Some cases will run quickly when "connection refused" is fast, 209 // or trigger the fallbackDelay on Windows. This value holds the 210 // lesser of the two delays. 211 var closedPortOrFallbackDelay time.Duration 212 if closedPortDelay < fallbackDelay { 213 closedPortOrFallbackDelay = closedPortDelay 214 } else { 215 closedPortOrFallbackDelay = fallbackDelay 216 } 217 218 origTestHookDialTCP := testHookDialTCP 219 defer func() { testHookDialTCP = origTestHookDialTCP }() 220 testHookDialTCP = slowDialTCP 221 222 nCopies := func(s string, n int) []string { 223 out := make([]string, n) 224 for i := 0; i < n; i++ { 225 out[i] = s 226 } 227 return out 228 } 229 230 var testCases = []struct { 231 primaries []string 232 fallbacks []string 233 teardownNetwork string 234 expectOk bool 235 expectElapsed time.Duration 236 }{ 237 // These should just work on the first try. 238 {[]string{"127.0.0.1"}, []string{}, "", true, instant}, 239 {[]string{"::1"}, []string{}, "", true, instant}, 240 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant}, 241 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant}, 242 // Primary is slow; fallback should kick in. 243 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay}, 244 // Skip a "connection refused" in the primary thread. 245 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay}, 246 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay}, 247 // Skip a "connection refused" in the fallback thread. 248 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay}, 249 // Primary refused, fallback without delay. 250 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay}, 251 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay}, 252 // Everything is refused. 253 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay}, 254 // Nothing to do; fail instantly. 255 {[]string{}, []string{}, "", false, instant}, 256 // Connecting to tons of addresses should not trip the deadline. 257 {nCopies("::1", 1000), []string{}, "", true, instant}, 258 } 259 260 handler := func(dss *dualStackServer, ln Listener) { 261 for { 262 c, err := ln.Accept() 263 if err != nil { 264 return 265 } 266 c.Close() 267 } 268 } 269 270 // Convert a list of IP strings into TCPAddrs. 271 makeAddrs := func(ips []string, port string) addrList { 272 var out addrList 273 for _, ip := range ips { 274 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port)) 275 if err != nil { 276 t.Fatal(err) 277 } 278 out = append(out, addr) 279 } 280 return out 281 } 282 283 for i, tt := range testCases { 284 dss, err := newDualStackServer() 285 if err != nil { 286 t.Fatal(err) 287 } 288 defer dss.teardown() 289 if err := dss.buildup(handler); err != nil { 290 t.Fatal(err) 291 } 292 if tt.teardownNetwork != "" { 293 // Destroy one of the listening sockets, creating an unreachable port. 294 dss.teardownNetwork(tt.teardownNetwork) 295 } 296 297 primaries := makeAddrs(tt.primaries, dss.port) 298 fallbacks := makeAddrs(tt.fallbacks, dss.port) 299 d := Dialer{ 300 FallbackDelay: fallbackDelay, 301 } 302 startTime := time.Now() 303 sd := &sysDialer{ 304 Dialer: d, 305 network: "tcp", 306 address: "?", 307 } 308 c, err := sd.dialParallel(context.Background(), primaries, fallbacks) 309 elapsed := time.Since(startTime) 310 311 if c != nil { 312 c.Close() 313 } 314 315 if tt.expectOk && err != nil { 316 t.Errorf("#%d: got %v; want nil", i, err) 317 } else if !tt.expectOk && err == nil { 318 t.Errorf("#%d: got nil; want non-nil", i) 319 } 320 321 // We used to always use 95 milliseconds as the slop, 322 // but that was flaky on Windows. See issue 35616. 323 slop := 95 * time.Millisecond 324 if fifth := tt.expectElapsed / 5; fifth > slop { 325 slop = fifth 326 } 327 expectElapsedMin := tt.expectElapsed - slop 328 expectElapsedMax := tt.expectElapsed + slop 329 if elapsed < expectElapsedMin { 330 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin) 331 } else if elapsed > expectElapsedMax { 332 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax) 333 } 334 335 // Repeat each case, ensuring that it can be canceled quickly. 336 ctx, cancel := context.WithCancel(context.Background()) 337 var wg sync.WaitGroup 338 wg.Add(1) 339 go func() { 340 time.Sleep(5 * time.Millisecond) 341 cancel() 342 wg.Done() 343 }() 344 startTime = time.Now() 345 c, err = sd.dialParallel(ctx, primaries, fallbacks) 346 if c != nil { 347 c.Close() 348 } 349 elapsed = time.Now().Sub(startTime) 350 if elapsed > 100*time.Millisecond { 351 t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed) 352 } 353 wg.Wait() 354 } 355} 356 357func lookupSlowFast(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 358 switch host { 359 case "slow6loopback4": 360 // Returns a slow IPv6 address, and a local IPv4 address. 361 return []IPAddr{ 362 {IP: ParseIP(slowDst6)}, 363 {IP: ParseIP("127.0.0.1")}, 364 }, nil 365 default: 366 return fn(ctx, network, host) 367 } 368} 369 370func TestDialerFallbackDelay(t *testing.T) { 371 testenv.MustHaveExternalNetwork(t) 372 373 if !supportsIPv4() || !supportsIPv6() { 374 t.Skip("both IPv4 and IPv6 are required") 375 } 376 377 origTestHookLookupIP := testHookLookupIP 378 defer func() { testHookLookupIP = origTestHookLookupIP }() 379 testHookLookupIP = lookupSlowFast 380 381 origTestHookDialTCP := testHookDialTCP 382 defer func() { testHookDialTCP = origTestHookDialTCP }() 383 testHookDialTCP = slowDialTCP 384 385 var testCases = []struct { 386 dualstack bool 387 delay time.Duration 388 expectElapsed time.Duration 389 }{ 390 // Use a very brief delay, which should fallback immediately. 391 {true, 1 * time.Nanosecond, 0}, 392 // Use a 200ms explicit timeout. 393 {true, 200 * time.Millisecond, 200 * time.Millisecond}, 394 // The default is 300ms. 395 {true, 0, 300 * time.Millisecond}, 396 } 397 398 handler := func(dss *dualStackServer, ln Listener) { 399 for { 400 c, err := ln.Accept() 401 if err != nil { 402 return 403 } 404 c.Close() 405 } 406 } 407 dss, err := newDualStackServer() 408 if err != nil { 409 t.Fatal(err) 410 } 411 defer dss.teardown() 412 if err := dss.buildup(handler); err != nil { 413 t.Fatal(err) 414 } 415 416 for i, tt := range testCases { 417 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay} 418 419 startTime := time.Now() 420 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) 421 elapsed := time.Now().Sub(startTime) 422 if err == nil { 423 c.Close() 424 } else if tt.dualstack { 425 t.Error(err) 426 } 427 expectMin := tt.expectElapsed - 1*time.Millisecond 428 expectMax := tt.expectElapsed + 95*time.Millisecond 429 if elapsed < expectMin { 430 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin) 431 } 432 if elapsed > expectMax { 433 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax) 434 } 435 } 436} 437 438func TestDialParallelSpuriousConnection(t *testing.T) { 439 if !supportsIPv4() || !supportsIPv6() { 440 t.Skip("both IPv4 and IPv6 are required") 441 } 442 443 var readDeadline time.Time 444 if td, ok := t.Deadline(); ok { 445 const arbitraryCleanupMargin = 1 * time.Second 446 readDeadline = td.Add(-arbitraryCleanupMargin) 447 } else { 448 readDeadline = time.Now().Add(5 * time.Second) 449 } 450 451 var wg sync.WaitGroup 452 wg.Add(2) 453 handler := func(dss *dualStackServer, ln Listener) { 454 // Accept one connection per address. 455 c, err := ln.Accept() 456 if err != nil { 457 t.Fatal(err) 458 } 459 // The client should close itself, without sending data. 460 c.SetReadDeadline(readDeadline) 461 var b [1]byte 462 if _, err := c.Read(b[:]); err != io.EOF { 463 t.Errorf("got %v; want %v", err, io.EOF) 464 } 465 c.Close() 466 wg.Done() 467 } 468 dss, err := newDualStackServer() 469 if err != nil { 470 t.Fatal(err) 471 } 472 defer dss.teardown() 473 if err := dss.buildup(handler); err != nil { 474 t.Fatal(err) 475 } 476 477 const fallbackDelay = 100 * time.Millisecond 478 479 origTestHookDialTCP := testHookDialTCP 480 defer func() { testHookDialTCP = origTestHookDialTCP }() 481 testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) { 482 // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancellation. 483 // This forces dialParallel to juggle two successful connections. 484 time.Sleep(fallbackDelay * 2) 485 486 // Now ignore the provided context (which will be canceled) and use a 487 // different one to make sure this completes with a valid connection, 488 // which we hope to be closed below: 489 sd := &sysDialer{network: net, address: raddr.String()} 490 return sd.doDialTCP(context.Background(), laddr, raddr) 491 } 492 493 d := Dialer{ 494 FallbackDelay: fallbackDelay, 495 } 496 sd := &sysDialer{ 497 Dialer: d, 498 network: "tcp", 499 address: "?", 500 } 501 502 makeAddr := func(ip string) addrList { 503 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port)) 504 if err != nil { 505 t.Fatal(err) 506 } 507 return addrList{addr} 508 } 509 510 // dialParallel returns one connection (and closes the other.) 511 c, err := sd.dialParallel(context.Background(), makeAddr("127.0.0.1"), makeAddr("::1")) 512 if err != nil { 513 t.Fatal(err) 514 } 515 c.Close() 516 517 // The server should've seen both connections. 518 wg.Wait() 519} 520 521func TestDialerPartialDeadline(t *testing.T) { 522 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) 523 var testCases = []struct { 524 now time.Time 525 deadline time.Time 526 addrs int 527 expectDeadline time.Time 528 expectErr error 529 }{ 530 // Regular division. 531 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, 532 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, 533 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, 534 // Bump against the 2-second sane minimum. 535 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, 536 // Total available is now below the sane minimum. 537 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, 538 // Null deadline. 539 {now, noDeadline, 1, noDeadline, nil}, 540 // Step the clock forward and cross the deadline. 541 {now.Add(-1 * time.Millisecond), now, 1, now, nil}, 542 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, 543 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, 544 } 545 for i, tt := range testCases { 546 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) 547 if err != tt.expectErr { 548 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) 549 } 550 if !deadline.Equal(tt.expectDeadline) { 551 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) 552 } 553 } 554} 555 556func TestDialerLocalAddr(t *testing.T) { 557 if !supportsIPv4() || !supportsIPv6() { 558 t.Skip("both IPv4 and IPv6 are required") 559 } 560 561 type test struct { 562 network, raddr string 563 laddr Addr 564 error 565 } 566 var tests = []test{ 567 {"tcp4", "127.0.0.1", nil, nil}, 568 {"tcp4", "127.0.0.1", &TCPAddr{}, nil}, 569 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 570 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 571 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}}, 572 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, 573 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, 574 {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, 575 {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, 576 {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, 577 578 {"tcp6", "::1", nil, nil}, 579 {"tcp6", "::1", &TCPAddr{}, nil}, 580 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 581 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 582 {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, 583 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, 584 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, 585 {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil}, 586 {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, 587 {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, 588 589 {"tcp", "127.0.0.1", nil, nil}, 590 {"tcp", "127.0.0.1", &TCPAddr{}, nil}, 591 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 592 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 593 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, 594 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, 595 {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, 596 {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, 597 {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, 598 599 {"tcp", "::1", nil, nil}, 600 {"tcp", "::1", &TCPAddr{}, nil}, 601 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 602 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 603 {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, 604 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, 605 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, 606 {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil}, 607 {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, 608 {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, 609 } 610 611 if supportsIPv4map() { 612 tests = append(tests, test{ 613 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil, 614 }) 615 } else { 616 tests = append(tests, test{ 617 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}, 618 }) 619 } 620 621 origTestHookLookupIP := testHookLookupIP 622 defer func() { testHookLookupIP = origTestHookLookupIP }() 623 testHookLookupIP = lookupLocalhost 624 handler := func(ls *localServer, ln Listener) { 625 for { 626 c, err := ln.Accept() 627 if err != nil { 628 return 629 } 630 c.Close() 631 } 632 } 633 var err error 634 var lss [2]*localServer 635 for i, network := range []string{"tcp4", "tcp6"} { 636 lss[i], err = newLocalServer(network) 637 if err != nil { 638 t.Fatal(err) 639 } 640 defer lss[i].teardown() 641 if err := lss[i].buildup(handler); err != nil { 642 t.Fatal(err) 643 } 644 } 645 646 for _, tt := range tests { 647 d := &Dialer{LocalAddr: tt.laddr} 648 var addr string 649 ip := ParseIP(tt.raddr) 650 if ip.To4() != nil { 651 addr = lss[0].Listener.Addr().String() 652 } 653 if ip.To16() != nil && ip.To4() == nil { 654 addr = lss[1].Listener.Addr().String() 655 } 656 c, err := d.Dial(tt.network, addr) 657 if err == nil && tt.error != nil || err != nil && tt.error == nil { 658 // A suspected kernel bug in macOS 10.12 occasionally results in 659 // timeout errors when dialing address ::1. The errors have not 660 // been observed on newer versions of the OS, so we don't plan to work 661 // around them. See https://golang.org/issue/22019. 662 if tt.raddr == "::1" && os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" && os.IsTimeout(err) { 663 t.Logf("ignoring timeout error on Darwin; see https://golang.org/issue/22019") 664 } else { 665 t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) 666 } 667 } 668 if err != nil { 669 if perr := parseDialError(err); perr != nil { 670 t.Error(perr) 671 } 672 continue 673 } 674 c.Close() 675 } 676} 677 678func TestDialerDualStack(t *testing.T) { 679 testenv.SkipFlaky(t, 13324) 680 681 if !supportsIPv4() || !supportsIPv6() { 682 t.Skip("both IPv4 and IPv6 are required") 683 } 684 685 closedPortDelay, expectClosedPortDelay := dialClosedPort(t) 686 if closedPortDelay > expectClosedPortDelay { 687 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) 688 } 689 690 origTestHookLookupIP := testHookLookupIP 691 defer func() { testHookLookupIP = origTestHookLookupIP }() 692 testHookLookupIP = lookupLocalhost 693 handler := func(dss *dualStackServer, ln Listener) { 694 for { 695 c, err := ln.Accept() 696 if err != nil { 697 return 698 } 699 c.Close() 700 } 701 } 702 703 var timeout = 150*time.Millisecond + closedPortDelay 704 for _, dualstack := range []bool{false, true} { 705 dss, err := newDualStackServer() 706 if err != nil { 707 t.Fatal(err) 708 } 709 defer dss.teardown() 710 if err := dss.buildup(handler); err != nil { 711 t.Fatal(err) 712 } 713 714 d := &Dialer{DualStack: dualstack, Timeout: timeout} 715 for range dss.lns { 716 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 717 if err != nil { 718 t.Error(err) 719 continue 720 } 721 switch addr := c.LocalAddr().(*TCPAddr); { 722 case addr.IP.To4() != nil: 723 dss.teardownNetwork("tcp4") 724 case addr.IP.To16() != nil && addr.IP.To4() == nil: 725 dss.teardownNetwork("tcp6") 726 } 727 c.Close() 728 } 729 } 730} 731 732func TestDialerKeepAlive(t *testing.T) { 733 handler := func(ls *localServer, ln Listener) { 734 for { 735 c, err := ln.Accept() 736 if err != nil { 737 return 738 } 739 c.Close() 740 } 741 } 742 ls, err := newLocalServer("tcp") 743 if err != nil { 744 t.Fatal(err) 745 } 746 defer ls.teardown() 747 if err := ls.buildup(handler); err != nil { 748 t.Fatal(err) 749 } 750 defer func() { testHookSetKeepAlive = func(time.Duration) {} }() 751 752 tests := []struct { 753 ka time.Duration 754 expected time.Duration 755 }{ 756 {-1, -1}, 757 {0, 15 * time.Second}, 758 {5 * time.Second, 5 * time.Second}, 759 {30 * time.Second, 30 * time.Second}, 760 } 761 762 for _, test := range tests { 763 var got time.Duration = -1 764 testHookSetKeepAlive = func(d time.Duration) { got = d } 765 d := Dialer{KeepAlive: test.ka} 766 c, err := d.Dial("tcp", ls.Listener.Addr().String()) 767 if err != nil { 768 t.Fatal(err) 769 } 770 c.Close() 771 if got != test.expected { 772 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected) 773 } 774 } 775} 776 777func TestDialCancel(t *testing.T) { 778 mustHaveExternalNetwork(t) 779 780 blackholeIPPort := JoinHostPort(slowDst4, "1234") 781 if !supportsIPv4() { 782 blackholeIPPort = JoinHostPort(slowDst6, "1234") 783 } 784 785 ticker := time.NewTicker(10 * time.Millisecond) 786 defer ticker.Stop() 787 788 const cancelTick = 5 // the timer tick we cancel the dial at 789 const timeoutTick = 100 790 791 var d Dialer 792 cancel := make(chan struct{}) 793 d.Cancel = cancel 794 errc := make(chan error, 1) 795 connc := make(chan Conn, 1) 796 go func() { 797 if c, err := d.Dial("tcp", blackholeIPPort); err != nil { 798 errc <- err 799 } else { 800 connc <- c 801 } 802 }() 803 ticks := 0 804 for { 805 select { 806 case <-ticker.C: 807 ticks++ 808 if ticks == cancelTick { 809 close(cancel) 810 } 811 if ticks == timeoutTick { 812 t.Fatal("timeout waiting for dial to fail") 813 } 814 case c := <-connc: 815 c.Close() 816 t.Fatal("unexpected successful connection") 817 case err := <-errc: 818 if perr := parseDialError(err); perr != nil { 819 t.Error(perr) 820 } 821 if ticks < cancelTick { 822 // Using strings.Contains is ugly but 823 // may work on plan9 and windows. 824 if strings.Contains(err.Error(), "connection refused") { 825 t.Skipf("connection to %v failed fast with %v", blackholeIPPort, err) 826 } 827 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v", 828 ticks, cancelTick-ticks, err) 829 } 830 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled { 831 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err) 832 } 833 return // success. 834 } 835 } 836} 837 838func TestCancelAfterDial(t *testing.T) { 839 if testing.Short() { 840 t.Skip("avoiding time.Sleep") 841 } 842 843 ln, err := newLocalListener("tcp") 844 if err != nil { 845 t.Fatal(err) 846 } 847 848 var wg sync.WaitGroup 849 wg.Add(1) 850 defer func() { 851 ln.Close() 852 wg.Wait() 853 }() 854 855 // Echo back the first line of each incoming connection. 856 go func() { 857 for { 858 c, err := ln.Accept() 859 if err != nil { 860 break 861 } 862 rb := bufio.NewReader(c) 863 line, err := rb.ReadString('\n') 864 if err != nil { 865 t.Error(err) 866 c.Close() 867 continue 868 } 869 if _, err := c.Write([]byte(line)); err != nil { 870 t.Error(err) 871 } 872 c.Close() 873 } 874 wg.Done() 875 }() 876 877 try := func() { 878 cancel := make(chan struct{}) 879 d := &Dialer{Cancel: cancel} 880 c, err := d.Dial("tcp", ln.Addr().String()) 881 882 // Immediately after dialing, request cancellation and sleep. 883 // Before Issue 15078 was fixed, this would cause subsequent operations 884 // to fail with an i/o timeout roughly 50% of the time. 885 close(cancel) 886 time.Sleep(10 * time.Millisecond) 887 888 if err != nil { 889 t.Fatal(err) 890 } 891 defer c.Close() 892 893 // Send some data to confirm that the connection is still alive. 894 const message = "echo!\n" 895 if _, err := c.Write([]byte(message)); err != nil { 896 t.Fatal(err) 897 } 898 899 // The server should echo the line, and close the connection. 900 rb := bufio.NewReader(c) 901 line, err := rb.ReadString('\n') 902 if err != nil { 903 t.Fatal(err) 904 } 905 if line != message { 906 t.Errorf("got %q; want %q", line, message) 907 } 908 if _, err := rb.ReadByte(); err != io.EOF { 909 t.Errorf("got %v; want %v", err, io.EOF) 910 } 911 } 912 913 // This bug manifested about 50% of the time, so try it a few times. 914 for i := 0; i < 10; i++ { 915 try() 916 } 917} 918 919// Issue 18806: it should always be possible to net.Dial a 920// net.Listener().Addr().String when the listen address was ":n", even 921// if the machine has halfway configured IPv6 such that it can bind on 922// "::" not connect back to that same address. 923func TestDialListenerAddr(t *testing.T) { 924 mustHaveExternalNetwork(t) 925 ln, err := Listen("tcp", ":0") 926 if err != nil { 927 t.Fatal(err) 928 } 929 defer ln.Close() 930 addr := ln.Addr().String() 931 c, err := Dial("tcp", addr) 932 if err != nil { 933 t.Fatalf("for addr %q, dial error: %v", addr, err) 934 } 935 c.Close() 936} 937 938func TestDialerControl(t *testing.T) { 939 switch runtime.GOOS { 940 case "plan9": 941 t.Skipf("not supported on %s", runtime.GOOS) 942 } 943 944 t.Run("StreamDial", func(t *testing.T) { 945 for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} { 946 if !testableNetwork(network) { 947 continue 948 } 949 ln, err := newLocalListener(network) 950 if err != nil { 951 t.Error(err) 952 continue 953 } 954 defer ln.Close() 955 d := Dialer{Control: controlOnConnSetup} 956 c, err := d.Dial(network, ln.Addr().String()) 957 if err != nil { 958 t.Error(err) 959 continue 960 } 961 c.Close() 962 } 963 }) 964 t.Run("PacketDial", func(t *testing.T) { 965 for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} { 966 if !testableNetwork(network) { 967 continue 968 } 969 c1, err := newLocalPacketListener(network) 970 if err != nil { 971 t.Error(err) 972 continue 973 } 974 if network == "unixgram" { 975 defer os.Remove(c1.LocalAddr().String()) 976 } 977 defer c1.Close() 978 d := Dialer{Control: controlOnConnSetup} 979 c2, err := d.Dial(network, c1.LocalAddr().String()) 980 if err != nil { 981 t.Error(err) 982 continue 983 } 984 c2.Close() 985 } 986 }) 987} 988 989// mustHaveExternalNetwork is like testenv.MustHaveExternalNetwork 990// except that it won't skip testing on non-mobile builders. 991func mustHaveExternalNetwork(t *testing.T) { 992 t.Helper() 993 mobile := runtime.GOOS == "android" || runtime.GOOS == "ios" 994 if testenv.Builder() == "" || mobile { 995 testenv.MustHaveExternalNetwork(t) 996 } 997} 998 999type contextWithNonZeroDeadline struct { 1000 context.Context 1001} 1002 1003func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) { 1004 // Return non-zero time.Time value with false indicating that no deadline is set. 1005 return time.Unix(0, 0), false 1006} 1007 1008func TestDialWithNonZeroDeadline(t *testing.T) { 1009 ln, err := newLocalListener("tcp") 1010 if err != nil { 1011 t.Fatal(err) 1012 } 1013 defer ln.Close() 1014 _, port, err := SplitHostPort(ln.Addr().String()) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 1019 ctx := contextWithNonZeroDeadline{Context: context.Background()} 1020 var dialer Dialer 1021 c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port)) 1022 if err != nil { 1023 t.Fatal(err) 1024 } 1025 c.Close() 1026} 1027