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