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