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