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