...
Run Format

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

View as plain text