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