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

View as plain text