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