...

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 aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
     6	
     7	package net
     8	
     9	import (
    10		"context"
    11		"errors"
    12		"os"
    13		"syscall"
    14	)
    15	
    16	func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctrlFn func(string, string, syscall.RawConn) error) (*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(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, ctrlFn)
    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	func (a *UnixAddr) toLocal(net string) sockaddr {
    98		return a
    99	}
   100	
   101	func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
   102		var addr *UnixAddr
   103		n, sa, err := c.fd.readFrom(b)
   104		switch sa := sa.(type) {
   105		case *syscall.SockaddrUnix:
   106			if sa.Name != "" {
   107				addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
   108			}
   109		}
   110		return n, addr, err
   111	}
   112	
   113	func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
   114		var sa syscall.Sockaddr
   115		n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
   116		switch sa := sa.(type) {
   117		case *syscall.SockaddrUnix:
   118			if sa.Name != "" {
   119				addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
   120			}
   121		}
   122		return
   123	}
   124	
   125	func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
   126		if c.fd.isConnected {
   127			return 0, ErrWriteToConnected
   128		}
   129		if addr == nil {
   130			return 0, errMissingAddress
   131		}
   132		if addr.Net != sotypeToNet(c.fd.sotype) {
   133			return 0, syscall.EAFNOSUPPORT
   134		}
   135		sa := &syscall.SockaddrUnix{Name: addr.Name}
   136		return c.fd.writeTo(b, sa)
   137	}
   138	
   139	func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
   140		if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
   141			return 0, 0, ErrWriteToConnected
   142		}
   143		var sa syscall.Sockaddr
   144		if addr != nil {
   145			if addr.Net != sotypeToNet(c.fd.sotype) {
   146				return 0, 0, syscall.EAFNOSUPPORT
   147			}
   148			sa = &syscall.SockaddrUnix{Name: addr.Name}
   149		}
   150		return c.fd.writeMsg(b, oob, sa)
   151	}
   152	
   153	func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
   154		fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", sd.Dialer.Control)
   155		if err != nil {
   156			return nil, err
   157		}
   158		return newUnixConn(fd), nil
   159	}
   160	
   161	func (ln *UnixListener) accept() (*UnixConn, error) {
   162		fd, err := ln.fd.accept()
   163		if err != nil {
   164			return nil, err
   165		}
   166		return newUnixConn(fd), nil
   167	}
   168	
   169	func (ln *UnixListener) close() error {
   170		// The operating system doesn't clean up
   171		// the file that announcing created, so
   172		// we have to clean it up ourselves.
   173		// There's a race here--we can't know for
   174		// sure whether someone else has come along
   175		// and replaced our socket name already--
   176		// but this sequence (remove then close)
   177		// is at least compatible with the auto-remove
   178		// sequence in ListenUnix. It's only non-Go
   179		// programs that can mess us up.
   180		// Even if there are racy calls to Close, we want to unlink only for the first one.
   181		ln.unlinkOnce.Do(func() {
   182			if ln.path[0] != '@' && ln.unlink {
   183				syscall.Unlink(ln.path)
   184			}
   185		})
   186		return ln.fd.Close()
   187	}
   188	
   189	func (ln *UnixListener) file() (*os.File, error) {
   190		f, err := ln.fd.dup()
   191		if err != nil {
   192			return nil, err
   193		}
   194		return f, nil
   195	}
   196	
   197	// SetUnlinkOnClose sets whether the underlying socket file should be removed
   198	// from the file system when the listener is closed.
   199	//
   200	// The default behavior is to unlink the socket file only when package net created it.
   201	// That is, when the listener and the underlying socket file were created by a call to
   202	// Listen or ListenUnix, then by default closing the listener will remove the socket file.
   203	// but if the listener was created by a call to FileListener to use an already existing
   204	// socket file, then by default closing the listener will not remove the socket file.
   205	func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
   206		l.unlink = unlink
   207	}
   208	
   209	func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
   210		fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
   211		if err != nil {
   212			return nil, err
   213		}
   214		return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
   215	}
   216	
   217	func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
   218		fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
   219		if err != nil {
   220			return nil, err
   221		}
   222		return newUnixConn(fd), nil
   223	}
   224	

View as plain text