github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/unixsock_posix.go (about) 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 }