rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/unixsock_posix.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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows 6 7 package net 8 9 import ( 10 "errors" 11 "os" 12 "syscall" 13 "time" 14 ) 15 16 func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Time) (*netFD, error) { 17 var sotype int 18 switch net { 19 case "unix": 20 sotype = syscall.SOCK_STREAM 21 case "unixgram": 22 sotype = syscall.SOCK_DGRAM 23 case "unixpacket": 24 sotype = syscall.SOCK_SEQPACKET 25 default: 26 return nil, UnknownNetworkError(net) 27 } 28 29 switch mode { 30 case "dial": 31 if laddr != nil && laddr.isWildcard() { 32 laddr = nil 33 } 34 if raddr != nil && raddr.isWildcard() { 35 raddr = nil 36 } 37 if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) { 38 return nil, errMissingAddress 39 } 40 case "listen": 41 default: 42 return nil, errors.New("unknown mode: " + mode) 43 } 44 45 fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline) 46 if err != nil { 47 return nil, err 48 } 49 return fd, nil 50 } 51 52 func sockaddrToUnix(sa syscall.Sockaddr) Addr { 53 if s, ok := sa.(*syscall.SockaddrUnix); ok { 54 return &UnixAddr{Name: s.Name, Net: "unix"} 55 } 56 return nil 57 } 58 59 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { 60 if s, ok := sa.(*syscall.SockaddrUnix); ok { 61 return &UnixAddr{Name: s.Name, Net: "unixgram"} 62 } 63 return nil 64 } 65 66 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { 67 if s, ok := sa.(*syscall.SockaddrUnix); ok { 68 return &UnixAddr{Name: s.Name, Net: "unixpacket"} 69 } 70 return nil 71 } 72 73 func sotypeToNet(sotype int) string { 74 switch sotype { 75 case syscall.SOCK_STREAM: 76 return "unix" 77 case syscall.SOCK_DGRAM: 78 return "unixgram" 79 case syscall.SOCK_SEQPACKET: 80 return "unixpacket" 81 default: 82 panic("sotypeToNet unknown socket type") 83 } 84 } 85 86 func (a *UnixAddr) family() int { 87 return syscall.AF_UNIX 88 } 89 90 func (a *UnixAddr) isWildcard() bool { 91 return a == nil || a.Name == "" 92 } 93 94 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) { 95 if a == nil { 96 return nil, nil 97 } 98 return &syscall.SockaddrUnix{Name: a.Name}, nil 99 } 100 101 // UnixConn is an implementation of the Conn interface for connections 102 // to Unix domain sockets. 103 type UnixConn struct { 104 conn 105 } 106 107 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } 108 109 // ReadFromUnix reads a packet from c, copying the payload into b. It 110 // returns the number of bytes copied into b and the source address of 111 // the packet. 112 // 113 // ReadFromUnix can be made to time out and return an error with 114 // Timeout() == true after a fixed time limit; see SetDeadline and 115 // SetReadDeadline. 116 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { 117 if !c.ok() { 118 return 0, nil, syscall.EINVAL 119 } 120 n, sa, err := c.fd.readFrom(b) 121 switch sa := sa.(type) { 122 case *syscall.SockaddrUnix: 123 if sa.Name != "" { 124 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 125 } 126 } 127 return 128 } 129 130 // ReadFrom implements the PacketConn ReadFrom method. 131 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { 132 if !c.ok() { 133 return 0, nil, syscall.EINVAL 134 } 135 n, addr, err := c.ReadFromUnix(b) 136 if addr == nil { 137 return n, nil, err 138 } 139 return n, addr, err 140 } 141 142 // ReadMsgUnix reads a packet from c, copying the payload into b and 143 // the associated out-of-band data into oob. It returns the number of 144 // bytes copied into b, the number of bytes copied into oob, the flags 145 // that were set on the packet, and the source address of the packet. 146 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) { 147 if !c.ok() { 148 return 0, 0, 0, nil, syscall.EINVAL 149 } 150 n, oobn, flags, sa, err := c.fd.readMsg(b, oob) 151 switch sa := sa.(type) { 152 case *syscall.SockaddrUnix: 153 if sa.Name != "" { 154 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} 155 } 156 } 157 return 158 } 159 160 // WriteToUnix writes a packet to addr via c, copying the payload from b. 161 // 162 // WriteToUnix can be made to time out and return an error with 163 // Timeout() == true after a fixed time limit; see SetDeadline and 164 // SetWriteDeadline. On packet-oriented connections, write timeouts 165 // are rare. 166 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { 167 if !c.ok() { 168 return 0, syscall.EINVAL 169 } 170 if c.fd.isConnected { 171 return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} 172 } 173 if addr == nil { 174 return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} 175 } 176 if addr.Net != sotypeToNet(c.fd.sotype) { 177 return 0, syscall.EAFNOSUPPORT 178 } 179 sa := &syscall.SockaddrUnix{Name: addr.Name} 180 return c.fd.writeTo(b, sa) 181 } 182 183 // WriteTo implements the PacketConn WriteTo method. 184 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) { 185 if !c.ok() { 186 return 0, syscall.EINVAL 187 } 188 a, ok := addr.(*UnixAddr) 189 if !ok { 190 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} 191 } 192 return c.WriteToUnix(b, a) 193 } 194 195 // WriteMsgUnix writes a packet to addr via c, copying the payload 196 // from b and the associated out-of-band data from oob. It returns 197 // the number of payload and out-of-band bytes written. 198 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) { 199 if !c.ok() { 200 return 0, 0, syscall.EINVAL 201 } 202 if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { 203 return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} 204 } 205 if addr != nil { 206 if addr.Net != sotypeToNet(c.fd.sotype) { 207 return 0, 0, syscall.EAFNOSUPPORT 208 } 209 sa := &syscall.SockaddrUnix{Name: addr.Name} 210 return c.fd.writeMsg(b, oob, sa) 211 } 212 return c.fd.writeMsg(b, oob, nil) 213 } 214 215 // CloseRead shuts down the reading side of the Unix domain connection. 216 // Most callers should just use Close. 217 func (c *UnixConn) CloseRead() error { 218 if !c.ok() { 219 return syscall.EINVAL 220 } 221 return c.fd.closeRead() 222 } 223 224 // CloseWrite shuts down the writing side of the Unix domain connection. 225 // Most callers should just use Close. 226 func (c *UnixConn) CloseWrite() error { 227 if !c.ok() { 228 return syscall.EINVAL 229 } 230 return c.fd.closeWrite() 231 } 232 233 // DialUnix connects to the remote address raddr on the network net, 234 // which must be "unix", "unixgram" or "unixpacket". If laddr is not 235 // nil, it is used as the local address for the connection. 236 func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { 237 switch net { 238 case "unix", "unixgram", "unixpacket": 239 default: 240 return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)} 241 } 242 return dialUnix(net, laddr, raddr, noDeadline) 243 } 244 245 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { 246 fd, err := unixSocket(net, laddr, raddr, "dial", deadline) 247 if err != nil { 248 return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err} 249 } 250 return newUnixConn(fd), nil 251 } 252 253 // UnixListener is a Unix domain socket listener. Clients should 254 // typically use variables of type Listener instead of assuming Unix 255 // domain sockets. 256 type UnixListener struct { 257 fd *netFD 258 path string 259 } 260 261 // ListenUnix announces on the Unix domain socket laddr and returns a 262 // Unix listener. The network net must be "unix" or "unixpacket". 263 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { 264 switch net { 265 case "unix", "unixpacket": 266 default: 267 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} 268 } 269 if laddr == nil { 270 return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} 271 } 272 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) 273 if err != nil { 274 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} 275 } 276 return &UnixListener{fd, fd.laddr.String()}, nil 277 } 278 279 // AcceptUnix accepts the next incoming call and returns the new 280 // connection. 281 func (l *UnixListener) AcceptUnix() (*UnixConn, error) { 282 if l == nil || l.fd == nil { 283 return nil, syscall.EINVAL 284 } 285 fd, err := l.fd.accept() 286 if err != nil { 287 return nil, err 288 } 289 c := newUnixConn(fd) 290 return c, nil 291 } 292 293 // Accept implements the Accept method in the Listener interface; it 294 // waits for the next call and returns a generic Conn. 295 func (l *UnixListener) Accept() (c Conn, err error) { 296 c1, err := l.AcceptUnix() 297 if err != nil { 298 return nil, err 299 } 300 return c1, nil 301 } 302 303 // Close stops listening on the Unix address. Already accepted 304 // connections are not closed. 305 func (l *UnixListener) Close() error { 306 if l == nil || l.fd == nil { 307 return syscall.EINVAL 308 } 309 310 // The operating system doesn't clean up 311 // the file that announcing created, so 312 // we have to clean it up ourselves. 313 // There's a race here--we can't know for 314 // sure whether someone else has come along 315 // and replaced our socket name already-- 316 // but this sequence (remove then close) 317 // is at least compatible with the auto-remove 318 // sequence in ListenUnix. It's only non-Go 319 // programs that can mess us up. 320 if l.path[0] != '@' { 321 syscall.Unlink(l.path) 322 } 323 return l.fd.Close() 324 } 325 326 // Addr returns the listener's network address. 327 // The Addr returned is shared by all invocations of Addr, so 328 // do not modify it. 329 func (l *UnixListener) Addr() Addr { return l.fd.laddr } 330 331 // SetDeadline sets the deadline associated with the listener. 332 // A zero time value disables the deadline. 333 func (l *UnixListener) SetDeadline(t time.Time) (err error) { 334 if l == nil || l.fd == nil { 335 return syscall.EINVAL 336 } 337 return l.fd.setDeadline(t) 338 } 339 340 // File returns a copy of the underlying os.File, set to blocking 341 // mode. It is the caller's responsibility to close f when finished. 342 // Closing l does not affect f, and closing f does not affect l. 343 // 344 // The returned os.File's file descriptor is different from the 345 // connection's. Attempting to change properties of the original 346 // using this duplicate may or may not have the desired effect. 347 func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() } 348 349 // ListenUnixgram listens for incoming Unix datagram packets addressed 350 // to the local address laddr. The network net must be "unixgram". 351 // The returned connection's ReadFrom and WriteTo methods can be used 352 // to receive and send packets with per-packet addressing. 353 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { 354 switch net { 355 case "unixgram": 356 default: 357 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} 358 } 359 if laddr == nil { 360 return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} 361 } 362 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) 363 if err != nil { 364 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} 365 } 366 return newUnixConn(fd), nil 367 }