Home | History | Annotate | Download | only in net
      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 package net
      6 
      7 import (
      8 	"flag"
      9 	"fmt"
     10 	"net/internal/socktest"
     11 	"os"
     12 	"runtime"
     13 	"sort"
     14 	"strings"
     15 	"sync"
     16 	"testing"
     17 )
     18 
     19 var (
     20 	sw socktest.Switch
     21 
     22 	// uninstallTestHooks runs just before a run of benchmarks.
     23 	testHookUninstaller sync.Once
     24 )
     25 
     26 var (
     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 
     46 func 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 
     62 type ipv6LinkLocalUnicastTest struct {
     63 	network, address string
     64 	nameLookup       bool
     65 }
     66 
     67 var (
     68 	ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest
     69 	ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest
     70 )
     71 
     72 func 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 
    156 func 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.
    169 func 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 
    188 func 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 
    200 func 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