Source file src/net/unixsock.go

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

View as plain text