| // Copyright 2011 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // +build !js,!plan9 | 
 |  | 
 | package net | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"fmt" | 
 | 	"internal/testenv" | 
 | 	"os" | 
 | 	"runtime" | 
 | 	"syscall" | 
 | 	"testing" | 
 | 	"time" | 
 | ) | 
 |  | 
 | func (ln *TCPListener) port() string { | 
 | 	_, port, err := SplitHostPort(ln.Addr().String()) | 
 | 	if err != nil { | 
 | 		return "" | 
 | 	} | 
 | 	return port | 
 | } | 
 |  | 
 | func (c *UDPConn) port() string { | 
 | 	_, port, err := SplitHostPort(c.LocalAddr().String()) | 
 | 	if err != nil { | 
 | 		return "" | 
 | 	} | 
 | 	return port | 
 | } | 
 |  | 
 | var tcpListenerTests = []struct { | 
 | 	network string | 
 | 	address string | 
 | }{ | 
 | 	{"tcp", ""}, | 
 | 	{"tcp", "0.0.0.0"}, | 
 | 	{"tcp", "::ffff:0.0.0.0"}, | 
 | 	{"tcp", "::"}, | 
 |  | 
 | 	{"tcp", "127.0.0.1"}, | 
 | 	{"tcp", "::ffff:127.0.0.1"}, | 
 | 	{"tcp", "::1"}, | 
 |  | 
 | 	{"tcp4", ""}, | 
 | 	{"tcp4", "0.0.0.0"}, | 
 | 	{"tcp4", "::ffff:0.0.0.0"}, | 
 |  | 
 | 	{"tcp4", "127.0.0.1"}, | 
 | 	{"tcp4", "::ffff:127.0.0.1"}, | 
 |  | 
 | 	{"tcp6", ""}, | 
 | 	{"tcp6", "::"}, | 
 |  | 
 | 	{"tcp6", "::1"}, | 
 | } | 
 |  | 
 | // TestTCPListener tests both single and double listen to a test | 
 | // listener with same address family, same listening address and | 
 | // same port. | 
 | func TestTCPListener(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	for _, tt := range tcpListenerTests { | 
 | 		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { | 
 | 			t.Logf("skipping %s test", tt.network+" "+tt.address) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		ln1, err := Listen(tt.network, JoinHostPort(tt.address, "0")) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if err := checkFirstListener(tt.network, ln1); err != nil { | 
 | 			ln1.Close() | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		ln2, err := Listen(tt.network, JoinHostPort(tt.address, ln1.(*TCPListener).port())) | 
 | 		if err == nil { | 
 | 			ln2.Close() | 
 | 		} | 
 | 		if err := checkSecondListener(tt.network, tt.address, err); err != nil { | 
 | 			ln1.Close() | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		ln1.Close() | 
 | 	} | 
 | } | 
 |  | 
 | var udpListenerTests = []struct { | 
 | 	network string | 
 | 	address string | 
 | }{ | 
 | 	{"udp", ""}, | 
 | 	{"udp", "0.0.0.0"}, | 
 | 	{"udp", "::ffff:0.0.0.0"}, | 
 | 	{"udp", "::"}, | 
 |  | 
 | 	{"udp", "127.0.0.1"}, | 
 | 	{"udp", "::ffff:127.0.0.1"}, | 
 | 	{"udp", "::1"}, | 
 |  | 
 | 	{"udp4", ""}, | 
 | 	{"udp4", "0.0.0.0"}, | 
 | 	{"udp4", "::ffff:0.0.0.0"}, | 
 |  | 
 | 	{"udp4", "127.0.0.1"}, | 
 | 	{"udp4", "::ffff:127.0.0.1"}, | 
 |  | 
 | 	{"udp6", ""}, | 
 | 	{"udp6", "::"}, | 
 |  | 
 | 	{"udp6", "::1"}, | 
 | } | 
 |  | 
 | // TestUDPListener tests both single and double listen to a test | 
 | // listener with same address family, same listening address and | 
 | // same port. | 
 | func TestUDPListener(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	for _, tt := range udpListenerTests { | 
 | 		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { | 
 | 			t.Logf("skipping %s test", tt.network+" "+tt.address) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		c1, err := ListenPacket(tt.network, JoinHostPort(tt.address, "0")) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if err := checkFirstListener(tt.network, c1); err != nil { | 
 | 			c1.Close() | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		c2, err := ListenPacket(tt.network, JoinHostPort(tt.address, c1.(*UDPConn).port())) | 
 | 		if err == nil { | 
 | 			c2.Close() | 
 | 		} | 
 | 		if err := checkSecondListener(tt.network, tt.address, err); err != nil { | 
 | 			c1.Close() | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		c1.Close() | 
 | 	} | 
 | } | 
 |  | 
 | var dualStackTCPListenerTests = []struct { | 
 | 	network1, address1 string // first listener | 
 | 	network2, address2 string // second listener | 
 | 	xerr               error  // expected error value, nil or other | 
 | }{ | 
 | 	// Test cases and expected results for the attempting 2nd listen on the same port | 
 | 	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd | 
 | 	// ------------------------------------------------------------------------------------ | 
 | 	// "tcp"  ""                 "tcp"  ""                    -        -       -       - | 
 | 	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       - | 
 | 	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       - | 
 | 	// ------------------------------------------------------------------------------------ | 
 | 	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok | 
 | 	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok | 
 | 	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok | 
 | 	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok | 
 | 	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok | 
 | 	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok | 
 | 	// ------------------------------------------------------------------------------------ | 
 | 	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok | 
 | 	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok | 
 | 	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok | 
 | 	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok | 
 | 	// ------------------------------------------------------------------------------------ | 
 | 	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok | 
 | 	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok | 
 | 	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok | 
 | 	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok | 
 | 	// | 
 | 	// Platform default configurations: | 
 | 	// darwin, kernel version 11.3.0 | 
 | 	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option) | 
 | 	// freebsd, kernel version 8.2 | 
 | 	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option) | 
 | 	// linux, kernel version 3.0.0 | 
 | 	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option) | 
 | 	// openbsd, kernel version 5.0 | 
 | 	//	net.inet6.ip6.v6only=1 (overriding is prohibited) | 
 |  | 
 | 	{"tcp", "", "tcp", "", syscall.EADDRINUSE}, | 
 | 	{"tcp", "", "tcp", "0.0.0.0", syscall.EADDRINUSE}, | 
 | 	{"tcp", "0.0.0.0", "tcp", "", syscall.EADDRINUSE}, | 
 |  | 
 | 	{"tcp", "", "tcp", "::", syscall.EADDRINUSE}, | 
 | 	{"tcp", "::", "tcp", "", syscall.EADDRINUSE}, | 
 | 	{"tcp", "0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, | 
 | 	{"tcp", "::", "tcp", "0.0.0.0", syscall.EADDRINUSE}, | 
 | 	{"tcp", "::ffff:0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, | 
 | 	{"tcp", "::", "tcp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, | 
 |  | 
 | 	{"tcp4", "", "tcp6", "", nil}, | 
 | 	{"tcp6", "", "tcp4", "", nil}, | 
 | 	{"tcp4", "0.0.0.0", "tcp6", "::", nil}, | 
 | 	{"tcp6", "::", "tcp4", "0.0.0.0", nil}, | 
 |  | 
 | 	{"tcp", "127.0.0.1", "tcp", "::1", nil}, | 
 | 	{"tcp", "::1", "tcp", "127.0.0.1", nil}, | 
 | 	{"tcp4", "127.0.0.1", "tcp6", "::1", nil}, | 
 | 	{"tcp6", "::1", "tcp4", "127.0.0.1", nil}, | 
 | } | 
 |  | 
 | // TestDualStackTCPListener tests both single and double listen | 
 | // to a test listener with various address families, different | 
 | // listening address and same port. | 
 | // | 
 | // On DragonFly BSD, we expect the kernel version of node under test | 
 | // to be greater than or equal to 4.4. | 
 | func TestDualStackTCPListener(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	for _, tt := range dualStackTCPListenerTests { | 
 | 		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { | 
 | 			t.Logf("skipping %s test", tt.network1+" "+tt.address1) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) { | 
 | 			tt.xerr = nil | 
 | 		} | 
 | 		var firstErr, secondErr error | 
 | 		for i := 0; i < 5; i++ { | 
 | 			lns, err := newDualStackListener() | 
 | 			if err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			port := lns[0].port() | 
 | 			for _, ln := range lns { | 
 | 				ln.Close() | 
 | 			} | 
 | 			var ln1 Listener | 
 | 			ln1, firstErr = Listen(tt.network1, JoinHostPort(tt.address1, port)) | 
 | 			if firstErr != nil { | 
 | 				continue | 
 | 			} | 
 | 			if err := checkFirstListener(tt.network1, ln1); err != nil { | 
 | 				ln1.Close() | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			ln2, err := Listen(tt.network2, JoinHostPort(tt.address2, ln1.(*TCPListener).port())) | 
 | 			if err == nil { | 
 | 				ln2.Close() | 
 | 			} | 
 | 			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { | 
 | 				ln1.Close() | 
 | 				continue | 
 | 			} | 
 | 			ln1.Close() | 
 | 			break | 
 | 		} | 
 | 		if firstErr != nil { | 
 | 			t.Error(firstErr) | 
 | 		} | 
 | 		if secondErr != nil { | 
 | 			t.Error(secondErr) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | var dualStackUDPListenerTests = []struct { | 
 | 	network1, address1 string // first listener | 
 | 	network2, address2 string // second listener | 
 | 	xerr               error  // expected error value, nil or other | 
 | }{ | 
 | 	{"udp", "", "udp", "", syscall.EADDRINUSE}, | 
 | 	{"udp", "", "udp", "0.0.0.0", syscall.EADDRINUSE}, | 
 | 	{"udp", "0.0.0.0", "udp", "", syscall.EADDRINUSE}, | 
 |  | 
 | 	{"udp", "", "udp", "::", syscall.EADDRINUSE}, | 
 | 	{"udp", "::", "udp", "", syscall.EADDRINUSE}, | 
 | 	{"udp", "0.0.0.0", "udp", "::", syscall.EADDRINUSE}, | 
 | 	{"udp", "::", "udp", "0.0.0.0", syscall.EADDRINUSE}, | 
 | 	{"udp", "::ffff:0.0.0.0", "udp", "::", syscall.EADDRINUSE}, | 
 | 	{"udp", "::", "udp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, | 
 |  | 
 | 	{"udp4", "", "udp6", "", nil}, | 
 | 	{"udp6", "", "udp4", "", nil}, | 
 | 	{"udp4", "0.0.0.0", "udp6", "::", nil}, | 
 | 	{"udp6", "::", "udp4", "0.0.0.0", nil}, | 
 |  | 
 | 	{"udp", "127.0.0.1", "udp", "::1", nil}, | 
 | 	{"udp", "::1", "udp", "127.0.0.1", nil}, | 
 | 	{"udp4", "127.0.0.1", "udp6", "::1", nil}, | 
 | 	{"udp6", "::1", "udp4", "127.0.0.1", nil}, | 
 | } | 
 |  | 
 | // TestDualStackUDPListener tests both single and double listen | 
 | // to a test listener with various address families, different | 
 | // listening address and same port. | 
 | // | 
 | // On DragonFly BSD, we expect the kernel version of node under test | 
 | // to be greater than or equal to 4.4. | 
 | func TestDualStackUDPListener(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 | 	if !supportsIPv4() || !supportsIPv6() { | 
 | 		t.Skip("both IPv4 and IPv6 are required") | 
 | 	} | 
 |  | 
 | 	for _, tt := range dualStackUDPListenerTests { | 
 | 		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { | 
 | 			t.Logf("skipping %s test", tt.network1+" "+tt.address1) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) { | 
 | 			tt.xerr = nil | 
 | 		} | 
 | 		var firstErr, secondErr error | 
 | 		for i := 0; i < 5; i++ { | 
 | 			cs, err := newDualStackPacketListener() | 
 | 			if err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			port := cs[0].port() | 
 | 			for _, c := range cs { | 
 | 				c.Close() | 
 | 			} | 
 | 			var c1 PacketConn | 
 | 			c1, firstErr = ListenPacket(tt.network1, JoinHostPort(tt.address1, port)) | 
 | 			if firstErr != nil { | 
 | 				continue | 
 | 			} | 
 | 			if err := checkFirstListener(tt.network1, c1); err != nil { | 
 | 				c1.Close() | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			c2, err := ListenPacket(tt.network2, JoinHostPort(tt.address2, c1.(*UDPConn).port())) | 
 | 			if err == nil { | 
 | 				c2.Close() | 
 | 			} | 
 | 			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { | 
 | 				c1.Close() | 
 | 				continue | 
 | 			} | 
 | 			c1.Close() | 
 | 			break | 
 | 		} | 
 | 		if firstErr != nil { | 
 | 			t.Error(firstErr) | 
 | 		} | 
 | 		if secondErr != nil { | 
 | 			t.Error(secondErr) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func differentWildcardAddr(i, j string) bool { | 
 | 	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") { | 
 | 		return false | 
 | 	} | 
 | 	if i == "[::]" && j == "[::]" { | 
 | 		return false | 
 | 	} | 
 | 	return true | 
 | } | 
 |  | 
 | func checkFirstListener(network string, ln interface{}) error { | 
 | 	switch network { | 
 | 	case "tcp": | 
 | 		fd := ln.(*TCPListener).fd | 
 | 		if err := checkDualStackAddrFamily(fd); err != nil { | 
 | 			return err | 
 | 		} | 
 | 	case "tcp4": | 
 | 		fd := ln.(*TCPListener).fd | 
 | 		if fd.family != syscall.AF_INET { | 
 | 			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) | 
 | 		} | 
 | 	case "tcp6": | 
 | 		fd := ln.(*TCPListener).fd | 
 | 		if fd.family != syscall.AF_INET6 { | 
 | 			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) | 
 | 		} | 
 | 	case "udp": | 
 | 		fd := ln.(*UDPConn).fd | 
 | 		if err := checkDualStackAddrFamily(fd); err != nil { | 
 | 			return err | 
 | 		} | 
 | 	case "udp4": | 
 | 		fd := ln.(*UDPConn).fd | 
 | 		if fd.family != syscall.AF_INET { | 
 | 			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) | 
 | 		} | 
 | 	case "udp6": | 
 | 		fd := ln.(*UDPConn).fd | 
 | 		if fd.family != syscall.AF_INET6 { | 
 | 			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) | 
 | 		} | 
 | 	default: | 
 | 		return UnknownNetworkError(network) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func checkSecondListener(network, address string, err error) error { | 
 | 	switch network { | 
 | 	case "tcp", "tcp4", "tcp6": | 
 | 		if err == nil { | 
 | 			return fmt.Errorf("%s should fail", network+" "+address) | 
 | 		} | 
 | 	case "udp", "udp4", "udp6": | 
 | 		if err == nil { | 
 | 			return fmt.Errorf("%s should fail", network+" "+address) | 
 | 		} | 
 | 	default: | 
 | 		return UnknownNetworkError(network) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func checkDualStackSecondListener(network, address string, err, xerr error) error { | 
 | 	switch network { | 
 | 	case "tcp", "tcp4", "tcp6": | 
 | 		if xerr == nil && err != nil || xerr != nil && err == nil { | 
 | 			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) | 
 | 		} | 
 | 	case "udp", "udp4", "udp6": | 
 | 		if xerr == nil && err != nil || xerr != nil && err == nil { | 
 | 			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) | 
 | 		} | 
 | 	default: | 
 | 		return UnknownNetworkError(network) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func checkDualStackAddrFamily(fd *netFD) error { | 
 | 	switch a := fd.laddr.(type) { | 
 | 	case *TCPAddr: | 
 | 		// If a node under test supports both IPv6 capability | 
 | 		// and IPv6 IPv4-mapping capability, we can assume | 
 | 		// that the node listens on a wildcard address with an | 
 | 		// AF_INET6 socket. | 
 | 		if supportsIPv4map() && fd.laddr.(*TCPAddr).isWildcard() { | 
 | 			if fd.family != syscall.AF_INET6 { | 
 | 				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) | 
 | 			} | 
 | 		} else { | 
 | 			if fd.family != a.family() { | 
 | 				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) | 
 | 			} | 
 | 		} | 
 | 	case *UDPAddr: | 
 | 		// If a node under test supports both IPv6 capability | 
 | 		// and IPv6 IPv4-mapping capability, we can assume | 
 | 		// that the node listens on a wildcard address with an | 
 | 		// AF_INET6 socket. | 
 | 		if supportsIPv4map() && fd.laddr.(*UDPAddr).isWildcard() { | 
 | 			if fd.family != syscall.AF_INET6 { | 
 | 				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) | 
 | 			} | 
 | 		} else { | 
 | 			if fd.family != a.family() { | 
 | 				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) | 
 | 			} | 
 | 		} | 
 | 	default: | 
 | 		return fmt.Errorf("unexpected protocol address type: %T", a) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func TestWildWildcardListener(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	defer func() { | 
 | 		if p := recover(); p != nil { | 
 | 			t.Fatalf("panicked: %v", p) | 
 | 		} | 
 | 	}() | 
 |  | 
 | 	if ln, err := Listen("tcp", ""); err == nil { | 
 | 		ln.Close() | 
 | 	} | 
 | 	if ln, err := ListenPacket("udp", ""); err == nil { | 
 | 		ln.Close() | 
 | 	} | 
 | 	if ln, err := ListenTCP("tcp", nil); err == nil { | 
 | 		ln.Close() | 
 | 	} | 
 | 	if ln, err := ListenUDP("udp", nil); err == nil { | 
 | 		ln.Close() | 
 | 	} | 
 | 	if ln, err := ListenIP("ip:icmp", nil); err == nil { | 
 | 		ln.Close() | 
 | 	} | 
 | } | 
 |  | 
 | var ipv4MulticastListenerTests = []struct { | 
 | 	net   string | 
 | 	gaddr *UDPAddr // see RFC 4727 | 
 | }{ | 
 | 	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, | 
 |  | 
 | 	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, | 
 | } | 
 |  | 
 | // TestIPv4MulticastListener tests both single and double listen to a | 
 | // test listener with same address family, same group address and same | 
 | // port. | 
 | func TestIPv4MulticastListener(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	switch runtime.GOOS { | 
 | 	case "android", "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	case "solaris", "illumos": | 
 | 		t.Skipf("not supported on solaris or illumos, see golang.org/issue/7399") | 
 | 	} | 
 | 	if !supportsIPv4() { | 
 | 		t.Skip("IPv4 is not supported") | 
 | 	} | 
 |  | 
 | 	closer := func(cs []*UDPConn) { | 
 | 		for _, c := range cs { | 
 | 			if c != nil { | 
 | 				c.Close() | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for _, ifi := range []*Interface{loopbackInterface(), nil} { | 
 | 		// Note that multicast interface assignment by system | 
 | 		// is not recommended because it usually relies on | 
 | 		// routing stuff for finding out an appropriate | 
 | 		// nexthop containing both network and link layer | 
 | 		// adjacencies. | 
 | 		if ifi == nil || !*testIPv4 { | 
 | 			continue | 
 | 		} | 
 | 		for _, tt := range ipv4MulticastListenerTests { | 
 | 			var err error | 
 | 			cs := make([]*UDPConn, 2) | 
 | 			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			closer(cs) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | var ipv6MulticastListenerTests = []struct { | 
 | 	net   string | 
 | 	gaddr *UDPAddr // see RFC 4727 | 
 | }{ | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, | 
 | 	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, | 
 |  | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, | 
 | 	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, | 
 | } | 
 |  | 
 | // TestIPv6MulticastListener tests both single and double listen to a | 
 | // test listener with same address family, same group address and same | 
 | // port. | 
 | func TestIPv6MulticastListener(t *testing.T) { | 
 | 	testenv.MustHaveExternalNetwork(t) | 
 |  | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	case "solaris", "illumos": | 
 | 		t.Skipf("not supported on solaris or illumos, see issue 7399") | 
 | 	} | 
 | 	if !supportsIPv6() { | 
 | 		t.Skip("IPv6 is not supported") | 
 | 	} | 
 | 	if os.Getuid() != 0 { | 
 | 		t.Skip("must be root") | 
 | 	} | 
 |  | 
 | 	closer := func(cs []*UDPConn) { | 
 | 		for _, c := range cs { | 
 | 			if c != nil { | 
 | 				c.Close() | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for _, ifi := range []*Interface{loopbackInterface(), nil} { | 
 | 		// Note that multicast interface assignment by system | 
 | 		// is not recommended because it usually relies on | 
 | 		// routing stuff for finding out an appropriate | 
 | 		// nexthop containing both network and link layer | 
 | 		// adjacencies. | 
 | 		if ifi == nil && !*testIPv6 { | 
 | 			continue | 
 | 		} | 
 | 		for _, tt := range ipv6MulticastListenerTests { | 
 | 			var err error | 
 | 			cs := make([]*UDPConn, 2) | 
 | 			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { | 
 | 				closer(cs) | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			closer(cs) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func checkMulticastListener(c *UDPConn, ip IP) error { | 
 | 	if ok, err := multicastRIBContains(ip); err != nil { | 
 | 		return err | 
 | 	} else if !ok { | 
 | 		return fmt.Errorf("%s not found in multicast rib", ip.String()) | 
 | 	} | 
 | 	la := c.LocalAddr() | 
 | 	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 { | 
 | 		return fmt.Errorf("got %v; want a proper address with non-zero port number", la) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func multicastRIBContains(ip IP) (bool, error) { | 
 | 	switch runtime.GOOS { | 
 | 	case "aix", "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "illumos", "windows": | 
 | 		return true, nil // not implemented yet | 
 | 	case "linux": | 
 | 		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" { | 
 | 			return true, nil // not implemented yet | 
 | 		} | 
 | 	} | 
 | 	ift, err := Interfaces() | 
 | 	if err != nil { | 
 | 		return false, err | 
 | 	} | 
 | 	for _, ifi := range ift { | 
 | 		ifmat, err := ifi.MulticastAddrs() | 
 | 		if err != nil { | 
 | 			return false, err | 
 | 		} | 
 | 		for _, ifma := range ifmat { | 
 | 			if ifma.(*IPAddr).IP.Equal(ip) { | 
 | 				return true, nil | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return false, nil | 
 | } | 
 |  | 
 | // Issue 21856. | 
 | func TestClosingListener(t *testing.T) { | 
 | 	ln, err := newLocalListener("tcp") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	addr := ln.Addr() | 
 |  | 
 | 	go func() { | 
 | 		for { | 
 | 			c, err := ln.Accept() | 
 | 			if err != nil { | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		} | 
 | 	}() | 
 |  | 
 | 	// Let the goroutine start. We don't sleep long: if the | 
 | 	// goroutine doesn't start, the test will pass without really | 
 | 	// testing anything, which is OK. | 
 | 	time.Sleep(time.Millisecond) | 
 |  | 
 | 	ln.Close() | 
 |  | 
 | 	ln2, err := Listen("tcp", addr.String()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	ln2.Close() | 
 | } | 
 |  | 
 | func TestListenConfigControl(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	t.Run("StreamListen", func(t *testing.T) { | 
 | 		for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} { | 
 | 			if !testableNetwork(network) { | 
 | 				continue | 
 | 			} | 
 | 			ln, err := newLocalListener(network) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			address := ln.Addr().String() | 
 | 			ln.Close() | 
 | 			lc := ListenConfig{Control: controlOnConnSetup} | 
 | 			ln, err = lc.Listen(context.Background(), network, address) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			ln.Close() | 
 | 		} | 
 | 	}) | 
 | 	t.Run("PacketListen", func(t *testing.T) { | 
 | 		for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} { | 
 | 			if !testableNetwork(network) { | 
 | 				continue | 
 | 			} | 
 | 			c, err := newLocalPacketListener(network) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			address := c.LocalAddr().String() | 
 | 			c.Close() | 
 | 			if network == "unixgram" { | 
 | 				os.Remove(address) | 
 | 			} | 
 | 			lc := ListenConfig{Control: controlOnConnSetup} | 
 | 			c, err = lc.ListenPacket(context.Background(), network, address) | 
 | 			if err != nil { | 
 | 				t.Error(err) | 
 | 				continue | 
 | 			} | 
 | 			c.Close() | 
 | 			if network == "unixgram" { | 
 | 				os.Remove(address) | 
 | 			} | 
 | 		} | 
 | 	}) | 
 | } |