net: consolidate common socket functions for Plan 9

This CL extends changeset 13126:fc4a62e14aba to Plan 9.

R=ality, golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/6820124
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
new file mode 100644
index 0000000..6d7ab38
--- /dev/null
+++ b/src/pkg/net/fd_plan9.go
@@ -0,0 +1,115 @@
+// Copyright 2009 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 (
+	"io"
+	"os"
+	"syscall"
+	"time"
+)
+
+// Network file descritor.
+type netFD struct {
+	proto, name, dir string
+	ctl, data        *os.File
+	laddr, raddr     Addr
+}
+
+var canCancelIO = true // used for testing current package
+
+func sysInit() {
+}
+
+func newFD(proto, name string, ctl *os.File, laddr, raddr Addr) *netFD {
+	return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
+}
+
+func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
+
+func (fd *netFD) Read(b []byte) (n int, err error) {
+	if !fd.ok() {
+		return 0, syscall.EINVAL
+	}
+	if fd.data == nil {
+		fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
+		if err != nil {
+			return 0, err
+		}
+	}
+	n, err = fd.data.Read(b)
+	if fd.proto == "udp" && err == io.EOF {
+		n = 0
+		err = nil
+	}
+	return
+}
+
+func (fd *netFD) Write(b []byte) (n int, err error) {
+	if !fd.ok() {
+		return 0, syscall.EINVAL
+	}
+	if fd.data == nil {
+		fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
+		if err != nil {
+			return 0, err
+		}
+	}
+	return fd.data.Write(b)
+}
+
+func (fd *netFD) CloseRead() error {
+	if !fd.ok() {
+		return syscall.EINVAL
+	}
+	return syscall.EPLAN9
+}
+
+func (fd *netFD) CloseWrite() error {
+	if !fd.ok() {
+		return syscall.EINVAL
+	}
+	return syscall.EPLAN9
+}
+
+func (fd *netFD) Close() error {
+	if !fd.ok() {
+		return syscall.EINVAL
+	}
+	err := fd.ctl.Close()
+	if err != nil {
+		return err
+	}
+	if fd.data != nil {
+		err = fd.data.Close()
+	}
+	fd.ctl = nil
+	fd.data = nil
+	return err
+}
+
+func (fd *netFD) dup() (*os.File, error) {
+	return nil, syscall.EPLAN9
+}
+
+func setDeadline(fd *netFD, t time.Time) error {
+	return syscall.EPLAN9
+}
+
+func setReadDeadline(fd *netFD, t time.Time) error {
+	return syscall.EPLAN9
+}
+
+func setWriteDeadline(fd *netFD, t time.Time) error {
+	return syscall.EPLAN9
+}
+
+func setReadBuffer(fd *netFD, bytes int) error {
+	return syscall.EPLAN9
+}
+
+func setWriteBuffer(fd *netFD, bytes int) error {
+	return syscall.EPLAN9
+}
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index 4111acf..138c3b4 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -8,10 +8,7 @@
 
 import (
 	"errors"
-	"io"
 	"os"
-	"syscall"
-	"time"
 )
 
 // /sys/include/ape/sys/socket.h:/SOMAXCONN
@@ -24,11 +21,6 @@
 	return false, false
 }
 
-var canCancelIO = true // used for testing current package
-
-func sysInit() {
-}
-
 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
 	addr := IPv4zero // address contains port only
@@ -76,120 +68,6 @@
 	return addr, nil
 }
 
