...
Run Format

Source file src/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 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	}
   399	

View as plain text