1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build !js
6// +build !js
7
8package net
9
10import (
11	"flag"
12	"fmt"
13	"net/internal/socktest"
14	"os"
15	"runtime"
16	"sort"
17	"strings"
18	"sync"
19	"testing"
20)
21
22var (
23	sw socktest.Switch
24
25	// uninstallTestHooks runs just before a run of benchmarks.
26	testHookUninstaller sync.Once
27)
28
29var (
30	testTCPBig = flag.Bool("tcpbig", false, "whether to test massive size of data per read or write call on TCP connection")
31
32	testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
33
34	// If external IPv4 connectivity exists, we can try dialing
35	// non-node/interface local scope IPv4 addresses.
36	// On Windows, Lookup APIs may not return IPv4-related
37	// resource records when a node has no external IPv4
38	// connectivity.
39	testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists")
40
41	// If external IPv6 connectivity exists, we can try dialing
42	// non-node/interface local scope IPv6 addresses.
43	// On Windows, Lookup APIs may not return IPv6-related
44	// resource records when a node has no external IPv6
45	// connectivity.
46	testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists")
47)
48
49func TestMain(m *testing.M) {
50	setupTestData()
51	installTestHooks()
52
53	st := m.Run()
54
55	testHookUninstaller.Do(uninstallTestHooks)
56	if testing.Verbose() {
57		printRunningGoroutines()
58		printInflightSockets()
59		printSocketStats()
60	}
61	forceCloseSockets()
62	os.Exit(st)
63}
64
65type ipv6LinkLocalUnicastTest struct {
66	network, address string
67	nameLookup       bool
68}
69
70var (
71	ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest
72	ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest
73)
74
75func setupTestData() {
76	if supportsIPv4() {
77		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
78			{"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
79			{"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
80		}...)
81		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
82			{"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
83			{"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
84		}...)
85		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
86			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
87			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
88		}...)
89	}
90
91	if supportsIPv6() {
92		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil})
93		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil})
94		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
95
96		// Issue 20911: don't return IPv4 addresses for
97		// Resolve*Addr calls of the IPv6 unspecified address.
98		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp", "[::]:4", &TCPAddr{IP: IPv6unspecified, Port: 4}, nil})
99		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp", "[::]:4", &UDPAddr{IP: IPv6unspecified, Port: 4}, nil})
100		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip", "::", &IPAddr{IP: IPv6unspecified}, nil})
101	}
102
103	ifi := loopbackInterface()
104	if ifi != nil {
105		index := fmt.Sprintf("%v", ifi.Index)
106		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
107			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
108			{"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
109		}...)
110		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
111			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
112			{"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
113		}...)
114		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
115			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneCache.name(ifi.Index)}, nil},
116			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
117		}...)
118	}
119
120	addr := ipv6LinkLocalUnicastAddr(ifi)
121	if addr != "" {
122		if runtime.GOOS != "dragonfly" {
123			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
124				{"tcp", "[" + addr + "%" + ifi.Name + "]:0", false},
125			}...)
126			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
127				{"udp", "[" + addr + "%" + ifi.Name + "]:0", false},
128			}...)
129		}
130		ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
131			{"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false},
132		}...)
133		ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
134			{"udp6", "[" + addr + "%" + ifi.Name + "]:0", false},
135		}...)
136		switch runtime.GOOS {
137		case "darwin", "ios", "dragonfly", "freebsd", "openbsd", "netbsd":
138			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
139				{"tcp", "[localhost%" + ifi.Name + "]:0", true},
140				{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
141			}...)
142			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
143				{"udp", "[localhost%" + ifi.Name + "]:0", true},
144				{"udp6", "[localhost%" + ifi.Name + "]:0", true},
145			}...)
146		case "linux":
147			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
148				{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
149				{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
150			}...)
151			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
152				{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
153				{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
154			}...)
155		}
156	}
157}
158
159func printRunningGoroutines() {
160	gss := runningGoroutines()
161	if len(gss) == 0 {
162		return
163	}
164	fmt.Fprintf(os.Stderr, "Running goroutines:\n")
165	for _, gs := range gss {
166		fmt.Fprintf(os.Stderr, "%v\n", gs)
167	}
168	fmt.Fprintf(os.Stderr, "\n")
169}
170
171// runningGoroutines returns a list of remaining goroutines.
172func runningGoroutines() []string {
173	var gss []string
174	b := make([]byte, 2<<20)
175	b = b[:runtime.Stack(b, true)]
176	for _, s := range strings.Split(string(b), "\n\n") {
177		ss := strings.SplitN(s, "\n", 2)
178		if len(ss) != 2 {
179			continue
180		}
181		stack := strings.TrimSpace(ss[1])
182		if !strings.Contains(stack, "created by net") {
183			continue
184		}
185		gss = append(gss, stack)
186	}
187	sort.Strings(gss)
188	return gss
189}
190
191func printInflightSockets() {
192	sos := sw.Sockets()
193	if len(sos) == 0 {
194		return
195	}
196	fmt.Fprintf(os.Stderr, "Inflight sockets:\n")
197	for s, so := range sos {
198		fmt.Fprintf(os.Stderr, "%v: %v\n", s, so)
199	}
200	fmt.Fprintf(os.Stderr, "\n")
201}
202
203func printSocketStats() {
204	sts := sw.Stats()
205	if len(sts) == 0 {
206		return
207	}
208	fmt.Fprintf(os.Stderr, "Socket statistical information:\n")
209	for _, st := range sts {
210		fmt.Fprintf(os.Stderr, "%v\n", st)
211	}
212	fmt.Fprintf(os.Stderr, "\n")
213}
214