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