Home | History | Annotate | Download | only in net
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package net
      6 
      7 import (
      8 	"context"
      9 	"os"
     10 	"sync"
     11 	"syscall"
     12 	"time"
     13 )
     14 
     15 // UnixAddr represents the address of a Unix domain socket end point.
     16 type UnixAddr struct {
     17 	Name string
     18 	Net  string
     19 }
     20 
     21 // Network returns the address's network name, "unix", "unixgram" or
     22 // "unixpacket".
     23 func (a *UnixAddr) Network() string {
     24 	return a.Net
     25 }
     26 
     27 func (a *UnixAddr) String() string {
     28 	if a == nil {
     29 		return "<nil>"
     30 	}
     31 	return a.Name
     32 }
     33 
     34 func (a *UnixAddr) isWildcard() bool {
     35 	return a == nil || a.Name == ""
     36 }
     37 
     38 func (a *UnixAddr) opAddr() Addr {
     39 	if a == nil {
     40 		return nil
     41 	}
     42 	return a
     43 }
     44 
     45 // ResolveUnixAddr parses addr as a Unix domain socket address.
     46 // The string net gives the network name, "unix", "unixgram" or
     47 // "unixpacket".
     48 func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
     49 	switch net {
     50 	case "unix", "unixgram", "unixpacket":
     51 		return &UnixAddr{Name: addr, Net: net}, nil
     52 	default:
     53 		return nil, UnknownNetworkError(net)
     54 	}
     55 }
     56 
     57 // UnixConn is an implementation of the Conn interface for connections
     58 // to Unix domain sockets.
     59 type UnixConn struct {
     60 	conn
     61 }
     62 
     63 // CloseRead shuts down the reading side of the Unix domain connection.
     64 // Most callers should just use Close.
     65 func (c *UnixConn) CloseRead() error {
     66 	if !c.ok() {
     67 		return syscall.EINVAL
     68 	}
     69 	if err := c.fd.closeRead(); err != nil {
     70 		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     71 	}
     72 	return nil
     73 }
     74 
     75 // CloseWrite shuts down the writing side of the Unix domain connection.
     76 // Most callers should just use Close.
     77 func (c *UnixConn) CloseWrite() error {
     78 	if !c.ok() {
     79 		return syscall.EINVAL
     80 	}
     81 	if err := c.fd.closeWrite(); err != nil {
     82 		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     83 	}
     84 	return nil
     85 }
     86 
     87 // ReadFromUnix reads a packet from c, copying the payload into b. It
     88 // returns the number of bytes copied into b and the source address of
     89 // the packet.
     90 //
     91 // ReadFromUnix can be made to time out and return an error with
     92 // Timeout() == true after a fixed time limit; see SetDeadline and
     93 // SetReadDeadline.
     94 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
     95 	if !c.ok() {
     96 		return 0, nil, syscall.EINVAL
     97 	}
     98 	n, addr, err := c.readFrom(b)
     99 	if err != nil {
    100 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    101 	}
    102 	return n, addr, err
    103 }
    104 
    105 // ReadFrom implements the PacketConn ReadFrom method.
    106 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
    107 	if !c.ok() {
    108 		return 0, nil, syscall.EINVAL
    109 	}
    110 	n, addr, err := c.readFrom(b)
    111 	if err != nil {
    112 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    113 	}
    114 	if addr == nil {
    115 		return n, nil, err
    116 	}
    117 	return n, addr, err
    118 }
    119 
    120 // ReadMsgUnix reads a packet from c, copying the payload into b and
    121 // the associated out-of-band data into oob. It returns the number of
    122 // bytes copied into b, the number of bytes copied into oob, the flags
    123 // that were set on the packet, and the source address of the packet.
    124 //
    125 // Note that if len(b) == 0 and len(oob) > 0, this function will still
    126 // read (and discard) 1 byte from the connection.
    127 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
    128 	if !c.ok() {
    129 		return 0, 0, 0, nil, syscall.EINVAL
    130 	}
    131 	n, oobn, flags, addr, err = c.readMsg(b, oob)
    132 	if err != nil {
    133 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    134 	}
    135 	return
    136 }
    137 
    138 // WriteToUnix writes a packet to addr via c, copying the payload from b.
    139 //
    140 // WriteToUnix can be made to time out and return an error with
    141 // Timeout() == true after a fixed time limit; see SetDeadline and
    142 // SetWriteDeadline. On packet-oriented connections, write timeouts
    143 // are rare.
    144 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
    145 	if !c.ok() {
    146 		return 0, syscall.EINVAL
    147 	}
    148 	n, err := c.writeTo(b, addr)
    149 	if err != nil {
    150 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
    151 	}
    152 	return n, err
    153 }
    154 
    155 // WriteTo implements the PacketConn WriteTo method.
    156 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
    157 	if !c.ok() {
    158 		return 0, syscall.EINVAL
    159 	}
    160 	a, ok := addr.(*UnixAddr)
    161 	if !ok {
    162 		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
    163 	}
    164 	n, err := c.writeTo(b, a)
    165 	if err != nil {
    166 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
    167 	}
    168 	return n, err
    169 }
    170 
    171 // WriteMsgUnix writes a packet to addr via c, copying the payload
    172 // from b and the associated out-of-band data from oob. It returns
    173 // the number of payload and out-of-band bytes written.
    174 //
    175 // Note that if len(b) == 0 and len(oob) > 0, this function will still
    176 // write 1 byte to the connection.
    177 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
    178 	if !c.ok() {
    179 		return 0, 0, syscall.EINVAL
    180 	}
    181 	n, oobn, err = c.writeMsg(b, oob, addr)
    182 	if err != nil {
    183 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
    184 	}
    185 	return
    186 }
    187 
    188 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
    189 
    190 // DialUnix connects to the remote address raddr on the network net,
    191 // which must be "unix", "unixgram" or "unixpacket".  If laddr is not
    192 // nil, it is used as the local address for the connection.
    193 func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
    194 	switch net {
    195 	case "unix", "unixgram", "unixpacket":
    196 	default:
    197 		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
    198 	}
    199 	c, err := dialUnix(context.Background(), net, laddr, raddr)
    200 	if err != nil {
    201 		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
    202 	}
    203 	return c, nil
    204 }
    205 
    206 // UnixListener is a Unix domain socket listener. Clients should
    207 // typically use variables of type Listener instead of assuming Unix
    208 // domain sockets.
    209 type UnixListener struct {
    210 	fd         *netFD
    211 	path       string
    212 	unlink     bool
    213 	unlinkOnce sync.Once
    214 }
    215 
    216 func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
    217 
    218 // AcceptUnix accepts the next incoming call and returns the new
    219 // connection.
    220 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
    221 	if !l.ok() {
    222 		return nil, syscall.EINVAL
    223 	}
    224 	c, err := l.accept()
    225 	if err != nil {
    226 		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    227 	}
    228 	return c, nil
    229 }
    230 
    231 // Accept implements the Accept method in the Listener interface.
    232 // Returned connections will be of type *UnixConn.
    233 func (l *UnixListener) Accept() (Conn, error) {
    234 	if !l.ok() {
    235 		return nil, syscall.EINVAL
    236 	}
    237 	c, err := l.accept()
    238 	if err != nil {
    239 		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    240 	}
    241 	return c, nil
    242 }
    243 
    244 // Close stops listening on the Unix address. Already accepted
    245 // connections are not closed.
    246 func (l *UnixListener) Close() error {
    247 	if !l.ok() {
    248 		return syscall.EINVAL
    249 	}
    250 	if err := l.close(); err != nil {
    251 		return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    252 	}
    253 	return nil
    254 }
    255 
    256 // Addr returns the listener's network address.
    257 // The Addr returned is shared by all invocations of Addr, so
    258 // do not modify it.
    259 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
    260 
    261 // SetDeadline sets the deadline associated with the listener.
    262 // A zero time value disables the deadline.
    263 func (l *UnixListener) SetDeadline(t time.Time) error {
    264 	if !l.ok() {
    265 		return syscall.EINVAL
    266 	}
    267 	if err := l.fd.setDeadline(t); err != nil {
    268 		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    269 	}
    270 	return nil
    271 }
    272 
    273 // File returns a copy of the underlying os.File, set to blocking
    274 // mode. It is the caller's responsibility to close f when finished.
    275 // Closing l does not affect f, and closing f does not affect l.
    276 //
    277 // The returned os.File's file descriptor is different from the
    278 // connection's. Attempting to change properties of the original
    279 // using this duplicate may or may not have the desired effect.
    280 func (l *UnixListener) File() (f *os.File, err error) {
    281 	if !l.ok() {
    282 		return nil, syscall.EINVAL
    283 	}
    284 	f, err = l.file()
    285 	if err != nil {
    286 		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    287 	}
    288 	return
    289 }
    290 
    291 // ListenUnix announces on the Unix domain socket laddr and returns a
    292 // Unix listener. The network net must be "unix" or "unixpacket".
    293 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
    294 	switch net {
    295 	case "unix", "unixpacket":
    296 	default:
    297 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
    298 	}
    299 	if laddr == nil {
    300 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
    301 	}
    302 	ln, err := listenUnix(context.Background(), net, laddr)
    303 	if err != nil {
    304 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
    305 	}
    306 	return ln, nil
    307 }
    308 
    309 // ListenUnixgram listens for incoming Unix datagram packets addressed
    310 // to the local address laddr. The network net must be "unixgram".
    311 // The returned connection's ReadFrom and WriteTo methods can be used
    312 // to receive and send packets with per-packet addressing.
    313 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
    314 	switch net {
    315 	case "unixgram":
    316 	default:
    317 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
    318 	}
    319 	if laddr == nil {
    320 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
    321 	}
    322 	c, err := listenUnixgram(context.Background(), net, laddr)
    323 	if err != nil {
    324 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
    325 	}
    326 	return c, nil
    327 }
    328