github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/net/unixsock.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 package net 6 7 import ( 8 "context" 9 "os" 10 "sync" 11 "syscall" 12 "time" 13 ) 14 15 // BUG(mikio): On JS, NaCl and Plan 9, methods and functions related 16 // to UnixConn and UnixListener are not implemented. 17 18 // BUG(mikio): On Windows, methods and functions related to UnixConn 19 // and UnixListener don't work for "unixgram" and "unixpacket". 20 21 // UnixAddr represents the address of a Unix domain socket end point. 22 type UnixAddr struct { 23 Name string 24 Net string 25 } 26 27 // Network returns the address's network name, "unix", "unixgram" or 28 // "unixpacket". 29 func (a *UnixAddr) Network() string { 30 return a.Net 31 } 32 33 func (a *UnixAddr) String() string { 34 if a == nil { 35 return "<nil>" 36 } 37 return a.Name 38 } 39 40 func (a *UnixAddr) isWildcard() bool { 41 return a == nil || a.Name == "" 42 } 43 44 func (a *UnixAddr) opAddr() Addr { 45 if a == nil { 46 return nil 47 } 48 return a 49 } 50 51 // ResolveUnixAddr returns an address of Unix domain socket end point. 52 // 53 // The network must be a Unix network name. 54 // 55 // See func Dial for a description of the network and address 56 // parameters. 57 func ResolveUnixAddr(network, address string) (*UnixAddr, error) { 58 switch network { 59 case "unix", "unixgram", "unixpacket": 60 return &UnixAddr{Name: address, Net: network}, nil 61 default: 62 return nil, UnknownNetworkError(network) 63 } 64 } 65 66 // UnixConn is an implementation of the Conn interface for connections 67 // to Unix domain sockets. 68 type UnixConn struct { 69 conn 70 } 71 72 // SyscallConn returns a raw network connection. 73 // This implements the syscall.Conn interface. 74 func (c *UnixConn) SyscallConn() (syscall.RawConn, error) { 75 if !c.ok() { 76 return nil, syscall.EINVAL 77 } 78 return newRawConn(c.fd) 79 } 80 81 // CloseRead shuts down the reading side of the Unix domain connection. 82 // Most callers should just use Close. 83 func (c *UnixConn) CloseRead() error { 84 if !c.ok() { 85 return syscall.EINVAL 86 } 87 if err := c.fd.closeRead(); err != nil { 88 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 89 } 90 return nil 91 } 92 93 // CloseWrite shuts down the writing side of the Unix domain connection. 94 // Most callers should just use Close. 95 func (c *UnixConn) CloseWrite() error { 96 if !c.ok() { 97 return syscall.EINVAL 98 } 99 if err := c.fd.closeWrite(); err != nil { 100 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 101 } 102 return nil 103 } 104 105 // ReadFromUnix acts like ReadFrom but returns a UnixAddr. 106 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { 107 if !c.ok() { 108 return 0, nil, syscall.EINVAL 109 } 110 n, addr, err := c.readFrom(b) 111 if err != nil { 112 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 113 } 114 return n, addr, err 115 } 116 117 // ReadFrom implements the PacketConn ReadFrom method. 118 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { 119 if !c.ok() { 120 return 0, nil, syscall.EINVAL 121 } 122 n, addr, err := c.readFrom(b) 123 if err != nil { 124 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 125 } 126 if addr == nil { 127 return n, nil, err 128 } 129 return n, addr, err 130 } 131 132 // ReadMsgUnix reads a message from c, copying the payload into b and 133 // the associated out-of-band data into oob. It returns the number of 134 // bytes copied into b, the number of bytes copied into oob, the flags 135 // that were set on the message and the source address of the message. 136 // 137 // Note that if len(b) == 0 and len(oob) > 0, this function will still 138 // read (and discard) 1 byte from the connection. 139 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { 140 if !c.ok() { 141 return 0, 0, 0, nil, syscall.EINVAL 142 } 143 n, oobn, flags, addr, err = c.readMsg(b, oob) 144 if err != nil { 145 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 146 } 147 return 148 } 149 150 // WriteToUnix acts like WriteTo but takes a UnixAddr. 151 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { 152 if !c.ok() { 153 return 0, syscall.EINVAL 154 } 155 n, err := c.writeTo(b, addr) 156 if err != nil { 157 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} 158 } 159 return n, err 160 } 161 162 // WriteTo implements the PacketConn WriteTo method. 163 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) { 164 if !c.ok() { 165 return 0, syscall.EINVAL 166 } 167 a, ok := addr.(*UnixAddr) 168 if !ok { 169 return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} 170 } 171 n, err := c.writeTo(b, a) 172 if err != nil { 173 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err} 174 } 175 return n, err 176 } 177 178 // WriteMsgUnix writes a message to addr via c, copying the payload 179 // from b and the associated out-of-band data from oob. It returns the 180 // number of payload and out-of-band bytes written. 181 // 182 // Note that if len(b) == 0 and len(oob) > 0, this function will still 183 // write 1 byte to the connection. 184 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { 185 if !c.ok() { 186 return 0, 0, syscall.EINVAL 187 } 188 n, oobn, err = c.writeMsg(b, oob, addr) 189 if err != nil { 190 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} 191 } 192 return 193 } 194 195 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } 196 197 // DialUnix acts like Dial for Unix networks. 198 // 199 // The network must be a Unix network name; see func Dial for details. 200 // 201 // If laddr is non-nil, it is used as the local address for the 202 // connection. 203 func DialUnix(network string, laddr, raddr *UnixAddr) (*UnixConn, error) { 204 switch network { 205 case "unix", "unixgram", "unixpacket": 206 default: 207 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)} 208 } 209 sd := &sysDialer{network: network, address: raddr.String()} 210 c, err := sd.dialUnix(context.Background(), laddr, raddr) 211 if err != nil { 212 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} 213 } 214 return c, nil 215 } 216 217 // UnixListener is a Unix domain socket listener. Clients should 218 // typically use variables of type Listener instead of assuming Unix 219 // domain sockets. 220 type UnixListener struct { 221 fd *netFD 222 path string 223 unlink bool 224 unlinkOnce sync.Once 225 } 226 227 func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil } 228 229 // SyscallConn returns a raw network connection. 230 // This implements the syscall.Conn interface. 231 // 232 // The returned RawConn only supports calling Control. Read and 233 // Write return an error. 234 func (l *UnixListener) SyscallConn() (syscall.RawConn, error) { 235 if !l.ok() { 236 return nil, syscall.EINVAL 237 } 238 return newRawListener(l.fd) 239 } 240 241 // AcceptUnix accepts the next incoming call and returns the new 242 // connection. 243 func (l *UnixListener) AcceptUnix() (*UnixConn, error) { 244 if !l.ok() { 245 return nil, syscall.EINVAL 246 } 247 c, err := l.accept() 248 if err != nil { 249 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 250 } 251 return c, nil 252 } 253 254 // Accept implements the Accept method in the Listener interface. 255 // Returned connections will be of type *UnixConn. 256 func (l *UnixListener) Accept() (Conn, error) { 257 if !l.ok() { 258 return nil, syscall.EINVAL 259 } 260 c, err := l.accept() 261 if err != nil { 262 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 263 } 264 return c, nil 265 } 266 267 // Close stops listening on the Unix address. Already accepted 268 // connections are not closed. 269 func (l *UnixListener) Close() error { 270 if !l.ok() { 271 return syscall.EINVAL 272 } 273 if err := l.close(); err != nil { 274 return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 275 } 276 return nil 277 } 278 279 // Addr returns the listener's network address. 280 // The Addr returned is shared by all invocations of Addr, so 281 // do not modify it. 282 func (l *UnixListener) Addr() Addr { return l.fd.laddr } 283 284 // SetDeadline sets the deadline associated with the listener. 285 // A zero time value disables the deadline. 286 func (l *UnixListener) SetDeadline(t time.Time) error { 287 if !l.ok() { 288 return syscall.EINVAL 289 } 290 if err := l.fd.pfd.SetDeadline(t); err != nil { 291 return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 292 } 293 return nil 294 } 295 296 // File returns a copy of the underlying os.File. 297 // It is the caller's responsibility to close f when finished. 298 // Closing l does not affect f, and closing f does not affect l. 299 // 300 // The returned os.File's file descriptor is different from the 301 // connection's. Attempting to change properties of the original 302 // using this duplicate may or may not have the desired effect. 303 func (l *UnixListener) File() (f *os.File, err error) { 304 if !l.ok() { 305 return nil, syscall.EINVAL 306 } 307 f, err = l.file() 308 if err != nil { 309 err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 310 } 311 return 312 } 313 314 // ListenUnix acts like Listen for Unix networks. 315 // 316 // The network must be "unix" or "unixpacket". 317 func ListenUnix(network string, laddr *UnixAddr) (*UnixListener, error) { 318 switch network { 319 case "unix", "unixpacket": 320 default: 321 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)} 322 } 323 if laddr == nil { 324 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress} 325 } 326 sl := &sysListener{network: network, address: laddr.String()} 327 ln, err := sl.listenUnix(context.Background(), laddr) 328 if err != nil { 329 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} 330 } 331 return ln, nil 332 } 333 334 // ListenUnixgram acts like ListenPacket for Unix networks. 335 // 336 // The network must be "unixgram". 337 func ListenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error) { 338 switch network { 339 case "unixgram": 340 default: 341 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)} 342 } 343 if laddr == nil { 344 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: errMissingAddress} 345 } 346 sl := &sysListener{network: network, address: laddr.String()} 347 c, err := sl.listenUnixgram(context.Background(), laddr) 348 if err != nil { 349 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} 350 } 351 return c, nil 352 }