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