-type plan9Conn struct {
-	proto, name, dir string
-	ctl, data        *os.File
-	laddr, raddr     Addr
-}
-
-func newPlan9Conn(proto, name string, ctl *os.File, laddr, raddr Addr) *plan9Conn {
-	return &plan9Conn{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
-}
-
-func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the Conn Read method.
-func (c *plan9Conn) Read(b []byte) (n int, err error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	if c.data == nil {
-		c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
-		if err != nil {
-			return 0, err
-		}
-	}
-	n, err = c.data.Read(b)
-	if c.proto == "udp" && err == io.EOF {
-		n = 0
-		err = nil
-	}
-	return
-}
-
-// Write implements the Conn Write method.
-func (c *plan9Conn) Write(b []byte) (n int, err error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	if c.data == nil {
-		c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
-		if err != nil {
-			return 0, err
-		}
-	}
-	return c.data.Write(b)
-}
-
-// Close closes the connection.
-func (c *plan9Conn) Close() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	err := c.ctl.Close()
-	if err != nil {
-		return err
-	}
-	if c.data != nil {
-		err = c.data.Close()
-	}
-	c.ctl = nil
-	c.data = nil
-	return err
-}
-
-// LocalAddr returns the local network address.
-func (c *plan9Conn) LocalAddr() Addr {
-	if !c.ok() {
-		return nil
-	}
-	return c.laddr
-}
-
-// RemoteAddr returns the remote network address.
-func (c *plan9Conn) RemoteAddr() Addr {
-	if !c.ok() {
-		return nil
-	}
-	return c.raddr
-}
-
-// SetDeadline implements the Conn SetDeadline method.
-func (c *plan9Conn) SetDeadline(t time.Time) error {
-	return syscall.EPLAN9
-}
-
-// SetReadDeadline implements the Conn SetReadDeadline method.
-func (c *plan9Conn) SetReadDeadline(t time.Time) error {
-	return syscall.EPLAN9
-}
-
-// SetWriteDeadline implements the Conn SetWriteDeadline method.
-func (c *plan9Conn) SetWriteDeadline(t time.Time) error {
-	return syscall.EPLAN9
-}
-
-// SetReadBuffer sets the size of the operating system's receive
-// buffer associated with the connection.
-func (c *plan9Conn) SetReadBuffer(bytes int) error {
-	return syscall.EPLAN9
-}
-
-// SetWriteBuffer sets the size of the operating system's transmit
-// buffer associated with the connection.
-func (c *plan9Conn) SetWriteBuffer(bytes int) error {
-	return syscall.EPLAN9
-}
-
-// File returns a copy of the underlying os.File, set to blocking
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *plan9Conn) File() (f *os.File, err error) {
-	return nil, syscall.EPLAN9
-}
-
 func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
 	var (
 		ip   IP
@@ -226,114 +104,72 @@
 	return f, dest, proto, string(buf[:n]), nil
 }
 
