github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/net/dial_test.go (about)

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