unixsock.mx raw
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 package net
6
7 import (
8 "context"
9 "os"
10 "sync"
11 "syscall"
12 "time"
13 )
14
15 // BUG(mikio): On JS, WASIP1 and Plan 9, methods and functions related
16 // to UnixConn and UnixListener are not implemented.
17
18 // BUG(mikio): On Windows, methods and functions related to UnixConn
19 // and UnixListener don't work for "unixgram" and "unixpacket".
20
21 // UnixAddr represents the address of a Unix domain socket end point.
22 type UnixAddr struct {
23 Name []byte
24 Net []byte
25 }
26
27 // Network returns the address's network name, "unix", "unixgram" or
28 // "unixpacket".
29 func (a *UnixAddr) Network() []byte {
30 return a.Net
31 }
32
33 func (a *UnixAddr) String() string {
34 if a == nil {
35 return "<nil>"
36 }
37 return a.Name
38 }
39
40 func (a *UnixAddr) isWildcard() bool {
41 return a == nil || a.Name == ""
42 }
43
44 func (a *UnixAddr) opAddr() Addr {
45 if a == nil {
46 return nil
47 }
48 return a
49 }
50
51 // ResolveUnixAddr returns an address of Unix domain socket end point.
52 //
53 // The network must be a Unix network name.
54 //
55 // See func [Dial] for a description of the network and address
56 // parameters.
57 func ResolveUnixAddr(network, address []byte) (*UnixAddr, error) {
58 switch network {
59 case "unix", "unixgram", "unixpacket":
60 return &UnixAddr{Name: address, Net: network}, nil
61 default:
62 return nil, UnknownNetworkError(network)
63 }
64 }
65
66 // UnixConn is an implementation of the [Conn] interface for connections
67 // to Unix domain sockets.
68 type UnixConn struct {
69 conn
70 }
71
72 // SyscallConn returns a raw network connection.
73 // This implements the [syscall.Conn] interface.
74 func (c *UnixConn) SyscallConn() (syscall.RawConn, error) {
75 if !c.ok() {
76 return nil, syscall.EINVAL
77 }
78 return newRawConn(c.fd), nil
79 }
80
81 // CloseRead shuts down the reading side of the Unix domain connection.
82 // Most callers should just use [UnixConn.Close].
83 func (c *UnixConn) CloseRead() error {
84 if !c.ok() {
85 return syscall.EINVAL
86 }
87 if err := c.fd.closeRead(); err != nil {
88 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
89 }
90 return nil
91 }
92
93 // CloseWrite shuts down the writing side of the Unix domain connection.
94 // Most callers should just use [UnixConn.Close].
95 func (c *UnixConn) CloseWrite() error {
96 if !c.ok() {
97 return syscall.EINVAL
98 }
99 if err := c.fd.closeWrite(); err != nil {
100 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
101 }
102 return nil
103 }
104
105 // ReadFromUnix acts like [UnixConn.ReadFrom] but returns a [UnixAddr].
106 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
107 if !c.ok() {
108 return 0, nil, syscall.EINVAL
109 }
110 n, addr, err := c.readFrom(b)
111 if err != nil {
112 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
113 }
114 return n, addr, err
115 }
116
117 // ReadFrom implements the [PacketConn].ReadFrom method.
118 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
119 if !c.ok() {
120 return 0, nil, syscall.EINVAL
121 }
122 n, addr, err := c.readFrom(b)
123 if err != nil {
124 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
125 }
126 if addr == nil {
127 return n, nil, err
128 }
129 return n, addr, err
130 }
131
132 // ReadMsgUnix reads a message from c, copying the payload into b and
133 // the associated out-of-band data into oob. It returns the number of
134 // bytes copied into b, the number of bytes copied into oob, the flags
135 // that were set on the message and the source address of the message.
136 //
137 // Note that if len(b) == 0 and len(oob) > 0, this function will still
138 // read (and discard) 1 byte from the connection.
139 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
140 if !c.ok() {
141 return 0, 0, 0, nil, syscall.EINVAL
142 }
143 n, oobn, flags, addr, err = c.readMsg(b, oob)
144 if err != nil {
145 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
146 }
147 return
148 }
149
150 // WriteToUnix acts like [UnixConn.WriteTo] but takes a [UnixAddr].
151 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
152 if !c.ok() {
153 return 0, syscall.EINVAL
154 }
155 n, err := c.writeTo(b, addr)
156 if err != nil {
157 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
158 }
159 return n, err
160 }
161
162 // WriteTo implements the [PacketConn].WriteTo method.
163 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
164 if !c.ok() {
165 return 0, syscall.EINVAL
166 }
167 a, ok := addr.(*UnixAddr)
168 if !ok {
169 return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
170 }
171 n, err := c.writeTo(b, a)
172 if err != nil {
173 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
174 }
175 return n, err
176 }
177
178 // WriteMsgUnix writes a message to addr via c, copying the payload
179 // from b and the associated out-of-band data from oob. It returns the
180 // number of payload and out-of-band bytes written.
181 //
182 // Note that if len(b) == 0 and len(oob) > 0, this function will still
183 // write 1 byte to the connection.
184 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
185 if !c.ok() {
186 return 0, 0, syscall.EINVAL
187 }
188 n, oobn, err = c.writeMsg(b, oob, addr)
189 if err != nil {
190 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
191 }
192 return
193 }
194
195 func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
196
197 // DialUnix acts like [Dial] for Unix networks.
198 //
199 // The network must be a Unix network name; see func [Dial] for details.
200 //
201 // If laddr is non-nil, it is used as the local address for the
202 // connection.
203 func DialUnix(network []byte, laddr, raddr *UnixAddr) (*UnixConn, error) {
204 switch network {
205 case "unix", "unixgram", "unixpacket":
206 default:
207 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)}
208 }
209 sd := &sysDialer{network: network, address: raddr.String()}
210 c, err := sd.dialUnix(context.Background(), laddr, raddr)
211 if err != nil {
212 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
213 }
214 return c, nil
215 }
216
217 // UnixListener is a Unix domain socket listener. Clients should
218 // typically use variables of type [Listener] instead of assuming Unix
219 // domain sockets.
220 type UnixListener struct {
221 fd *netFD
222 path []byte
223 unlink bool
224 unlinkOnce sync.Once
225 }
226
227 func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
228
229 // SyscallConn returns a raw network connection.
230 // This implements the [syscall.Conn] interface.
231 //
232 // The returned [syscall.RawConn] only supports calling Control. Read and
233 // Write return an error.
234 func (l *UnixListener) SyscallConn() (syscall.RawConn, error) {
235 if !l.ok() {
236 return nil, syscall.EINVAL
237 }
238 return newRawListener(l.fd), nil
239 }
240
241 // AcceptUnix accepts the next incoming call and returns the new
242 // connection.
243 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
244 if !l.ok() {
245 return nil, syscall.EINVAL
246 }
247 c, err := l.accept()
248 if err != nil {
249 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
250 }
251 return c, nil
252 }
253
254 // Accept implements the Accept method in the [Listener] interface.
255 // Returned connections will be of type [*UnixConn].
256 func (l *UnixListener) Accept() (Conn, error) {
257 if !l.ok() {
258 return nil, syscall.EINVAL
259 }
260 c, err := l.accept()
261 if err != nil {
262 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
263 }
264 return c, nil
265 }
266
267 // Close stops listening on the Unix address. Already accepted
268 // connections are not closed.
269 func (l *UnixListener) Close() error {
270 if !l.ok() {
271 return syscall.EINVAL
272 }
273 if err := l.close(); err != nil {
274 return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
275 }
276 return nil
277 }
278
279 // Addr returns the listener's network address.
280 // The [Addr] returned is shared by all invocations of Addr, so
281 // do not modify it.
282 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
283
284 // SetDeadline sets the deadline associated with the listener.
285 // A zero time value disables the deadline.
286 func (l *UnixListener) SetDeadline(t time.Time) error {
287 if !l.ok() {
288 return syscall.EINVAL
289 }
290 return l.fd.SetDeadline(t)
291 }
292
293 // File returns a copy of the underlying [os.File].
294 // It is the caller's responsibility to close f when finished.
295 // Closing l does not affect f, and closing f does not affect l.
296 //
297 // The returned [os.File]'s file descriptor is different from the
298 // connection's. Attempting to change properties of the original
299 // using this duplicate may or may not have the desired effect.
300 //
301 // On Windows, the returned os.File's file descriptor is not
302 // usable on other processes.
303 func (l *UnixListener) File() (f *os.File, err error) {
304 if !l.ok() {
305 return nil, syscall.EINVAL
306 }
307 f, err = l.file()
308 if err != nil {
309 err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
310 }
311 return
312 }
313
314 // ListenUnix acts like [Listen] for Unix networks.
315 //
316 // The network must be "unix" or "unixpacket".
317 func ListenUnix(network []byte, laddr *UnixAddr) (*UnixListener, error) {
318 switch network {
319 case "unix", "unixpacket":
320 default:
321 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
322 }
323 if laddr == nil {
324 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
325 }
326 sl := &sysListener{network: network, address: laddr.String()}
327 ln, err := sl.listenUnix(context.Background(), laddr)
328 if err != nil {
329 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
330 }
331 return ln, nil
332 }
333
334 // ListenUnixgram acts like [ListenPacket] for Unix networks.
335 //
336 // The network must be "unixgram".
337 func ListenUnixgram(network []byte, laddr *UnixAddr) (*UnixConn, error) {
338 switch network {
339 case "unixgram":
340 default:
341 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
342 }
343 if laddr == nil {
344 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: errMissingAddress}
345 }
346 sl := &sysListener{network: network, address: laddr.String()}
347 c, err := sl.listenUnixgram(context.Background(), laddr)
348 if err != nil {
349 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
350 }
351 return c, nil
352 }
353