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