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

View as plain text