2013-03-07 14:51:06 -07:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
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) {
|
|
|
|
switch runtime.GOOS {
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
case "nacl", "plan9":
|
2013-03-07 14:51:06 -07:00
|
|
|
t.Skipf("skipping test on %q", runtime.GOOS)
|
2014-02-24 20:31:01 -07:00
|
|
|
case "solaris":
|
|
|
|
t.Skipf("skipping test on solaris, see issue 7399")
|
2013-03-07 14:51:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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 && !*testExternal {
|
|
|
|
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.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, 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.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, 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) {
|
|
|
|
switch runtime.GOOS {
|
2014-02-24 20:31:01 -07:00
|
|
|
case "plan9":
|
2013-03-07 14:51:06 -07:00
|
|
|
t.Skipf("skipping test on %q", runtime.GOOS)
|
2014-02-24 20:31:01 -07:00
|
|
|
case "solaris":
|
|
|
|
t.Skipf("skipping test on solaris, see issue 7399")
|
2013-03-07 14:51:06 -07:00
|
|
|
}
|
|
|
|
if !supportsIPv6 {
|
|
|
|
t.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
if os.Getuid() != 0 {
|
|
|
|
t.Skip("skipping test; 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.
|
2013-03-12 18:00:01 -06:00
|
|
|
if ifi == nil && (!*testExternal || !*testIPv6) {
|
2013-03-07 14:51:06 -07:00
|
|
|
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.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, 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.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, 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("%q not found in multicast RIB", ip.String())
|
|
|
|
}
|
|
|
|
la := c.LocalAddr()
|
|
|
|
if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
|
|
|
|
return fmt.Errorf("got %v; expected a proper address with non-zero port number", la)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func multicastRIBContains(ip IP) (bool, error) {
|
|
|
|
switch runtime.GOOS {
|
2013-08-23 10:18:22 -06:00
|
|
|
case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
|
2013-03-07 14:51:06 -07:00
|
|
|
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
|
|
|
|
}
|