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