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

View as plain text