David K. Bainbridge | 215e024 | 2017-09-05 23:18:24 -0700 | [diff] [blame] | 1 | // Copyright 2014 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 nettest provides utilities for network testing. |
| 6 | package nettest // import "golang.org/x/net/internal/nettest" |
| 7 | |
| 8 | import ( |
| 9 | "fmt" |
| 10 | "io/ioutil" |
| 11 | "net" |
| 12 | "os" |
| 13 | "runtime" |
| 14 | ) |
| 15 | |
| 16 | var ( |
| 17 | supportsIPv4 bool |
| 18 | supportsIPv6 bool |
| 19 | ) |
| 20 | |
| 21 | func init() { |
| 22 | if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil { |
| 23 | ln.Close() |
| 24 | supportsIPv4 = true |
| 25 | } |
| 26 | if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil { |
| 27 | ln.Close() |
| 28 | supportsIPv6 = true |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | // SupportsIPv4 reports whether the platform supports IPv4 networking |
| 33 | // functionality. |
| 34 | func SupportsIPv4() bool { return supportsIPv4 } |
| 35 | |
| 36 | // SupportsIPv6 reports whether the platform supports IPv6 networking |
| 37 | // functionality. |
| 38 | func SupportsIPv6() bool { return supportsIPv6 } |
| 39 | |
| 40 | // SupportsRawIPSocket reports whether the platform supports raw IP |
| 41 | // sockets. |
| 42 | func SupportsRawIPSocket() (string, bool) { |
| 43 | return supportsRawIPSocket() |
| 44 | } |
| 45 | |
| 46 | // SupportsIPv6MulticastDeliveryOnLoopback reports whether the |
| 47 | // platform supports IPv6 multicast packet delivery on software |
| 48 | // loopback interface. |
| 49 | func SupportsIPv6MulticastDeliveryOnLoopback() bool { |
| 50 | return supportsIPv6MulticastDeliveryOnLoopback() |
| 51 | } |
| 52 | |
| 53 | // ProtocolNotSupported reports whether err is a protocol not |
| 54 | // supported error. |
| 55 | func ProtocolNotSupported(err error) bool { |
| 56 | return protocolNotSupported(err) |
| 57 | } |
| 58 | |
| 59 | // TestableNetwork reports whether network is testable on the current |
| 60 | // platform configuration. |
| 61 | func TestableNetwork(network string) bool { |
| 62 | // This is based on logic from standard library's |
| 63 | // net/platform_test.go. |
| 64 | switch network { |
| 65 | case "unix", "unixgram": |
| 66 | switch runtime.GOOS { |
| 67 | case "android", "nacl", "plan9", "windows": |
| 68 | return false |
| 69 | } |
| 70 | if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { |
| 71 | return false |
| 72 | } |
| 73 | case "unixpacket": |
| 74 | switch runtime.GOOS { |
| 75 | case "android", "darwin", "freebsd", "nacl", "plan9", "windows": |
| 76 | return false |
| 77 | } |
| 78 | } |
| 79 | return true |
| 80 | } |
| 81 | |
| 82 | // NewLocalListener returns a listener which listens to a loopback IP |
| 83 | // address or local file system path. |
| 84 | // Network must be "tcp", "tcp4", "tcp6", "unix" or "unixpacket". |
| 85 | func NewLocalListener(network string) (net.Listener, error) { |
| 86 | switch network { |
| 87 | case "tcp": |
| 88 | if supportsIPv4 { |
| 89 | if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil { |
| 90 | return ln, nil |
| 91 | } |
| 92 | } |
| 93 | if supportsIPv6 { |
| 94 | return net.Listen("tcp6", "[::1]:0") |
| 95 | } |
| 96 | case "tcp4": |
| 97 | if supportsIPv4 { |
| 98 | return net.Listen("tcp4", "127.0.0.1:0") |
| 99 | } |
| 100 | case "tcp6": |
| 101 | if supportsIPv6 { |
| 102 | return net.Listen("tcp6", "[::1]:0") |
| 103 | } |
| 104 | case "unix", "unixpacket": |
| 105 | return net.Listen(network, localPath()) |
| 106 | } |
| 107 | return nil, fmt.Errorf("%s is not supported", network) |
| 108 | } |
| 109 | |
| 110 | // NewLocalPacketListener returns a packet listener which listens to a |
| 111 | // loopback IP address or local file system path. |
| 112 | // Network must be "udp", "udp4", "udp6" or "unixgram". |
| 113 | func NewLocalPacketListener(network string) (net.PacketConn, error) { |
| 114 | switch network { |
| 115 | case "udp": |
| 116 | if supportsIPv4 { |
| 117 | if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil { |
| 118 | return c, nil |
| 119 | } |
| 120 | } |
| 121 | if supportsIPv6 { |
| 122 | return net.ListenPacket("udp6", "[::1]:0") |
| 123 | } |
| 124 | case "udp4": |
| 125 | if supportsIPv4 { |
| 126 | return net.ListenPacket("udp4", "127.0.0.1:0") |
| 127 | } |
| 128 | case "udp6": |
| 129 | if supportsIPv6 { |
| 130 | return net.ListenPacket("udp6", "[::1]:0") |
| 131 | } |
| 132 | case "unixgram": |
| 133 | return net.ListenPacket(network, localPath()) |
| 134 | } |
| 135 | return nil, fmt.Errorf("%s is not supported", network) |
| 136 | } |
| 137 | |
| 138 | func localPath() string { |
| 139 | f, err := ioutil.TempFile("", "nettest") |
| 140 | if err != nil { |
| 141 | panic(err) |
| 142 | } |
| 143 | path := f.Name() |
| 144 | f.Close() |
| 145 | os.Remove(path) |
| 146 | return path |
| 147 | } |