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

View as plain text