diff --git a/src/net/unixsock.go b/src/net/unixsock.go index 1945774641..d1eb0b62ee 100644 --- a/src/net/unixsock.go +++ b/src/net/unixsock.go @@ -4,6 +4,12 @@ package net +import ( + "os" + "syscall" + "time" +) + // UnixAddr represents the address of a Unix domain socket end point. type UnixAddr struct { Name string @@ -45,3 +51,268 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, error) { return nil, UnknownNetworkError(net) } } + +// UnixConn is an implementation of the Conn interface for connections +// to Unix domain sockets. +type UnixConn struct { + conn +} + +// CloseRead shuts down the reading side of the Unix domain connection. +// Most callers should just use Close. +func (c *UnixConn) CloseRead() error { + if !c.ok() { + return syscall.EINVAL + } + if err := c.fd.closeRead(); err != nil { + return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil +} + +// CloseWrite shuts down the writing side of the Unix domain connection. +// Most callers should just use Close. +func (c *UnixConn) CloseWrite() error { + if !c.ok() { + return syscall.EINVAL + } + if err := c.fd.closeWrite(); err != nil { + return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil +} + +// ReadFromUnix reads a packet from c, copying the payload into b. It +// returns the number of bytes copied into b and the source address of +// the packet. +// +// ReadFromUnix can be made to time out and return an error with +// Timeout() == true after a fixed time limit; see SetDeadline and +// SetReadDeadline. +func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { + if !c.ok() { + return 0, nil, syscall.EINVAL + } + n, addr, err := c.readFrom(b) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, addr, err +} + +// ReadFrom implements the PacketConn ReadFrom method. +func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { + if !c.ok() { + return 0, nil, syscall.EINVAL + } + n, addr, err := c.readFrom(b) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if addr == nil { + return n, nil, err + } + return n, addr, err +} + +// ReadMsgUnix reads a packet from c, copying the payload into b and +// the associated out-of-band data into oob. It returns the number of +// bytes copied into b, the number of bytes copied into oob, the flags +// that were set on the packet, and the source address of the packet. +func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { + if !c.ok() { + return 0, 0, 0, nil, syscall.EINVAL + } + n, oobn, flags, addr, err = c.readMsg(b, oob) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return +} + +// WriteToUnix writes a packet to addr via c, copying the payload from b. +// +// WriteToUnix can be made to time out and return an error with +// Timeout() == true after a fixed time limit; see SetDeadline and +// SetWriteDeadline. On packet-oriented connections, write timeouts +// are rare. +func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + n, err := c.writeTo(b, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return n, err +} + +// WriteTo implements the PacketConn WriteTo method. +func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + a, ok := addr.(*UnixAddr) + if !ok { + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} + } + n, err := c.writeTo(b, a) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err} + } + return n, err +} + +// WriteMsgUnix writes a packet to addr via c, copying the payload +// from b and the associated out-of-band data from oob. It returns +// the number of payload and out-of-band bytes written. +func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { + if !c.ok() { + return 0, 0, syscall.EINVAL + } + n, oobn, err = c.writeMsg(b, oob, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return +} + +func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } + +// DialUnix connects to the remote address raddr on the network net, +// which must be "unix", "unixgram" or "unixpacket". If laddr is not +// nil, it is used as the local address for the connection. +func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { + switch net { + case "unix", "unixgram", "unixpacket": + default: + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} + } + c, err := dialUnix(net, laddr, raddr, noDeadline) + if err != nil { + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} + } + return c, nil +} + +// UnixListener is a Unix domain socket listener. Clients should +// typically use variables of type Listener instead of assuming Unix +// domain sockets. +type UnixListener struct { + fd *netFD + path string + unlink bool +} + +func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil } + +// AcceptUnix accepts the next incoming call and returns the new +// connection. +func (l *UnixListener) AcceptUnix() (*UnixConn, error) { + if !l.ok() { + return nil, syscall.EINVAL + } + c, err := l.accept() + if err != nil { + return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return c, nil +} + +// Accept implements the Accept method in the Listener interface. +// Returned connections will be of type *UnixConn. +func (l *UnixListener) Accept() (Conn, error) { + if !l.ok() { + return nil, syscall.EINVAL + } + c, err := l.accept() + if err != nil { + return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return c, nil +} + +// Close stops listening on the Unix address. Already accepted +// connections are not closed. +func (l *UnixListener) Close() error { + if !l.ok() { + return syscall.EINVAL + } + if err := l.close(); err != nil { + return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return nil +} + +// Addr returns the listener's network address. +// The Addr returned is shared by all invocations of Addr, so +// do not modify it. +func (l *UnixListener) Addr() Addr { return l.fd.laddr } + +// SetDeadline sets the deadline associated with the listener. +// A zero time value disables the deadline. +func (l *UnixListener) SetDeadline(t time.Time) error { + if !l.ok() { + return syscall.EINVAL + } + if err := l.fd.setDeadline(t); err != nil { + return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return nil +} + +// 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. +// +// The returned os.File's file descriptor is different from the +// connection's. Attempting to change properties of the original +// using this duplicate may or may not have the desired effect. +func (l *UnixListener) File() (f *os.File, err error) { + if !l.ok() { + return nil, syscall.EINVAL + } + f, err = l.file() + if err != nil { + err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return +} + +// ListenUnix announces on the Unix domain socket laddr and returns a +// Unix listener. The network net must be "unix" or "unixpacket". +func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { + switch net { + case "unix", "unixpacket": + default: + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} + } + if laddr == nil { + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress} + } + ln, err := listenUnix(net, laddr) + if err != nil { + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} + } + return ln, nil +} + +// ListenUnixgram listens for incoming Unix datagram packets addressed +// to the local address laddr. The network net must be "unixgram". +// The returned connection's ReadFrom and WriteTo methods can be used +// to receive and send packets with per-packet addressing. +func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { + switch net { + case "unixgram": + default: + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} + } + if laddr == nil { + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress} + } + c, err := listenUnixgram(net, laddr) + if err != nil { + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} + } + return c, nil +} diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go index d0e3ca72e8..5d5b18f467 100644 --- a/src/net/unixsock_plan9.go +++ b/src/net/unixsock_plan9.go @@ -10,138 +10,42 @@ import ( "time" ) -// UnixConn is an implementation of the Conn interface for connections -// to Unix domain sockets. -type UnixConn struct { - conn +func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) { + return 0, nil, syscall.EPLAN9 } -// ReadFromUnix reads a packet from c, copying the payload into b. It -// returns the number of bytes copied into b and the source address of -// the packet. -// -// ReadFromUnix can be made to time out and return an error with -// Timeout() == true after a fixed time limit; see SetDeadline and -// SetReadDeadline. -func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { - return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} +func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { + return 0, 0, 0, nil, syscall.EPLAN9 } -// ReadFrom implements the PacketConn ReadFrom method. -func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { - return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} +func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) { + return 0, syscall.EPLAN9 } -// ReadMsgUnix reads a packet from c, copying the payload into b and -// the associated out-of-band data into oob. It returns the number of -// bytes copied into b, the number of bytes copied into oob, the flags -// that were set on the packet, and the source address of the packet. -func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { - return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} +func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { + return 0, 0, syscall.EPLAN9 } -// WriteToUnix writes a packet to addr via c, copying the payload from b. -// -// WriteToUnix can be made to time out and return an error with -// Timeout() == true after a fixed time limit; see SetDeadline and -// SetWriteDeadline. On packet-oriented connections, write timeouts -// are rare. -func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { - return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} +func dialUnix(network string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { + return nil, syscall.EPLAN9 } -// WriteTo implements the PacketConn WriteTo method. -func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) { - return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9} +func (ln *UnixListener) accept() (*UnixConn, error) { + return nil, syscall.EPLAN9 } -// WriteMsgUnix writes a packet to addr via c, copying the payload -// from b and the associated out-of-band data from oob. It returns -// the number of payload and out-of-band bytes written. -func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { - return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} +func (ln *UnixListener) close() error { + return syscall.EPLAN9 } -// CloseRead shuts down the reading side of the Unix domain connection. -// Most callers should just use Close. -func (c *UnixConn) CloseRead() error { - return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} +func (ln *UnixListener) file() (*os.File, error) { + return nil, syscall.EPLAN9 } -// CloseWrite shuts down the writing side of the Unix domain connection. -// Most callers should just use Close. -func (c *UnixConn) CloseWrite() error { - return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} +func listenUnix(network string, laddr *UnixAddr) (*UnixListener, error) { + return nil, syscall.EPLAN9 } -// DialUnix connects to the remote address raddr on the network net, -// which must be "unix", "unixgram" or "unixpacket". If laddr is not -// nil, it is used as the local address for the connection. -func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { - return dialUnix(net, laddr, raddr, noDeadline) -} - -func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { - return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9} -} - -// UnixListener is a Unix domain socket listener. Clients should -// typically use variables of type Listener instead of assuming Unix -// domain sockets. -type UnixListener struct { - fd *netFD -} - -// ListenUnix announces on the Unix domain socket laddr and returns a -// Unix listener. The network net must be "unix" or "unixpacket". -func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9} -} - -// AcceptUnix accepts the next incoming call and returns the new -// connection. -func (l *UnixListener) AcceptUnix() (*UnixConn, error) { - return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} -} - -// Accept implements the Accept method in the Listener interface; it -// waits for the next call and returns a generic Conn. -func (l *UnixListener) Accept() (Conn, error) { - return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} -} - -// Close stops listening on the Unix address. Already accepted -// connections are not closed. -func (l *UnixListener) Close() error { - return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} -} - -// Addr returns the listener's network address. -// The Addr returned is shared by all invocations of Addr, so -// do not modify it. -func (l *UnixListener) Addr() Addr { return nil } - -// SetDeadline sets the deadline associated with the listener. -// A zero time value disables the deadline. -func (l *UnixListener) SetDeadline(t time.Time) error { - return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: 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. -// -// The returned os.File's file descriptor is different from the -// connection's. Attempting to change properties of the original -// using this duplicate may or may not have the desired effect. -func (l *UnixListener) File() (*os.File, error) { - return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} -} - -// ListenUnixgram listens for incoming Unix datagram packets addressed -// to the local address laddr. The network net must be "unixgram". -// The returned connection's ReadFrom and WriteTo methods can be used -// to receive and send packets with per-packet addressing. -func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9} +func listenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error) { + return nil, syscall.EPLAN9 } diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go index 4e2f785596..9275e1034c 100644 --- a/src/net/unixsock_posix.go +++ b/src/net/unixsock_posix.go @@ -94,25 +94,7 @@ func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) { return &syscall.SockaddrUnix{Name: a.Name}, nil } -// UnixConn is an implementation of the Conn interface for connections -// to Unix domain sockets. -type UnixConn struct { - conn -} - -func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } - -// ReadFromUnix reads a packet from c, copying the payload into b. It -// returns the number of bytes copied into b and the source address of -// the packet. -// -// ReadFromUnix can be made to time out and return an error with -// Timeout() == true after a fixed time limit; see SetDeadline and -// SetReadDeadline. -func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { - if !c.ok() { - return 0, nil, syscall.EINVAL - } +func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) { var addr *UnixAddr n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { @@ -121,148 +103,47 @@ func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} } } - if err != nil { - err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} - } return n, addr, err } -// ReadFrom implements the PacketConn ReadFrom method. -func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { - if !c.ok() { - return 0, nil, syscall.EINVAL - } - n, addr, err := c.ReadFromUnix(b) - if addr == nil { - return n, nil, err - } - return n, addr, err -} - -// ReadMsgUnix reads a packet from c, copying the payload into b and -// the associated out-of-band data into oob. It returns the number of -// bytes copied into b, the number of bytes copied into oob, the flags -// that were set on the packet, and the source address of the packet. -func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { - if !c.ok() { - return 0, 0, 0, nil, syscall.EINVAL - } - n, oobn, flags, sa, err := c.fd.readMsg(b, oob) +func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { + var sa syscall.Sockaddr + n, oobn, flags, sa, err = c.fd.readMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrUnix: if sa.Name != "" { addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} } } - if err != nil { - err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} - } return } -// WriteToUnix writes a packet to addr via c, copying the payload from b. -// -// WriteToUnix can be made to time out and return an error with -// Timeout() == true after a fixed time limit; see SetDeadline and -// SetWriteDeadline. On packet-oriented connections, write timeouts -// are rare. -func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { - if !c.ok() { - return 0, syscall.EINVAL - } +func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) { if c.fd.isConnected { - return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} + return 0, ErrWriteToConnected } if addr == nil { - return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} + return 0, errMissingAddress } if addr.Net != sotypeToNet(c.fd.sotype) { - return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT} + return 0, syscall.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} - n, err := c.fd.writeTo(b, sa) - if err != nil { - err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} - } - return n, err + return c.fd.writeTo(b, sa) } -// WriteTo implements the PacketConn WriteTo method. -func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) { - if !c.ok() { - return 0, syscall.EINVAL - } - a, ok := addr.(*UnixAddr) - if !ok { - return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} - } - return c.WriteToUnix(b, a) -} - -// WriteMsgUnix writes a packet to addr via c, copying the payload -// from b and the associated out-of-band data from oob. It returns -// the number of payload and out-of-band bytes written. -func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { - if !c.ok() { - return 0, 0, syscall.EINVAL - } +func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} + return 0, 0, ErrWriteToConnected } var sa syscall.Sockaddr if addr != nil { if addr.Net != sotypeToNet(c.fd.sotype) { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT} + return 0, 0, syscall.EAFNOSUPPORT } sa = &syscall.SockaddrUnix{Name: addr.Name} } - n, oobn, err = c.fd.writeMsg(b, oob, sa) - if err != nil { - err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} - } - return -} - -// CloseRead shuts down the reading side of the Unix domain connection. -// Most callers should just use Close. -func (c *UnixConn) CloseRead() error { - if !c.ok() { - return syscall.EINVAL - } - err := c.fd.closeRead() - if err != nil { - err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} - } - return err -} - -// CloseWrite shuts down the writing side of the Unix domain connection. -// Most callers should just use Close. -func (c *UnixConn) CloseWrite() error { - if !c.ok() { - return syscall.EINVAL - } - err := c.fd.closeWrite() - if err != nil { - err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} - } - return err -} - -// DialUnix connects to the remote address raddr on the network net, -// which must be "unix", "unixgram" or "unixpacket". If laddr is not -// nil, it is used as the local address for the connection. -func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { - switch net { - case "unix", "unixgram", "unixpacket": - default: - return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} - } - c, err := dialUnix(net, laddr, raddr, noDeadline) - if err != nil { - return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} - } - return c, nil + return c.fd.writeMsg(b, oob, sa) } func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { @@ -273,63 +154,15 @@ func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn return newUnixConn(fd), nil } -// UnixListener is a Unix domain socket listener. Clients should -// typically use variables of type Listener instead of assuming Unix -// domain sockets. -type UnixListener struct { - fd *netFD - path string - unlink bool -} - -// ListenUnix announces on the Unix domain socket laddr and returns a -// Unix listener. The network net must be "unix" or "unixpacket". -func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { - switch net { - case "unix", "unixpacket": - default: - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} - } - if laddr == nil { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress} - } - fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) +func (ln *UnixListener) accept() (*UnixConn, error) { + fd, err := ln.fd.accept() if err != nil { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} - } - return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil -} - -// AcceptUnix accepts the next incoming call and returns the new -// connection. -func (l *UnixListener) AcceptUnix() (*UnixConn, error) { - if l == nil || l.fd == nil { - return nil, syscall.EINVAL - } - fd, err := l.fd.accept() - if err != nil { - return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + return nil, err } return newUnixConn(fd), nil } -// Accept implements the Accept method in the Listener interface. -// Returned connections will be of type *UnixConn. -func (l *UnixListener) Accept() (Conn, error) { - c, err := l.AcceptUnix() - if err != nil { - return nil, err - } - return c, nil -} - -// Close stops listening on the Unix address. Already accepted -// connections are not closed. -func (l *UnixListener) Close() error { - if l == nil || l.fd == nil { - return syscall.EINVAL - } - +func (ln *UnixListener) close() error { // The operating system doesn't clean up // the file that announcing created, so // we have to clean it up ourselves. @@ -340,64 +173,32 @@ func (l *UnixListener) Close() error { // is at least compatible with the auto-remove // sequence in ListenUnix. It's only non-Go // programs that can mess us up. - if l.path[0] != '@' && l.unlink { - syscall.Unlink(l.path) + if ln.path[0] != '@' && ln.unlink { + syscall.Unlink(ln.path) } - err := l.fd.Close() - if err != nil { - err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err} - } - return err + return ln.fd.Close() } -// Addr returns the listener's network address. -// The Addr returned is shared by all invocations of Addr, so -// do not modify it. -func (l *UnixListener) Addr() Addr { return l.fd.laddr } - -// SetDeadline sets the deadline associated with the listener. -// A zero time value disables the deadline. -func (l *UnixListener) SetDeadline(t time.Time) error { - if l == nil || l.fd == nil { - return syscall.EINVAL +func (ln *UnixListener) file() (*os.File, error) { + f, err := ln.fd.dup() + if err != nil { + return nil, err } - if err := l.fd.setDeadline(t); err != nil { - return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} - } - return nil + return f, nil } -// 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. -// -// The returned os.File's file descriptor is different from the -// connection's. Attempting to change properties of the original -// using this duplicate may or may not have the desired effect. -func (l *UnixListener) File() (f *os.File, err error) { - f, err = l.fd.dup() +func listenUnix(network string, laddr *UnixAddr) (*UnixListener, error) { + fd, err := unixSocket(network, laddr, nil, "listen", noDeadline) if err != nil { - err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + return nil, err } - return + return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil } -// ListenUnixgram listens for incoming Unix datagram packets addressed -// to the local address laddr. The network net must be "unixgram". -// The returned connection's ReadFrom and WriteTo methods can be used -// to receive and send packets with per-packet addressing. -func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { - switch net { - case "unixgram": - default: - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} - } - if laddr == nil { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress} - } - fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) +func listenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error) { + fd, err := unixSocket(network, laddr, nil, "listen", noDeadline) if err != nil { - return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} + return nil, err } return newUnixConn(fd), nil }