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