* gcc-interface/gigi.h (fill_vms_descriptor): Take GNU_TYPE instead of
[official-gcc.git] / libgo / go / net / unixsock.go
blob8c26a7bafd50a8ed4f52d42d64364987dbce0512
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.
5 // Unix domain sockets
7 package net
9 import (
10 "os"
11 "syscall"
14 func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
15 var proto int
16 switch net {
17 default:
18 return nil, UnknownNetworkError(net)
19 case "unix":
20 proto = syscall.SOCK_STREAM
21 case "unixgram":
22 proto = syscall.SOCK_DGRAM
23 case "unixpacket":
24 proto = syscall.SOCK_SEQPACKET
27 var la, ra syscall.Sockaddr
28 switch mode {
29 default:
30 panic("unixSocket mode " + mode)
32 case "dial":
33 if laddr != nil {
34 la = &syscall.SockaddrUnix{Name: laddr.Name}
36 if raddr != nil {
37 ra = &syscall.SockaddrUnix{Name: raddr.Name}
38 } else if proto != syscall.SOCK_DGRAM || laddr == nil {
39 return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
42 case "listen":
43 if laddr == nil {
44 return nil, &OpError{mode, net, nil, errMissingAddress}
46 la = &syscall.SockaddrUnix{Name: laddr.Name}
47 if raddr != nil {
48 return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
52 f := sockaddrToUnix
53 if proto == syscall.SOCK_DGRAM {
54 f = sockaddrToUnixgram
55 } else if proto == syscall.SOCK_SEQPACKET {
56 f = sockaddrToUnixpacket
59 fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
60 if oserr != nil {
61 goto Error
63 return fd, nil
65 Error:
66 addr := raddr
67 if mode == "listen" {
68 addr = laddr
70 return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
73 // UnixAddr represents the address of a Unix domain socket end point.
74 type UnixAddr struct {
75 Name string
76 Net string
79 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
80 if s, ok := sa.(*syscall.SockaddrUnix); ok {
81 return &UnixAddr{s.Name, "unix"}
83 return nil
86 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
87 if s, ok := sa.(*syscall.SockaddrUnix); ok {
88 return &UnixAddr{s.Name, "unixgram"}
90 return nil
93 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
94 if s, ok := sa.(*syscall.SockaddrUnix); ok {
95 return &UnixAddr{s.Name, "unixpacket"}
97 return nil
100 func protoToNet(proto int) string {
101 switch proto {
102 case syscall.SOCK_STREAM:
103 return "unix"
104 case syscall.SOCK_SEQPACKET:
105 return "unixpacket"
106 case syscall.SOCK_DGRAM:
107 return "unixgram"
108 default:
109 panic("protoToNet unknown protocol")
111 return ""
114 // Network returns the address's network name, "unix" or "unixgram".
115 func (a *UnixAddr) Network() string {
116 return a.Net
119 func (a *UnixAddr) String() string {
120 if a == nil {
121 return "<nil>"
123 return a.Name
126 func (a *UnixAddr) toAddr() Addr {
127 if a == nil { // nil *UnixAddr
128 return nil // nil interface
130 return a
133 // ResolveUnixAddr parses addr as a Unix domain socket address.
134 // The string net gives the network name, "unix", "unixgram" or
135 // "unixpacket".
136 func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
137 switch net {
138 case "unix":
139 case "unixpacket":
140 case "unixgram":
141 default:
142 return nil, UnknownNetworkError(net)
144 return &UnixAddr{addr, net}, nil
147 // UnixConn is an implementation of the Conn interface
148 // for connections to Unix domain sockets.
149 type UnixConn struct {
150 fd *netFD
153 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
155 func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
157 // Implementation of the Conn interface - see Conn for documentation.
159 // Read implements the net.Conn Read method.
160 func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
161 if !c.ok() {
162 return 0, os.EINVAL
164 return c.fd.Read(b)
167 // Write implements the net.Conn Write method.
168 func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
169 if !c.ok() {
170 return 0, os.EINVAL
172 return c.fd.Write(b)
175 // Close closes the Unix domain connection.
176 func (c *UnixConn) Close() os.Error {
177 if !c.ok() {
178 return os.EINVAL
180 err := c.fd.Close()
181 c.fd = nil
182 return err
185 // LocalAddr returns the local network address, a *UnixAddr.
186 // Unlike in other protocols, LocalAddr is usually nil for dialed connections.
187 func (c *UnixConn) LocalAddr() Addr {
188 if !c.ok() {
189 return nil
191 return c.fd.laddr
194 // RemoteAddr returns the remote network address, a *UnixAddr.
195 // Unlike in other protocols, RemoteAddr is usually nil for connections
196 // accepted by a listener.
197 func (c *UnixConn) RemoteAddr() Addr {
198 if !c.ok() {
199 return nil
201 return c.fd.raddr
204 // SetTimeout implements the net.Conn SetTimeout method.
205 func (c *UnixConn) SetTimeout(nsec int64) os.Error {
206 if !c.ok() {
207 return os.EINVAL
209 return setTimeout(c.fd, nsec)
212 // SetReadTimeout implements the net.Conn SetReadTimeout method.
213 func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
214 if !c.ok() {
215 return os.EINVAL
217 return setReadTimeout(c.fd, nsec)
220 // SetWriteTimeout implements the net.Conn SetWriteTimeout method.
221 func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
222 if !c.ok() {
223 return os.EINVAL
225 return setWriteTimeout(c.fd, nsec)
228 // SetReadBuffer sets the size of the operating system's
229 // receive buffer associated with the connection.
230 func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
231 if !c.ok() {
232 return os.EINVAL
234 return setReadBuffer(c.fd, bytes)
237 // SetWriteBuffer sets the size of the operating system's
238 // transmit buffer associated with the connection.
239 func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
240 if !c.ok() {
241 return os.EINVAL
243 return setWriteBuffer(c.fd, bytes)
246 // ReadFromUnix reads a packet from c, copying the payload into b.
247 // It returns the number of bytes copied into b and the return address
248 // that was on the packet.
250 // ReadFromUnix can be made to time out and return
251 // an error with Timeout() == true after a fixed time limit;
252 // see SetTimeout and SetReadTimeout.
253 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
254 if !c.ok() {
255 return 0, nil, os.EINVAL
257 n, sa, err := c.fd.ReadFrom(b)
258 switch sa := sa.(type) {
259 case *syscall.SockaddrUnix:
260 addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
262 return
265 // ReadFrom implements the net.PacketConn ReadFrom method.
266 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
267 if !c.ok() {
268 return 0, nil, os.EINVAL
270 n, uaddr, err := c.ReadFromUnix(b)
271 return n, uaddr.toAddr(), err
274 // WriteToUnix writes a packet to addr via c, copying the payload from b.
276 // WriteToUnix can be made to time out and return
277 // an error with Timeout() == true after a fixed time limit;
278 // see SetTimeout and SetWriteTimeout.
279 // On packet-oriented connections, write timeouts are rare.
280 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
281 if !c.ok() {
282 return 0, os.EINVAL
284 if addr.Net != protoToNet(c.fd.proto) {
285 return 0, os.EAFNOSUPPORT
287 sa := &syscall.SockaddrUnix{Name: addr.Name}
288 return c.fd.WriteTo(b, sa)
291 // WriteTo implements the net.PacketConn WriteTo method.
292 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
293 if !c.ok() {
294 return 0, os.EINVAL
296 a, ok := addr.(*UnixAddr)
297 if !ok {
298 return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
300 return c.WriteToUnix(b, a)
303 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
304 if !c.ok() {
305 return 0, 0, 0, nil, os.EINVAL
307 n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
308 switch sa := sa.(type) {
309 case *syscall.SockaddrUnix:
310 addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
312 return
315 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
316 if !c.ok() {
317 return 0, 0, os.EINVAL
319 if addr != nil {
320 if addr.Net != protoToNet(c.fd.proto) {
321 return 0, 0, os.EAFNOSUPPORT
323 sa := &syscall.SockaddrUnix{Name: addr.Name}
324 return c.fd.WriteMsg(b, oob, sa)
326 return c.fd.WriteMsg(b, oob, nil)
329 // File returns a copy of the underlying os.File, set to blocking mode.
330 // It is the caller's responsibility to close f when finished.
331 // Closing c does not affect f, and closing f does not affect c.
332 func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
334 // DialUnix connects to the remote address raddr on the network net,
335 // which must be "unix" or "unixgram". If laddr is not nil, it is used
336 // as the local address for the connection.
337 func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
338 fd, e := unixSocket(net, laddr, raddr, "dial")
339 if e != nil {
340 return nil, e
342 return newUnixConn(fd), nil
345 // UnixListener is a Unix domain socket listener.
346 // Clients should typically use variables of type Listener
347 // instead of assuming Unix domain sockets.
348 type UnixListener struct {
349 fd *netFD
350 path string
353 // ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
354 // Net must be "unix" (stream sockets).
355 func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
356 if net != "unix" && net != "unixgram" && net != "unixpacket" {
357 return nil, UnknownNetworkError(net)
359 if laddr != nil {
360 laddr = &UnixAddr{laddr.Name, net} // make our own copy
362 fd, err := unixSocket(net, laddr, nil, "listen")
363 if err != nil {
364 return nil, err
366 e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
367 if e1 != 0 {
368 closesocket(fd.sysfd)
369 return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
371 return &UnixListener{fd, laddr.Name}, nil
374 // AcceptUnix accepts the next incoming call and returns the new connection
375 // and the remote address.
376 func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
377 if l == nil || l.fd == nil {
378 return nil, os.EINVAL
380 fd, e := l.fd.accept(sockaddrToUnix)
381 if e != nil {
382 return nil, e
384 c = newUnixConn(fd)
385 return c, nil
388 // Accept implements the Accept method in the Listener interface;
389 // it waits for the next call and returns a generic Conn.
390 func (l *UnixListener) Accept() (c Conn, err os.Error) {
391 c1, err := l.AcceptUnix()
392 if err != nil {
393 return nil, err
395 return c1, nil
398 // Close stops listening on the Unix address.
399 // Already accepted connections are not closed.
400 func (l *UnixListener) Close() os.Error {
401 if l == nil || l.fd == nil {
402 return os.EINVAL
405 // The operating system doesn't clean up
406 // the file that announcing created, so
407 // we have to clean it up ourselves.
408 // There's a race here--we can't know for
409 // sure whether someone else has come along
410 // and replaced our socket name already--
411 // but this sequence (remove then close)
412 // is at least compatible with the auto-remove
413 // sequence in ListenUnix. It's only non-Go
414 // programs that can mess us up.
415 if l.path[0] != '@' {
416 syscall.Unlink(l.path)
418 err := l.fd.Close()
419 l.fd = nil
420 return err
423 // Addr returns the listener's network address.
424 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
426 // File returns a copy of the underlying os.File, set to blocking mode.
427 // It is the caller's responsibility to close f when finished.
428 // Closing c does not affect f, and closing f does not affect c.
429 func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
431 // ListenUnixgram listens for incoming Unix datagram packets addressed to the
432 // local address laddr. The returned connection c's ReadFrom
433 // and WriteTo methods can be used to receive and send UDP
434 // packets with per-packet addressing. The network net must be "unixgram".
435 func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
436 switch net {
437 case "unixgram":
438 default:
439 return nil, UnknownNetworkError(net)
441 if laddr == nil {
442 return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
444 fd, e := unixSocket(net, laddr, nil, "listen")
445 if e != nil {
446 return nil, e
448 return newUDPConn(fd), nil