github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/net/unixsock_posix.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  // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
     6  
     7  package net
     8  
     9  import (
    10  	"errors"
    11  	"os"
    12  	"syscall"
    13  	"time"
    14  )
    15  
    16  func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Time) (*netFD, error) {
    17  	var sotype int
    18  	switch net {
    19  	case "unix":
    20  		sotype = syscall.SOCK_STREAM
    21  	case "unixgram":
    22  		sotype = syscall.SOCK_DGRAM
    23  	case "unixpacket":
    24  		sotype = syscall.SOCK_SEQPACKET
    25  	default:
    26  		return nil, UnknownNetworkError(net)
    27  	}
    28  
    29  	switch mode {
    30  	case "dial":
    31  		if laddr != nil && laddr.isWildcard() {
    32  			laddr = nil
    33  		}
    34  		if raddr != nil && raddr.isWildcard() {
    35  			raddr = nil
    36  		}
    37  		if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
    38  			return nil, errMissingAddress
    39  		}
    40  	case "listen":
    41  	default:
    42  		return nil, errors.New("unknown mode: " + mode)
    43  	}
    44  
    45  	fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	return fd, nil
    50  }
    51  
    52  func sockaddrToUnix(sa syscall.Sockaddr) Addr {
    53  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
    54  		return &UnixAddr{Name: s.Name, Net: "unix"}
    55  	}
    56  	return nil
    57  }
    58  
    59  func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
    60  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
    61  		return &UnixAddr{Name: s.Name, Net: "unixgram"}
    62  	}
    63  	return nil
    64  }
    65  
    66  func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
    67  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
    68  		return &UnixAddr{Name: s.Name, Net: "unixpacket"}
    69  	}
    70  	return nil
    71  }
    72  
    73  func sotypeToNet(sotype int) string {
    74  	switch sotype {
    75  	case syscall.SOCK_STREAM:
    76  		return "unix"
    77  	case syscall.SOCK_DGRAM:
    78  		return "unixgram"
    79  	case syscall.SOCK_SEQPACKET:
    80  		return "unixpacket"
    81  	default:
    82  		panic("sotypeToNet unknown socket type")
    83  	}
    84  }
    85  
    86  func (a *UnixAddr) family() int {
    87  	return syscall.AF_UNIX
    88  }
    89  
    90  func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
    91  	if a == nil {
    92  		return nil, nil
    93  	}
    94  	return &syscall.SockaddrUnix{Name: a.Name}, nil
    95  }
    96  
    97  // UnixConn is an implementation of the Conn interface for connections
    98  // to Unix domain sockets.
    99  type UnixConn struct {
   100  	conn
   101  }
   102  
   103  func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
   104  
   105  // ReadFromUnix reads a packet from c, copying the payload into b.  It
   106  // returns the number of bytes copied into b and the source address of
   107  // the packet.
   108  //
   109  // ReadFromUnix can be made to time out and return an error with
   110  // Timeout() == true after a fixed time limit; see SetDeadline and
   111  // SetReadDeadline.
   112  func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
   113  	if !c.ok() {
   114  		return 0, nil, syscall.EINVAL
   115  	}
   116  	var addr *UnixAddr
   117  	n, sa, err := c.fd.readFrom(b)
   118  	switch sa := sa.(type) {
   119  	case *syscall.SockaddrUnix:
   120  		if sa.Name != "" {
   121  			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
   122  		}
   123  	}
   124  	if err != nil {
   125  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   126  	}
   127  	return n, addr, err
   128  }
   129  
   130  // ReadFrom implements the PacketConn ReadFrom method.
   131  func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
   132  	if !c.ok() {
   133  		return 0, nil, syscall.EINVAL
   134  	}
   135  	n, addr, err := c.ReadFromUnix(b)
   136  	if addr == nil {
   137  		return n, nil, err
   138  	}
   139  	return n, addr, err
   140  }
   141  
   142  // ReadMsgUnix reads a packet from c, copying the payload into b and
   143  // the associated out-of-band data into oob.  It returns the number of
   144  // bytes copied into b, the number of bytes copied into oob, the flags
   145  // that were set on the packet, and the source address of the packet.
   146  func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
   147  	if !c.ok() {
   148  		return 0, 0, 0, nil, syscall.EINVAL
   149  	}
   150  	n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
   151  	switch sa := sa.(type) {
   152  	case *syscall.SockaddrUnix:
   153  		if sa.Name != "" {
   154  			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
   155  		}
   156  	}
   157  	if err != nil {
   158  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   159  	}
   160  	return
   161  }
   162  
   163  // WriteToUnix writes a packet to addr via c, copying the payload from b.
   164  //
   165  // WriteToUnix can be made to time out and return an error with
   166  // Timeout() == true after a fixed time limit; see SetDeadline and
   167  // SetWriteDeadline.  On packet-oriented connections, write timeouts
   168  // are rare.
   169  func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
   170  	if !c.ok() {
   171  		return 0, syscall.EINVAL
   172  	}
   173  	if c.fd.isConnected {
   174  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
   175  	}
   176  	if addr == nil {
   177  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
   178  	}
   179  	if addr.Net != sotypeToNet(c.fd.sotype) {
   180  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
   181  	}
   182  	sa := &syscall.SockaddrUnix{Name: addr.Name}
   183  	n, err := c.fd.writeTo(b, sa)
   184  	if err != nil {
   185  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
   186  	}
   187  	return n, err
   188  }
   189  
   190  // WriteTo implements the PacketConn WriteTo method.
   191  func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
   192  	if !c.ok() {
   193  		return 0, syscall.EINVAL
   194  	}
   195  	a, ok := addr.(*UnixAddr)
   196  	if !ok {
   197  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
   198  	}
   199  	return c.WriteToUnix(b, a)
   200  }
   201  
   202  // WriteMsgUnix writes a packet to addr via c, copying the payload
   203  // from b and the associated out-of-band data from oob.  It returns
   204  // the number of payload and out-of-band bytes written.
   205  func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
   206  	if !c.ok() {
   207  		return 0, 0, syscall.EINVAL
   208  	}
   209  	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
   210  		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
   211  	}
   212  	var sa syscall.Sockaddr
   213  	if addr != nil {
   214  		if addr.Net != sotypeToNet(c.fd.sotype) {
   215  			return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
   216  		}
   217  		sa = &syscall.SockaddrUnix{Name: addr.Name}
   218  	}
   219  	n, oobn, err = c.fd.writeMsg(b, oob, sa)
   220  	if err != nil {
   221  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
   222  	}
   223  	return
   224  }
   225  
   226  // CloseRead shuts down the reading side of the Unix domain connection.
   227  // Most callers should just use Close.
   228  func (c *UnixConn) CloseRead() error {
   229  	if !c.ok() {
   230  		return syscall.EINVAL
   231  	}
   232  	err := c.fd.closeRead()
   233  	if err != nil {
   234  		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   235  	}
   236  	return err
   237  }
   238  
   239  // CloseWrite shuts down the writing side of the Unix domain connection.
   240  // Most callers should just use Close.
   241  func (c *UnixConn) CloseWrite() error {
   242  	if !c.ok() {
   243  		return syscall.EINVAL
   244  	}
   245  	err := c.fd.closeWrite()
   246  	if err != nil {
   247  		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   248  	}
   249  	return err
   250  }
   251  
   252  // DialUnix connects to the remote address raddr on the network net,
   253  // which must be "unix", "unixgram" or "unixpacket".  If laddr is not
   254  // nil, it is used as the local address for the connection.
   255  func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
   256  	switch net {
   257  	case "unix", "unixgram", "unixpacket":
   258  	default:
   259  		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
   260  	}
   261  	return dialUnix(net, laddr, raddr, noDeadline)
   262  }
   263  
   264  func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
   265  	fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
   266  	if err != nil {
   267  		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
   268  	}
   269  	return newUnixConn(fd), nil
   270  }
   271  
   272  // UnixListener is a Unix domain socket listener.  Clients should
   273  // typically use variables of type Listener instead of assuming Unix
   274  // domain sockets.
   275  type UnixListener struct {
   276  	fd   *netFD
   277  	path string
   278  }
   279  
   280  // ListenUnix announces on the Unix domain socket laddr and returns a
   281  // Unix listener.  The network net must be "unix" or "unixpacket".
   282  func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
   283  	switch net {
   284  	case "unix", "unixpacket":
   285  	default:
   286  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
   287  	}
   288  	if laddr == nil {
   289  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
   290  	}
   291  	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
   292  	if err != nil {
   293  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
   294  	}
   295  	return &UnixListener{fd: fd, path: fd.laddr.String()}, nil
   296  }
   297  
   298  // AcceptUnix accepts the next incoming call and returns the new
   299  // connection.
   300  func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
   301  	if l == nil || l.fd == nil {
   302  		return nil, syscall.EINVAL
   303  	}
   304  	fd, err := l.fd.accept()
   305  	if err != nil {
   306  		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   307  	}
   308  	return newUnixConn(fd), nil
   309  }
   310  
   311  // Accept implements the Accept method in the Listener interface; it
   312  // waits for the next call and returns a generic Conn.
   313  func (l *UnixListener) Accept() (c Conn, err error) {
   314  	c1, err := l.AcceptUnix()
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  	return c1, nil
   319  }
   320  
   321  // Close stops listening on the Unix address.  Already accepted
   322  // connections are not closed.
   323  func (l *UnixListener) Close() error {
   324  	if l == nil || l.fd == nil {
   325  		return syscall.EINVAL
   326  	}
   327  
   328  	// The operating system doesn't clean up
   329  	// the file that announcing created, so
   330  	// we have to clean it up ourselves.
   331  	// There's a race here--we can't know for
   332  	// sure whether someone else has come along
   333  	// and replaced our socket name already--
   334  	// but this sequence (remove then close)
   335  	// is at least compatible with the auto-remove
   336  	// sequence in ListenUnix.  It's only non-Go
   337  	// programs that can mess us up.
   338  	if l.path[0] != '@' {
   339  		syscall.Unlink(l.path)
   340  	}
   341  	err := l.fd.Close()
   342  	if err != nil {
   343  		err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err}
   344  	}
   345  	return err
   346  }
   347  
   348  // Addr returns the listener's network address.
   349  // The Addr returned is shared by all invocations of Addr, so
   350  // do not modify it.
   351  func (l *UnixListener) Addr() Addr { return l.fd.laddr }
   352  
   353  // SetDeadline sets the deadline associated with the listener.
   354  // A zero time value disables the deadline.
   355  func (l *UnixListener) SetDeadline(t time.Time) error {
   356  	if l == nil || l.fd == nil {
   357  		return syscall.EINVAL
   358  	}
   359  	if err := l.fd.setDeadline(t); err != nil {
   360  		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   361  	}
   362  	return nil
   363  }
   364  
   365  // File returns a copy of the underlying os.File, set to blocking
   366  // mode.  It is the caller's responsibility to close f when finished.
   367  // Closing l does not affect f, and closing f does not affect l.
   368  //
   369  // The returned os.File's file descriptor is different from the
   370  // connection's.  Attempting to change properties of the original
   371  // using this duplicate may or may not have the desired effect.
   372  func (l *UnixListener) File() (f *os.File, err error) {
   373  	f, err = l.fd.dup()
   374  	if err != nil {
   375  		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
   376  	}
   377  	return
   378  }
   379  
   380  // ListenUnixgram listens for incoming Unix datagram packets addressed
   381  // to the local address laddr.  The network net must be "unixgram".
   382  // The returned connection's ReadFrom and WriteTo methods can be used
   383  // to receive and send packets with per-packet addressing.
   384  func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
   385  	switch net {
   386  	case "unixgram":
   387  	default:
   388  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
   389  	}
   390  	if laddr == nil {
   391  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
   392  	}
   393  	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
   394  	if err != nil {
   395  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
   396  	}
   397  	return newUnixConn(fd), nil
   398  }