Source file src/net/dial_test.go

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

View as plain text