go.net/ipv4: fix flaky test cases
Fixes golang/go#5709.
Fixes golang/go#5811.
LGTM=dave
R=dave
CC=golang-codereviews
https://golang.org/cl/21360043
diff --git a/ipv4/mocktransponder_test.go b/ipv4/mocktransponder_test.go
index 2fc8ad9..9e1ec6d 100644
--- a/ipv4/mocktransponder_test.go
+++ b/ipv4/mocktransponder_test.go
@@ -5,74 +5,10 @@
package ipv4_test
import (
- "code.google.com/p/go.net/ipv4"
"net"
"testing"
- "time"
)
-// writeThenReadPayload transmits IPv4 datagram payloads to the
-// loopback address or interface and captures the loopback'd datagram
-// payloads.
-func writeThenReadPayload(t *testing.T, i int, c *ipv4.PacketConn, wb []byte, dst net.Addr) []byte {
- rb := make([]byte, 1500)
- c.SetTOS(i + 1)
- var ip net.IP
- switch v := dst.(type) {
- case *net.UDPAddr:
- ip = v.IP
- case *net.IPAddr:
- ip = v.IP
- }
- if ip.IsMulticast() {
- c.SetMulticastTTL(i + 1)
- } else {
- c.SetTTL(i + 1)
- }
- c.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if _, err := c.WriteTo(wb, nil, dst); err != nil {
- t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
- }
- n, cm, _, err := c.ReadFrom(rb)
- if err != nil {
- t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
- }
- t.Logf("rcvd cmsg: %v", cm)
- return rb[:n]
-}
-
-// writeThenReadDatagram transmits ICMP for IPv4 datagrams to the
-// loopback address or interface and captures the response datagrams
-// from the protocol stack within the kernel.
-func writeThenReadDatagram(t *testing.T, i int, c *ipv4.RawConn, wb []byte, src, dst net.Addr) []byte {
- rb := make([]byte, ipv4.HeaderLen+len(wb))
- wh := &ipv4.Header{
- Version: ipv4.Version,
- Len: ipv4.HeaderLen,
- TOS: i + 1,
- TotalLen: ipv4.HeaderLen + len(wb),
- TTL: i + 1,
- Protocol: 1,
- }
- if src != nil {
- wh.Src = src.(*net.IPAddr).IP
- }
- if dst != nil {
- wh.Dst = dst.(*net.IPAddr).IP
- }
- c.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if err := c.WriteTo(wh, wb, nil); err != nil {
- t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
- }
- rh, b, cm, err := c.ReadFrom(rb)
- if err != nil {
- t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
- }
- t.Logf("rcvd cmsg: %v", cm.String())
- t.Logf("rcvd hdr: %v", rh.String())
- return b
-}
-
func isUnicast(ip net.IP) bool {
return ip.To4() != nil && (ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsGlobalUnicast())
}
@@ -133,3 +69,14 @@
}
return nil, false
}
+
+func acceptor(t *testing.T, ln net.Listener, done chan<- bool) {
+ defer func() { done <- true }()
+
+ c, err := ln.Accept()
+ if err != nil {
+ t.Errorf("net.Listener.Accept failed: %v", err)
+ return
+ }
+ c.Close()
+}
diff --git a/ipv4/multicast_test.go b/ipv4/multicast_test.go
index a12d242..879780c 100644
--- a/ipv4/multicast_test.go
+++ b/ipv4/multicast_test.go
@@ -2,63 +2,93 @@
// 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"
+ "runtime"
"testing"
+ "time"
)
-func TestReadWriteMulticastIPPayloadUDP(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("to avoid external network")
+func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
}
- c, err := net.ListenPacket("udp4", "224.0.0.0:1024") // see RFC 4727
+ c, err := net.ListenPacket("udp4", "224.0.0.0:0") // see RFC 4727
if err != nil {
t.Fatalf("net.ListenPacket failed: %v", err)
}
defer c.Close()
- ifi := loopbackInterface()
- if ifi == nil {
- t.Skip("an appropriate interface not found")
+ _, port, err := net.SplitHostPort(c.LocalAddr().String())
+ if err != nil {
+ t.Fatalf("net.SplitHostPort failed: %v", err)
}
- dst, err := net.ResolveUDPAddr("udp4", "224.0.0.254:1024") // see RFC 4727
+ dst, err := net.ResolveUDPAddr("udp4", "224.0.0.254:"+port) // see RFC 4727
if err != nil {
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
}
p := ipv4.NewPacketConn(c)
+ defer p.Close()
if err := p.JoinGroup(ifi, dst); err != nil {
t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
}
if err := p.SetMulticastInterface(ifi); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
}
+ if _, err := p.MulticastInterface(); err != nil {
+ t.Fatalf("ipv4.PacketConn.MulticastInterface failed: %v", err)
+ }
if err := p.SetMulticastLoopback(true); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
}
+ if _, err := p.MulticastLoopback(); err != nil {
+ t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
+ }
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
if err := p.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
}
- writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
+ if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetDeadline failed: %v", err)
+ }
+ p.SetMulticastTTL(i + 1)
+ if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), nil, dst); err != nil {
+ t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
+ }
+ b := make([]byte, 128)
+ if _, cm, _, err := p.ReadFrom(b); err != nil {
+ t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ }
}
}
-func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("to avoid external network")
+func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("not supported on %q", runtime.GOOS)
}
if os.Getuid() != 0 {
t.Skip("must be root")
}
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
@@ -66,23 +96,30 @@
}
defer c.Close()
- ifi := loopbackInterface()
- if ifi == nil {
- t.Skip("an appropriate interface not found")
- }
dst, err := net.ResolveIPAddr("ip4", "224.0.0.254") // see RFC 4727
if err != nil {
t.Fatalf("net.ResolveIPAddr failed: %v", err)
}
p := ipv4.NewPacketConn(c)
+ defer p.Close()
if err := p.JoinGroup(ifi, dst); err != nil {
t.Fatalf("ipv4.PacketConn.JoinGroup on %v failed: %v", ifi, err)
}
if err := p.SetMulticastInterface(ifi); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
}
+ if _, err := p.MulticastInterface(); err != nil {
+ t.Fatalf("ipv4.PacketConn.MulticastInterface failed: %v", err)
+ }
+ if err := p.SetMulticastLoopback(true); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
+ }
+ if _, err := p.MulticastLoopback(); err != nil {
+ t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
+ }
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmpMessage{
Type: ipv4.ICMPTypeEcho, Code: 0,
@@ -97,24 +134,43 @@
if err := p.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
}
- rb := writeThenReadPayload(t, i, p, wb, dst)
- m, err := parseICMPMessage(rb)
- if err != nil {
- t.Fatalf("parseICMPMessage failed: %v", err)
+ if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetDeadline failed: %v", err)
}
- if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
- t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ p.SetMulticastTTL(i + 1)
+ if _, err := p.WriteTo(wb, nil, dst); err != nil {
+ t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
+ }
+ b := make([]byte, 128)
+ if n, cm, _, err := p.ReadFrom(b); err != nil {
+ t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ m, err := parseICMPMessage(b[:n])
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ switch {
+ case m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
+ case m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
+ default:
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ }
}
}
}
-func TestReadWriteMulticastIPDatagram(t *testing.T) {
+func TestRawConnReadWriteMulticastICMP(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("to avoid external network")
}
if os.Getuid() != 0 {
t.Skip("must be root")
}
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
@@ -122,10 +178,6 @@
}
defer c.Close()
- ifi := loopbackInterface()
- if ifi == nil {
- t.Skip("an appropriate interface not found")
- }
dst, err := net.ResolveIPAddr("ip4", "224.0.0.254") // see RFC 4727
if err != nil {
t.Fatalf("ResolveIPAddr failed: %v", err)
@@ -135,13 +187,24 @@
if err != nil {
t.Fatalf("ipv4.NewRawConn failed: %v", err)
}
+ defer r.Close()
if err := r.JoinGroup(ifi, dst); err != nil {
t.Fatalf("ipv4.RawConn.JoinGroup on %v failed: %v", ifi, err)
}
if err := r.SetMulticastInterface(ifi); err != nil {
- t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
+ t.Fatalf("ipv4.RawConn.SetMulticastInterface failed: %v", err)
+ }
+ if _, err := r.MulticastInterface(); err != nil {
+ t.Fatalf("ipv4.RawConn.MulticastInterface failed: %v", err)
+ }
+ if err := r.SetMulticastLoopback(true); err != nil {
+ t.Fatalf("ipv4.RawConn.SetMulticastLoopback failed: %v", err)
+ }
+ if _, err := r.MulticastLoopback(); err != nil {
+ t.Fatalf("ipv4.RawConn.MulticastLoopback failed: %v", err)
}
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmpMessage{
Type: ipv4.ICMPTypeEcho, Code: 0,
@@ -153,16 +216,39 @@
if err != nil {
t.Fatalf("icmpMessage.Marshal failed: %v", err)
}
+ wh := &ipv4.Header{
+ Version: ipv4.Version,
+ Len: ipv4.HeaderLen,
+ TOS: i + 1,
+ TotalLen: ipv4.HeaderLen + len(wb),
+ Protocol: 1,
+ Dst: dst.IP,
+ }
if err := r.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
}
- rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
- m, err := parseICMPMessage(rb)
- if err != nil {
- t.Fatalf("parseICMPMessage failed: %v", err)
+ if err := r.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.RawConn.SetDeadline failed: %v", err)
}
- if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
- t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ r.SetMulticastTTL(i + 1)
+ if err := r.WriteTo(wh, wb, nil); err != nil {
+ t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
+ }
+ rb := make([]byte, ipv4.HeaderLen+128)
+ if rh, b, cm, err := r.ReadFrom(rb); err != nil {
+ t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ m, err := parseICMPMessage(b)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ switch {
+ case isUnicast(rh.Dst) && m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
+ case rh.Dst.IsMulticast() && m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
+ default:
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ }
}
}
}
diff --git a/ipv4/multicastsockopt_test.go b/ipv4/multicastsockopt_test.go
index 009364d..c476f34 100644
--- a/ipv4/multicastsockopt_test.go
+++ b/ipv4/multicastsockopt_test.go
@@ -2,8 +2,6 @@
// 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 windows
-
package ipv4_test
import (
@@ -14,8 +12,66 @@
"testing"
)
-type testMulticastConn interface {
- testUnicastConn
+var packetConnMulticastSocketOptionTests = []struct {
+ net, proto, addr string
+ gaddr net.Addr
+}{
+ {"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}}, // see RFC 4727
+ {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}}, // see RFC 4727
+}
+
+func TestPacketConnMulticastSocketOptions(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
+ for _, tt := range packetConnMulticastSocketOptionTests {
+ if tt.net == "ip4" && os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+ c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c.Close()
+
+ testMulticastSocketOptions(t, ipv4.NewPacketConn(c), ifi, tt.gaddr)
+ }
+}
+
+func TestRawConnMulticastSocketOptions(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ if os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
+ 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.NewRawConn failed: %v", err)
+ }
+
+ testMulticastSocketOptions(t, r, ifi, &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}) /// see RFC 4727
+}
+
+type testIPv4MulticastConn interface {
MulticastTTL() (int, error)
SetMulticastTTL(ttl int) error
MulticastLoopback() (bool, error)
@@ -24,103 +80,32 @@
LeaveGroup(*net.Interface, net.Addr) error
}
-type multicastSockoptTest struct {
- tos int
- ttl int
- mcttl int
- mcloop bool
- gaddr net.IP
-}
-
-var multicastSockoptTests = []multicastSockoptTest{
- {DiffServCS0 | NotECNTransport, 127, 128, false, net.IPv4(224, 0, 0, 249)}, // see RFC 4727
- {DiffServAF11 | NotECNTransport, 255, 254, true, net.IPv4(224, 0, 0, 250)}, // see RFC 4727
-}
-
-func TestUDPMulticastSockopt(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("to avoid external network")
- }
-
- for _, tt := range multicastSockoptTests {
- 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)
- testMulticastSockopt(t, tt, p, &net.UDPAddr{IP: tt.gaddr})
- }
-}
-
-func TestIPMulticastSockopt(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("to avoid external network")
- }
- if os.Getuid() != 0 {
- t.Skip("must be root")
- }
-
- for _, tt := range multicastSockoptTests {
- c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
- if err != nil {
- t.Fatalf("net.ListenPacket failed: %v", err)
- }
- defer c.Close()
-
- r, _ := ipv4.NewRawConn(c)
- testMulticastSockopt(t, tt, r, &net.IPAddr{IP: tt.gaddr})
- }
-}
-
-func testMulticastSockopt(t *testing.T, tt multicastSockoptTest, c testMulticastConn, gaddr net.Addr) {
- switch runtime.GOOS {
- case "windows":
- // IP_TOS option is supported on Windows 8 and beyond.
- t.Logf("skipping IP_TOS test on %q", runtime.GOOS)
- default:
- if err := c.SetTOS(tt.tos); err != nil {
- t.Fatalf("ipv4.PacketConn.SetTOS failed: %v", err)
- }
- if v, err := c.TOS(); err != nil {
- t.Fatalf("ipv4.PacketConn.TOS failed: %v", err)
- } else if v != tt.tos {
- t.Fatalf("Got unexpected TOS value %v; expected %v", v, tt.tos)
- }
- }
-
- if err := c.SetTTL(tt.ttl); err != nil {
- t.Fatalf("ipv4.PacketConn.SetTTL failed: %v", err)
- }
- if v, err := c.TTL(); err != nil {
- t.Fatalf("ipv4.PacketConn.TTL failed: %v", err)
- } else if v != tt.ttl {
- t.Fatalf("Got unexpected TTL value %v; expected %v", v, tt.ttl)
- }
-
- if err := c.SetMulticastTTL(tt.mcttl); err != nil {
+func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, gaddr net.Addr) {
+ const ttl = 255
+ if err := c.SetMulticastTTL(ttl); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastTTL failed: %v", err)
}
if v, err := c.MulticastTTL(); err != nil {
t.Fatalf("ipv4.PacketConn.MulticastTTL failed: %v", err)
- } else if v != tt.mcttl {
- t.Fatalf("Got unexpected MulticastTTL value %v; expected %v", v, tt.mcttl)
+ } else if v != ttl {
+ t.Fatalf("got unexpected multicast TTL value %v; expected %v", v, ttl)
}
- if err := c.SetMulticastLoopback(tt.mcloop); err != nil {
- t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
- }
- if v, err := c.MulticastLoopback(); err != nil {
- t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
- } else if v != tt.mcloop {
- t.Fatalf("Got unexpected MulticastLoopback value %v; expected %v", v, tt.mcloop)
+ for _, toggle := range []bool{true, false} {
+ if err := c.SetMulticastLoopback(toggle); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
+ }
+ if v, err := c.MulticastLoopback(); err != nil {
+ t.Fatalf("ipv4.PacketConn.MulticastLoopback failed: %v", err)
+ } else if v != toggle {
+ t.Fatalf("got unexpected multicast loopback %v; expected %v", v, toggle)
+ }
}
- if err := c.JoinGroup(nil, gaddr); err != nil {
- t.Fatalf("ipv4.PacketConn.JoinGroup(%v) failed: %v", gaddr, err)
+ if err := c.JoinGroup(ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.JoinGroup(%v, %v) failed: %v", ifi, gaddr, err)
}
- if err := c.LeaveGroup(nil, gaddr); err != nil {
- t.Fatalf("ipv4.PacketConn.LeaveGroup(%v) failed: %v", gaddr, err)
+ if err := c.LeaveGroup(ifi, gaddr); err != nil {
+ t.Fatalf("ipv4.PacketConn.LeaveGroup(%v, %v) failed: %v", ifi, gaddr, err)
}
}
diff --git a/ipv4/unicast_test.go b/ipv4/unicast_test.go
index 23552ec..9845928 100644
--- a/ipv4/unicast_test.go
+++ b/ipv4/unicast_test.go
@@ -2,15 +2,15 @@
// 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"
+ "runtime"
"testing"
+ "time"
)
func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
@@ -57,6 +57,7 @@
defer c.Close()
p := ipv4.NewPacketConn(c)
+ defer p.Close()
cf := ipv4.FlagTTL | ipv4.FlagInterface
if err := p.SetControlMessage(cf, true); err != nil {
b.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
@@ -83,7 +84,16 @@
}
}
-func TestReadWriteUnicastIPPayloadUDP(t *testing.T) {
+func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
c, err := net.ListenPacket("udp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("net.ListenPacket failed: %v", err)
@@ -95,19 +105,44 @@
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
}
p := ipv4.NewPacketConn(c)
+ defer p.Close()
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
if err := p.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
}
- writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
+ p.SetTTL(i + 1)
+ if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetWriteDeadline failed: %v", err)
+ }
+ if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), nil, dst); err != nil {
+ t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
+ }
+ rb := make([]byte, 128)
+ if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetReadDeadline failed: %v", err)
+ }
+ if _, cm, _, err := p.ReadFrom(rb); err != nil {
+ t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ }
}
}
-func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
+func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
if os.Getuid() != 0 {
t.Skip("must be root")
}
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
@@ -120,7 +155,9 @@
t.Fatalf("ResolveIPAddr failed: %v", err)
}
p := ipv4.NewPacketConn(c)
+ defer p.Close()
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmpMessage{
Type: ipv4.ICMPTypeEcho, Code: 0,
@@ -135,21 +172,49 @@
if err := p.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
}
- rb := writeThenReadPayload(t, i, p, wb, dst)
- m, err := parseICMPMessage(rb)
- if err != nil {
- t.Fatalf("parseICMPMessage failed: %v", err)
+ p.SetTTL(i + 1)
+ if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetWriteDeadline failed: %v", err)
}
- if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
- t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ if _, err := p.WriteTo(wb, nil, dst); err != nil {
+ t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
+ }
+ b := make([]byte, 128)
+ loop:
+ if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetReadDeadline failed: %v", err)
+ }
+ if n, cm, _, err := p.ReadFrom(b); err != nil {
+ t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ m, err := parseICMPMessage(b[:n])
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
+ // On Linux we must handle own sent packets.
+ goto loop
+ }
+ if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ }
}
}
}
-func TestReadWriteUnicastIPDatagram(t *testing.T) {
+func TestRawConnReadWriteUnicastICMP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
if os.Getuid() != 0 {
t.Skip("must be root")
}
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
@@ -165,7 +230,9 @@
if err != nil {
t.Fatalf("ipv4.NewRawConn failed: %v", err)
}
+ defer r.Close()
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmpMessage{
Type: ipv4.ICMPTypeEcho, Code: 0,
@@ -177,16 +244,44 @@
if err != nil {
t.Fatalf("icmpMessage.Marshal failed: %v", err)
}
+ wh := &ipv4.Header{
+ Version: ipv4.Version,
+ Len: ipv4.HeaderLen,
+ TOS: i + 1,
+ TotalLen: ipv4.HeaderLen + len(wb),
+ TTL: i + 1,
+ Protocol: 1,
+ Dst: dst.IP,
+ }
if err := r.SetControlMessage(cf, toggle); err != nil {
t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
}
- rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
- m, err := parseICMPMessage(rb)
- if err != nil {
- t.Fatalf("parseICMPMessage failed: %v", err)
+ if err := r.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.RawConn.SetWriteDeadline failed: %v", err)
}
- if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
- t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ if err := r.WriteTo(wh, wb, nil); err != nil {
+ t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
+ }
+ rb := make([]byte, ipv4.HeaderLen+128)
+ loop:
+ if err := r.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
+ t.Fatalf("ipv4.RawConn.SetReadDeadline failed: %v", err)
+ }
+ if _, b, cm, err := r.ReadFrom(rb); err != nil {
+ t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
+ } else {
+ t.Logf("rcvd cmsg: %v", cm)
+ m, err := parseICMPMessage(b)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
+ // On Linux we must handle own sent packets.
+ goto loop
+ }
+ if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
+ }
}
}
}
diff --git a/ipv4/unicastsockopt_test.go b/ipv4/unicastsockopt_test.go
index 3816ab3..3f415f8 100644
--- a/ipv4/unicastsockopt_test.go
+++ b/ipv4/unicastsockopt_test.go
@@ -2,144 +2,134 @@
// 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 windows
-
package ipv4_test
import (
"code.google.com/p/go.net/ipv4"
- "errors"
"net"
"os"
"runtime"
"testing"
)
-type testUnicastConn interface {
+func TestConnUnicastSocketOptions(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
+ ln, err := net.Listen("tcp4", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("net.Listen failed: %v", err)
+ }
+ defer ln.Close()
+
+ done := make(chan bool)
+ go acceptor(t, ln, done)
+
+ c, err := net.Dial("tcp4", ln.Addr().String())
+ if err != nil {
+ t.Fatalf("net.Dial failed: %v", err)
+ }
+ defer c.Close()
+
+ testUnicastSocketOptions(t, ipv4.NewConn(c))
+
+ <-done
+}
+
+var packetConnUnicastSocketOptionTests = []struct {
+ net, proto, addr string
+}{
+ {"udp4", "", "127.0.0.1:0"},
+ {"ip4", ":icmp", "127.0.0.1"},
+}
+
+func TestPacketConnUnicastSocketOptions(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
+ for _, tt := range packetConnUnicastSocketOptionTests {
+ if tt.net == "ip4" && os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+ c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
+ if err != nil {
+ t.Fatalf("net.ListenPacket(%q, %q) failed: %v", tt.net+tt.proto, tt.addr, err)
+ }
+ defer c.Close()
+
+ testUnicastSocketOptions(t, ipv4.NewPacketConn(c))
+ }
+}
+
+func TestRawConnUnicastSocketOptions(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("not supported on %q", runtime.GOOS)
+ }
+ if os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skipf("not available on %q", runtime.GOOS)
+ }
+
+ c, err := net.ListenPacket("ip4:icmp", "127.0.0.1")
+ if err != nil {
+ t.Fatalf("net.ListenPacket failed: %v", err)
+ }
+ defer c.Close()
+
+ r, err := ipv4.NewRawConn(c)
+ if err != nil {
+ t.Fatalf("ipv4.NewRawConn failed: %v", err)
+ }
+
+ testUnicastSocketOptions(t, r)
+}
+
+type testIPv4UnicastConn interface {
TOS() (int, error)
SetTOS(int) error
TTL() (int, error)
SetTTL(int) error
}
-type unicastSockoptTest struct {
- tos int
- ttl int
-}
-
-var unicastSockoptTests = []unicastSockoptTest{
- {DiffServCS0 | NotECNTransport, 127},
- {DiffServAF11 | NotECNTransport, 255},
-}
-
-func TestTCPUnicastSockopt(t *testing.T) {
- for _, tt := range unicastSockoptTests {
- listener := make(chan net.Listener)
- go tcpListener(t, "127.0.0.1:0", listener)
- ln := <-listener
- if ln == nil {
- return
- }
- defer ln.Close()
- c, err := net.Dial("tcp4", ln.Addr().String())
- if err != nil {
- t.Errorf("net.Dial failed: %v", err)
- return
- }
- defer c.Close()
-
- cc := ipv4.NewConn(c)
- if err := testUnicastSockopt(t, tt, cc); err != nil {
- break
- }
- }
-}
-
-func tcpListener(t *testing.T, addr string, listener chan<- net.Listener) {
- ln, err := net.Listen("tcp4", addr)
- if err != nil {
- t.Errorf("net.Listen failed: %v", err)
- listener <- nil
- return
- }
- listener <- ln
- c, err := ln.Accept()
- if err != nil {
- return
- }
- c.Close()
-}
-
-func TestUDPUnicastSockopt(t *testing.T) {
- for _, tt := range unicastSockoptTests {
- c, err := net.ListenPacket("udp4", "127.0.0.1:0")
- if err != nil {
- t.Errorf("net.ListenPacket failed: %v", err)
- return
- }
- defer c.Close()
-
- p := ipv4.NewPacketConn(c)
- if err := testUnicastSockopt(t, tt, p); err != nil {
- break
- }
- }
-}
-
-func TestIPUnicastSockopt(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("must be root")
- }
-
- for _, tt := range unicastSockoptTests {
- c, err := net.ListenPacket("ip4:icmp", "127.0.0.1")
- if err != nil {
- t.Errorf("net.ListenPacket failed: %v", err)
- return
- }
- defer c.Close()
-
- r, err := ipv4.NewRawConn(c)
- if err != nil {
- t.Errorf("ipv4.NewRawConn failed: %v", err)
- return
- }
- if err := testUnicastSockopt(t, tt, r); err != nil {
- break
- }
- }
-}
-
-func testUnicastSockopt(t *testing.T, tt unicastSockoptTest, c testUnicastConn) error {
+func testUnicastSocketOptions(t *testing.T, c testIPv4UnicastConn) {
+ tos := DiffServCS0 | NotECNTransport
switch runtime.GOOS {
case "windows":
// IP_TOS option is supported on Windows 8 and beyond.
- t.Logf("skipping IP_TOS test on %q", runtime.GOOS)
- default:
- if err := c.SetTOS(tt.tos); err != nil {
- t.Errorf("ipv4.Conn.SetTOS failed: %v", err)
- return err
- }
- if v, err := c.TOS(); err != nil {
- t.Errorf("ipv4.Conn.TOS failed: %v", err)
- return err
- } else if v != tt.tos {
- t.Errorf("Got unexpected TOS value %v; expected %v", v, tt.tos)
- return errors.New("Got unexpected TOS value")
- }
+ t.Skipf("skipping IP_TOS test on %q", runtime.GOOS)
}
- if err := c.SetTTL(tt.ttl); err != nil {
- t.Errorf("ipv4.Conn.SetTTL failed: %v", err)
- return err
+ if err := c.SetTOS(tos); err != nil {
+ t.Fatalf("ipv4.Conn.SetTOS failed: %v", err)
+ }
+ if v, err := c.TOS(); err != nil {
+ t.Fatalf("ipv4.Conn.TOS failed: %v", err)
+ } else if v != tos {
+ t.Fatalf("got unexpected TOS value %v; expected %v", v, tos)
+ }
+ const ttl = 255
+ if err := c.SetTTL(ttl); err != nil {
+ t.Fatalf("ipv4.Conn.SetTTL failed: %v", err)
}
if v, err := c.TTL(); err != nil {
- t.Errorf("ipv4.Conn.TTL failed: %v", err)
- return err
- } else if v != tt.ttl {
- t.Errorf("Got unexpected TTL value %v; expected %v", v, tt.ttl)
- return errors.New("Got unexpected TTL value")
+ t.Fatalf("ipv4.Conn.TTL failed: %v", err)
+ } else if v != ttl {
+ t.Fatalf("got unexpected TTL value %v; expected %v", v, ttl)
}
-
- return nil
}