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 // Unix domain sockets | 5 // Unix domain sockets |
6 | 6 |
7 package net | 7 package net |
8 | 8 |
9 import ( | 9 import ( |
10 "os" | 10 "os" |
11 "syscall" | 11 "syscall" |
12 ) | 12 ) |
13 | 13 |
14 func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
os.Error) { | 14 func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
os.Error) { |
15 var proto int | 15 var proto int |
16 switch net { | 16 switch net { |
17 default: | 17 default: |
18 return nil, UnknownNetworkError(net) | 18 return nil, UnknownNetworkError(net) |
19 case "unix": | 19 case "unix": |
20 proto = syscall.SOCK_STREAM | 20 proto = syscall.SOCK_STREAM |
21 case "unixgram": | 21 case "unixgram": |
22 proto = syscall.SOCK_DGRAM | 22 proto = syscall.SOCK_DGRAM |
| 23 case "unixpacket": |
| 24 proto = syscall.SOCK_SEQPACKET |
23 } | 25 } |
24 | 26 |
25 var la, ra syscall.Sockaddr | 27 var la, ra syscall.Sockaddr |
26 switch mode { | 28 switch mode { |
27 default: | 29 default: |
28 panic("unixSocket mode " + mode) | 30 panic("unixSocket mode " + mode) |
29 | 31 |
30 case "dial": | 32 case "dial": |
31 if laddr != nil { | 33 if laddr != nil { |
32 la = &syscall.SockaddrUnix{Name: laddr.Name} | 34 la = &syscall.SockaddrUnix{Name: laddr.Name} |
33 } | 35 } |
34 if raddr != nil { | 36 if raddr != nil { |
35 ra = &syscall.SockaddrUnix{Name: raddr.Name} | 37 ra = &syscall.SockaddrUnix{Name: raddr.Name} |
36 } else if proto != syscall.SOCK_DGRAM || laddr == nil { | 38 } else if proto != syscall.SOCK_DGRAM || laddr == nil { |
37 return nil, &OpError{Op: mode, Net: net, Error: errMissi
ngAddress} | 39 return nil, &OpError{Op: mode, Net: net, Error: errMissi
ngAddress} |
38 } | 40 } |
39 | 41 |
40 case "listen": | 42 case "listen": |
41 if laddr == nil { | 43 if laddr == nil { |
42 return nil, &OpError{mode, net, nil, errMissingAddress} | 44 return nil, &OpError{mode, net, nil, errMissingAddress} |
43 } | 45 } |
44 la = &syscall.SockaddrUnix{Name: laddr.Name} | 46 la = &syscall.SockaddrUnix{Name: laddr.Name} |
45 if raddr != nil { | 47 if raddr != nil { |
46 return nil, &OpError{Op: mode, Net: net, Addr: raddr, Er
ror: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}} | 48 return nil, &OpError{Op: mode, Net: net, Addr: raddr, Er
ror: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}} |
47 } | 49 } |
48 } | 50 } |
49 | 51 |
50 f := sockaddrToUnix | 52 f := sockaddrToUnix |
51 » if proto != syscall.SOCK_STREAM { | 53 » if proto == syscall.SOCK_DGRAM { |
52 f = sockaddrToUnixgram | 54 f = sockaddrToUnixgram |
| 55 } else if proto == syscall.SOCK_SEQPACKET { |
| 56 f = sockaddrToUnixpacket |
53 } | 57 } |
| 58 |
54 fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f) | 59 fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f) |
55 if oserr != nil { | 60 if oserr != nil { |
56 goto Error | 61 goto Error |
57 } | 62 } |
58 return fd, nil | 63 return fd, nil |
59 | 64 |
60 Error: | 65 Error: |
61 addr := raddr | 66 addr := raddr |
62 if mode == "listen" { | 67 if mode == "listen" { |
63 addr = laddr | 68 addr = laddr |
64 } | 69 } |
65 return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr} | 70 return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr} |
66 } | 71 } |
67 | 72 |
68 // UnixAddr represents the address of a Unix domain socket end point. | 73 // UnixAddr represents the address of a Unix domain socket end point. |
69 type UnixAddr struct { | 74 type UnixAddr struct { |
70 » Name string | 75 » Name string |
71 » Datagram bool | 76 » Net string |
72 } | 77 } |
73 | 78 |
74 func sockaddrToUnix(sa syscall.Sockaddr) Addr { | 79 func sockaddrToUnix(sa syscall.Sockaddr) Addr { |
75 if s, ok := sa.(*syscall.SockaddrUnix); ok { | 80 if s, ok := sa.(*syscall.SockaddrUnix); ok { |
76 » » return &UnixAddr{s.Name, false} | 81 » » return &UnixAddr{s.Name, "unix"} |
77 } | 82 } |
78 return nil | 83 return nil |
79 } | 84 } |
80 | 85 |
81 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { | 86 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { |
82 if s, ok := sa.(*syscall.SockaddrUnix); ok { | 87 if s, ok := sa.(*syscall.SockaddrUnix); ok { |
83 » » return &UnixAddr{s.Name, true} | 88 » » return &UnixAddr{s.Name, "unixgram"} |
84 } | 89 } |
85 return nil | 90 return nil |
86 } | 91 } |
87 | 92 |
| 93 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { |
| 94 if s, ok := sa.(*syscall.SockaddrUnix); ok { |
| 95 return &UnixAddr{s.Name, "unixpacket"} |
| 96 } |
| 97 return nil |
| 98 } |
| 99 |
| 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") |
| 110 } |
| 111 return "" |
| 112 } |
| 113 |
88 // Network returns the address's network name, "unix" or "unixgram". | 114 // Network returns the address's network name, "unix" or "unixgram". |
89 func (a *UnixAddr) Network() string { | 115 func (a *UnixAddr) Network() string { |
90 » if a == nil || !a.Datagram { | 116 » return a.Net |
91 » » return "unix" | |
92 » } | |
93 » return "unixgram" | |
94 } | 117 } |
95 | 118 |
96 func (a *UnixAddr) String() string { | 119 func (a *UnixAddr) String() string { |
97 if a == nil { | 120 if a == nil { |
98 return "<nil>" | 121 return "<nil>" |
99 } | 122 } |
100 return a.Name | 123 return a.Name |
101 } | 124 } |
102 | 125 |
103 func (a *UnixAddr) toAddr() Addr { | 126 func (a *UnixAddr) toAddr() Addr { |
104 if a == nil { // nil *UnixAddr | 127 if a == nil { // nil *UnixAddr |
105 return nil // nil interface | 128 return nil // nil interface |
106 } | 129 } |
107 return a | 130 return a |
108 } | 131 } |
109 | 132 |
110 // ResolveUnixAddr parses addr as a Unix domain socket address. | 133 // ResolveUnixAddr parses addr as a Unix domain socket address. |
111 // The string net gives the network name, "unix" or "unixgram". | 134 // The string net gives the network name, "unix", "unixgram" or |
| 135 // "unixpacket". |
112 func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) { | 136 func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) { |
113 var datagram bool | |
114 switch net { | 137 switch net { |
115 case "unix": | 138 case "unix": |
| 139 case "unixpacket": |
116 case "unixgram": | 140 case "unixgram": |
117 datagram = true | |
118 default: | 141 default: |
119 return nil, UnknownNetworkError(net) | 142 return nil, UnknownNetworkError(net) |
120 } | 143 } |
121 » return &UnixAddr{addr, datagram}, nil | 144 » return &UnixAddr{addr, net}, nil |
122 } | 145 } |
123 | 146 |
124 // UnixConn is an implementation of the Conn interface | 147 // UnixConn is an implementation of the Conn interface |
125 // for connections to Unix domain sockets. | 148 // for connections to Unix domain sockets. |
126 type UnixConn struct { | 149 type UnixConn struct { |
127 fd *netFD | 150 fd *netFD |
128 } | 151 } |
129 | 152 |
130 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} } | 153 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} } |
131 | 154 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 // ReadFromUnix can be made to time out and return | 250 // ReadFromUnix can be made to time out and return |
228 // an error with Timeout() == true after a fixed time limit; | 251 // an error with Timeout() == true after a fixed time limit; |
229 // see SetTimeout and SetReadTimeout. | 252 // see SetTimeout and SetReadTimeout. |
230 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error)
{ | 253 func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error)
{ |
231 if !c.ok() { | 254 if !c.ok() { |
232 return 0, nil, os.EINVAL | 255 return 0, nil, os.EINVAL |
233 } | 256 } |
234 n, sa, err := c.fd.ReadFrom(b) | 257 n, sa, err := c.fd.ReadFrom(b) |
235 switch sa := sa.(type) { | 258 switch sa := sa.(type) { |
236 case *syscall.SockaddrUnix: | 259 case *syscall.SockaddrUnix: |
237 » » addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM} | 260 » » addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} |
238 } | 261 } |
239 return | 262 return |
240 } | 263 } |
241 | 264 |
242 // ReadFrom implements the net.PacketConn ReadFrom method. | 265 // ReadFrom implements the net.PacketConn ReadFrom method. |
243 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) { | 266 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) { |
244 if !c.ok() { | 267 if !c.ok() { |
245 return 0, nil, os.EINVAL | 268 return 0, nil, os.EINVAL |
246 } | 269 } |
247 n, uaddr, err := c.ReadFromUnix(b) | 270 n, uaddr, err := c.ReadFromUnix(b) |
248 return n, uaddr.toAddr(), err | 271 return n, uaddr.toAddr(), err |
249 } | 272 } |
250 | 273 |
251 // WriteToUnix writes a packet to addr via c, copying the payload from b. | 274 // WriteToUnix writes a packet to addr via c, copying the payload from b. |
252 // | 275 // |
253 // WriteToUnix can be made to time out and return | 276 // WriteToUnix can be made to time out and return |
254 // an error with Timeout() == true after a fixed time limit; | 277 // an error with Timeout() == true after a fixed time limit; |
255 // see SetTimeout and SetWriteTimeout. | 278 // see SetTimeout and SetWriteTimeout. |
256 // On packet-oriented connections, write timeouts are rare. | 279 // On packet-oriented connections, write timeouts are rare. |
257 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) { | 280 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) { |
258 if !c.ok() { | 281 if !c.ok() { |
259 return 0, os.EINVAL | 282 return 0, os.EINVAL |
260 } | 283 } |
261 » if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) { | 284 » if addr.Net != protoToNet(c.fd.proto) { |
262 return 0, os.EAFNOSUPPORT | 285 return 0, os.EAFNOSUPPORT |
263 } | 286 } |
264 sa := &syscall.SockaddrUnix{Name: addr.Name} | 287 sa := &syscall.SockaddrUnix{Name: addr.Name} |
265 return c.fd.WriteTo(b, sa) | 288 return c.fd.WriteTo(b, sa) |
266 } | 289 } |
267 | 290 |
268 // WriteTo implements the net.PacketConn WriteTo method. | 291 // WriteTo implements the net.PacketConn WriteTo method. |
269 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) { | 292 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) { |
270 if !c.ok() { | 293 if !c.ok() { |
271 return 0, os.EINVAL | 294 return 0, os.EINVAL |
272 } | 295 } |
273 a, ok := addr.(*UnixAddr) | 296 a, ok := addr.(*UnixAddr) |
274 if !ok { | 297 if !ok { |
275 return 0, &OpError{"writeto", "unix", addr, os.EINVAL} | 298 return 0, &OpError{"writeto", "unix", addr, os.EINVAL} |
276 } | 299 } |
277 return c.WriteToUnix(b, a) | 300 return c.WriteToUnix(b, a) |
278 } | 301 } |
279 | 302 |
280 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
r, err os.Error) { | 303 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
r, err os.Error) { |
281 if !c.ok() { | 304 if !c.ok() { |
282 return 0, 0, 0, nil, os.EINVAL | 305 return 0, 0, 0, nil, os.EINVAL |
283 } | 306 } |
284 n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) | 307 n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) |
285 switch sa := sa.(type) { | 308 switch sa := sa.(type) { |
286 case *syscall.SockaddrUnix: | 309 case *syscall.SockaddrUnix: |
287 » » addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM} | 310 » » addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} |
288 } | 311 } |
289 return | 312 return |
290 } | 313 } |
291 | 314 |
292 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
os.Error) { | 315 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
os.Error) { |
293 if !c.ok() { | 316 if !c.ok() { |
294 return 0, 0, os.EINVAL | 317 return 0, 0, os.EINVAL |
295 } | 318 } |
296 if addr != nil { | 319 if addr != nil { |
297 » » if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) { | 320 » » if addr.Net != protoToNet(c.fd.proto) { |
298 return 0, 0, os.EAFNOSUPPORT | 321 return 0, 0, os.EAFNOSUPPORT |
299 } | 322 } |
300 sa := &syscall.SockaddrUnix{Name: addr.Name} | 323 sa := &syscall.SockaddrUnix{Name: addr.Name} |
301 return c.fd.WriteMsg(b, oob, sa) | 324 return c.fd.WriteMsg(b, oob, sa) |
302 } | 325 } |
303 return c.fd.WriteMsg(b, oob, nil) | 326 return c.fd.WriteMsg(b, oob, nil) |
304 } | 327 } |
305 | 328 |
306 // File returns a copy of the underlying os.File, set to blocking mode. | 329 // 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. | 330 // It is the caller's responsibility to close f when finished. |
(...skipping 15 matching lines...) Expand all Loading... |
323 // Clients should typically use variables of type Listener | 346 // Clients should typically use variables of type Listener |
324 // instead of assuming Unix domain sockets. | 347 // instead of assuming Unix domain sockets. |
325 type UnixListener struct { | 348 type UnixListener struct { |
326 fd *netFD | 349 fd *netFD |
327 path string | 350 path string |
328 } | 351 } |
329 | 352 |
330 // ListenUnix announces on the Unix domain socket laddr and returns a Unix liste
ner. | 353 // ListenUnix announces on the Unix domain socket laddr and returns a Unix liste
ner. |
331 // Net must be "unix" (stream sockets). | 354 // Net must be "unix" (stream sockets). |
332 func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) { | 355 func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) { |
333 » if net != "unix" && net != "unixgram" { | 356 » if net != "unix" && net != "unixgram" && net != "unixpacket" { |
334 return nil, UnknownNetworkError(net) | 357 return nil, UnknownNetworkError(net) |
335 } | 358 } |
336 if laddr != nil { | 359 if laddr != nil { |
337 » » laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own
copy | 360 » » laddr = &UnixAddr{laddr.Name, net} // make our own copy |
338 } | 361 } |
339 fd, err := unixSocket(net, laddr, nil, "listen") | 362 fd, err := unixSocket(net, laddr, nil, "listen") |
340 if err != nil { | 363 if err != nil { |
341 return nil, err | 364 return nil, err |
342 } | 365 } |
343 e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); | 366 e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); |
344 if e1 != 0 { | 367 if e1 != 0 { |
345 syscall.Close(fd.sysfd) | 368 syscall.Close(fd.sysfd) |
346 return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err
or: os.Errno(e1)} | 369 return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err
or: os.Errno(e1)} |
347 } | 370 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 } | 440 } |
418 if laddr == nil { | 441 if laddr == nil { |
419 return nil, &OpError{"listen", "unixgram", nil, errMissingAddres
s} | 442 return nil, &OpError{"listen", "unixgram", nil, errMissingAddres
s} |
420 } | 443 } |
421 fd, e := unixSocket(net, laddr, nil, "listen") | 444 fd, e := unixSocket(net, laddr, nil, "listen") |
422 if e != nil { | 445 if e != nil { |
423 return nil, e | 446 return nil, e |
424 } | 447 } |
425 return newUDPConn(fd), nil | 448 return newUDPConn(fd), nil |
426 } | 449 } |
OLD | NEW |