OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // +build darwin freebsd linux netbsd openbsd windows | 5 // +build darwin freebsd linux netbsd openbsd windows |
6 | 6 |
7 // Unix domain sockets | 7 // Unix domain sockets |
8 | 8 |
9 package net | 9 package net |
10 | 10 |
11 import ( | 11 import ( |
| 12 "errors" |
12 "os" | 13 "os" |
13 "syscall" | 14 "syscall" |
14 "time" | 15 "time" |
15 ) | 16 ) |
16 | 17 |
17 func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
ime) (fd *netFD, err error) { | 18 func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
ime) (*netFD, error) { |
18 var sotype int | 19 var sotype int |
19 switch net { | 20 switch net { |
20 default: | |
21 return nil, UnknownNetworkError(net) | |
22 case "unix": | 21 case "unix": |
23 sotype = syscall.SOCK_STREAM | 22 sotype = syscall.SOCK_STREAM |
24 case "unixgram": | 23 case "unixgram": |
25 sotype = syscall.SOCK_DGRAM | 24 sotype = syscall.SOCK_DGRAM |
26 case "unixpacket": | 25 case "unixpacket": |
27 sotype = syscall.SOCK_SEQPACKET | 26 sotype = syscall.SOCK_SEQPACKET |
| 27 default: |
| 28 return nil, UnknownNetworkError(net) |
28 } | 29 } |
29 | 30 |
30 var la, ra syscall.Sockaddr | 31 var la, ra syscall.Sockaddr |
31 switch mode { | 32 switch mode { |
32 default: | |
33 panic("unixSocket mode " + mode) | |
34 | |
35 case "dial": | 33 case "dial": |
36 if laddr != nil { | 34 if laddr != nil { |
37 la = &syscall.SockaddrUnix{Name: laddr.Name} | 35 la = &syscall.SockaddrUnix{Name: laddr.Name} |
38 } | 36 } |
39 if raddr != nil { | 37 if raddr != nil { |
40 ra = &syscall.SockaddrUnix{Name: raddr.Name} | 38 ra = &syscall.SockaddrUnix{Name: raddr.Name} |
41 } else if sotype != syscall.SOCK_DGRAM || laddr == nil { | 39 } else if sotype != syscall.SOCK_DGRAM || laddr == nil { |
42 return nil, &OpError{Op: mode, Net: net, Err: errMissing
Address} | 40 return nil, &OpError{Op: mode, Net: net, Err: errMissing
Address} |
43 } | 41 } |
44 | |
45 case "listen": | 42 case "listen": |
46 if laddr == nil { | |
47 return nil, &OpError{mode, net, nil, errMissingAddress} | |
48 } | |
49 la = &syscall.SockaddrUnix{Name: laddr.Name} | 43 la = &syscall.SockaddrUnix{Name: laddr.Name} |
50 » » if raddr != nil { | 44 » default: |
51 » » » return nil, &OpError{Op: mode, Net: net, Addr: raddr, Er
r: &AddrError{Err: "unexpected remote address", Addr: raddr.String()}} | 45 » » return nil, errors.New("unknown mode: " + mode) |
52 » » } | |
53 } | 46 } |
54 | 47 |
55 f := sockaddrToUnix | 48 f := sockaddrToUnix |
56 if sotype == syscall.SOCK_DGRAM { | 49 if sotype == syscall.SOCK_DGRAM { |
57 f = sockaddrToUnixgram | 50 f = sockaddrToUnixgram |
58 } else if sotype == syscall.SOCK_SEQPACKET { | 51 } else if sotype == syscall.SOCK_SEQPACKET { |
59 f = sockaddrToUnixpacket | 52 f = sockaddrToUnixpacket |
60 } | 53 } |
61 | 54 |
62 » fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, deadlin
e, f) | 55 » fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, deadli
ne, f) |
63 if err != nil { | 56 if err != nil { |
64 » » goto Error | 57 » » goto error |
65 } | 58 } |
66 return fd, nil | 59 return fd, nil |
67 | 60 |
68 Error: | 61 error: |
69 addr := raddr | 62 addr := raddr |
70 » if mode == "listen" { | 63 » switch mode { |
| 64 » case "listen": |
71 addr = laddr | 65 addr = laddr |
72 } | 66 } |
73 return nil, &OpError{Op: mode, Net: net, Addr: addr, Err: err} | 67 return nil, &OpError{Op: mode, Net: net, Addr: addr, Err: err} |
74 } | 68 } |
75 | 69 |
76 func sockaddrToUnix(sa syscall.Sockaddr) Addr { | 70 func sockaddrToUnix(sa syscall.Sockaddr) Addr { |
77 if s, ok := sa.(*syscall.SockaddrUnix); ok { | 71 if s, ok := sa.(*syscall.SockaddrUnix); ok { |
78 return &UnixAddr{s.Name, "unix"} | 72 return &UnixAddr{s.Name, "unix"} |
79 } | 73 } |
80 return nil | 74 return nil |
(...skipping 20 matching lines...) Expand all Loading... |
101 case syscall.SOCK_SEQPACKET: | 95 case syscall.SOCK_SEQPACKET: |
102 return "unixpacket" | 96 return "unixpacket" |
103 case syscall.SOCK_DGRAM: | 97 case syscall.SOCK_DGRAM: |
104 return "unixgram" | 98 return "unixgram" |
105 default: | 99 default: |
106 panic("sotypeToNet unknown socket type") | 100 panic("sotypeToNet unknown socket type") |
107 } | 101 } |
108 return "" | 102 return "" |
109 } | 103 } |
110 | 104 |
111 // UnixConn is an implementation of the Conn interface | 105 // UnixConn is an implementation of the Conn interface for connections |
112 // for connections to Unix domain sockets. | 106 // to Unix domain sockets. |
113 type UnixConn struct { | 107 type UnixConn struct { |
114 conn | 108 conn |
115 } | 109 } |
116 | 110 |
117 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } | 111 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } |
118 | 112 |
119 // ReadFromUnix reads a packet from c, copying the payload into b. | 113 // ReadFromUnix reads a packet from c, copying the payload into b. It |
120 // It returns the number of bytes copied into b and the source address | 114 // returns the number of bytes copied into b and the source address of |
121 // of the packet. | 115 // the packet. |
122 // | 116 // |
123 // ReadFromUnix can be made to time out and return | 117 // ReadFromUnix can be made to time out and return an error with |
124 // an error with Timeout() == true after a fixed time limit; | 118 // Timeout() == true after a fixed time limit; see SetDeadline and |
125 // see SetDeadline and SetReadDeadline. | 119 // SetReadDeadline. |
126 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { | 120 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { |
127 if !c.ok() { | 121 if !c.ok() { |
128 return 0, nil, syscall.EINVAL | 122 return 0, nil, syscall.EINVAL |
129 } | 123 } |
130 n, sa, err := c.fd.ReadFrom(b) | 124 n, sa, err := c.fd.ReadFrom(b) |
131 switch sa := sa.(type) { | 125 switch sa := sa.(type) { |
132 case *syscall.SockaddrUnix: | 126 case *syscall.SockaddrUnix: |
133 addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} | 127 addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} |
134 } | 128 } |
135 return | 129 return |
136 } | 130 } |
137 | 131 |
138 // ReadFrom implements the PacketConn ReadFrom method. | 132 // ReadFrom implements the PacketConn ReadFrom method. |
139 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) { | 133 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) { |
140 if !c.ok() { | 134 if !c.ok() { |
141 return 0, nil, syscall.EINVAL | 135 return 0, nil, syscall.EINVAL |
142 } | 136 } |
143 n, uaddr, err := c.ReadFromUnix(b) | 137 n, uaddr, err := c.ReadFromUnix(b) |
144 return n, uaddr.toAddr(), err | 138 return n, uaddr.toAddr(), err |
145 } | 139 } |
146 | 140 |
| 141 // ReadMsgUnix reads a packet from c, copying the payload into b and |
| 142 // the associated out-of-band data into oob. It returns the number of |
| 143 // bytes copied into b, the number of bytes copied into oob, the flags |
| 144 // that were set on the packet, and the source address of the packet. |
| 145 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
r, err error) { |
| 146 if !c.ok() { |
| 147 return 0, 0, 0, nil, syscall.EINVAL |
| 148 } |
| 149 n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) |
| 150 switch sa := sa.(type) { |
| 151 case *syscall.SockaddrUnix: |
| 152 addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} |
| 153 } |
| 154 return |
| 155 } |
| 156 |
147 // WriteToUnix writes a packet to addr via c, copying the payload from b. | 157 // WriteToUnix writes a packet to addr via c, copying the payload from b. |
148 // | 158 // |
149 // WriteToUnix can be made to time out and return | 159 // WriteToUnix can be made to time out and return an error with |
150 // an error with Timeout() == true after a fixed time limit; | 160 // Timeout() == true after a fixed time limit; see SetDeadline and |
151 // see SetDeadline and SetWriteDeadline. | 161 // SetWriteDeadline. On packet-oriented connections, write timeouts |
152 // On packet-oriented connections, write timeouts are rare. | 162 // are rare. |
153 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { | 163 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { |
154 if !c.ok() { | 164 if !c.ok() { |
155 return 0, syscall.EINVAL | 165 return 0, syscall.EINVAL |
156 } | 166 } |
157 if addr.Net != sotypeToNet(c.fd.sotype) { | 167 if addr.Net != sotypeToNet(c.fd.sotype) { |
158 return 0, syscall.EAFNOSUPPORT | 168 return 0, syscall.EAFNOSUPPORT |
159 } | 169 } |
160 sa := &syscall.SockaddrUnix{Name: addr.Name} | 170 sa := &syscall.SockaddrUnix{Name: addr.Name} |
161 return c.fd.WriteTo(b, sa) | 171 return c.fd.WriteTo(b, sa) |
162 } | 172 } |
163 | 173 |
164 // WriteTo implements the PacketConn WriteTo method. | 174 // WriteTo implements the PacketConn WriteTo method. |
165 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) { | 175 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) { |
166 if !c.ok() { | 176 if !c.ok() { |
167 return 0, syscall.EINVAL | 177 return 0, syscall.EINVAL |
168 } | 178 } |
169 a, ok := addr.(*UnixAddr) | 179 a, ok := addr.(*UnixAddr) |
170 if !ok { | 180 if !ok { |
171 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} | 181 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} |
172 } | 182 } |
173 return c.WriteToUnix(b, a) | 183 return c.WriteToUnix(b, a) |
174 } | 184 } |
175 | 185 |
176 // ReadMsgUnix reads a packet from c, copying the payload into b | 186 // WriteMsgUnix writes a packet to addr via c, copying the payload |
177 // and the associated out-of-band data into oob. | 187 // from b and the associated out-of-band data from oob. It returns |
178 // It returns the number of bytes copied into b, the number of | 188 // the number of payload and out-of-band bytes written. |
179 // bytes copied into oob, the flags that were set on the packet, | |
180 // and the source address of the packet. | |
181 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
r, err error) { | |
182 » if !c.ok() { | |
183 » » return 0, 0, 0, nil, syscall.EINVAL | |
184 » } | |
185 » n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) | |
186 » switch sa := sa.(type) { | |
187 » case *syscall.SockaddrUnix: | |
188 » » addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} | |
189 » } | |
190 » return | |
191 } | |
192 | |
193 // WriteMsgUnix writes a packet to addr via c, copying the payload from b | |
194 // and the associated out-of-band data from oob. It returns the number | |
195 // of payload and out-of-band bytes written. | |
196 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
error) { | 189 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
error) { |
197 if !c.ok() { | 190 if !c.ok() { |
198 return 0, 0, syscall.EINVAL | 191 return 0, 0, syscall.EINVAL |
199 } | 192 } |
200 if addr != nil { | 193 if addr != nil { |
201 if addr.Net != sotypeToNet(c.fd.sotype) { | 194 if addr.Net != sotypeToNet(c.fd.sotype) { |
202 return 0, 0, syscall.EAFNOSUPPORT | 195 return 0, 0, syscall.EAFNOSUPPORT |
203 } | 196 } |
204 sa := &syscall.SockaddrUnix{Name: addr.Name} | 197 sa := &syscall.SockaddrUnix{Name: addr.Name} |
205 return c.fd.WriteMsg(b, oob, sa) | 198 return c.fd.WriteMsg(b, oob, sa) |
(...skipping 13 matching lines...) Expand all Loading... |
219 // CloseWrite shuts down the writing side of the Unix domain connection. | 212 // CloseWrite shuts down the writing side of the Unix domain connection. |
220 // Most callers should just use Close. | 213 // Most callers should just use Close. |
221 func (c *UnixConn) CloseWrite() error { | 214 func (c *UnixConn) CloseWrite() error { |
222 if !c.ok() { | 215 if !c.ok() { |
223 return syscall.EINVAL | 216 return syscall.EINVAL |
224 } | 217 } |
225 return c.fd.CloseWrite() | 218 return c.fd.CloseWrite() |
226 } | 219 } |
227 | 220 |
228 // DialUnix connects to the remote address raddr on the network net, | 221 // DialUnix connects to the remote address raddr on the network net, |
229 // which must be "unix" or "unixgram". If laddr is not nil, it is used | 222 // which must be "unix", "unixgram" or "unixpacket". If laddr is not |
230 // as the local address for the connection. | 223 // nil, it is used as the local address for the connection. |
231 func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { | 224 func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { |
232 return dialUnix(net, laddr, raddr, noDeadline) | 225 return dialUnix(net, laddr, raddr, noDeadline) |
233 } | 226 } |
234 | 227 |
235 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn
, error) { | 228 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn
, error) { |
| 229 switch net { |
| 230 case "unix", "unixgram", "unixpacket": |
| 231 default: |
| 232 return nil, UnknownNetworkError(net) |
| 233 } |
236 fd, err := unixSocket(net, laddr, raddr, "dial", deadline) | 234 fd, err := unixSocket(net, laddr, raddr, "dial", deadline) |
237 if err != nil { | 235 if err != nil { |
238 return nil, err | 236 return nil, err |
239 } | 237 } |
240 return newUnixConn(fd), nil | 238 return newUnixConn(fd), nil |
241 } | 239 } |
242 | 240 |
243 // UnixListener is a Unix domain socket listener. | 241 // UnixListener is a Unix domain socket listener. Clients should |
244 // Clients should typically use variables of type Listener | 242 // typically use variables of type Listener instead of assuming Unix |
245 // instead of assuming Unix domain sockets. | 243 // domain sockets. |
246 type UnixListener struct { | 244 type UnixListener struct { |
247 fd *netFD | 245 fd *netFD |
248 path string | 246 path string |
249 } | 247 } |
250 | 248 |
251 // ListenUnix announces on the Unix domain socket laddr and returns a Unix liste
ner. | 249 // ListenUnix announces on the Unix domain socket laddr and returns a |
252 // Net must be "unix" (stream sockets). | 250 // Unix listener. The network net must be "unix", "unixgram" or |
| 251 // "unixpacket". |
253 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { | 252 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { |
254 » if net != "unix" && net != "unixgram" && net != "unixpacket" { | 253 » switch net { |
| 254 » case "unix", "unixgram", "unixpacket": |
| 255 » default: |
255 return nil, UnknownNetworkError(net) | 256 return nil, UnknownNetworkError(net) |
256 } | 257 } |
257 » if laddr != nil { | 258 » if laddr == nil { |
258 » » laddr = &UnixAddr{laddr.Name, net} // make our own copy | 259 » » return nil, &OpError{"listen", net, nil, errMissingAddress} |
259 } | 260 } |
260 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) | 261 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) |
261 if err != nil { | 262 if err != nil { |
262 return nil, err | 263 return nil, err |
263 } | 264 } |
264 err = syscall.Listen(fd.sysfd, listenerBacklog) | 265 err = syscall.Listen(fd.sysfd, listenerBacklog) |
265 if err != nil { | 266 if err != nil { |
266 closesocket(fd.sysfd) | 267 closesocket(fd.sysfd) |
267 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: e
rr} | 268 return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: e
rr} |
268 } | 269 } |
269 return &UnixListener{fd, laddr.Name}, nil | 270 return &UnixListener{fd, laddr.Name}, nil |
270 } | 271 } |
271 | 272 |
272 // AcceptUnix accepts the next incoming call and returns the new connection | 273 // AcceptUnix accepts the next incoming call and returns the new |
273 // and the remote address. | 274 // connection and the remote address. |
274 func (l *UnixListener) AcceptUnix() (*UnixConn, error) { | 275 func (l *UnixListener) AcceptUnix() (*UnixConn, error) { |
275 if l == nil || l.fd == nil { | 276 if l == nil || l.fd == nil { |
276 return nil, syscall.EINVAL | 277 return nil, syscall.EINVAL |
277 } | 278 } |
278 fd, err := l.fd.accept(sockaddrToUnix) | 279 fd, err := l.fd.accept(sockaddrToUnix) |
279 if err != nil { | 280 if err != nil { |
280 return nil, err | 281 return nil, err |
281 } | 282 } |
282 c := newUnixConn(fd) | 283 c := newUnixConn(fd) |
283 return c, nil | 284 return c, nil |
284 } | 285 } |
285 | 286 |
286 // Accept implements the Accept method in the Listener interface; | 287 // Accept implements the Accept method in the Listener interface; it |
287 // it waits for the next call and returns a generic Conn. | 288 // waits for the next call and returns a generic Conn. |
288 func (l *UnixListener) Accept() (c Conn, err error) { | 289 func (l *UnixListener) Accept() (c Conn, err error) { |
289 c1, err := l.AcceptUnix() | 290 c1, err := l.AcceptUnix() |
290 if err != nil { | 291 if err != nil { |
291 return nil, err | 292 return nil, err |
292 } | 293 } |
293 return c1, nil | 294 return c1, nil |
294 } | 295 } |
295 | 296 |
296 // Close stops listening on the Unix address. | 297 // Close stops listening on the Unix address. Already accepted |
297 // Already accepted connections are not closed. | 298 // connections are not closed. |
298 func (l *UnixListener) Close() error { | 299 func (l *UnixListener) Close() error { |
299 if l == nil || l.fd == nil { | 300 if l == nil || l.fd == nil { |
300 return syscall.EINVAL | 301 return syscall.EINVAL |
301 } | 302 } |
302 | 303 |
303 // The operating system doesn't clean up | 304 // The operating system doesn't clean up |
304 // the file that announcing created, so | 305 // the file that announcing created, so |
305 // we have to clean it up ourselves. | 306 // we have to clean it up ourselves. |
306 // There's a race here--we can't know for | 307 // There's a race here--we can't know for |
307 // sure whether someone else has come along | 308 // sure whether someone else has come along |
(...skipping 13 matching lines...) Expand all Loading... |
321 | 322 |
322 // SetDeadline sets the deadline associated with the listener. | 323 // SetDeadline sets the deadline associated with the listener. |
323 // A zero time value disables the deadline. | 324 // A zero time value disables the deadline. |
324 func (l *UnixListener) SetDeadline(t time.Time) (err error) { | 325 func (l *UnixListener) SetDeadline(t time.Time) (err error) { |
325 if l == nil || l.fd == nil { | 326 if l == nil || l.fd == nil { |
326 return syscall.EINVAL | 327 return syscall.EINVAL |
327 } | 328 } |
328 return setDeadline(l.fd, t) | 329 return setDeadline(l.fd, t) |
329 } | 330 } |
330 | 331 |
331 // File returns a copy of the underlying os.File, set to blocking mode. | 332 // File returns a copy of the underlying os.File, set to blocking |
332 // It is the caller's responsibility to close f when finished. | 333 // mode. It is the caller's responsibility to close f when finished. |
333 // Closing l does not affect f, and closing f does not affect l. | 334 // Closing l does not affect f, and closing f does not affect l. |
334 func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() } | 335 func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() } |
335 | 336 |
336 // ListenUnixgram listens for incoming Unix datagram packets addressed to the | 337 // ListenUnixgram listens for incoming Unix datagram packets addressed |
337 // local address laddr. The returned connection c's ReadFrom | 338 // to the local address laddr. The returned connection c's ReadFrom |
338 // and WriteTo methods can be used to receive and send UDP | 339 // and WriteTo methods can be used to receive and send packets with |
339 // packets with per-packet addressing. The network net must be "unixgram". | 340 // per-packet addressing. The network net must be "unixgram". |
340 func ListenUnixgram(net string, laddr *UnixAddr) (*UDPConn, error) { | 341 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { |
341 switch net { | 342 switch net { |
342 case "unixgram": | 343 case "unixgram": |
343 default: | 344 default: |
344 return nil, UnknownNetworkError(net) | 345 return nil, UnknownNetworkError(net) |
345 } | 346 } |
346 if laddr == nil { | 347 if laddr == nil { |
347 return nil, &OpError{"listen", net, nil, errMissingAddress} | 348 return nil, &OpError{"listen", net, nil, errMissingAddress} |
348 } | 349 } |
349 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) | 350 fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) |
350 if err != nil { | 351 if err != nil { |
351 return nil, err | 352 return nil, err |
352 } | 353 } |
353 » return newUDPConn(fd), nil | 354 » return newUnixConn(fd), nil |
354 } | 355 } |
OLD | NEW |