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