From 2ac799cfbcf212675d64ea0df835ca6c2e2aa368 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 8 Mar 2013 06:51:06 +0900 Subject: [PATCH] net: fix multicast listener tests This CL splits multicast listener tests into two; for IPv4 and for IPv6. It also removes redundant test inputs and makes sure that assignment of multicast interface to stablize the tests. Fixes #4059. R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/7565043 --- src/pkg/net/multicast_posix_test.go | 180 --------------------------- src/pkg/net/multicast_test.go | 184 ++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 180 deletions(-) delete mode 100644 src/pkg/net/multicast_posix_test.go create mode 100644 src/pkg/net/multicast_test.go diff --git a/src/pkg/net/multicast_posix_test.go b/src/pkg/net/multicast_posix_test.go deleted file mode 100644 index ff1edaf838c..00000000000 --- a/src/pkg/net/multicast_posix_test.go +++ /dev/null @@ -1,180 +0,0 @@ -// 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 !plan9 - -package net - -import ( - "errors" - "os" - "runtime" - "testing" -) - -var multicastListenerTests = []struct { - net string - gaddr *UDPAddr - flags Flags - ipv6 bool // test with underlying AF_INET6 socket -}{ - // cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers - - {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false}, - {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false}, - {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true}, - - {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false}, - {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false}, - - {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, 0, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, 0, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, 0, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, 0, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, 0, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true}, - {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true}, -} - -// TestMulticastListener tests both single and double listen to a test -// listener with same address family, same group address and same port. -func TestMulticastListener(t *testing.T) { - switch runtime.GOOS { - case "netbsd", "openbsd", "plan9", "solaris", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) - case "linux": - if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" { - t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH) - } - } - - for _, tt := range multicastListenerTests { - if tt.ipv6 && (!*testIPv6 || !supportsIPv6 || os.Getuid() != 0) { - continue - } - ifi, err := availMulticastInterface(t, tt.flags) - if err != nil { - continue - } - c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr) - if err != nil { - t.Fatalf("First ListenMulticastUDP failed: %v", err) - } - checkMulticastListener(t, err, c1, tt.gaddr) - c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr) - if err != nil { - t.Fatalf("Second ListenMulticastUDP failed: %v", err) - } - checkMulticastListener(t, err, c2, tt.gaddr) - c2.Close() - c1.Close() - } -} - -func TestSimpleMulticastListener(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - case "windows": - if testing.Short() || !*testExternal { - t.Skip("skipping test on windows to avoid firewall") - } - } - - for _, tt := range multicastListenerTests { - if tt.ipv6 { - continue - } - tt.flags = FlagUp | FlagMulticast // for windows testing - ifi, err := availMulticastInterface(t, tt.flags) - if err != nil { - continue - } - c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr) - if err != nil { - t.Fatalf("First ListenMulticastUDP failed: %v", err) - } - checkSimpleMulticastListener(t, err, c1, tt.gaddr) - c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr) - if err != nil { - t.Fatalf("Second ListenMulticastUDP failed: %v", err) - } - checkSimpleMulticastListener(t, err, c2, tt.gaddr) - c2.Close() - c1.Close() - } -} - -func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) { - if !multicastRIBContains(t, gaddr.IP) { - t.Errorf("%q not found in RIB", gaddr.String()) - return - } - la := c.LocalAddr() - if la == nil { - t.Error("LocalAddr failed") - return - } - if a, ok := la.(*UDPAddr); !ok || a.Port == 0 { - t.Errorf("got %v; expected a proper address with non-zero port number", la) - return - } -} - -func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) { - la := c.LocalAddr() - if la == nil { - t.Error("LocalAddr failed") - return - } - if a, ok := la.(*UDPAddr); !ok || a.Port == 0 { - t.Errorf("got %v; expected a proper address with non-zero port number", la) - return - } -} - -func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) { - var ifi *Interface - if flags != Flags(0) { - ift, err := Interfaces() - if err != nil { - t.Fatalf("Interfaces failed: %v", err) - } - for _, x := range ift { - if x.Flags&flags == flags { - ifi = &x - break - } - } - if ifi == nil { - return nil, errors.New("an appropriate multicast interface not found") - } - } - return ifi, nil -} - -func multicastRIBContains(t *testing.T, ip IP) bool { - ift, err := Interfaces() - if err != nil { - t.Fatalf("Interfaces failed: %v", err) - } - for _, ifi := range ift { - ifmat, err := ifi.MulticastAddrs() - if err != nil { - t.Fatalf("MulticastAddrs failed: %v", err) - } - for _, ifma := range ifmat { - if ifma.(*IPAddr).IP.Equal(ip) { - return true - } - } - } - return false -} diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go new file mode 100644 index 00000000000..7d2e9c0e34e --- /dev/null +++ b/src/pkg/net/multicast_test.go @@ -0,0 +1,184 @@ +// 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 { + case "plan9": + t.Skipf("skipping test on %q", runtime.GOOS) + } + + 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 { + case "plan9", "solaris", "windows": + t.Skipf("skipping test on %q", runtime.GOOS) + } + 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. + if ifi == nil && !*testExternal { + 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 { + case "netbsd", "openbsd", "plan9", "solaris", "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 +}