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