-func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err error) {
+func dialPlan9(net string, laddr, raddr Addr) (*netFD, error) {
 	f, dest, proto, name, err := startPlan9(net, raddr)
 	if err != nil {
-		return
+		return nil, err
 	}
 	_, err = f.WriteString("connect " + dest)
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
 	laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
 	raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
-	return newPlan9Conn(proto, name, f, laddr, raddr), nil
+	return newFD(proto, name, f, laddr, raddr), nil
 }
 
-type plan9Listener struct {
-	proto, name, dir string
-	ctl              *os.File
-	laddr            Addr
-}
-
-func listenPlan9(net string, laddr Addr) (l *plan9Listener, err error) {
+func listenPlan9(net string, laddr Addr) (*netFD, error) {
 	f, dest, proto, name, err := startPlan9(net, laddr)
 	if err != nil {
-		return
+		return nil, err
 	}
 	_, err = f.WriteString("announce " + dest)
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
 	laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
-	l = new(plan9Listener)
-	l.proto = proto
-	l.name = name
-	l.dir = "/net/" + proto + "/" + name
-	l.ctl = f
-	l.laddr = laddr
-	return l, nil
+	return &netFD{proto: proto, name: name, dir: "/net/" + proto + "/" + name, ctl: f, laddr: laddr}, nil
 }
 
-func (l *plan9Listener) plan9Conn() *plan9Conn {
-	return newPlan9Conn(l.proto, l.name, l.ctl, l.laddr, nil)
+func (l *netFD) netFD() *netFD {
+	return newFD(l.proto, l.name, l.ctl, l.laddr, nil)
 }
 
-func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err error) {
+func (l *netFD) acceptPlan9() (*netFD, error) {
 	f, err := os.Open(l.dir + "/listen")
 	if err != nil {
-		return
+		return nil, err
 	}
 	var buf [16]byte
 	n, err := f.Read(buf[:])
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
 	name := string(buf[:n])
 	laddr, err := readPlan9Addr(l.proto, l.dir+"/local")
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
 	raddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
 	if err != nil {
 		f.Close()
-		return
+		return nil, err
 	}
-	return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
-}
-
-func (l *plan9Listener) Accept() (c Conn, err error) {
-	c1, err := l.acceptPlan9()
-	if err != nil {
-		return
-	}
-	return c1, nil
-}
-
-func (l *plan9Listener) Close() error {
-	if l == nil || l.ctl == nil {
-		return syscall.EINVAL
-	}
-	return l.ctl.Close()
-}
-
-func (l *plan9Listener) Addr() Addr { return l.laddr }
-
-// SetDeadline sets the deadline associated with the listener.
-// A zero time value disables the deadline.
-func (l *plan9Listener) SetDeadline(t time.Time) error {
-	return syscall.EPLAN9
-}
-
-// File returns a copy of the underlying os.File, set to blocking
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-func (l *plan9Listener) File() (f *os.File, err error) {
-	return nil, syscall.EPLAN9
+	return newFD(l.proto, name, f, laddr, raddr), nil
 }
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 4f0edd4..feb92a2 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -44,6 +44,8 @@
 
 import (
 	"errors"
+	"os"
+	"syscall"
 	"time"
 )
 
@@ -103,6 +105,101 @@
 	SetWriteDeadline(t time.Time) error
 }
 
+type conn struct {
+	fd *netFD
+}
+
+func (c *conn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface.
+
+// Read implements the Conn Read method.
+func (c *conn) Read(b []byte) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	return c.fd.Read(b)
+}
+
+// Write implements the Conn Write method.
+func (c *conn) Write(b []byte) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	return c.fd.Write(b)
+}
+
+// Close closes the connection.
+func (c *conn) Close() error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return c.fd.Close()
+}
+
+// LocalAddr returns the local network address.
+func (c *conn) LocalAddr() Addr {
+	if !c.ok() {
+		return nil
+	}
+	return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (c *conn) RemoteAddr() Addr {
+	if !c.ok() {
+		return nil
+	}
+	return c.fd.raddr
+}
+
+// SetDeadline implements the Conn SetDeadline method.
+func (c *conn) SetDeadline(t time.Time) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return setDeadline(c.fd, t)
+}
+
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *conn) SetReadDeadline(t time.Time) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return setReadDeadline(c.fd, t)
+}
+
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *conn) SetWriteDeadline(t time.Time) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return setWriteDeadline(c.fd, t)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *conn) SetReadBuffer(bytes int) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *conn) SetWriteBuffer(bytes int) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	return setWriteBuffer(c.fd, bytes)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
+
 // An Error represents a network error.
 type Error interface {
 	error
diff --git a/src/pkg/net/net_posix.go b/src/pkg/net/net_posix.go
deleted file mode 100644
index 3bcc54f..0000000
--- a/src/pkg/net/net_posix.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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.
-
-// +build darwin freebsd linux netbsd openbsd windows
-
-// Base posix socket functions.
-
-package net
-
-import (
-	"os"
-	"syscall"
-	"time"
-)
-
-type conn struct {
-	fd *netFD
-}
-
-func (c *conn) ok() bool { return c != nil && c.fd != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the Conn Read method.
-func (c *conn) Read(b []byte) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	return c.fd.Read(b)
-}
-
-// Write implements the Conn Write method.
-func (c *conn) Write(b []byte) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	return c.fd.Write(b)
-}
-
-// LocalAddr returns the local network address.
-func (c *conn) LocalAddr() Addr {
-	if !c.ok() {
-		return nil
-	}
-	return c.fd.laddr
-}
-
-// RemoteAddr returns the remote network address.
-func (c *conn) RemoteAddr() Addr {
-	if !c.ok() {
-		return nil
-	}
-	return c.fd.raddr
-}
-
-// SetDeadline implements the Conn SetDeadline method.
-func (c *conn) SetDeadline(t time.Time) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return setDeadline(c.fd, t)
-}
-
-// SetReadDeadline implements the Conn SetReadDeadline method.
-func (c *conn) SetReadDeadline(t time.Time) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return setReadDeadline(c.fd, t)
-}
-
-// SetWriteDeadline implements the Conn SetWriteDeadline method.
-func (c *conn) SetWriteDeadline(t time.Time) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return setWriteDeadline(c.fd, t)
-}
-
-// SetReadBuffer sets the size of the operating system's
-// receive buffer associated with the connection.
-func (c *conn) SetReadBuffer(bytes int) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return setReadBuffer(c.fd, bytes)
-}
-
-// SetWriteBuffer sets the size of the operating system's
-// transmit buffer associated with the connection.
-func (c *conn) SetWriteBuffer(bytes int) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return setWriteBuffer(c.fd, bytes)
-}
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
-
-// Close closes the connection.
-func (c *conn) Close() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	return c.fd.Close()
-}
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index d4d39e8..cec5bd2 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -7,6 +7,8 @@
 package net
 
 import (
+	"io"
+	"os"
 	"syscall"
 	"time"
 )
