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