Skip to content

Commit 5ce0170

Browse files
committed
net: deduplicate Unix socket code
This change consolidates functions and methods related to UnixAddr, UnixConn and UnixListener for maintenance purpose, especially for documentation. The followup changes will update comments and examples. Updates #10624. Change-Id: I372d152099ac10956284e6b3863d7e4d9fe5c8e9 Reviewed-on: https://go-review.googlesource.com/20125 TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 028e48c commit 5ce0170

File tree

3 files changed

+323
-347
lines changed

3 files changed

+323
-347
lines changed

src/net/unixsock.go

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
package net
66

7+
import (
8+
"os"
9+
"syscall"
10+
"time"
11+
)
12+
713
// UnixAddr represents the address of a Unix domain socket end point.
814
type UnixAddr struct {
915
Name string
@@ -45,3 +51,268 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
4551
return nil, UnknownNetworkError(net)
4652
}
4753
}
54+
55+
// UnixConn is an implementation of the Conn interface for connections
56+
// to Unix domain sockets.
57+
type UnixConn struct {
58+
conn
59+
}
60+
61+
// CloseRead shuts down the reading side of the Unix domain connection.
62+
// Most callers should just use Close.
63+
func (c *UnixConn) CloseRead() error {
64+
if !c.ok() {
65+
return syscall.EINVAL
66+
}
67+
if err := c.fd.closeRead(); err != nil {
68+
return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
69+
}
70+
return nil
71+
}
72+
73+
// CloseWrite shuts down the writing side of the Unix domain connection.
74+
// Most callers should just use Close.
75+
func (c *UnixConn) CloseWrite() error {
76+
if !c.ok() {
77+
return syscall.EINVAL
78+
}
79+
if err := c.fd.closeWrite(); err != nil {
80+
return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
81+
}
82+
return nil
83+
}
84+
85+
// ReadFromUnix reads a packet from c, copying the payload into b. It
86+
// returns the number of bytes copied into b and the source address of
87+
// the packet.
88+
//
89+
// ReadFromUnix can be made to time out and return an error with
90+
// Timeout() == true after a fixed time limit; see SetDeadline and
91+
// SetReadDeadline.
92+
func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
93+
if !c.ok() {
94+
return 0, nil, syscall.EINVAL
95+
}
96+
n, addr, err := c.readFrom(b)
97+
if err != nil {
98+
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
99+
}
100+
return n, addr, err
101+
}
102+
103+
// ReadFrom implements the PacketConn ReadFrom method.
104+
func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
105+
if !c.ok() {
106+
return 0, nil, syscall.EINVAL
107+
}
108+
n, addr, err := c.readFrom(b)
109+
if err != nil {
110+
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
111+
}
112+
if addr == nil {
113+
return n, nil, err
114+
}
115+
return n, addr, err
116+
}
117+
118+
// ReadMsgUnix reads a packet from c, copying the payload into b and
119+
// the associated out-of-band data into oob. It returns the number of
120+
// bytes copied into b, the number of bytes copied into oob, the flags
121+
// that were set on the packet, and the source address of the packet.
122+
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
123+
if !c.ok() {
124+
return 0, 0, 0, nil, syscall.EINVAL
125+
}
126+
n, oobn, flags, addr, err = c.readMsg(b, oob)
127+
if err != nil {
128+
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
129+
}
130+
return
131+
}
132+
133+
// WriteToUnix writes a packet to addr via c, copying the payload from b.
134+
//
135+
// WriteToUnix can be made to time out and return an error with
136+
// Timeout() == true after a fixed time limit; see SetDeadline and
137+
// SetWriteDeadline. On packet-oriented connections, write timeouts
138+
// are rare.
139+
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
140+
if !c.ok() {
141+
return 0, syscall.EINVAL
142+
}
143+
n, err := c.writeTo(b, addr)
144+
if err != nil {
145+
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
146+
}
147+
return n, err
148+
}
149+
150+
// WriteTo implements the PacketConn WriteTo method.
151+
func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
152+
if !c.ok() {
153+
return 0, syscall.EINVAL
154+
}
155+
a, ok := addr.(*UnixAddr)
156+
if !ok {
157+
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
158+
}
159+
n, err := c.writeTo(b, a)
160+
if err != nil {
161+
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
162+
}
163+
return n, err
164+
}
165+
166+
// WriteMsgUnix writes a packet to addr via c, copying the payload
167+
// from b and the associated out-of-band data from oob. It returns
168+
// the number of payload and out-of-band bytes written.
169+
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
170+
if !c.ok() {
171+
return 0, 0, syscall.EINVAL
172+
}
173+
n, oobn, err = c.writeMsg(b, oob, addr)
174+
if err != nil {
175+
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
176+
}
177+
return
178+
}
179+
180+
func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
181+
182+
// DialUnix connects to the remote address raddr on the network net,
183+
// which must be "unix", "unixgram" or "unixpacket". If laddr is not
184+
// nil, it is used as the local address for the connection.
185+
func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
186+
switch net {
187+
case "unix", "unixgram", "unixpacket":
188+
default:
189+
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
190+
}
191+
c, err := dialUnix(net, laddr, raddr, noDeadline)
192+
if err != nil {
193+
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
194+
}
195+
return c, nil
196+
}
197+
198+
// UnixListener is a Unix domain socket listener. Clients should
199+
// typically use variables of type Listener instead of assuming Unix
200+
// domain sockets.
201+
type UnixListener struct {
202+
fd *netFD
203+
path string
204+
unlink bool
205+
}
206+
207+
func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
208+
209+
// AcceptUnix accepts the next incoming call and returns the new
210+
// connection.
211+
func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
212+
if !l.ok() {
213+
return nil, syscall.EINVAL
214+
}
215+
c, err := l.accept()
216+
if err != nil {
217+
return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
218+
}
219+
return c, nil
220+
}
221+
222+
// Accept implements the Accept method in the Listener interface.
223+
// Returned connections will be of type *UnixConn.
224+
func (l *UnixListener) Accept() (Conn, error) {
225+
if !l.ok() {
226+
return nil, syscall.EINVAL
227+
}
228+
c, err := l.accept()
229+
if err != nil {
230+
return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
231+
}
232+
return c, nil
233+
}
234+
235+
// Close stops listening on the Unix address. Already accepted
236+
// connections are not closed.
237+
func (l *UnixListener) Close() error {
238+
if !l.ok() {
239+
return syscall.EINVAL
240+
}
241+
if err := l.close(); err != nil {
242+
return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
243+
}
244+
return nil
245+
}
246+
247+
// Addr returns the listener's network address.
248+
// The Addr returned is shared by all invocations of Addr, so
249+
// do not modify it.
250+
func (l *UnixListener) Addr() Addr { return l.fd.laddr }
251+
252+
// SetDeadline sets the deadline associated with the listener.
253+
// A zero time value disables the deadline.
254+
func (l *UnixListener) SetDeadline(t time.Time) error {
255+
if !l.ok() {
256+
return syscall.EINVAL
257+
}
258+
if err := l.fd.setDeadline(t); err != nil {
259+
return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
260+
}
261+
return nil
262+
}
263+
264+
// File returns a copy of the underlying os.File, set to blocking
265+
// mode. It is the caller's responsibility to close f when finished.
266+
// Closing l does not affect f, and closing f does not affect l.
267+
//
268+
// The returned os.File's file descriptor is different from the
269+
// connection's. Attempting to change properties of the original
270+
// using this duplicate may or may not have the desired effect.
271+
func (l *UnixListener) File() (f *os.File, err error) {
272+
if !l.ok() {
273+
return nil, syscall.EINVAL
274+
}
275+
f, err = l.file()
276+
if err != nil {
277+
err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
278+
}
279+
return
280+
}
281+
282+
// ListenUnix announces on the Unix domain socket laddr and returns a
283+
// Unix listener. The network net must be "unix" or "unixpacket".
284+
func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
285+
switch net {
286+
case "unix", "unixpacket":
287+
default:
288+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
289+
}
290+
if laddr == nil {
291+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
292+
}
293+
ln, err := listenUnix(net, laddr)
294+
if err != nil {
295+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
296+
}
297+
return ln, nil
298+
}
299+
300+
// ListenUnixgram listens for incoming Unix datagram packets addressed
301+
// to the local address laddr. The network net must be "unixgram".
302+
// The returned connection's ReadFrom and WriteTo methods can be used
303+
// to receive and send packets with per-packet addressing.
304+
func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
305+
switch net {
306+
case "unixgram":
307+
default:
308+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
309+
}
310+
if laddr == nil {
311+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
312+
}
313+
c, err := listenUnixgram(net, laddr)
314+
if err != nil {
315+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
316+
}
317+
return c, nil
318+
}

0 commit comments

Comments
 (0)