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 returns an address of Unix domain socket end point.
     46 //
     47 // The network must be a Unix network name.
     48 //
     49 // See func Dial for a description of the network and address
     50 // parameters.
     51 func ResolveUnixAddr(network, address string) (*UnixAddr, error) {
     52 	switch network {
     53 	case "unix", "unixgram", "unixpacket":
     54 		return &UnixAddr{Name: address, Net: network}, nil
     55 	default:
     56 		return nil, UnknownNetworkError(network)
     57 	}
     58 }
     59 
     60 // UnixConn is an implementation of the Conn interface for connections
     61 // to Unix domain sockets.
     62 type UnixConn struct {
     63 	conn
     64 }
     65 
     66 // SyscallConn returns a raw network connection.
     67 // This implements the syscall.Conn interface.
     68 func (c *UnixConn) SyscallConn() (syscall.RawConn, error) {
     69 	if !c.ok() {
     70 		return nil, syscall.EINVAL
     71 	}
     72 	return newRawConn(c.fd)
     73 }
     74 
     75 // CloseRead shuts down the reading side of the Unix domain connection.
     76 // Most callers should just use Close.
     77 func (c *UnixConn) CloseRead() error {
     78 	if !c.ok() {
     79 		return syscall.EINVAL
     80 	}
     81 	if err := c.fd.closeRead(); 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 // CloseWrite shuts down the writing side of the Unix domain connection.
     88 // Most callers should just use Close.
     89 func (c *UnixConn) CloseWrite() error {
     90 	if !c.ok() {
     91 		return syscall.EINVAL
     92 	}
     93 	if err := c.fd.closeWrite(); err != nil {
     94 		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     95 	}
     96 	return nil
     97 }
     98 
     99 // ReadFromUnix acts like ReadFrom but returns a UnixAddr.
    100 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
    101 	if !c.ok() {
    102 		return 0, nil, syscall.EINVAL
    103 	}
    104 	n, addr, err := c.readFrom(b)
    105 	if err != nil {
    106 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    107 	}
    108 	return n, addr, err
    109 }
    110 
    111 // ReadFrom implements the PacketConn ReadFrom method.
    112 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
    113 	if !c.ok() {
    114 		return 0, nil, syscall.EINVAL
    115 	}
    116 	n, addr, err := c.readFrom(b)
    117 	if err != nil {
    118 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    119 	}
    120 	if addr == nil {
    121 		return n, nil, err
    122 	}
    123 	return n, addr, err
    124 }
    125 
    126 // ReadMsgUnix reads a message from c, copying the payload into b and
    127 // the associated out-of-band data into oob. It returns the number of
    128 // bytes copied into b, the number of bytes copied into oob, the flags
    129 // that were set on the message and the source address of the message.
    130 //
    131 // Note that if len(b) == 0 and len(oob) > 0, this function will still
    132 // read (and discard) 1 byte from the connection.
    133 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
    134 	if !c.ok() {
    135 		return 0, 0, 0, nil, syscall.EINVAL
    136 	}
    137 	n, oobn, flags, addr, err = c.readMsg(b, oob)
    138 	if err != nil {
    139 		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    140 	}
    141 	return
    142 }
    143 
    144 // WriteToUnix acts like WriteTo but takes a UnixAddr.
    145 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
    146 	if !c.ok() {
    147 		return 0, syscall.EINVAL
    148 	}
    149 	n, err := c.writeTo(b, addr)
    150 	if err != nil {
    151 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
    152 	}
    153 	return n, err
    154 }
    155 
    156 // WriteTo implements the PacketConn WriteTo method.
    157 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
    158 	if !c.ok() {
    159 		return 0, syscall.EINVAL
    160 	}
    161 	a, ok := addr.(*UnixAddr)
    162 	if !ok {
    163 		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
    164 	}
    165 	n, err := c.writeTo(b, a)
    166 	if err != nil {
    167 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
    168 	}
    169 	return n, err
    170 }
    171 
    172 // WriteMsgUnix writes a message to addr via c, copying the payload
    173 // from b and the associated out-of-band data from oob. It returns the
    174 // number of payload and out-of-band bytes written.
    175 //
    176 // Note that if len(b) == 0 and len(oob) > 0, this function will still
    177 // write 1 byte to the connection.
    178 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
    179 	if !c.ok() {
    180 		return 0, 0, syscall.EINVAL
    181 	}
    182 	n, oobn, err = c.writeMsg(b, oob, addr)
    183 	if err != nil {
    184 		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
    185 	}
    186 	return
    187 }
    188 
    189 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
    190 
    191 // DialUnix acts like Dial for Unix networks.
    192 //
    193 // The network must be a Unix network name; see func Dial for details.
    194 //
    195 // If laddr is non-nil, it is used as the local address for the
    196 // connection.
    197 func DialUnix(network string, laddr, raddr *UnixAddr) (*UnixConn, error) {
    198 	switch network {
    199 	case "unix", "unixgram", "unixpacket":
    200 	default:
    201 		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)}
    202 	}
    203 	c, err := dialUnix(context.Background(), network, laddr, raddr)
    204 	if err != nil {
    205 		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
    206 	}
    207 	return c, nil
    208 }
    209 
    210 // UnixListener is a Unix domain socket listener. Clients should
    211 // typically use variables of type Listener instead of assuming Unix
    212 // domain sockets.
    213 type UnixListener struct {
    214 	fd         *netFD
    215 	path       string
    216 	unlink     bool
    217 	unlinkOnce sync.Once
    218 }
    219 
    220 func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
    221 
    222 // SyscallConn returns a raw network connection.
    223 // This implements the syscall.Conn interface.
    224 //
    225 // The returned RawConn only supports calling Control. Read and
    226 // Write return an error.
    227 func (l *UnixListener) SyscallConn() (syscall.RawConn, error) {
    228 	if !l.ok() {
    229 		return nil, syscall.EINVAL
    230 	}
    231 	return newRawListener(l.fd)
    232 }
    233 
    234 // AcceptUnix accepts the next incoming call and returns the new
    235 // connection.
    236 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
    237 	if !l.ok() {
    238 		return nil, syscall.EINVAL
    239 	}
    240 	c, err := l.accept()
    241 	if err != nil {
    242 		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    243 	}
    244 	return c, nil
    245 }
    246 
    247 // Accept implements the Accept method in the Listener interface.
    248 // Returned connections will be of type *UnixConn.
    249 func (l *UnixListener) Accept() (Conn, error) {
    250 	if !l.ok() {
    251 		return nil, syscall.EINVAL
    252 	}
    253 	c, err := l.accept()
    254 	if err != nil {
    255 		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    256 	}
    257 	return c, nil
    258 }
    259 
    260 // Close stops listening on the Unix address. Already accepted
    261 // connections are not closed.
    262 func (l *UnixListener) Close() error {
    263 	if !l.ok() {
    264 		return syscall.EINVAL
    265 	}
    266 	if err := l.close(); err != nil {
    267 		return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    268 	}
    269 	return nil
    270 }
    271 
    272 // Addr returns the listener's network address.
    273 // The Addr returned is shared by all invocations of Addr, so
    274 // do not modify it.
    275 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
    276 
    277 // SetDeadline sets the deadline associated with the listener.
    278 // A zero time value disables the deadline.
    279 func (l *UnixListener) SetDeadline(t time.Time) error {
    280 	if !l.ok() {
    281 		return syscall.EINVAL
    282 	}
    283 	if err := l.fd.pfd.SetDeadline(t); err != nil {
    284 		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    285 	}
    286 	return nil
    287 }
    288 
    289 // File returns a copy of the underlying os.File, set to blocking
    290 // mode. It is the caller's responsibility to close f when finished.
    291 // Closing l does not affect f, and closing f does not affect l.
    292 //
    293 // The returned os.File's file descriptor is different from the
    294 // connection's. Attempting to change properties of the original
    295 // using this duplicate may or may not have the desired effect.
    296 func (l *UnixListener) File() (f *os.File, err error) {
    297 	if !l.ok() {
    298 		return nil, syscall.EINVAL
    299 	}
    300 	f, err = l.file()
    301 	if err != nil {
    302 		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
    303 	}
    304 	return
    305 }
    306 
    307 // ListenUnix acts like Listen for Unix networks.
    308 //
    309 // The network must be "unix" or "unixpacket".
    310 func ListenUnix(network string, laddr *UnixAddr) (*UnixListener, error) {
    311 	switch network {
    312 	case "unix", "unixpacket":
    313 	default:
    314 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
    315 	}
    316 	if laddr == nil {
    317 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
    318 	}
    319 	ln, err := listenUnix(context.Background(), network, laddr)
    320 	if err != nil {
    321 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
    322 	}
    323 	return ln, nil
    324 }
    325 
    326 // ListenUnixgram acts like ListenPacket for Unix networks.
    327 //
    328 // The network must be "unixgram".
    329 func ListenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error) {
    330 	switch network {
    331 	case "unixgram":
    332 	default:
    333 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
    334 	}
    335 	if laddr == nil {
    336 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: errMissingAddress}
    337 	}
    338 	c, err := listenUnixgram(context.Background(), network, laddr)
    339 	if err != nil {
    340 		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
    341 	}
    342 	return c, nil
    343 }
    344