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