github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/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  	"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  }