Source file src/net/ipsock_plan9.go
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "internal/bytealg"
10 "os"
11 "syscall"
12 )
13
14
15
16
17
18 func (p *ipStackCapabilities) probe() {
19 p.ipv4Enabled = probe(netdir+"/iproute", "4i")
20 p.ipv6Enabled = probe(netdir+"/iproute", "6i")
21 if p.ipv4Enabled && p.ipv6Enabled {
22 p.ipv4MappedIPv6Enabled = true
23 }
24 }
25
26 func probe(filename, query string) bool {
27 var file *file
28 var err error
29 if file, err = open(filename); err != nil {
30 return false
31 }
32 defer file.close()
33
34 r := false
35 for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
36 f := getFields(line)
37 if len(f) < 3 {
38 continue
39 }
40 for i := 0; i < len(f); i++ {
41 if query == f[i] {
42 r = true
43 break
44 }
45 }
46 }
47 return r
48 }
49
50
51 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
52 addr := IPv4zero
53 i := bytealg.IndexByteString(s, '!')
54 if i >= 0 {
55 addr = ParseIP(s[:i])
56 if addr == nil {
57 return nil, 0, &ParseError{Type: "IP address", Text: s}
58 }
59 }
60 p, _, ok := dtoi(s[i+1:])
61 if !ok {
62 return nil, 0, &ParseError{Type: "port", Text: s}
63 }
64 if p < 0 || p > 0xFFFF {
65 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
66 }
67 return addr, p, nil
68 }
69
70 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
71 var buf [128]byte
72
73 f, err := os.Open(filename)
74 if err != nil {
75 return
76 }
77 defer f.Close()
78 n, err := f.Read(buf[:])
79 if err != nil {
80 return
81 }
82 ip, port, err := parsePlan9Addr(string(buf[:n]))
83 if err != nil {
84 return
85 }
86 switch proto {
87 case "tcp":
88 addr = &TCPAddr{IP: ip, Port: port}
89 case "udp":
90 addr = &UDPAddr{IP: ip, Port: port}
91 default:
92 return nil, UnknownNetworkError(proto)
93 }
94 return addr, nil
95 }
96
97 func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
98 var (
99 ip IP
100 port int
101 )
102 switch a := addr.(type) {
103 case *TCPAddr:
104 proto = "tcp"
105 ip = a.IP
106 port = a.Port
107 case *UDPAddr:
108 proto = "udp"
109 ip = a.IP
110 port = a.Port
111 default:
112 err = UnknownNetworkError(net)
113 return
114 }
115
116 if port > 65535 {
117 err = InvalidAddrError("port should be < 65536")
118 return
119 }
120
121 clone, dest, err := queryCS1(ctx, proto, ip, port)
122 if err != nil {
123 return
124 }
125 f, err := os.OpenFile(clone, os.O_RDWR, 0)
126 if err != nil {
127 return
128 }
129 var buf [16]byte
130 n, err := f.Read(buf[:])
131 if err != nil {
132 f.Close()
133 return
134 }
135 return f, dest, proto, string(buf[:n]), nil
136 }
137
138 func fixErr(err error) {
139 oe, ok := err.(*OpError)
140 if !ok {
141 return
142 }
143 nonNilInterface := func(a Addr) bool {
144 switch a := a.(type) {
145 case *TCPAddr:
146 return a == nil
147 case *UDPAddr:
148 return a == nil
149 case *IPAddr:
150 return a == nil
151 default:
152 return false
153 }
154 }
155 if nonNilInterface(oe.Source) {
156 oe.Source = nil
157 }
158 if nonNilInterface(oe.Addr) {
159 oe.Addr = nil
160 }
161 if pe, ok := oe.Err.(*os.PathError); ok {
162 if _, ok = pe.Err.(syscall.ErrorString); ok {
163 oe.Err = pe.Err
164 }
165 }
166 }
167
168 func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
169 defer func() { fixErr(err) }()
170 type res struct {
171 fd *netFD
172 err error
173 }
174 resc := make(chan res)
175 go func() {
176 testHookDialChannel()
177 fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
178 select {
179 case resc <- res{fd, err}:
180 case <-ctx.Done():
181 if fd != nil {
182 fd.Close()
183 }
184 }
185 }()
186 select {
187 case res := <-resc:
188 return res.fd, res.err
189 case <-ctx.Done():
190 return nil, mapErr(ctx.Err())
191 }
192 }
193
194 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
195 if isWildcard(raddr) {
196 raddr = toLocal(raddr, net)
197 }
198 f, dest, proto, name, err := startPlan9(ctx, net, raddr)
199 if err != nil {
200 return nil, err
201 }
202 _, err = f.WriteString("connect " + dest)
203 if err != nil {
204 f.Close()
205 return nil, err
206 }
207 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
208 if err != nil {
209 f.Close()
210 return nil, err
211 }
212 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
213 if err != nil {
214 data.Close()
215 f.Close()
216 return nil, err
217 }
218 return newFD(proto, name, nil, f, data, laddr, raddr)
219 }
220
221 func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
222 defer func() { fixErr(err) }()
223 f, dest, proto, name, err := startPlan9(ctx, net, laddr)
224 if err != nil {
225 return nil, err
226 }
227 _, err = f.WriteString("announce " + dest)
228 if err != nil {
229 f.Close()
230 return nil, err
231 }
232 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
233 if err != nil {
234 f.Close()
235 return nil, err
236 }
237 return newFD(proto, name, nil, f, nil, laddr, nil)
238 }
239
240 func (fd *netFD) netFD() (*netFD, error) {
241 return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
242 }
243
244 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
245 defer func() { fixErr(err) }()
246 if err := fd.pfd.ReadLock(); err != nil {
247 return nil, err
248 }
249 defer fd.pfd.ReadUnlock()
250 listen, err := os.Open(fd.dir + "/listen")
251 if err != nil {
252 return nil, err
253 }
254 var buf [16]byte
255 n, err := listen.Read(buf[:])
256 if err != nil {
257 listen.Close()
258 return nil, err
259 }
260 name := string(buf[:n])
261 ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
262 if err != nil {
263 listen.Close()
264 return nil, err
265 }
266 data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
267 if err != nil {
268 listen.Close()
269 ctl.Close()
270 return nil, err
271 }
272 raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
273 if err != nil {
274 listen.Close()
275 ctl.Close()
276 data.Close()
277 return nil, err
278 }
279 return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
280 }
281
282 func isWildcard(a Addr) bool {
283 var wildcard bool
284 switch a := a.(type) {
285 case *TCPAddr:
286 wildcard = a.isWildcard()
287 case *UDPAddr:
288 wildcard = a.isWildcard()
289 case *IPAddr:
290 wildcard = a.isWildcard()
291 }
292 return wildcard
293 }
294
295 func toLocal(a Addr, net string) Addr {
296 switch a := a.(type) {
297 case *TCPAddr:
298 a.IP = loopbackIP(net)
299 case *UDPAddr:
300 a.IP = loopbackIP(net)
301 case *IPAddr:
302 a.IP = loopbackIP(net)
303 }
304 return a
305 }
306
View as plain text