net: Implement FileListener, FileConn, and File methods for Plan 9

Functions for representing network connections as files
and vice versa, on Plan 9.

Representing network connections as files is not so
straight-forward, because a network connection on Plan 9
is represented by a host of files rather than a single
file descriptor (as is the case on UNIX). We use the
type system to distinguish between listeners and
connections, returning the control file in the former
case and the data file in the latter case.

R=rsc, rminnich, ality, akumar, bradfitz
CC=golang-dev
https://golang.org/cl/7235068
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
index dc5e44c..1690879 100644
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -83,8 +83,29 @@
 	return err
 }
 
+// This method is only called via Conn.
 func (fd *netFD) dup() (*os.File, error) {
-	return nil, syscall.EPLAN9
+	if !fd.ok() || fd.data == nil {
+		return nil, syscall.EINVAL
+	}
+	return fd.file(fd.data, fd.dir+"/data")
+}
+
+func (l *TCPListener) dup() (*os.File, error) {
+	if !l.fd.ok() {
+		return nil, syscall.EINVAL
+	}
+	return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl")
+}
+
+func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
+	syscall.ForkLock.RLock()
+	dfd, err := syscall.Dup(int(f.Fd()), -1)
+	syscall.ForkLock.RUnlock()
+	if err != nil {
+		return nil, &OpError{"dup", s, fd.laddr, err}
+	}
+	return os.NewFile(uintptr(dfd), s), nil
 }
 
 func setDeadline(fd *netFD, t time.Time) error {