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