golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/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  // AcceptUnix accepts the next incoming call and returns the new
   223  // connection.
   224  func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
   225  	if !l.ok() {
   226  		return nil, syscall.EINVAL
   227  	}
   228  	c, err := l.accept()
   229  	if err != nil {
   230  		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   231  	}
   232  	return c, nil
   233  }
   234  
   235  // Accept implements the Accept method in the Listener interface.
   236  // Returned connections will be of type *UnixConn.
   237  func (l *UnixListener) Accept() (Conn, error) {
   238  	if !l.ok() {
   239  		return nil, syscall.EINVAL
   240  	}
   241  	c, err := l.accept()
   242  	if err != nil {
   243  		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   244  	}
   245  	return c, nil
   246  }
   247  
   248  // Close stops listening on the Unix address. Already accepted
   249  // connections are not closed.
   250  func (l *UnixListener) Close() error {
   251  	if !l.ok() {
   252  		return syscall.EINVAL
   253  	}
   254  	if err := l.close(); err != nil {
   255  		return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   256  	}
   257  	return nil
   258  }
   259  
   260  // Addr returns the listener's network address.
   261  // The Addr returned is shared by all invocations of Addr, so
   262  // do not modify it.
   263  func (l *UnixListener) Addr() Addr { return l.fd.laddr }
   264  
   265  // SetDeadline sets the deadline associated with the listener.
   266  // A zero time value disables the deadline.
   267  func (l *UnixListener) SetDeadline(t time.Time) error {
   268  	if !l.ok() {
   269  		return syscall.EINVAL
   270  	}
   271  	if err := l.fd.pfd.SetDeadline(t); err != nil {
   272  		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   273  	}
   274  	return nil
   275  }
   276  
   277  // File returns a copy of the underlying os.File, set to blocking
   278  // mode. It is the caller's responsibility to close f when finished.
   279  // Closing l does not affect f, and closing f does not affect l.
   280  //
   281  // The returned os.File's file descriptor is different from the
   282  // connection's. Attempting to change properties of the original
   283  // using this duplicate may or may not have the desired effect.
   284  func (l *UnixListener) File() (f *os.File, err error) {
   285  	if !l.ok() {
   286  		return nil, syscall.EINVAL
   287  	}
   288  	f, err = l.file()
   289  	if err != nil {
   290  		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   291  	}
   292  	return
   293  }
   294  
   295  // ListenUnix acts like Listen for Unix networks.
   296  //
   297  // The network must be "unix" or "unixpacket".
   298  func ListenUnix(network string, laddr *UnixAddr) (*UnixListener, error) {
   299  	switch network {
   300  	case "unix", "unixpacket":
   301  	default:
   302  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
   303  	}
   304  	if laddr == nil {
   305  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
   306  	}
   307  	ln, err := listenUnix(context.Background(), network, laddr)
   308  	if err != nil {
   309  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
   310  	}
   311  	return ln, nil
   312  }
   313  
   314  // ListenUnixgram acts like ListenPacket for Unix networks.
   315  //
   316  // The network must be "unixgram".
   317  func ListenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error) {
   318  	switch network {
   319  	case "unixgram":
   320  	default:
   321  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
   322  	}
   323  	if laddr == nil {
   324  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: errMissingAddress}
   325  	}
   326  	c, err := listenUnixgram(context.Background(), network, laddr)
   327  	if err != nil {
   328  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
   329  	}
   330  	return c, nil
   331  }