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