d226585e086f80c9d01e345b0ed1c1b35fa4b220
[platform/upstream/gcc.git] / libgo / go / net / ipsock_plan9.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 package net
6
7 import (
8         "context"
9         "internal/bytealg"
10         "os"
11         "syscall"
12 )
13
14 // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
15 // capabilities.
16 //
17 // Plan 9 uses IPv6 natively, see ip(3).
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 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
51 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
52         addr := IPv4zero // address contains port only
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 }