...

Source file src/net/unixsock_posix.go

Documentation: net

		 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  //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
		 6  // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
		 7  
		 8  package net
		 9  
		10  import (
		11  	"context"
		12  	"errors"
		13  	"os"
		14  	"syscall"
		15  )
		16  
		17  func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctrlFn func(string, string, syscall.RawConn) error) (*netFD, error) {
		18  	var sotype int
		19  	switch net {
		20  	case "unix":
		21  		sotype = syscall.SOCK_STREAM
		22  	case "unixgram":
		23  		sotype = syscall.SOCK_DGRAM
		24  	case "unixpacket":
		25  		sotype = syscall.SOCK_SEQPACKET
		26  	default:
		27  		return nil, UnknownNetworkError(net)
		28  	}
		29  
		30  	switch mode {
		31  	case "dial":
		32  		if laddr != nil && laddr.isWildcard() {
		33  			laddr = nil
		34  		}
		35  		if raddr != nil && raddr.isWildcard() {
		36  			raddr = nil
		37  		}
		38  		if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
		39  			return nil, errMissingAddress
		40  		}
		41  	case "listen":
		42  	default:
		43  		return nil, errors.New("unknown mode: " + mode)
		44  	}
		45  
		46  	fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, ctrlFn)
		47  	if err != nil {
		48  		return nil, err
		49  	}
		50  	return fd, nil
		51  }
		52  
		53  func sockaddrToUnix(sa syscall.Sockaddr) Addr {
		54  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		55  		return &UnixAddr{Name: s.Name, Net: "unix"}
		56  	}
		57  	return nil
		58  }
		59  
		60  func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
		61  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		62  		return &UnixAddr{Name: s.Name, Net: "unixgram"}
		63  	}
		64  	return nil
		65  }
		66  
		67  func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
		68  	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		69  		return &UnixAddr{Name: s.Name, Net: "unixpacket"}
		70  	}
		71  	return nil
		72  }
		73  
		74  func sotypeToNet(sotype int) string {
		75  	switch sotype {
		76  	case syscall.SOCK_STREAM:
		77  		return "unix"
		78  	case syscall.SOCK_DGRAM:
		79  		return "unixgram"
		80  	case syscall.SOCK_SEQPACKET:
		81  		return "unixpacket"
		82  	default:
		83  		panic("sotypeToNet unknown socket type")
		84  	}
		85  }
		86  
		87  func (a *UnixAddr) family() int {
		88  	return syscall.AF_UNIX
		89  }
		90  
		91  func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
		92  	if a == nil {
		93  		return nil, nil
		94  	}
		95  	return &syscall.SockaddrUnix{Name: a.Name}, nil
		96  }
		97  
		98  func (a *UnixAddr) toLocal(net string) sockaddr {
		99  	return a
	 100  }
	 101  
	 102  func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
	 103  	var addr *UnixAddr
	 104  	n, sa, err := c.fd.readFrom(b)
	 105  	switch sa := sa.(type) {
	 106  	case *syscall.SockaddrUnix:
	 107  		if sa.Name != "" {
	 108  			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
	 109  		}
	 110  	}
	 111  	return n, addr, err
	 112  }
	 113  
	 114  func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
	 115  	var sa syscall.Sockaddr
	 116  	n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags)
	 117  	if readMsgFlags == 0 && err == nil && oobn > 0 {
	 118  		setReadMsgCloseOnExec(oob[:oobn])
	 119  	}
	 120  
	 121  	switch sa := sa.(type) {
	 122  	case *syscall.SockaddrUnix:
	 123  		if sa.Name != "" {
	 124  			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
	 125  		}
	 126  	}
	 127  	return
	 128  }
	 129  
	 130  func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
	 131  	if c.fd.isConnected {
	 132  		return 0, ErrWriteToConnected
	 133  	}
	 134  	if addr == nil {
	 135  		return 0, errMissingAddress
	 136  	}
	 137  	if addr.Net != sotypeToNet(c.fd.sotype) {
	 138  		return 0, syscall.EAFNOSUPPORT
	 139  	}
	 140  	sa := &syscall.SockaddrUnix{Name: addr.Name}
	 141  	return c.fd.writeTo(b, sa)
	 142  }
	 143  
	 144  func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
	 145  	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
	 146  		return 0, 0, ErrWriteToConnected
	 147  	}
	 148  	var sa syscall.Sockaddr
	 149  	if addr != nil {
	 150  		if addr.Net != sotypeToNet(c.fd.sotype) {
	 151  			return 0, 0, syscall.EAFNOSUPPORT
	 152  		}
	 153  		sa = &syscall.SockaddrUnix{Name: addr.Name}
	 154  	}
	 155  	return c.fd.writeMsg(b, oob, sa)
	 156  }
	 157  
	 158  func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
	 159  	fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", sd.Dialer.Control)
	 160  	if err != nil {
	 161  		return nil, err
	 162  	}
	 163  	return newUnixConn(fd), nil
	 164  }
	 165  
	 166  func (ln *UnixListener) accept() (*UnixConn, error) {
	 167  	fd, err := ln.fd.accept()
	 168  	if err != nil {
	 169  		return nil, err
	 170  	}
	 171  	return newUnixConn(fd), nil
	 172  }
	 173  
	 174  func (ln *UnixListener) close() error {
	 175  	// The operating system doesn't clean up
	 176  	// the file that announcing created, so
	 177  	// we have to clean it up ourselves.
	 178  	// There's a race here--we can't know for
	 179  	// sure whether someone else has come along
	 180  	// and replaced our socket name already--
	 181  	// but this sequence (remove then close)
	 182  	// is at least compatible with the auto-remove
	 183  	// sequence in ListenUnix. It's only non-Go
	 184  	// programs that can mess us up.
	 185  	// Even if there are racy calls to Close, we want to unlink only for the first one.
	 186  	ln.unlinkOnce.Do(func() {
	 187  		if ln.path[0] != '@' && ln.unlink {
	 188  			syscall.Unlink(ln.path)
	 189  		}
	 190  	})
	 191  	return ln.fd.Close()
	 192  }
	 193  
	 194  func (ln *UnixListener) file() (*os.File, error) {
	 195  	f, err := ln.fd.dup()
	 196  	if err != nil {
	 197  		return nil, err
	 198  	}
	 199  	return f, nil
	 200  }
	 201  
	 202  // SetUnlinkOnClose sets whether the underlying socket file should be removed
	 203  // from the file system when the listener is closed.
	 204  //
	 205  // The default behavior is to unlink the socket file only when package net created it.
	 206  // That is, when the listener and the underlying socket file were created by a call to
	 207  // Listen or ListenUnix, then by default closing the listener will remove the socket file.
	 208  // but if the listener was created by a call to FileListener to use an already existing
	 209  // socket file, then by default closing the listener will not remove the socket file.
	 210  func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
	 211  	l.unlink = unlink
	 212  }
	 213  
	 214  func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
	 215  	fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
	 216  	if err != nil {
	 217  		return nil, err
	 218  	}
	 219  	return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
	 220  }
	 221  
	 222  func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
	 223  	fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
	 224  	if err != nil {
	 225  		return nil, err
	 226  	}
	 227  	return newUnixConn(fd), nil
	 228  }
	 229  

View as plain text