github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/ipv4/multicastsockopt_test.go (about)

     1  // Copyright 2012 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 ipv4_test
     6  
     7  import (
     8  	"net"
     9  	"runtime"
    10  	"testing"
    11  
    12  	"github.com/Andyfoo/golang/x/net/ipv4"
    13  	"github.com/Andyfoo/golang/x/net/nettest"
    14  )
    15  
    16  var packetConnMulticastSocketOptionTests = []struct {
    17  	net, proto, addr string
    18  	grp, src         net.Addr
    19  }{
    20  	{"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, nil}, // see RFC 4727
    21  	{"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil},  // see RFC 4727
    22  
    23  	{"udp4", "", "232.0.0.0:0", &net.UDPAddr{IP: net.IPv4(232, 0, 1, 249)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771
    24  	{"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}},  // see RFC 5771
    25  }
    26  
    27  func TestPacketConnMulticastSocketOptions(t *testing.T) {
    28  	switch runtime.GOOS {
    29  	case "fuchsia", "hurd", "js", "nacl", "plan9":
    30  		t.Skipf("not supported on %s", runtime.GOOS)
    31  	}
    32  	ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
    33  	if err != nil {
    34  		t.Skipf("not available on %s", runtime.GOOS)
    35  	}
    36  
    37  	ok := nettest.SupportsRawSocket()
    38  	for _, tt := range packetConnMulticastSocketOptionTests {
    39  		if tt.net == "ip4" && !ok {
    40  			t.Logf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
    41  			continue
    42  		}
    43  		c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
    44  		if err != nil {
    45  			t.Fatal(err)
    46  		}
    47  		defer c.Close()
    48  		p := ipv4.NewPacketConn(c)
    49  		defer p.Close()
    50  
    51  		if tt.src == nil {
    52  			testMulticastSocketOptions(t, p, ifi, tt.grp)
    53  		} else {
    54  			testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src)
    55  		}
    56  	}
    57  }
    58  
    59  var rawConnMulticastSocketOptionTests = []struct {
    60  	grp, src net.Addr
    61  }{
    62  	{&net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil}, // see RFC 4727
    63  
    64  	{&net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771
    65  }
    66  
    67  func TestRawConnMulticastSocketOptions(t *testing.T) {
    68  	switch runtime.GOOS {
    69  	case "fuchsia", "hurd", "js", "nacl", "plan9":
    70  		t.Skipf("not supported on %s", runtime.GOOS)
    71  	}
    72  	if !nettest.SupportsRawSocket() {
    73  		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
    74  	}
    75  	ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
    76  	if err != nil {
    77  		t.Skipf("not available on %s", runtime.GOOS)
    78  	}
    79  
    80  	for _, tt := range rawConnMulticastSocketOptionTests {
    81  		c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
    82  		if err != nil {
    83  			t.Fatal(err)
    84  		}
    85  		defer c.Close()
    86  		r, err := ipv4.NewRawConn(c)
    87  		if err != nil {
    88  			t.Fatal(err)
    89  		}
    90  		defer r.Close()
    91  
    92  		if tt.src == nil {
    93  			testMulticastSocketOptions(t, r, ifi, tt.grp)
    94  		} else {
    95  			testSourceSpecificMulticastSocketOptions(t, r, ifi, tt.grp, tt.src)
    96  		}
    97  	}
    98  }
    99  
   100  type testIPv4MulticastConn interface {
   101  	MulticastTTL() (int, error)
   102  	SetMulticastTTL(ttl int) error
   103  	MulticastLoopback() (bool, error)
   104  	SetMulticastLoopback(bool) error
   105  	JoinGroup(*net.Interface, net.Addr) error
   106  	LeaveGroup(*net.Interface, net.Addr) error
   107  	JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
   108  	LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
   109  	ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
   110  	IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
   111  }
   112  
   113  func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp net.Addr) {
   114  	t.Helper()
   115  
   116  	const ttl = 255
   117  	if err := c.SetMulticastTTL(ttl); err != nil {
   118  		t.Error(err)
   119  		return
   120  	}
   121  	if v, err := c.MulticastTTL(); err != nil {
   122  		t.Error(err)
   123  		return
   124  	} else if v != ttl {
   125  		t.Errorf("got %v; want %v", v, ttl)
   126  		return
   127  	}
   128  
   129  	for _, toggle := range []bool{true, false} {
   130  		if err := c.SetMulticastLoopback(toggle); err != nil {
   131  			t.Error(err)
   132  			return
   133  		}
   134  		if v, err := c.MulticastLoopback(); err != nil {
   135  			t.Error(err)
   136  			return
   137  		} else if v != toggle {
   138  			t.Errorf("got %v; want %v", v, toggle)
   139  			return
   140  		}
   141  	}
   142  
   143  	if err := c.JoinGroup(ifi, grp); err != nil {
   144  		t.Error(err)
   145  		return
   146  	}
   147  	if err := c.LeaveGroup(ifi, grp); err != nil {
   148  		t.Error(err)
   149  		return
   150  	}
   151  }
   152  
   153  func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp, src net.Addr) {
   154  	t.Helper()
   155  
   156  	// MCAST_JOIN_GROUP -> MCAST_BLOCK_SOURCE -> MCAST_UNBLOCK_SOURCE -> MCAST_LEAVE_GROUP
   157  	if err := c.JoinGroup(ifi, grp); err != nil {
   158  		t.Error(err)
   159  		return
   160  	}
   161  	if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil {
   162  		switch runtime.GOOS {
   163  		case "freebsd", "linux":
   164  		default: // platforms that don't support IGMPv2/3 fail here
   165  			t.Logf("not supported on %s", runtime.GOOS)
   166  			return
   167  		}
   168  		t.Error(err)
   169  		return
   170  	}
   171  	if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil {
   172  		t.Error(err)
   173  		return
   174  	}
   175  	if err := c.LeaveGroup(ifi, grp); err != nil {
   176  		t.Error(err)
   177  		return
   178  	}
   179  
   180  	// MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_SOURCE_GROUP
   181  	if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
   182  		t.Error(err)
   183  		return
   184  	}
   185  	if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil {
   186  		t.Error(err)
   187  		return
   188  	}
   189  
   190  	// MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_GROUP
   191  	if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
   192  		t.Error(err)
   193  		return
   194  	}
   195  	if err := c.LeaveGroup(ifi, grp); err != nil {
   196  		t.Error(err)
   197  		return
   198  	}
   199  }