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