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

View as plain text