@@ -14,7 +16,16 @@
 // TCPConn is an implementation of the Conn interface for TCP network
 // connections.
 type TCPConn struct {
-	plan9Conn
+	conn
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+	return &TCPConn{conn{fd}}
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
+	return 0, syscall.EPLAN9
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -23,7 +34,7 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return syscall.EPLAN9
+	return c.fd.CloseRead()
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -32,6 +43,35 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
+	return c.fd.CloseWrite()
+}
+
+// SetLinger sets the behavior of Close() on a connection which still
+// has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), Close returns immediately and the
+// operating system finishes sending the data in the background.
+//
+// If sec == 0, Close returns immediately and the operating system
+// discards any unsent or unacknowledged data.
+//
+// If sec > 0, Close blocks for at most sec seconds waiting for data
+// to be sent and acknowledged.
+func (c *TCPConn) SetLinger(sec int) error {
+	return syscall.EPLAN9
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) error {
+	return syscall.EPLAN9
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets (Nagle's
+// algorithm).  The default is true (no delay), meaning that data is
+// sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) error {
 	return syscall.EPLAN9
 }
 
@@ -42,7 +82,7 @@
 	return dialTCP(net, laddr, raddr, noDeadline)
 }
 
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (c *TCPConn, err error) {
+func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
 	if !deadline.IsZero() {
 		panic("net.dialTCP: deadline not implemented on Plan 9")
 	}
@@ -54,35 +94,80 @@
 	if raddr == nil {
 		return nil, &OpError{"dial", net, nil, errMissingAddress}
 	}
-	c1, err := dialPlan9(net, laddr, raddr)
+	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
-		return
+		return nil, err
 	}
-	return &TCPConn{*c1}, nil
+	return &TCPConn{conn{fd}}, nil
 }
 
 // TCPListener is a TCP network listener.  Clients should typically
 // use variables of type Listener instead of assuming TCP.
 type TCPListener struct {
-	plan9Listener
+	fd *netFD
 }
 
+// AcceptTCP accepts the next incoming call and returns the new
+// connection and the remote address.
+func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
+	if l == nil || l.fd == nil || l.fd.ctl == nil {
+		return nil, syscall.EINVAL
+	}
+	fd, err := l.fd.acceptPlan9()
+	if err != nil {
+		return nil, err
+	}
+	return newTCPConn(fd), nil
+}
+
+// Accept implements the Accept method in the Listener interface; it
+// waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (Conn, error) {
+	if l == nil || l.fd == nil || l.fd.ctl == nil {
+		return nil, syscall.EINVAL
+	}
+	c, err := l.AcceptTCP()
+	if err != nil {
+		return nil, err
+	}
+	return c, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
 func (l *TCPListener) Close() error {
-	if l == nil || l.ctl == nil {
+	if l == nil || l.fd == nil || l.fd.ctl == nil {
 		return syscall.EINVAL
 	}
-	if _, err := l.ctl.WriteString("hangup"); err != nil {
-		l.ctl.Close()
+	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
+		l.fd.ctl.Close()
 		return err
 	}
-	return l.ctl.Close()
+	return l.fd.ctl.Close()
 }
 
+// Addr returns the listener's network address, a *TCPAddr.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *TCPListener) SetDeadline(t time.Time) error {
+	if l == nil || l.fd == nil || l.fd.ctl == nil {
+		return syscall.EINVAL
+	}
+	return setDeadline(l.fd, t)
+}
+
+// File returns a copy of the underlying os.File, set to blocking
+// mode.  It is the caller's responsibility to close f when finished.
+// Closing l does not affect f, and closing f does not affect l.
+func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
+
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
 // port of 0, it means to listen on some available port.  The caller
 // can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
