net: add FileConn, FilePacketConn, FileListener

R=iant, rsc, brainman
CC=golang-dev
https://golang.org/cl/4306042
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
new file mode 100644
index 0000000..1824d04
--- /dev/null
+++ b/src/pkg/net/file_test.go
@@ -0,0 +1,131 @@
+// Copyright 2011 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
+
+import (
+	"os"
+	"reflect"
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+type listenerFile interface {
+	Listener
+	File() (f *os.File, err os.Error)
+}
+
+type packetConnFile interface {
+	PacketConn
+	File() (f *os.File, err os.Error)
+}
+
+type connFile interface {
+	Conn
+	File() (f *os.File, err os.Error)
+}
+
+func testFileListener(t *testing.T, net, laddr string) {
+	if net == "tcp" {
+		laddr += ":0" // any available port
+	}
+	l, err := Listen(net, laddr)
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+	defer l.Close()
+	lf := l.(listenerFile)
+	f, err := lf.File()
+	if err != nil {
+		t.Fatalf("File failed: %v", err)
+	}
+	c, err := FileListener(f)
+	if err != nil {
+		t.Fatalf("FileListener failed: %v", err)
+	}
+	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
+		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
+	}
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func TestFileListener(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		return
+	}
+	testFileListener(t, "tcp", "127.0.0.1")
+	testFileListener(t, "tcp", "127.0.0.1")
+	if kernelSupportsIPv6() {
+		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+		testFileListener(t, "tcp", "127.0.0.1")
+		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+	}
+	if syscall.OS == "linux" {
+		testFileListener(t, "unix", "@gotest/net")
+		testFileListener(t, "unixpacket", "@gotest/net")
+	}
+}
+
+func testFilePacketConn(t *testing.T, pcf packetConnFile) {
+	f, err := pcf.File()
+	if err != nil {
+		t.Fatalf("File failed: %v", err)
+	}
+	c, err := FilePacketConn(f)
+	if err != nil {
+		t.Fatalf("FilePacketConn failed: %v", err)
+	}
+	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
+		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
+	}
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func testFilePacketConnListen(t *testing.T, net, laddr string) {
+	l, err := ListenPacket(net, laddr)
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+	testFilePacketConn(t, l.(packetConnFile))
+	if err := l.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func testFilePacketConnDial(t *testing.T, net, raddr string) {
+	c, err := Dial(net, "", raddr)
+	if err != nil {
+		t.Fatalf("Dial failed: %v", err)
+	}
+	testFilePacketConn(t, c.(packetConnFile))
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func TestFilePacketConn(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		return
+	}
+	testFilePacketConnListen(t, "udp", "127.0.0.1:0")
+	testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
+	if kernelSupportsIPv6() {
+		testFilePacketConnListen(t, "udp", "[::1]:0")
+		testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
+	}
+	if syscall.OS == "linux" {
+		testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+	}
+}