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
This commit is contained in:
Mikio Hara
2014-04-27 19:26:58 +09:00
parent fbcd5c9bb3
commit 8ecd624185
5 changed files with 430 additions and 327 deletions

View File

@@ -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 @@ func isMulticastAvailable(ifi *net.Interface) (net.IP, bool) {
}
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()
}

View File

@@ -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 @@ func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
}
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 @@ func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
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 @@ func TestReadWriteMulticastIPDatagram(t *testing.T) {
}
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 @@ func TestReadWriteMulticastIPDatagram(t *testing.T) {
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 @@ func TestReadWriteMulticastIPDatagram(t *testing.T) {
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)
}
}
}
}

View File

@@ -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 @@ import (
"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 @@ type testMulticastConn interface {
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)
}
}

View File

@@ -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 @@ func BenchmarkReadWriteIPv4UDP(b *testing.B) {
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 benchmarkReadWriteIPv4UDP(b *testing.B, p *ipv4.PacketConn, wb, rb []byte,
}
}
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 @@ func TestReadWriteUnicastIPPayloadUDP(t *testing.T) {
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 @@ func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
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 @@ func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
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 @@ func TestReadWriteUnicastIPDatagram(t *testing.T) {
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 @@ func TestReadWriteUnicastIPDatagram(t *testing.T) {
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)
}
}
}
}

View File

@@ -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
}