go.net/ipv4: new package
Package ipv4 implements IP-level socket options for the Internet
Protocol version 4. It also provides raw IP socket access methods
including IPv4 header manipulation.
Fixes golang/go#3684.
Fixes golang/go#3820.
This CL requires CL 6426047;
net: add read, write message methods to IPConn, UDPConn
R=rsc, dave, alex.brainman
CC=gobot, golang-dev
https://golang.org/cl/6482044
diff --git a/ipv4/multicastlistener_test.go b/ipv4/multicastlistener_test.go
new file mode 100644
index 0000000..4199c05
--- /dev/null
+++ b/ipv4/multicastlistener_test.go
@@ -0,0 +1,244 @@
+// Copyright 2012 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 darwin freebsd linux netbsd openbsd
+
+package ipv4_test
+
+import (
+ "code.google.com/p/go.net/ipv4"
+ "net"
+ "os"
+ "testing"
+)
+
+var udpMultipleGroupListenerTests = []struct {
+ gaddr *net.UDPAddr
+}{
+ {&net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}}, // see RFC 4727
+ {&net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)}}, // see RFC 4727
+ {&net.UDPAddr{IP: net.IPv4(224, 0, 0, 254)}}, // see RFC 4727
+}
+
+func TestUDPSingleConnWithMultipleGroupListeners(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+
+ for _, tt := range udpMultipleGroupListenerTests {
+ // listen to a wildcard address with no reusable port
+ c, err := net.ListenPacket("udp4", "0.0.0.0:0")
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c.Close()
+
+ p := ipv4.NewPacketConn(c)
+
+ var mift []*net.Interface
+ ift, err := net.Interfaces()
+ if err != nil {
+ t.Fatalf("net.Interfaces failed: %v", err)
+ }
+ for i, ifi := range ift {
+ if _, ok := isGoodForMulticast(&ifi); !ok {
+ continue
+ }
+ if err := p.JoinGroup(&ifi, tt.gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.JoinGroup %v on %v failed: %v", tt.gaddr, ifi, err)
+ }
+ mift = append(mift, &ift[i])
+ }
+ for _, ifi := range mift {
+ if err := p.LeaveGroup(ifi, tt.gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.LeaveGroup %v on %v failed: %v", tt.gaddr, ifi, err)
+ }
+ }
+ }
+}
+
+func TestUDPMultipleConnWithMultipleGroupListeners(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+
+ for _, tt := range udpMultipleGroupListenerTests {
+ // listen to a group address, actually a wildcard address
+ // with reusable port
+ c1, err := net.ListenPacket("udp4", "224.0.0.0:1024") // see RFC 4727
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c1.Close()
+
+ c2, err := net.ListenPacket("udp4", "224.0.0.0:1024") // see RFC 4727
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c2.Close()
+
+ var ps [2]*ipv4.PacketConn
+ ps[0] = ipv4.NewPacketConn(c1)
+ ps[1] = ipv4.NewPacketConn(c2)
+
+ var mift []*net.Interface
+ ift, err := net.Interfaces()
+ if err != nil {
+ t.Fatalf("net.Interfaces failed: %v", err)
+ }
+ for i, ifi := range ift {
+ if _, ok := isGoodForMulticast(&ifi); !ok {
+ continue
+ }
+ for _, p := range ps {
+ if err := p.JoinGroup(&ifi, tt.gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.JoinGroup %v on %v failed: %v", tt.gaddr, ifi, err)
+ }
+ }
+ mift = append(mift, &ift[i])
+ }
+ for _, ifi := range mift {
+ for _, p := range ps {
+ if err := p.LeaveGroup(ifi, tt.gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.LeaveGroup %v on %v failed: %v", tt.gaddr, ifi, err)
+ }
+ }
+ }
+ }
+}
+
+func TestIPSingleConnWithSingleGroupListener(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ if os.Getuid() != 0 {
+ t.Logf("skipping test; must be root")
+ return
+ }
+
+ // listen to a wildcard address
+ c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c.Close()
+
+ r, err := ipv4.NewRawConn(c)
+ if err != nil {
+ t.Fatalf("ipv4.RawConn failed: %v", err)
+ }
+
+ gaddr := &net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
+ var mift []*net.Interface
+ ift, err := net.Interfaces()
+ if err != nil {
+ t.Fatalf("net.Interfaces failed: %v", err)
+ }
+ for i, ifi := range ift {
+ if _, ok := isGoodForMulticast(&ifi); !ok {
+ continue
+ }
+ if err := r.JoinGroup(&ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
+ }
+ mift = append(mift, &ift[i])
+ }
+ for _, ifi := range mift {
+ if err := r.LeaveGroup(ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.RawConn.LeaveGroup on %v failed: %v", ifi, err)
+ }
+ }
+}
+
+func TestUDPPerInterfaceSingleConnWithSingleGroupListener(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+
+ gaddr := &net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
+ type ml struct {
+ c *ipv4.PacketConn
+ ifi *net.Interface
+ }
+ var mlt []*ml
+
+ ift, err := net.Interfaces()
+ if err != nil {
+ t.Fatalf("net.Interfaces failed: %v", err)
+ }
+ for i, ifi := range ift {
+ ip, ok := isGoodForMulticast(&ifi)
+ if !ok {
+ continue
+ }
+ // listen to a unicast interface address
+ c, err := net.ListenPacket("udp4", ip.String()+":"+"1024") // see RFC 4727
+ if err != nil {
+ t.Fatalf("net.ListenPacket with %v failed: %v", ip, err)
+ }
+ defer c.Close()
+ p := ipv4.NewPacketConn(c)
+ if err := p.JoinGroup(&ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
+ }
+ mlt = append(mlt, &ml{p, &ift[i]})
+ }
+ for _, m := range mlt {
+ if err := m.c.LeaveGroup(m.ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
+ }
+ }
+}
+
+func TestIPPerInterfaceSingleConnWithSingleGroupListener(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ if os.Getuid() != 0 {
+ t.Logf("skipping test; must be root")
+ return
+ }
+
+ gaddr := &net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727
+ type ml struct {
+ c *ipv4.RawConn
+ ifi *net.Interface
+ }
+ var mlt []*ml
+
+ ift, err := net.Interfaces()
+ if err != nil {
+ t.Fatalf("net.Interfaces failed: %v", err)
+ }
+ for i, ifi := range ift {
+ ip, ok := isGoodForMulticast(&ifi)
+ if !ok {
+ continue
+ }
+ // listen to a unicast interface address
+ c, err := net.ListenPacket("ip4:253", ip.String()) // see RFC 4727
+ if err != nil {
+ t.Fatalf("net.ListenPacket with %v failed: %v", ip, err)
+ }
+ defer c.Close()
+ r, err := ipv4.NewRawConn(c)
+ if err != nil {
+ t.Fatalf("ipv4.NewRawConn failed: %v", err)
+ }
+ if err := r.JoinGroup(&ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
+ }
+ mlt = append(mlt, &ml{r, &ift[i]})
+ }
+ for _, m := range mlt {
+ if err := m.c.LeaveGroup(m.ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.RawConn.LeaveGroup on %v failed: %v", m.ifi, err)
+ }
+ }
+}