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