Source file src/net/dial_test.go

Documentation: net

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

View as plain text