diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go new file mode 100644 index 0000000000..037ce80505 --- /dev/null +++ b/src/pkg/net/conn_test.go @@ -0,0 +1,103 @@ +// 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. + +package net_test + +import ( + "net" + "os" + "runtime" + "testing" + "time" +) + +var connTests = []struct { + net string + addr string +}{ + {"tcp", "127.0.0.1:0"}, + {"unix", "/tmp/gotest.net"}, + {"unixpacket", "/tmp/gotest.net"}, +} + +func TestConnAndListener(t *testing.T) { + for _, tt := range connTests { + switch tt.net { + case "unix", "unixpacket": + switch runtime.GOOS { + case "plan9", "windows": + continue + } + if tt.net == "unixpacket" && runtime.GOOS != "linux" { + continue + } + os.Remove(tt.addr) + } + + ln, err := net.Listen(tt.net, tt.addr) + if err != nil { + t.Errorf("net.Listen failed: %v", err) + return + } + ln.Addr() + defer ln.Close() + + done := make(chan int) + go transponder(t, ln, done) + + c, err := net.Dial(tt.net, ln.Addr().String()) + if err != nil { + t.Errorf("net.Dial failed: %v", err) + return + } + c.LocalAddr() + c.RemoteAddr() + c.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c.Close() + + if _, err := c.Write([]byte("CONN TEST")); err != nil { + t.Errorf("net.Conn.Write failed: %v", err) + return + } + rb := make([]byte, 128) + if _, err := c.Read(rb); err != nil { + t.Errorf("net.Conn.Read failed: %v", err) + } + + <-done + switch tt.net { + case "unix", "unixpacket": + os.Remove(tt.addr) + } + } +} + +func transponder(t *testing.T, ln net.Listener, done chan<- int) { + defer func() { done <- 1 }() + + c, err := ln.Accept() + if err != nil { + t.Errorf("net.Listener.Accept failed: %v", err) + return + } + c.LocalAddr() + c.RemoteAddr() + c.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c.Close() + + b := make([]byte, 128) + n, err := c.Read(b) + if err != nil { + t.Errorf("net.Conn.Read failed: %v", err) + return + } + if _, err := c.Write(b[:n]); err != nil { + t.Errorf("net.Conn.Write failed: %v", err) + return + } +} diff --git a/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go new file mode 100644 index 0000000000..5075baa609 --- /dev/null +++ b/src/pkg/net/packetconn_test.go @@ -0,0 +1,161 @@ +// 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. + +package net_test + +import ( + "net" + "os" + "runtime" + "strings" + "testing" + "time" +) + +var packetConnTests = []struct { + net string + addr1 string + addr2 string +}{ + {"udp", "127.0.0.1:0", "127.0.0.1:0"}, + {"ip:icmp", "127.0.0.1", "127.0.0.1"}, + {"unixgram", "/tmp/gotest.net1", "/tmp/gotest.net2"}, +} + +func TestPacketConn(t *testing.T) { + for _, tt := range packetConnTests { + var wb []byte + netstr := strings.Split(tt.net, ":") + switch netstr[0] { + case "udp": + wb = []byte("UDP PACKETCONN TEST") + case "ip": + switch runtime.GOOS { + case "plan9": + continue + } + if os.Getuid() != 0 { + continue + } + id := os.Getpid() & 0xffff + wb = newICMPEchoRequest(id, 1, 128, []byte("IP PACKETCONN TEST ")) + case "unixgram": + switch runtime.GOOS { + case "plan9", "windows": + continue + } + os.Remove(tt.addr1) + os.Remove(tt.addr2) + wb = []byte("UNIXGRAM PACKETCONN TEST") + default: + continue + } + + c1, err := net.ListenPacket(tt.net, tt.addr1) + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + c1.LocalAddr() + c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c1.Close() + + c2, err := net.ListenPacket(tt.net, tt.addr2) + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + c2.LocalAddr() + c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c2.Close() + + if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil { + t.Fatalf("net.PacketConn.WriteTo failed: %v", err) + } + rb2 := make([]byte, 128) + if _, _, err := c2.ReadFrom(rb2); err != nil { + t.Fatalf("net.PacketConn.ReadFrom failed: %v", err) + } + if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil { + t.Fatalf("net.PacketConn.WriteTo failed: %v", err) + } + rb1 := make([]byte, 128) + if _, _, err := c1.ReadFrom(rb1); err != nil { + t.Fatalf("net.PacketConn.ReadFrom failed: %v", err) + } + + switch netstr[0] { + case "unixgram": + os.Remove(tt.addr1) + os.Remove(tt.addr2) + } + } +} + +func TestConnAndPacketConn(t *testing.T) { + for _, tt := range packetConnTests { + var wb []byte + netstr := strings.Split(tt.net, ":") + switch netstr[0] { + case "udp": + wb = []byte("UDP PACKETCONN TEST") + case "ip": + switch runtime.GOOS { + case "plan9": + continue + } + if os.Getuid() != 0 { + continue + } + id := os.Getpid() & 0xffff + wb = newICMPEchoRequest(id, 1, 128, []byte("IP PACKETCONN TEST")) + default: + continue + } + + c1, err := net.ListenPacket(tt.net, tt.addr1) + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + c1.LocalAddr() + c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c1.Close() + + c2, err := net.Dial(tt.net, c1.LocalAddr().String()) + if err != nil { + t.Fatalf("net.Dial failed: %v", err) + } + c2.LocalAddr() + c2.RemoteAddr() + c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + defer c2.Close() + + if _, err := c2.Write(wb); err != nil { + t.Fatalf("net.Conn.Write failed: %v", err) + } + rb1 := make([]byte, 128) + if _, _, err := c1.ReadFrom(rb1); err != nil { + t.Fatalf("net.PacetConn.ReadFrom failed: %v", err) + } + var dst net.Addr + if netstr[0] == "ip" { + dst = &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)} + } else { + dst = c2.LocalAddr() + } + if _, err := c1.WriteTo(wb, dst); err != nil { + t.Fatalf("net.PacketConn.WriteTo failed: %v", err) + } + rb2 := make([]byte, 128) + if _, err := c2.Read(rb2); err != nil { + t.Fatalf("net.Conn.Read failed: %v", err) + } + } +} diff --git a/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go new file mode 100644 index 0000000000..5cdceb7721 --- /dev/null +++ b/src/pkg/net/protoconn_test.go @@ -0,0 +1,185 @@ +// 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. + +package net_test + +import ( + "bytes" + "net" + "os" + "runtime" + "testing" + "time" +) + +func TestUDPConnSpecificMethods(t *testing.T) { + la, err := net.ResolveUDPAddr("udp4", "127.0.0.1:0") + if err != nil { + t.Fatalf("net.ResolveUDPAddr failed: %v", err) + } + c, err := net.ListenUDP("udp4", la) + if err != nil { + t.Fatalf("net.ListenUDP failed: %v", err) + } + c.File() + c.LocalAddr() + c.RemoteAddr() + c.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadBuffer(2048) + c.SetWriteBuffer(2048) + defer c.Close() + + wb := []byte("UDPCONN TEST") + if _, err := c.WriteToUDP(wb, c.LocalAddr().(*net.UDPAddr)); err != nil { + t.Fatalf("net.UDPConn.WriteToUDP failed: %v", err) + } + rb := make([]byte, 128) + if _, _, err := c.ReadFromUDP(rb); err != nil { + t.Fatalf("net.UDPConn.ReadFromUDP failed: %v", err) + } +} + +func TestIPConnSpecificMethods(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Logf("skipping read test on %q", runtime.GOOS) + return + } + if os.Getuid() != 0 { + t.Logf("skipping test; must be root") + return + } + + la, err := net.ResolveIPAddr("ip4", "127.0.0.1") + if err != nil { + t.Fatalf("net.ResolveIPAddr failed: %v", err) + } + c, err := net.ListenIP("ip4:icmp", la) + if err != nil { + t.Fatalf("net.ListenIP failed: %v", err) + } + c.File() + c.LocalAddr() + c.RemoteAddr() + c.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c.SetReadBuffer(2048) + c.SetWriteBuffer(2048) + defer c.Close() + + id := os.Getpid() & 0xffff + wb := newICMPEchoRequest(id, 1, 128, []byte("IPCONN TEST ")) + if _, err := c.WriteToIP(wb, c.LocalAddr().(*net.IPAddr)); err != nil { + t.Fatalf("net.IPConn.WriteToIP failed: %v", err) + } + rb := make([]byte, 20+128) + if _, _, err := c.ReadFromIP(rb); err != nil { + t.Fatalf("net.IPConn.ReadFromIP failed: %v", err) + } +} + +// TODO: Find out the use case of ListenUnixgram, I have no idea. +func TestUnixConnSpecificMethods(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Logf("skipping test on %q", runtime.GOOS) + return + } + + p1, p2 := "/tmp/gotest.net1", "/tmp/gotest.net2" + os.Remove(p1) + os.Remove(p2) + + a1, err := net.ResolveUnixAddr("unixgram", p1) + if err != nil { + t.Fatalf("net.ResolveUnixAddr failed: %v", err) + } + c1, err := net.DialUnix("unixgram", a1, nil) + if err != nil { + t.Fatalf("net.DialUnix failed: %v", err) + } + c1.File() + c1.LocalAddr() + c1.RemoteAddr() + c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetReadBuffer(2048) + c1.SetWriteBuffer(2048) + defer c1.Close() + defer os.Remove(p1) + + a2, err := net.ResolveUnixAddr("unixgram", p2) + if err != nil { + t.Fatalf("net.ResolveUnixAddr failed: %v", err) + } + c2, err := net.DialUnix("unixgram", a2, nil) + if err != nil { + t.Fatalf("net.DialUnix failed: %v", err) + } + c2.File() + c2.LocalAddr() + c2.RemoteAddr() + c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetReadBuffer(2048) + c2.SetWriteBuffer(2048) + defer c2.Close() + defer os.Remove(p2) + + wb := []byte("UNIXCONN TEST") + if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil { + t.Fatalf("net.UnixConn.WriteMsgUnix failed: %v", err) + } + rb2 := make([]byte, 128) + if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil { + t.Fatalf("net.UnixConn.ReadMsgUnix failed: %v", err) + } + if _, err := c2.WriteToUnix(wb, a1); err != nil { + t.Fatalf("net.UnixConn.WriteToUnix failed: %v", err) + } + rb1 := make([]byte, 128) + if _, _, err := c1.ReadFromUnix(rb1); err != nil { + t.Fatalf("net.UnixConn.ReadFromUnix failed: %v", err) + } +} + +func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte { + b := newICMPInfoMessage(id, seqnum, msglen, filler) + b[0] = 8 + // calculate ICMP checksum + cklen := len(b) + s := uint32(0) + for i := 0; i < cklen-1; i += 2 { + s += uint32(b[i+1])<<8 | uint32(b[i]) + } + if cklen&1 == 1 { + s += uint32(b[cklen-1]) + } + s = (s >> 16) + (s & 0xffff) + s = s + (s >> 16) + // place checksum back in header; using ^= avoids the + // assumption the checksum bytes are zero + b[2] ^= byte(^s & 0xff) + b[3] ^= byte(^s >> 8) + return b +} + +func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte { + b := make([]byte, msglen) + copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1)) + b[0] = 0 // type + b[1] = 0 // code + b[2] = 0 // checksum + b[3] = 0 // checksum + b[4] = byte(id >> 8) // identifier + b[5] = byte(id & 0xff) // identifier + b[6] = byte(seqnum >> 8) // sequence number + b[7] = byte(seqnum & 0xff) // sequence number + return b +}