...

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

View as plain text