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