src/pkg/net/unixsock_posix.go - The Go Programming Language

Golang

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