Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / net / ipsock_plan9.go
blob93f0f4eec36cf0c3b5358ef4779db2973ac7501d
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.
5 package net
7 import (
8 "context"
9 "internal/bytealg"
10 "os"
11 "syscall"
14 // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
15 // capabilities.
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
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
32 defer file.close()
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
40 for i := 0; i < len(f); i++ {
41 if query == f[i] {
42 r = true
43 break
47 return r
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}
60 p, _, ok := dtoi(s[i+1:])
61 if !ok {
62 return nil, 0, &ParseError{Type: "port", Text: s}
64 if p < 0 || p > 0xFFFF {
65 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
67 return addr, p, nil
70 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
71 var buf [128]byte
73 f, err := os.Open(filename)
74 if err != nil {
75 return
77 defer f.Close()
78 n, err := f.Read(buf[:])
79 if err != nil {
80 return
82 ip, port, err := parsePlan9Addr(string(buf[:n]))
83 if err != nil {
84 return
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)
94 return addr, nil
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
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
116 if port > 65535 {
117 err = InvalidAddrError("port should be < 65536")
118 return
121 clone, dest, err := queryCS1(ctx, proto, ip, port)
122 if err != nil {
123 return
125 f, err := os.OpenFile(clone, os.O_RDWR, 0)
126 if err != nil {
127 return
129 var buf [16]byte
130 n, err := f.Read(buf[:])
131 if err != nil {
132 f.Close()
133 return
135 return f, dest, proto, string(buf[:n]), nil
138 func fixErr(err error) {
139 oe, ok := err.(*OpError)
140 if !ok {
141 return
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
155 if nonNilInterface(oe.Source) {
156 oe.Source = nil
158 if nonNilInterface(oe.Addr) {
159 oe.Addr = nil
161 if pe, ok := oe.Err.(*os.PathError); ok {
162 if _, ok = pe.Err.(syscall.ErrorString); ok {
163 oe.Err = pe.Err
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
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()
186 select {
187 case res := <-resc:
188 return res.fd, res.err
189 case <-ctx.Done():
190 return nil, mapErr(ctx.Err())
194 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
195 if isWildcard(raddr) {
196 raddr = toLocal(raddr, net)
198 f, dest, proto, name, err := startPlan9(ctx, net, raddr)
199 if err != nil {
200 return nil, err
202 _, err = f.WriteString("connect " + dest)
203 if err != nil {
204 f.Close()
205 return nil, err
207 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
208 if err != nil {
209 f.Close()
210 return nil, err
212 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
213 if err != nil {
214 data.Close()
215 f.Close()
216 return nil, err
218 return newFD(proto, name, nil, f, data, laddr, raddr)
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
227 _, err = f.WriteString("announce " + dest)
228 if err != nil {
229 f.Close()
230 return nil, &OpError{Op: "announce", Net: net, Source: laddr, Addr: nil, Err: err}
232 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
233 if err != nil {
234 f.Close()
235 return nil, err
237 return newFD(proto, name, nil, f, nil, laddr, nil)
240 func (fd *netFD) netFD() (*netFD, error) {
241 return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
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
249 defer fd.pfd.ReadUnlock()
250 listen, err := os.Open(fd.dir + "/listen")
251 if err != nil {
252 return nil, err
254 var buf [16]byte
255 n, err := listen.Read(buf[:])
256 if err != nil {
257 listen.Close()
258 return nil, err
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
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
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
279 return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
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()
292 return wildcard
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)
304 return a