github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/net/unixsock.go (about)

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