]> Cypherpunks.ru repositories - gostls13.git/blob - src/net/unixsock_posix.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / net / unixsock_posix.go
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 //go:build unix || js || wasip1 || windows
6
7 package net
8
9 import (
10         "context"
11         "errors"
12         "os"
13         "syscall"
14 )
15
16 func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctxCtrlFn func(context.Context, string, string, syscall.RawConn) error) (*netFD, error) {
17         var sotype int
18         switch net {
19         case "unix":
20                 sotype = syscall.SOCK_STREAM
21         case "unixgram":
22                 sotype = syscall.SOCK_DGRAM
23         case "unixpacket":
24                 sotype = syscall.SOCK_SEQPACKET
25         default:
26                 return nil, UnknownNetworkError(net)
27         }
28
29         switch mode {
30         case "dial":
31                 if laddr != nil && laddr.isWildcard() {
32                         laddr = nil
33                 }
34                 if raddr != nil && raddr.isWildcard() {
35                         raddr = nil
36                 }
37                 if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
38                         return nil, errMissingAddress
39                 }
40         case "listen":
41         default:
42                 return nil, errors.New("unknown mode: " + mode)
43         }
44
45         fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, ctxCtrlFn)
46         if err != nil {
47                 return nil, err
48         }
49         return fd, nil
50 }
51
52 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
53         if s, ok := sa.(*syscall.SockaddrUnix); ok {
54                 return &UnixAddr{Name: s.Name, Net: "unix"}
55         }
56         return nil
57 }
58
59 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
60         if s, ok := sa.(*syscall.SockaddrUnix); ok {
61                 return &UnixAddr{Name: s.Name, Net: "unixgram"}
62         }
63         return nil
64 }
65
66 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
67         if s, ok := sa.(*syscall.SockaddrUnix); ok {
68                 return &UnixAddr{Name: s.Name, Net: "unixpacket"}
69         }
70         return nil
71 }
72
73 func sotypeToNet(sotype int) string {
74         switch sotype {
75         case syscall.SOCK_STREAM:
76                 return "unix"
77         case syscall.SOCK_DGRAM:
78                 return "unixgram"
79         case syscall.SOCK_SEQPACKET:
80                 return "unixpacket"
81         default:
82                 panic("sotypeToNet unknown socket type")
83         }
84 }
85
86 func (a *UnixAddr) family() int {
87         return syscall.AF_UNIX
88 }
89
90 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
91         if a == nil {
92                 return nil, nil
93         }
94         return &syscall.SockaddrUnix{Name: a.Name}, nil
95 }
96
97 func (a *UnixAddr) toLocal(net string) sockaddr {
98         return a
99 }
100
101 func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
102         var addr *UnixAddr
103         n, sa, err := c.fd.readFrom(b)
104         switch sa := sa.(type) {
105         case *syscall.SockaddrUnix:
106                 if sa.Name != "" {
107                         addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
108                 }
109         }
110         return n, addr, err
111 }
112
113 func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
114         var sa syscall.Sockaddr
115         n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags)
116         if readMsgFlags == 0 && err == nil && oobn > 0 {
117                 setReadMsgCloseOnExec(oob[:oobn])
118         }
119
120         switch sa := sa.(type) {
121         case *syscall.SockaddrUnix:
122                 if sa.Name != "" {
123                         addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
124                 }
125         }
126         return
127 }
128
129 func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
130         if c.fd.isConnected {
131                 return 0, ErrWriteToConnected
132         }
133         if addr == nil {
134                 return 0, errMissingAddress
135         }
136         if addr.Net != sotypeToNet(c.fd.sotype) {
137                 return 0, syscall.EAFNOSUPPORT
138         }
139         sa := &syscall.SockaddrUnix{Name: addr.Name}
140         return c.fd.writeTo(b, sa)
141 }
142
143 func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
144         if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
145                 return 0, 0, ErrWriteToConnected
146         }
147         var sa syscall.Sockaddr
148         if addr != nil {
149                 if addr.Net != sotypeToNet(c.fd.sotype) {
150                         return 0, 0, syscall.EAFNOSUPPORT
151                 }
152                 sa = &syscall.SockaddrUnix{Name: addr.Name}
153         }
154         return c.fd.writeMsg(b, oob, sa)
155 }
156
157 func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
158         ctrlCtxFn := sd.Dialer.ControlContext
159         if ctrlCtxFn == nil && sd.Dialer.Control != nil {
160                 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
161                         return sd.Dialer.Control(network, address, c)
162                 }
163         }
164         fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", ctrlCtxFn)
165         if err != nil {
166                 return nil, err
167         }
168         return newUnixConn(fd), nil
169 }
170
171 func (ln *UnixListener) accept() (*UnixConn, error) {
172         fd, err := ln.fd.accept()
173         if err != nil {
174                 return nil, err
175         }
176         return newUnixConn(fd), nil
177 }
178
179 func (ln *UnixListener) close() error {
180         // The operating system doesn't clean up
181         // the file that announcing created, so
182         // we have to clean it up ourselves.
183         // There's a race here--we can't know for
184         // sure whether someone else has come along
185         // and replaced our socket name already--
186         // but this sequence (remove then close)
187         // is at least compatible with the auto-remove
188         // sequence in ListenUnix. It's only non-Go
189         // programs that can mess us up.
190         // Even if there are racy calls to Close, we want to unlink only for the first one.
191         ln.unlinkOnce.Do(func() {
192                 if ln.path[0] != '@' && ln.unlink {
193                         syscall.Unlink(ln.path)
194                 }
195         })
196         return ln.fd.Close()
197 }
198
199 func (ln *UnixListener) file() (*os.File, error) {
200         f, err := ln.fd.dup()
201         if err != nil {
202                 return nil, err
203         }
204         return f, nil
205 }
206
207 // SetUnlinkOnClose sets whether the underlying socket file should be removed
208 // from the file system when the listener is closed.
209 //
210 // The default behavior is to unlink the socket file only when package net created it.
211 // That is, when the listener and the underlying socket file were created by a call to
212 // Listen or ListenUnix, then by default closing the listener will remove the socket file.
213 // but if the listener was created by a call to FileListener to use an already existing
214 // socket file, then by default closing the listener will not remove the socket file.
215 func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
216         l.unlink = unlink
217 }
218
219 func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
220         var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error
221         if sl.ListenConfig.Control != nil {
222                 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
223                         return sl.ListenConfig.Control(network, address, c)
224                 }
225         }
226         fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn)
227         if err != nil {
228                 return nil, err
229         }
230         return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
231 }
232
233 func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
234         var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error
235         if sl.ListenConfig.Control != nil {
236                 ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
237                         return sl.ListenConfig.Control(network, address, c)
238                 }
239         }
240         fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", ctrlCtxFn)
241         if err != nil {
242                 return nil, err
243         }
244         return newUnixConn(fd), nil
245 }