| // Copyright 2011 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // +build !js | 
 |  | 
 | package net | 
 |  | 
 | import ( | 
 | 	"bufio" | 
 | 	"context" | 
 | 	"internal/poll" | 
 | 	"internal/testenv" | 
 | 	"io" | 
 | 	"os" | 
 | 	"runtime" | 
 | 	"sync" | 
 | 	"testing" | 
 | 	"time" | 
 | ) | 
 |  | 
 | var prohibitionaryDialArgTests = []struct { | 
 | 	network string | 
 | 	address string | 
 | }{ | 
 | 	{"tcp6", "127.0.0.1"}, | 
 | 	{"tcp6", "::ffff:127.0.0.1"}, | 
 | } | 
 |  | 
 | func TestProhibitionaryDialArg(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 | 	if !supportsIPv4map() { | 
 | 		t.Skip("mapping ipv4 address inside ipv6 address not supported") | 
 | 	} | 
 |  | 
 | 	ln, err := Listen("tcp", "[::]:0") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer ln.Close() | 
 |  | 
 | 	_, port, err := SplitHostPort(ln.Addr().String()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	for i, tt := range prohibitionaryDialArgTests { | 
 | 		c, err := Dial(tt.network, JoinHostPort(tt.address, port)) | 
 | 		if err == nil { | 
 | 			c.Close() | 
 | 			t.Errorf("#%d: %v", i, err) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialLocal(t *testing.T) { | 
 | 	ln, err := newLocalListener("tcp") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer ln.Close() | 
 | 	_, port, err := SplitHostPort(ln.Addr().String()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	c, err := Dial("tcp", JoinHostPort("", port)) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	c.Close() | 
 | } | 
 |  | 
 | func TestDialerDualStackFDLeak(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("%s does not have full support of socktest", runtime.GOOS) | 
 | 	case "windows": | 
 | 		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) | 
 | 	case "openbsd": | 
 | 		testenv.SkipFlaky(t, 15157) | 
 | 	} | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	before := sw.Sockets() | 
 | 	origTestHookLookupIP := testHookLookupIP | 
 | 	defer func() { testHookLookupIP = origTestHookLookupIP }() | 
 | 	testHookLookupIP = lookupLocalhost | 
 | 	handler := func(dss *dualStackServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 | 	dss, err := newDualStackServer() | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	if err := dss.buildup(handler); err != nil { | 
 | 		dss.teardown() | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	const N = 10 | 
 | 	var wg sync.WaitGroup | 
 | 	wg.Add(N) | 
 | 	d := &Dialer{DualStack: true, Timeout: 5 * time.Second} | 
 | 	for i := 0; i < N; i++ { | 
 | 		go func() { | 
 | 			defer wg.Done() | 
 | 			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		}() | 
 | 	} | 
 | 	wg.Wait() | 
 | 	dss.teardown() | 
 | 	after := sw.Sockets() | 
 | 	if len(after) != len(before) { | 
 | 		t.Errorf("got %d; want %d", len(after), len(before)) | 
 | 	} | 
 | } | 
 |  | 
 | // Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is | 
 | // expected to hang until the timeout elapses. These addresses are reserved | 
 | // for benchmarking by RFC 6890. | 
 | const ( | 
 | 	slowDst4 = "198.18.0.254" | 
 | 	slowDst6 = "2001:2::254" | 
 | ) | 
 |  | 
 | // In some environments, the slow IPs may be explicitly unreachable, and fail | 
 | // more quickly than expected. This test hook prevents dialTCP from returning | 
 | // before the deadline. | 
 | func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) { | 
 | 	sd := &sysDialer{network: network, address: raddr.String()} | 
 | 	c, err := sd.doDialTCP(ctx, laddr, raddr) | 
 | 	if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { | 
 | 		// Wait for the deadline, or indefinitely if none exists. | 
 | 		<-ctx.Done() | 
 | 	} | 
 | 	return c, err | 
 | } | 
 |  | 
 | func dialClosedPort() (actual, expected time.Duration) { | 
 | 	// Estimate the expected time for this platform. | 
 | 	// On Windows, dialing a closed port takes roughly 1 second, | 
 | 	// but other platforms should be instantaneous. | 
 | 	if runtime.GOOS == "windows" { | 
 | 		expected = 1500 * time.Millisecond | 
 | 	} else if runtime.GOOS == "darwin" { | 
 | 		expected = 150 * time.Millisecond | 
 | 	} else { | 
 | 		expected = 95 * time.Millisecond | 
 | 	} | 
 |  | 
 | 	l, err := Listen("tcp", "127.0.0.1:0") | 
 | 	if err != nil { | 
 | 		return 999 * time.Hour, expected | 
 | 	} | 
 | 	addr := l.Addr().String() | 
 | 	l.Close() | 
 | 	// On OpenBSD, interference from TestSelfConnect is mysteriously | 
 | 	// causing the first attempt to hang for a few seconds, so we throw | 
 | 	// away the first result and keep the second. | 
 | 	for i := 1; ; i++ { | 
 | 		startTime := time.Now() | 
 | 		c, err := Dial("tcp", addr) | 
 | 		if err == nil { | 
 | 			c.Close() | 
 | 		} | 
 | 		elapsed := time.Now().Sub(startTime) | 
 | 		if i == 2 { | 
 | 			return elapsed, expected | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialParallel(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	closedPortDelay, expectClosedPortDelay := dialClosedPort() | 
 | 	if closedPortDelay > expectClosedPortDelay { | 
 | 		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) | 
 | 	} | 
 |  | 
 | 	const instant time.Duration = 0 | 
 | 	const fallbackDelay = 200 * time.Millisecond | 
 |  | 
 | 	// Some cases will run quickly when "connection refused" is fast, | 
 | 	// or trigger the fallbackDelay on Windows. This value holds the | 
 | 	// lesser of the two delays. | 
 | 	var closedPortOrFallbackDelay time.Duration | 
 | 	if closedPortDelay < fallbackDelay { | 
 | 		closedPortOrFallbackDelay = closedPortDelay | 
 | 	} else { | 
 | 		closedPortOrFallbackDelay = fallbackDelay | 
 | 	} | 
 |  | 
 | 	origTestHookDialTCP := testHookDialTCP | 
 | 	defer func() { testHookDialTCP = origTestHookDialTCP }() | 
 | 	testHookDialTCP = slowDialTCP | 
 |  | 
 | 	nCopies := func(s string, n int) []string { | 
 | 		out := make([]string, n) | 
 | 		for i := 0; i < n; i++ { | 
 | 			out[i] = s | 
 | 		} | 
 | 		return out | 
 | 	} | 
 |  | 
 | 	var testCases = []struct { | 
 | 		primaries       []string | 
 | 		fallbacks       []string | 
 | 		teardownNetwork string | 
 | 		expectOk        bool | 
 | 		expectElapsed   time.Duration | 
 | 	}{ | 
 | 		// These should just work on the first try. | 
 | 		{[]string{"127.0.0.1"}, []string{}, "", true, instant}, | 
 | 		{[]string{"::1"}, []string{}, "", true, instant}, | 
 | 		{[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant}, | 
 | 		{[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant}, | 
 | 		// Primary is slow; fallback should kick in. | 
 | 		{[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay}, | 
 | 		// Skip a "connection refused" in the primary thread. | 
 | 		{[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay}, | 
 | 		{[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay}, | 
 | 		// Skip a "connection refused" in the fallback thread. | 
 | 		{[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay}, | 
 | 		// Primary refused, fallback without delay. | 
 | 		{[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay}, | 
 | 		{[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay}, | 
 | 		// Everything is refused. | 
 | 		{[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay}, | 
 | 		// Nothing to do; fail instantly. | 
 | 		{[]string{}, []string{}, "", false, instant}, | 
 | 		// Connecting to tons of addresses should not trip the deadline. | 
 | 		{nCopies("::1", 1000), []string{}, "", true, instant}, | 
 | 	} | 
 |  | 
 | 	handler := func(dss *dualStackServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Convert a list of IP strings into TCPAddrs. | 
 | 	makeAddrs := func(ips []string, port string) addrList { | 
 | 		var out addrList | 
 | 		for _, ip := range ips { | 
 | 			addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port)) | 
 | 			if err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			out = append(out, addr) | 
 | 		} | 
 | 		return out | 
 | 	} | 
 |  | 
 | 	for i, tt := range testCases { | 
 | 		dss, err := newDualStackServer() | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer dss.teardown() | 
 | 		if err := dss.buildup(handler); err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if tt.teardownNetwork != "" { | 
 | 			// Destroy one of the listening sockets, creating an unreachable port. | 
 | 			dss.teardownNetwork(tt.teardownNetwork) | 
 | 		} | 
 |  | 
 | 		primaries := makeAddrs(tt.primaries, dss.port) | 
 | 		fallbacks := makeAddrs(tt.fallbacks, dss.port) | 
 | 		d := Dialer{ | 
 | 			FallbackDelay: fallbackDelay, | 
 | 		} | 
 | 		startTime := time.Now() | 
 | 		sd := &sysDialer{ | 
 | 			Dialer:  d, | 
 | 			network: "tcp", | 
 | 			address: "?", | 
 | 		} | 
 | 		c, err := sd.dialParallel(context.Background(), primaries, fallbacks) | 
 | 		elapsed := time.Since(startTime) | 
 |  | 
 | 		if c != nil { | 
 | 			c.Close() | 
 | 		} | 
 |  | 
 | 		if tt.expectOk && err != nil { | 
 | 			t.Errorf("#%d: got %v; want nil", i, err) | 
 | 		} else if !tt.expectOk && err == nil { | 
 | 			t.Errorf("#%d: got nil; want non-nil", i) | 
 | 		} | 
 |  | 
 | 		expectElapsedMin := tt.expectElapsed - 95*time.Millisecond | 
 | 		expectElapsedMax := tt.expectElapsed + 95*time.Millisecond | 
 | 		if elapsed < expectElapsedMin { | 
 | 			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin) | 
 | 		} else if elapsed > expectElapsedMax { | 
 | 			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax) | 
 | 		} | 
 |  | 
 | 		// Repeat each case, ensuring that it can be canceled quickly. | 
 | 		ctx, cancel := context.WithCancel(context.Background()) | 
 | 		var wg sync.WaitGroup | 
 | 		wg.Add(1) | 
 | 		go func() { | 
 | 			time.Sleep(5 * time.Millisecond) | 
 | 			cancel() | 
 | 			wg.Done() | 
 | 		}() | 
 | 		startTime = time.Now() | 
 | 		c, err = sd.dialParallel(ctx, primaries, fallbacks) | 
 | 		if c != nil { | 
 | 			c.Close() | 
 | 		} | 
 | 		elapsed = time.Now().Sub(startTime) | 
 | 		if elapsed > 100*time.Millisecond { | 
 | 			t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed) | 
 | 		} | 
 | 		wg.Wait() | 
 | 	} | 
 | } | 
 |  | 
 | func lookupSlowFast(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { | 
 | 	switch host { | 
 | 	case "slow6loopback4": | 
 | 		// Returns a slow IPv6 address, and a local IPv4 address. | 
 | 		return []IPAddr{ | 
 | 			{IP: ParseIP(slowDst6)}, | 
 | 			{IP: ParseIP("127.0.0.1")}, | 
 | 		}, nil | 
 | 	default: | 
 | 		return fn(ctx, network, host) | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialerFallbackDelay(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	origTestHookLookupIP := testHookLookupIP | 
 | 	defer func() { testHookLookupIP = origTestHookLookupIP }() | 
 | 	testHookLookupIP = lookupSlowFast | 
 |  | 
 | 	origTestHookDialTCP := testHookDialTCP | 
 | 	defer func() { testHookDialTCP = origTestHookDialTCP }() | 
 | 	testHookDialTCP = slowDialTCP | 
 |  | 
 | 	var testCases = []struct { | 
 | 		dualstack     bool | 
 | 		delay         time.Duration | 
 | 		expectElapsed time.Duration | 
 | 	}{ | 
 | 		// Use a very brief delay, which should fallback immediately. | 
 | 		{true, 1 * time.Nanosecond, 0}, | 
 | 		// Use a 200ms explicit timeout. | 
 | 		{true, 200 * time.Millisecond, 200 * time.Millisecond}, | 
 | 		// The default is 300ms. | 
 | 		{true, 0, 300 * time.Millisecond}, | 
 | 	} | 
 |  | 
 | 	handler := func(dss *dualStackServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 | 	dss, err := newDualStackServer() | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer dss.teardown() | 
 | 	if err := dss.buildup(handler); err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	for i, tt := range testCases { | 
 | 		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay} | 
 |  | 
 | 		startTime := time.Now() | 
 | 		c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) | 
 | 		elapsed := time.Now().Sub(startTime) | 
 | 		if err == nil { | 
 | 			c.Close() | 
 | 		} else if tt.dualstack { | 
 | 			t.Error(err) | 
 | 		} | 
 | 		expectMin := tt.expectElapsed - 1*time.Millisecond | 
 | 		expectMax := tt.expectElapsed + 95*time.Millisecond | 
 | 		if elapsed < expectMin { | 
 | 			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin) | 
 | 		} | 
 | 		if elapsed > expectMax { | 
 | 			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialParallelSpuriousConnection(t *testing.T) { | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	var wg sync.WaitGroup | 
 | 	wg.Add(2) | 
 | 	handler := func(dss *dualStackServer, ln Listener) { | 
 | 		// Accept one connection per address. | 
 | 		c, err := ln.Accept() | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		// The client should close itself, without sending data. | 
 | 		c.SetReadDeadline(time.Now().Add(1 * time.Second)) | 
 | 		var b [1]byte | 
 | 		if _, err := c.Read(b[:]); err != io.EOF { | 
 | 			t.Errorf("got %v; want %v", err, io.EOF) | 
 | 		} | 
 | 		c.Close() | 
 | 		wg.Done() | 
 | 	} | 
 | 	dss, err := newDualStackServer() | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer dss.teardown() | 
 | 	if err := dss.buildup(handler); err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	const fallbackDelay = 100 * time.Millisecond | 
 |  | 
 | 	origTestHookDialTCP := testHookDialTCP | 
 | 	defer func() { testHookDialTCP = origTestHookDialTCP }() | 
 | 	testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) { | 
 | 		// Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation. | 
 | 		// This forces dialParallel to juggle two successful connections. | 
 | 		time.Sleep(fallbackDelay * 2) | 
 |  | 
 | 		// Now ignore the provided context (which will be canceled) and use a | 
 | 		// different one to make sure this completes with a valid connection, | 
 | 		// which we hope to be closed below: | 
 | 		sd := &sysDialer{network: net, address: raddr.String()} | 
 | 		return sd.doDialTCP(context.Background(), laddr, raddr) | 
 | 	} | 
 |  | 
 | 	d := Dialer{ | 
 | 		FallbackDelay: fallbackDelay, | 
 | 	} | 
 | 	sd := &sysDialer{ | 
 | 		Dialer:  d, | 
 | 		network: "tcp", | 
 | 		address: "?", | 
 | 	} | 
 |  | 
 | 	makeAddr := func(ip string) addrList { | 
 | 		addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port)) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		return addrList{addr} | 
 | 	} | 
 |  | 
 | 	// dialParallel returns one connection (and closes the other.) | 
 | 	c, err := sd.dialParallel(context.Background(), makeAddr("127.0.0.1"), makeAddr("::1")) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	c.Close() | 
 |  | 
 | 	// The server should've seen both connections. | 
 | 	wg.Wait() | 
 | } | 
 |  | 
 | func TestDialerPartialDeadline(t *testing.T) { | 
 | 	now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) | 
 | 	var testCases = []struct { | 
 | 		now            time.Time | 
 | 		deadline       time.Time | 
 | 		addrs          int | 
 | 		expectDeadline time.Time | 
 | 		expectErr      error | 
 | 	}{ | 
 | 		// Regular division. | 
 | 		{now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, | 
 | 		{now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, | 
 | 		{now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, | 
 | 		// Bump against the 2-second sane minimum. | 
 | 		{now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, | 
 | 		// Total available is now below the sane minimum. | 
 | 		{now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, | 
 | 		// Null deadline. | 
 | 		{now, noDeadline, 1, noDeadline, nil}, | 
 | 		// Step the clock forward and cross the deadline. | 
 | 		{now.Add(-1 * time.Millisecond), now, 1, now, nil}, | 
 | 		{now.Add(0 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout}, | 
 | 		{now.Add(1 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout}, | 
 | 	} | 
 | 	for i, tt := range testCases { | 
 | 		deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) | 
 | 		if err != tt.expectErr { | 
 | 			t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) | 
 | 		} | 
 | 		if !deadline.Equal(tt.expectDeadline) { | 
 | 			t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialerLocalAddr(t *testing.T) { | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	type test struct { | 
 | 		network, raddr string | 
 | 		laddr          Addr | 
 | 		error | 
 | 	} | 
 | 	var tests = []test{ | 
 | 		{"tcp4", "127.0.0.1", nil, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{}, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, | 
 | 		{"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, | 
 | 		{"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, | 
 | 		{"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, | 
 |  | 
 | 		{"tcp6", "::1", nil, nil}, | 
 | 		{"tcp6", "::1", &TCPAddr{}, nil}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, | 
 | 		{"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil}, | 
 | 		{"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, | 
 | 		{"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, | 
 |  | 
 | 		{"tcp", "127.0.0.1", nil, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{}, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, | 
 | 		{"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, | 
 | 		{"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, | 
 | 		{"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, | 
 |  | 
 | 		{"tcp", "::1", nil, nil}, | 
 | 		{"tcp", "::1", &TCPAddr{}, nil}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, | 
 | 		{"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil}, | 
 | 		{"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, | 
 | 		{"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, | 
 | 	} | 
 |  | 
 | 	if supportsIPv4map() { | 
 | 		tests = append(tests, test{ | 
 | 			"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil, | 
 | 		}) | 
 | 	} else { | 
 | 		tests = append(tests, test{ | 
 | 			"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}, | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	origTestHookLookupIP := testHookLookupIP | 
 | 	defer func() { testHookLookupIP = origTestHookLookupIP }() | 
 | 	testHookLookupIP = lookupLocalhost | 
 | 	handler := func(ls *localServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 | 	var err error | 
 | 	var lss [2]*localServer | 
 | 	for i, network := range []string{"tcp4", "tcp6"} { | 
 | 		lss[i], err = newLocalServer(network) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer lss[i].teardown() | 
 | 		if err := lss[i].buildup(handler); err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for _, tt := range tests { | 
 | 		d := &Dialer{LocalAddr: tt.laddr} | 
 | 		var addr string | 
 | 		ip := ParseIP(tt.raddr) | 
 | 		if ip.To4() != nil { | 
 | 			addr = lss[0].Listener.Addr().String() | 
 | 		} | 
 | 		if ip.To16() != nil && ip.To4() == nil { | 
 | 			addr = lss[1].Listener.Addr().String() | 
 | 		} | 
 | 		c, err := d.Dial(tt.network, addr) | 
 | 		if err == nil && tt.error != nil || err != nil && tt.error == nil { | 
 | 			// On Darwin this occasionally times out. | 
 | 			// We don't know why. Issue #22019. | 
 | 			if runtime.GOOS == "darwin" && tt.error == nil && os.IsTimeout(err) { | 
 | 				t.Logf("ignoring timeout error on Darwin; see https://golang.org/issue/22019") | 
 | 			} else { | 
 | 				t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) | 
 | 			} | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseDialError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			continue | 
 | 		} | 
 | 		c.Close() | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialerDualStack(t *testing.T) { | 
 | 	testenv.SkipFlaky(t, 13324) | 
 |  | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	closedPortDelay, expectClosedPortDelay := dialClosedPort() | 
 | 	if closedPortDelay > expectClosedPortDelay { | 
 | 		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) | 
 | 	} | 
 |  | 
 | 	origTestHookLookupIP := testHookLookupIP | 
 | 	defer func() { testHookLookupIP = origTestHookLookupIP }() | 
 | 	testHookLookupIP = lookupLocalhost | 
 | 	handler := func(dss *dualStackServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 |  | 
 | 	var timeout = 150*time.Millisecond + closedPortDelay | 
 | 	for _, dualstack := range []bool{false, true} { | 
 | 		dss, err := newDualStackServer() | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer dss.teardown() | 
 | 		if err := dss.buildup(handler); err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		d := &Dialer{DualStack: dualstack, Timeout: timeout} | 
 | 		for range dss.lns { | 
 | 			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			switch addr := c.LocalAddr().(*TCPAddr); { | 
 | 			case addr.IP.To4() != nil: | 
 | 				dss.teardownNetwork("tcp4") | 
 | 			case addr.IP.To16() != nil && addr.IP.To4() == nil: | 
 | 				dss.teardownNetwork("tcp6") | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialerKeepAlive(t *testing.T) { | 
 | 	handler := func(ls *localServer, ln Listener) { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	} | 
 | 	ls, err := newLocalServer("tcp") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer ls.teardown() | 
 | 	if err := ls.buildup(handler); err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer func() { testHookSetKeepAlive = func(time.Duration) {} }() | 
 |  | 
 | 	tests := []struct { | 
 | 		ka       time.Duration | 
 | 		expected time.Duration | 
 | 	}{ | 
 | 		{-1, -1}, | 
 | 		{0, 15 * time.Second}, | 
 | 		{5 * time.Second, 5 * time.Second}, | 
 | 		{30 * time.Second, 30 * time.Second}, | 
 | 	} | 
 |  | 
 | 	for _, test := range tests { | 
 | 		var got time.Duration = -1 | 
 | 		testHookSetKeepAlive = func(d time.Duration) { got = d } | 
 | 		d := Dialer{KeepAlive: test.ka} | 
 | 		c, err := d.Dial("tcp", ls.Listener.Addr().String()) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		c.Close() | 
 | 		if got != test.expected { | 
 | 			t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestDialCancel(t *testing.T) { | 
 | 	switch testenv.Builder() { | 
 | 	case "linux-arm64-buildlet": | 
 | 		t.Skip("skipping on linux-arm64-buildlet; incompatible network config? issue 15191") | 
 | 	} | 
 | 	mustHaveExternalNetwork(t) | 
 |  | 
 | 	if runtime.GOOS == "nacl" { | 
 | 		// nacl doesn't have external network access. | 
 | 		t.Skipf("skipping on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	blackholeIPPort := JoinHostPort(slowDst4, "1234") | 
 | 	if !supportsIPv4() { | 
 | 		blackholeIPPort = JoinHostPort(slowDst6, "1234") | 
 | 	} | 
 |  | 
 | 	ticker := time.NewTicker(10 * time.Millisecond) | 
 | 	defer ticker.Stop() | 
 |  | 
 | 	const cancelTick = 5 // the timer tick we cancel the dial at | 
 | 	const timeoutTick = 100 | 
 |  | 
 | 	var d Dialer | 
 | 	cancel := make(chan struct{}) | 
 | 	d.Cancel = cancel | 
 | 	errc := make(chan error, 1) | 
 | 	connc := make(chan Conn, 1) | 
 | 	go func() { | 
 | 		if c, err := d.Dial("tcp", blackholeIPPort); err != nil { | 
 | 			errc <- err | 
 | 		} else { | 
 | 			connc <- c | 
 | 		} | 
 | 	}() | 
 | 	ticks := 0 | 
 | 	for { | 
 | 		select { | 
 | 		case <-ticker.C: | 
 | 			ticks++ | 
 | 			if ticks == cancelTick { | 
 | 				close(cancel) | 
 | 			} | 
 | 			if ticks == timeoutTick { | 
 | 				t.Fatal("timeout waiting for dial to fail") | 
 | 			} | 
 | 		case c := <-connc: | 
 | 			c.Close() | 
 | 			t.Fatal("unexpected successful connection") | 
 | 		case err := <-errc: | 
 | 			if perr := parseDialError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			if ticks < cancelTick { | 
 | 				t.Fatalf("dial error after %d ticks (%d before cancel sent): %v", | 
 | 					ticks, cancelTick-ticks, err) | 
 | 			} | 
 | 			if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled { | 
 | 				t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err) | 
 | 			} | 
 | 			return // success. | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestCancelAfterDial(t *testing.T) { | 
 | 	if testing.Short() { | 
 | 		t.Skip("avoiding time.Sleep") | 
 | 	} | 
 |  | 
 | 	ln, err := newLocalListener("tcp") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	var wg sync.WaitGroup | 
 | 	wg.Add(1) | 
 | 	defer func() { | 
 | 		ln.Close() | 
 | 		wg.Wait() | 
 | 	}() | 
 |  | 
 | 	// Echo back the first line of each incoming connection. | 
 | 	go func() { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				break | 
 | 			} | 
 | 			rb := bufio.NewReader(c) | 
 | 			line, err := rb.ReadString('\n') | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				c.Close() | 
 | 				continue | 
 | 			} | 
 | 			if _, err := c.Write([]byte(line)); err != nil { | 
 | 				t.Error(err) | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 		wg.Done() | 
 | 	}() | 
 |  | 
 | 	try := func() { | 
 | 		cancel := make(chan struct{}) | 
 | 		d := &Dialer{Cancel: cancel} | 
 | 		c, err := d.Dial("tcp", ln.Addr().String()) | 
 |  | 
 | 		// Immediately after dialing, request cancelation and sleep. | 
 | 		// Before Issue 15078 was fixed, this would cause subsequent operations | 
 | 		// to fail with an i/o timeout roughly 50% of the time. | 
 | 		close(cancel) | 
 | 		time.Sleep(10 * time.Millisecond) | 
 |  | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer c.Close() | 
 |  | 
 | 		// Send some data to confirm that the connection is still alive. | 
 | 		const message = "echo!\n" | 
 | 		if _, err := c.Write([]byte(message)); err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		// The server should echo the line, and close the connection. | 
 | 		rb := bufio.NewReader(c) | 
 | 		line, err := rb.ReadString('\n') | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if line != message { | 
 | 			t.Errorf("got %q; want %q", line, message) | 
 | 		} | 
 | 		if _, err := rb.ReadByte(); err != io.EOF { | 
 | 			t.Errorf("got %v; want %v", err, io.EOF) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// This bug manifested about 50% of the time, so try it a few times. | 
 | 	for i := 0; i < 10; i++ { | 
 | 		try() | 
 | 	} | 
 | } | 
 |  | 
 | // Issue 18806: it should always be possible to net.Dial a | 
 | // net.Listener().Addr().String when the listen address was ":n", even | 
 | // if the machine has halfway configured IPv6 such that it can bind on | 
 | // "::" not connect back to that same address. | 
 | func TestDialListenerAddr(t *testing.T) { | 
 | 	mustHaveExternalNetwork(t) | 
 | 	ln, err := Listen("tcp", ":0") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer ln.Close() | 
 | 	addr := ln.Addr().String() | 
 | 	c, err := Dial("tcp", addr) | 
 | 	if err != nil { | 
 | 		t.Fatalf("for addr %q, dial error: %v", addr, err) | 
 | 	} | 
 | 	c.Close() | 
 | } | 
 |  | 
 | func TestDialerControl(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "nacl", "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	t.Run("StreamDial", func(t *testing.T) { | 
 | 		for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} { | 
 | 			if !testableNetwork(network) { | 
 | 				continue | 
 | 			} | 
 | 			ln, err := newLocalListener(network) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			defer ln.Close() | 
 | 			d := Dialer{Control: controlOnConnSetup} | 
 | 			c, err := d.Dial(network, ln.Addr().String()) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	}) | 
 | 	t.Run("PacketDial", func(t *testing.T) { | 
 | 		for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} { | 
 | 			if !testableNetwork(network) { | 
 | 				continue | 
 | 			} | 
 | 			c1, err := newLocalPacketListener(network) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			if network == "unixgram" { | 
 | 				defer os.Remove(c1.LocalAddr().String()) | 
 | 			} | 
 | 			defer c1.Close() | 
 | 			d := Dialer{Control: controlOnConnSetup} | 
 | 			c2, err := d.Dial(network, c1.LocalAddr().String()) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			c2.Close() | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | // mustHaveExternalNetwork is like testenv.MustHaveExternalNetwork | 
 | // except that it won't skip testing on non-iOS builders. | 
 | func mustHaveExternalNetwork(t *testing.T) { | 
 | 	t.Helper() | 
 | 	ios := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") | 
 | 	if testenv.Builder() == "" || ios { | 
 | 		testenv.MustHaveExternalNetwork(t) | 
 | 	} | 
 | } |