Source file
src/net/unixsock_posix.go
Documentation: net
1
2
3
4
5
6
7
8 package net
9
10 import (
11 "context"
12 "errors"
13 "os"
14 "syscall"
15 )
16
17 func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string, ctrlFn func(string, string, syscall.RawConn) error) (*netFD, error) {
18 var sotype int
19 switch net {
20 case "unix":
21 sotype = syscall.SOCK_STREAM
22 case "unixgram":
23 sotype = syscall.SOCK_DGRAM
24 case "unixpacket":
25 sotype = syscall.SOCK_SEQPACKET
26 default:
27 return nil, UnknownNetworkError(net)
28 }
29
30 switch mode {
31 case "dial":
32 if laddr != nil && laddr.isWildcard() {
33 laddr = nil
34 }
35 if raddr != nil && raddr.isWildcard() {
36 raddr = nil
37 }
38 if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
39 return nil, errMissingAddress
40 }
41 case "listen":
42 default:
43 return nil, errors.New("unknown mode: " + mode)
44 }
45
46 fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, ctrlFn)
47 if err != nil {
48 return nil, err
49 }
50 return fd, nil
51 }
52
53 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
54 if s, ok := sa.(*syscall.SockaddrUnix); ok {
55 return &UnixAddr{Name: s.Name, Net: "unix"}
56 }
57 return nil
58 }
59
60 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
61 if s, ok := sa.(*syscall.SockaddrUnix); ok {
62 return &UnixAddr{Name: s.Name, Net: "unixgram"}
63 }
64 return nil
65 }
66
67 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
68 if s, ok := sa.(*syscall.SockaddrUnix); ok {
69 return &UnixAddr{Name: s.Name, Net: "unixpacket"}
70 }
71 return nil
72 }
73
74 func sotypeToNet(sotype int) string {
75 switch sotype {
76 case syscall.SOCK_STREAM:
77 return "unix"
78 case syscall.SOCK_DGRAM:
79 return "unixgram"
80 case syscall.SOCK_SEQPACKET:
81 return "unixpacket"
82 default:
83 panic("sotypeToNet unknown socket type")
84 }
85 }
86
87 func (a *UnixAddr) family() int {
88 return syscall.AF_UNIX
89 }
90
91 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
92 if a == nil {
93 return nil, nil
94 }
95 return &syscall.SockaddrUnix{Name: a.Name}, nil
96 }
97
98 func (a *UnixAddr) toLocal(net string) sockaddr {
99 return a
100 }
101
102 func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
103 var addr *UnixAddr
104 n, sa, err := c.fd.readFrom(b)
105 switch sa := sa.(type) {
106 case *syscall.SockaddrUnix:
107 if sa.Name != "" {
108 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
109 }
110 }
111 return n, addr, err
112 }
113
114 func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
115 var sa syscall.Sockaddr
116 n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags)
117 if readMsgFlags == 0 && err == nil && oobn > 0 {
118 setReadMsgCloseOnExec(oob[:oobn])
119 }
120
121 switch sa := sa.(type) {
122 case *syscall.SockaddrUnix:
123 if sa.Name != "" {
124 addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
125 }
126 }
127 return
128 }
129
130 func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
131 if c.fd.isConnected {
132 return 0, ErrWriteToConnected
133 }
134 if addr == nil {
135 return 0, errMissingAddress
136 }
137 if addr.Net != sotypeToNet(c.fd.sotype) {
138 return 0, syscall.EAFNOSUPPORT
139 }
140 sa := &syscall.SockaddrUnix{Name: addr.Name}
141 return c.fd.writeTo(b, sa)
142 }
143
144 func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
145 if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
146 return 0, 0, ErrWriteToConnected
147 }
148 var sa syscall.Sockaddr
149 if addr != nil {
150 if addr.Net != sotypeToNet(c.fd.sotype) {
151 return 0, 0, syscall.EAFNOSUPPORT
152 }
153 sa = &syscall.SockaddrUnix{Name: addr.Name}
154 }
155 return c.fd.writeMsg(b, oob, sa)
156 }
157
158 func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
159 fd, err := unixSocket(ctx, sd.network, laddr, raddr, "dial", sd.Dialer.Control)
160 if err != nil {
161 return nil, err
162 }
163 return newUnixConn(fd), nil
164 }
165
166 func (ln *UnixListener) accept() (*UnixConn, error) {
167 fd, err := ln.fd.accept()
168 if err != nil {
169 return nil, err
170 }
171 return newUnixConn(fd), nil
172 }
173
174 func (ln *UnixListener) close() error {
175
176
177
178
179
180
181
182
183
184
185
186 ln.unlinkOnce.Do(func() {
187 if ln.path[0] != '@' && ln.unlink {
188 syscall.Unlink(ln.path)
189 }
190 })
191 return ln.fd.Close()
192 }
193
194 func (ln *UnixListener) file() (*os.File, error) {
195 f, err := ln.fd.dup()
196 if err != nil {
197 return nil, err
198 }
199 return f, nil
200 }
201
202
203
204
205
206
207
208
209
210 func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
211 l.unlink = unlink
212 }
213
214 func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
215 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
216 if err != nil {
217 return nil, err
218 }
219 return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
220 }
221
222 func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
223 fd, err := unixSocket(ctx, sl.network, laddr, nil, "listen", sl.ListenConfig.Control)
224 if err != nil {
225 return nil, err
226 }
227 return newUnixConn(fd), nil
228 }
229
View as plain text