Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/dial_test.go

Documentation: net

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

View as plain text