github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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  	"io"
     9  	"net/internal/socktest"
    10  	"runtime"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  var prohibitionaryDialArgTests = []struct {
    17  	network string
    18  	address string
    19  }{
    20  	{"tcp6", "127.0.0.1"},
    21  	{"tcp6", "::ffff:127.0.0.1"},
    22  }
    23  
    24  func TestProhibitionaryDialArg(t *testing.T) {
    25  	switch runtime.GOOS {
    26  	case "plan9":
    27  		t.Skipf("not supported on %s", runtime.GOOS)
    28  	}
    29  	if testing.Short() || !*testExternal {
    30  		t.Skip("avoid external network")
    31  	}
    32  	if !supportsIPv4map {
    33  		t.Skip("mapping ipv4 address inside ipv6 address not supported")
    34  	}
    35  
    36  	ln, err := Listen("tcp", "[::]:0")
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	defer ln.Close()
    41  
    42  	_, port, err := SplitHostPort(ln.Addr().String())
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  
    47  	for i, tt := range prohibitionaryDialArgTests {
    48  		c, err := Dial(tt.network, JoinHostPort(tt.address, port))
    49  		if err == nil {
    50  			c.Close()
    51  			t.Errorf("#%d: %v", i, err)
    52  		}
    53  	}
    54  }
    55  
    56  func TestSelfConnect(t *testing.T) {
    57  	if runtime.GOOS == "windows" {
    58  		// TODO(brainman): do not know why it hangs.
    59  		t.Skip("known-broken test on windows")
    60  	}
    61  
    62  	// Test that Dial does not honor self-connects.
    63  	// See the comment in DialTCP.
    64  
    65  	// Find a port that would be used as a local address.
    66  	l, err := Listen("tcp", "127.0.0.1:0")
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	c, err := Dial("tcp", l.Addr().String())
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	addr := c.LocalAddr().String()
    75  	c.Close()
    76  	l.Close()
    77  
    78  	// Try to connect to that address repeatedly.
    79  	n := 100000
    80  	if testing.Short() {
    81  		n = 1000
    82  	}
    83  	switch runtime.GOOS {
    84  	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
    85  		// Non-Linux systems take a long time to figure
    86  		// out that there is nothing listening on localhost.
    87  		n = 100
    88  	}
    89  	for i := 0; i < n; i++ {
    90  		c, err := DialTimeout("tcp", addr, time.Millisecond)
    91  		if err == nil {
    92  			if c.LocalAddr().String() == addr {
    93  				t.Errorf("#%d: Dial %q self-connect", i, addr)
    94  			} else {
    95  				t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
    96  			}
    97  			c.Close()
    98  		}
    99  	}
   100  }
   101  
   102  func TestDialTimeoutFDLeak(t *testing.T) {
   103  	switch runtime.GOOS {
   104  	case "plan9":
   105  		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
   106  	}
   107  
   108  	const T = 100 * time.Millisecond
   109  
   110  	switch runtime.GOOS {
   111  	case "plan9", "windows":
   112  		origTestHookDialChannel := testHookDialChannel
   113  		testHookDialChannel = func() { time.Sleep(2 * T) }
   114  		defer func() { testHookDialChannel = origTestHookDialChannel }()
   115  		if runtime.GOOS == "plan9" {
   116  			break
   117  		}
   118  		fallthrough
   119  	default:
   120  		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
   121  			time.Sleep(2 * T)
   122  			return nil, errTimeout
   123  		})
   124  		defer sw.Set(socktest.FilterConnect, nil)
   125  	}
   126  
   127  	// Avoid tracking open-close jitterbugs between netFD and
   128  	// socket that leads to confusion of information inside
   129  	// socktest.Switch.
   130  	// It may happen when the Dial call bumps against TCP
   131  	// simultaneous open. See selfConnect in tcpsock_posix.go.
   132  	defer func() {
   133  		sw.Set(socktest.FilterClose, nil)
   134  		forceCloseSockets()
   135  	}()
   136  	var mu sync.Mutex
   137  	var attempts int
   138  	sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
   139  		mu.Lock()
   140  		attempts++
   141  		mu.Unlock()
   142  		return nil, errTimedout
   143  	})
   144  
   145  	const N = 100
   146  	var wg sync.WaitGroup
   147  	wg.Add(N)
   148  	for i := 0; i < N; i++ {
   149  		go func() {
   150  			defer wg.Done()
   151  			// This dial never starts to send any SYN
   152  			// segment because of above socket filter and
   153  			// test hook.
   154  			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
   155  			if err == nil {
   156  				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
   157  				c.Close()
   158  			}
   159  		}()
   160  	}
   161  	wg.Wait()
   162  	if attempts < N {
   163  		t.Errorf("got %d; want >= %d", attempts, N)
   164  	}
   165  }
   166  
   167  func TestDialerDualStackFDLeak(t *testing.T) {
   168  	switch runtime.GOOS {
   169  	case "plan9":
   170  		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
   171  	case "windows":
   172  		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
   173  	}
   174  	if !supportsIPv4 || !supportsIPv6 {
   175  		t.Skip("both IPv4 and IPv6 are required")
   176  	}
   177  
   178  	origTestHookLookupIP := testHookLookupIP
   179  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   180  	testHookLookupIP = lookupLocalhost
   181  	handler := func(dss *dualStackServer, ln Listener) {
   182  		for {
   183  			c, err := ln.Accept()
   184  			if err != nil {
   185  				return
   186  			}
   187  			c.Close()
   188  		}
   189  	}
   190  	dss, err := newDualStackServer([]streamListener{
   191  		{network: "tcp4", address: "127.0.0.1"},
   192  		{network: "tcp6", address: "::1"},
   193  	})
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  	defer dss.teardown()
   198  	if err := dss.buildup(handler); err != nil {
   199  		t.Fatal(err)
   200  	}
   201  
   202  	before := sw.Sockets()
   203  	const T = 100 * time.Millisecond
   204  	const N = 10
   205  	var wg sync.WaitGroup
   206  	wg.Add(N)
   207  	d := &Dialer{DualStack: true, Timeout: T}
   208  	for i := 0; i < N; i++ {
   209  		go func() {
   210  			defer wg.Done()
   211  			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
   212  			if err != nil {
   213  				t.Error(err)
   214  				return
   215  			}
   216  			c.Close()
   217  		}()
   218  	}
   219  	wg.Wait()
   220  	time.Sleep(2 * T) // wait for the dial racers to stop
   221  	after := sw.Sockets()
   222  	if len(after) != len(before) {
   223  		t.Errorf("got %d; want %d", len(after), len(before))
   224  	}
   225  }
   226  
   227  // Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
   228  // expected to hang until the timeout elapses. These addresses are reserved
   229  // for benchmarking by RFC 6890.
   230  const (
   231  	slowDst4    = "192.18.0.254"
   232  	slowDst6    = "2001:2::254"
   233  	slowTimeout = 1 * time.Second
   234  )
   235  
   236  // In some environments, the slow IPs may be explicitly unreachable, and fail
   237  // more quickly than expected. This test hook prevents dialTCP from returning
   238  // before the deadline.
   239  func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
   240  	c, err := dialTCP(net, laddr, raddr, deadline)
   241  	if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
   242  		time.Sleep(deadline.Sub(time.Now()))
   243  	}
   244  	return c, err
   245  }
   246  
   247  func dialClosedPort() (actual, expected time.Duration) {
   248  	// Estimate the expected time for this platform.
   249  	// On Windows, dialing a closed port takes roughly 1 second,
   250  	// but other platforms should be instantaneous.
   251  	if runtime.GOOS == "windows" {
   252  		expected = 1500 * time.Millisecond
   253  	} else {
   254  		expected = 95 * time.Millisecond
   255  	}
   256  
   257  	l, err := Listen("tcp", "127.0.0.1:0")
   258  	if err != nil {
   259  		return 999 * time.Hour, expected
   260  	}
   261  	addr := l.Addr().String()
   262  	l.Close()
   263  	// On OpenBSD, interference from TestSelfConnect is mysteriously
   264  	// causing the first attempt to hang for a few seconds, so we throw
   265  	// away the first result and keep the second.
   266  	for i := 1; ; i++ {
   267  		startTime := time.Now()
   268  		c, err := Dial("tcp", addr)
   269  		if err == nil {
   270  			c.Close()
   271  		}
   272  		elapsed := time.Now().Sub(startTime)
   273  		if i == 2 {
   274  			return elapsed, expected
   275  		}
   276  	}
   277  }
   278  
   279  func TestDialParallel(t *testing.T) {
   280  	if testing.Short() || !*testExternal {
   281  		t.Skip("avoid external network")
   282  	}
   283  	if !supportsIPv4 || !supportsIPv6 {
   284  		t.Skip("both IPv4 and IPv6 are required")
   285  	}
   286  
   287  	closedPortDelay, expectClosedPortDelay := dialClosedPort()
   288  	if closedPortDelay > expectClosedPortDelay {
   289  		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
   290  	}
   291  
   292  	const instant time.Duration = 0
   293  	const fallbackDelay = 200 * time.Millisecond
   294  
   295  	// Some cases will run quickly when "connection refused" is fast,
   296  	// or trigger the fallbackDelay on Windows.  This value holds the
   297  	// lesser of the two delays.
   298  	var closedPortOrFallbackDelay time.Duration
   299  	if closedPortDelay < fallbackDelay {
   300  		closedPortOrFallbackDelay = closedPortDelay
   301  	} else {
   302  		closedPortOrFallbackDelay = fallbackDelay
   303  	}
   304  
   305  	origTestHookDialTCP := testHookDialTCP
   306  	defer func() { testHookDialTCP = origTestHookDialTCP }()
   307  	testHookDialTCP = slowDialTCP
   308  
   309  	nCopies := func(s string, n int) []string {
   310  		out := make([]string, n)
   311  		for i := 0; i < n; i++ {
   312  			out[i] = s
   313  		}
   314  		return out
   315  	}
   316  
   317  	var testCases = []struct {
   318  		primaries       []string
   319  		fallbacks       []string
   320  		teardownNetwork string
   321  		expectOk        bool
   322  		expectElapsed   time.Duration
   323  	}{
   324  		// These should just work on the first try.
   325  		{[]string{"127.0.0.1"}, []string{}, "", true, instant},
   326  		{[]string{"::1"}, []string{}, "", true, instant},
   327  		{[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
   328  		{[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
   329  		// Primary is slow; fallback should kick in.
   330  		{[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
   331  		// Skip a "connection refused" in the primary thread.
   332  		{[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
   333  		{[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
   334  		// Skip a "connection refused" in the fallback thread.
   335  		{[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
   336  		// Primary refused, fallback without delay.
   337  		{[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
   338  		{[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
   339  		// Everything is refused.
   340  		{[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
   341  		// Nothing to do; fail instantly.
   342  		{[]string{}, []string{}, "", false, instant},
   343  		// Connecting to tons of addresses should not trip the deadline.
   344  		{nCopies("::1", 1000), []string{}, "", true, instant},
   345  	}
   346  
   347  	handler := func(dss *dualStackServer, ln Listener) {
   348  		for {
   349  			c, err := ln.Accept()
   350  			if err != nil {
   351  				return
   352  			}
   353  			c.Close()
   354  		}
   355  	}
   356  
   357  	// Convert a list of IP strings into TCPAddrs.
   358  	makeAddrs := func(ips []string, port string) addrList {
   359  		var out addrList
   360  		for _, ip := range ips {
   361  			addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
   362  			if err != nil {
   363  				t.Fatal(err)
   364  			}
   365  			out = append(out, addr)
   366  		}
   367  		return out
   368  	}
   369  
   370  	for i, tt := range testCases {
   371  		dss, err := newDualStackServer([]streamListener{
   372  			{network: "tcp4", address: "127.0.0.1"},
   373  			{network: "tcp6", address: "::1"},
   374  		})
   375  		if err != nil {
   376  			t.Fatal(err)
   377  		}
   378  		defer dss.teardown()
   379  		if err := dss.buildup(handler); err != nil {
   380  			t.Fatal(err)
   381  		}
   382  		if tt.teardownNetwork != "" {
   383  			// Destroy one of the listening sockets, creating an unreachable port.
   384  			dss.teardownNetwork(tt.teardownNetwork)
   385  		}
   386  
   387  		primaries := makeAddrs(tt.primaries, dss.port)
   388  		fallbacks := makeAddrs(tt.fallbacks, dss.port)
   389  		d := Dialer{
   390  			FallbackDelay: fallbackDelay,
   391  			Timeout:       slowTimeout,
   392  		}
   393  		ctx := &dialContext{
   394  			Dialer:        d,
   395  			network:       "tcp",
   396  			address:       "?",
   397  			finalDeadline: d.deadline(time.Now()),
   398  		}
   399  		startTime := time.Now()
   400  		c, err := dialParallel(ctx, primaries, fallbacks)
   401  		elapsed := time.Now().Sub(startTime)
   402  
   403  		if c != nil {
   404  			c.Close()
   405  		}
   406  
   407  		if tt.expectOk && err != nil {
   408  			t.Errorf("#%d: got %v; want nil", i, err)
   409  		} else if !tt.expectOk && err == nil {
   410  			t.Errorf("#%d: got nil; want non-nil", i)
   411  		}
   412  
   413  		expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
   414  		expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
   415  		if !(elapsed >= expectElapsedMin) {
   416  			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
   417  		} else if !(elapsed <= expectElapsedMax) {
   418  			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
   419  		}
   420  	}
   421  	// Wait for any slowDst4/slowDst6 connections to timeout.
   422  	time.Sleep(slowTimeout * 3 / 2)
   423  }
   424  
   425  func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
   426  	switch host {
   427  	case "slow6loopback4":
   428  		// Returns a slow IPv6 address, and a local IPv4 address.
   429  		return []IPAddr{
   430  			{IP: ParseIP(slowDst6)},
   431  			{IP: ParseIP("127.0.0.1")},
   432  		}, nil
   433  	default:
   434  		return fn(host)
   435  	}
   436  }
   437  
   438  func TestDialerFallbackDelay(t *testing.T) {
   439  	if testing.Short() || !*testExternal {
   440  		t.Skip("avoid external network")
   441  	}
   442  	if !supportsIPv4 || !supportsIPv6 {
   443  		t.Skip("both IPv4 and IPv6 are required")
   444  	}
   445  
   446  	origTestHookLookupIP := testHookLookupIP
   447  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   448  	testHookLookupIP = lookupSlowFast
   449  
   450  	origTestHookDialTCP := testHookDialTCP
   451  	defer func() { testHookDialTCP = origTestHookDialTCP }()
   452  	testHookDialTCP = slowDialTCP
   453  
   454  	var testCases = []struct {
   455  		dualstack     bool
   456  		delay         time.Duration
   457  		expectElapsed time.Duration
   458  	}{
   459  		// Use a very brief delay, which should fallback immediately.
   460  		{true, 1 * time.Nanosecond, 0},
   461  		// Use a 200ms explicit timeout.
   462  		{true, 200 * time.Millisecond, 200 * time.Millisecond},
   463  		// The default is 300ms.
   464  		{true, 0, 300 * time.Millisecond},
   465  		// This case is last, in order to wait for hanging slowDst6 connections.
   466  		{false, 0, slowTimeout},
   467  	}
   468  
   469  	handler := func(dss *dualStackServer, ln Listener) {
   470  		for {
   471  			c, err := ln.Accept()
   472  			if err != nil {
   473  				return
   474  			}
   475  			c.Close()
   476  		}
   477  	}
   478  	dss, err := newDualStackServer([]streamListener{
   479  		{network: "tcp", address: "127.0.0.1"},
   480  	})
   481  	if err != nil {
   482  		t.Fatal(err)
   483  	}
   484  	defer dss.teardown()
   485  	if err := dss.buildup(handler); err != nil {
   486  		t.Fatal(err)
   487  	}
   488  
   489  	for i, tt := range testCases {
   490  		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
   491  
   492  		startTime := time.Now()
   493  		c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
   494  		elapsed := time.Now().Sub(startTime)
   495  		if err == nil {
   496  			c.Close()
   497  		} else if tt.dualstack {
   498  			t.Error(err)
   499  		}
   500  		expectMin := tt.expectElapsed - 1*time.Millisecond
   501  		expectMax := tt.expectElapsed + 95*time.Millisecond
   502  		if !(elapsed >= expectMin) {
   503  			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
   504  		}
   505  		if !(elapsed <= expectMax) {
   506  			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
   507  		}
   508  	}
   509  }
   510  
   511  func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
   512  	ln, err := newLocalListener("tcp")
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	defer ln.Close()
   517  
   518  	d := Dialer{}
   519  	ctx := &dialContext{
   520  		Dialer:        d,
   521  		network:       "tcp",
   522  		address:       "?",
   523  		finalDeadline: d.deadline(time.Now()),
   524  	}
   525  
   526  	results := make(chan dialResult)
   527  	cancel := make(chan struct{})
   528  
   529  	// Spawn a connection in the background.
   530  	go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
   531  
   532  	// Receive it at the server.
   533  	c, err := ln.Accept()
   534  	if err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	defer c.Close()
   538  
   539  	// Tell dialSerialAsync that someone else won the race.
   540  	close(cancel)
   541  
   542  	// The connection should close itself, without sending data.
   543  	c.SetReadDeadline(time.Now().Add(1 * time.Second))
   544  	var b [1]byte
   545  	if _, err := c.Read(b[:]); err != io.EOF {
   546  		t.Errorf("got %v; want %v", err, io.EOF)
   547  	}
   548  }
   549  
   550  func TestDialerPartialDeadline(t *testing.T) {
   551  	now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
   552  	var testCases = []struct {
   553  		now            time.Time
   554  		deadline       time.Time
   555  		addrs          int
   556  		expectDeadline time.Time
   557  		expectErr      error
   558  	}{
   559  		// Regular division.
   560  		{now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
   561  		{now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
   562  		{now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
   563  		// Bump against the 2-second sane minimum.
   564  		{now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
   565  		// Total available is now below the sane minimum.
   566  		{now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
   567  		// Null deadline.
   568  		{now, noDeadline, 1, noDeadline, nil},
   569  		// Step the clock forward and cross the deadline.
   570  		{now.Add(-1 * time.Millisecond), now, 1, now, nil},
   571  		{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
   572  		{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
   573  	}
   574  	for i, tt := range testCases {
   575  		deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
   576  		if err != tt.expectErr {
   577  			t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
   578  		}
   579  		if deadline != tt.expectDeadline {
   580  			t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
   581  		}
   582  	}
   583  }
   584  
   585  func TestDialerLocalAddr(t *testing.T) {
   586  	ch := make(chan error, 1)
   587  	handler := func(ls *localServer, ln Listener) {
   588  		c, err := ln.Accept()
   589  		if err != nil {
   590  			ch <- err
   591  			return
   592  		}
   593  		defer c.Close()
   594  		ch <- nil
   595  	}
   596  	ls, err := newLocalServer("tcp")
   597  	if err != nil {
   598  		t.Fatal(err)
   599  	}
   600  	defer ls.teardown()
   601  	if err := ls.buildup(handler); err != nil {
   602  		t.Fatal(err)
   603  	}
   604  
   605  	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
   606  	if err != nil {
   607  		t.Fatal(err)
   608  	}
   609  	laddr.Port = 0
   610  	d := &Dialer{LocalAddr: laddr}
   611  	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
   612  	if err != nil {
   613  		t.Fatal(err)
   614  	}
   615  	defer c.Close()
   616  	c.Read(make([]byte, 1))
   617  	err = <-ch
   618  	if err != nil {
   619  		t.Error(err)
   620  	}
   621  }
   622  
   623  func TestDialerDualStack(t *testing.T) {
   624  	if !supportsIPv4 || !supportsIPv6 {
   625  		t.Skip("both IPv4 and IPv6 are required")
   626  	}
   627  
   628  	closedPortDelay, expectClosedPortDelay := dialClosedPort()
   629  	if closedPortDelay > expectClosedPortDelay {
   630  		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
   631  	}
   632  
   633  	origTestHookLookupIP := testHookLookupIP
   634  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   635  	testHookLookupIP = lookupLocalhost
   636  	handler := func(dss *dualStackServer, ln Listener) {
   637  		for {
   638  			c, err := ln.Accept()
   639  			if err != nil {
   640  				return
   641  			}
   642  			c.Close()
   643  		}
   644  	}
   645  
   646  	var timeout = 150*time.Millisecond + closedPortDelay
   647  	for _, dualstack := range []bool{false, true} {
   648  		dss, err := newDualStackServer([]streamListener{
   649  			{network: "tcp4", address: "127.0.0.1"},
   650  			{network: "tcp6", address: "::1"},
   651  		})
   652  		if err != nil {
   653  			t.Fatal(err)
   654  		}
   655  		defer dss.teardown()
   656  		if err := dss.buildup(handler); err != nil {
   657  			t.Fatal(err)
   658  		}
   659  
   660  		d := &Dialer{DualStack: dualstack, Timeout: timeout}
   661  		for range dss.lns {
   662  			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
   663  			if err != nil {
   664  				t.Error(err)
   665  				continue
   666  			}
   667  			switch addr := c.LocalAddr().(*TCPAddr); {
   668  			case addr.IP.To4() != nil:
   669  				dss.teardownNetwork("tcp4")
   670  			case addr.IP.To16() != nil && addr.IP.To4() == nil:
   671  				dss.teardownNetwork("tcp6")
   672  			}
   673  			c.Close()
   674  		}
   675  	}
   676  	time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
   677  }
   678  
   679  func TestDialerKeepAlive(t *testing.T) {
   680  	handler := func(ls *localServer, ln Listener) {
   681  		for {
   682  			c, err := ln.Accept()
   683  			if err != nil {
   684  				return
   685  			}
   686  			c.Close()
   687  		}
   688  	}
   689  	ls, err := newLocalServer("tcp")
   690  	if err != nil {
   691  		t.Fatal(err)
   692  	}
   693  	defer ls.teardown()
   694  	if err := ls.buildup(handler); err != nil {
   695  		t.Fatal(err)
   696  	}
   697  	defer func() { testHookSetKeepAlive = func() {} }()
   698  
   699  	for _, keepAlive := range []bool{false, true} {
   700  		got := false
   701  		testHookSetKeepAlive = func() { got = true }
   702  		var d Dialer
   703  		if keepAlive {
   704  			d.KeepAlive = 30 * time.Second
   705  		}
   706  		c, err := d.Dial("tcp", ls.Listener.Addr().String())
   707  		if err != nil {
   708  			t.Fatal(err)
   709  		}
   710  		c.Close()
   711  		if got != keepAlive {
   712  			t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
   713  		}
   714  	}
   715  }