+func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
@@ -91,9 +176,9 @@
 	if laddr == nil {
 		laddr = &TCPAddr{}
 	}
-	l1, err := listenPlan9(net, laddr)
+	fd, err := listenPlan9(net, laddr)
 	if err != nil {
-		return
+		return nil, err
 	}
-	return &TCPListener{*l1}, nil
+	return &TCPListener{fd}, nil
 }
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index 767a421..6a828e1 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -16,7 +16,7 @@
 // UDPConn is the implementation of the Conn and PacketConn
 // interfaces for UDP network connections.
 type UDPConn struct {
-	plan9Conn
+	conn
 }
 
 // UDP-specific methods.
@@ -32,14 +32,14 @@
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
-	if c.data == nil {
-		c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+	if c.fd.data == nil {
+		c.fd.data, err = os.OpenFile(c.fd.dir+"/data", os.O_RDWR, 0)
 		if err != nil {
 			return 0, nil, err
 		}
 	}
 	buf := make([]byte, udpHeaderSize+len(b))
-	m, err := c.data.Read(buf)
+	m, err := c.fd.data.Read(buf)
 	if err != nil {
 		return
 	}
@@ -81,23 +81,23 @@
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	if c.data == nil {
-		c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+	if c.fd.data == nil {
+		c.fd.data, err = os.OpenFile(c.fd.dir+"/data", os.O_RDWR, 0)
 		if err != nil {
 			return 0, err
 		}
 	}
 	h := new(udpHeader)
 	h.raddr = addr.IP.To16()
-	h.laddr = c.laddr.(*UDPAddr).IP.To16()
+	h.laddr = c.fd.laddr.(*UDPAddr).IP.To16()
 	h.ifcaddr = IPv6zero // ignored (receive only)
 	h.rport = uint16(addr.Port)
-	h.lport = uint16(c.laddr.(*UDPAddr).Port)
+	h.lport = uint16(c.fd.laddr.(*UDPAddr).Port)
 
 	buf := make([]byte, udpHeaderSize+len(b))
 	i := copy(buf, h.Bytes())
 	copy(buf[i:], b)
-	return c.data.Write(buf)
+	return c.fd.data.Write(buf)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -107,7 +107,7 @@
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.dir, addr, syscall.EINVAL}
+		return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
@@ -126,7 +126,7 @@
 	return dialUDP(net, laddr, raddr, noDeadline)
 }
 
-func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (c *UDPConn, err error) {
+func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
 	if !deadline.IsZero() {
 		panic("net.dialUDP: deadline not implemented on Plan 9")
 	}
@@ -138,11 +138,11 @@
 	if raddr == nil {
 		return nil, &OpError{"dial", net, nil, errMissingAddress}
 	}
-	c1, err := dialPlan9(net, laddr, raddr)
+	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
-		return
+		return nil, err
 	}
-	return &UDPConn{*c1}, nil
+	return &UDPConn{conn{fd}}, nil
 }
 
 const udpHeaderSize = 16*3 + 2*2
@@ -177,7 +177,7 @@
 // address laddr.  The returned connection c's ReadFrom and WriteTo
 // methods can be used to receive and send UDP packets with per-packet
 // addressing.
-func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
+func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
@@ -188,13 +188,13 @@
 	}
 	l, err := listenPlan9(net, laddr)
 	if err != nil {
-		return
+		return nil, err
 	}
 	_, err = l.ctl.WriteString("headers")
 	if err != nil {
-		return
+		return nil, err
 	}
-	return &UDPConn{*l.plan9Conn()}, nil
+	return &UDPConn{conn{l.netFD()}}, nil
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets