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