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