Run Format

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

View as plain text