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