libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / ipsock_plan9.go
blob312e4adb47debef9e1fe659d30d8946814b9f4a0
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 "os"
10 "syscall"
13 // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
14 // capabilities.
16 // Plan 9 uses IPv6 natively, see ip(3).
17 func (p *ipStackCapabilities) probe() {
18 p.ipv4Enabled = probe(netdir+"/iproute", "4i")
19 p.ipv6Enabled = probe(netdir+"/iproute", "6i")
20 if p.ipv4Enabled && p.ipv6Enabled {
21 p.ipv4MappedIPv6Enabled = true
25 func probe(filename, query string) bool {
26 var file *file
27 var err error
28 if file, err = open(filename); err != nil {
29 return false
31 defer file.close()
33 r := false
34 for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
35 f := getFields(line)
36 if len(f) < 3 {
37 continue
39 for i := 0; i < len(f); i++ {
40 if query == f[i] {
41 r = true
42 break
46 return r
49 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
50 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
51 addr := IPv4zero // address contains port only
52 i := byteIndex(s, '!')
53 if i >= 0 {
54 addr = ParseIP(s[:i])
55 if addr == nil {
56 return nil, 0, &ParseError{Type: "IP address", Text: s}
59 p, _, ok := dtoi(s[i+1:])
60 if !ok {
61 return nil, 0, &ParseError{Type: "port", Text: s}
63 if p < 0 || p > 0xFFFF {
64 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
66 return addr, p, nil
69 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
70 var buf [128]byte
72 f, err := os.Open(filename)
73 if err != nil {
74 return
76 defer f.Close()
77 n, err := f.Read(buf[:])
78 if err != nil {
79 return
81 ip, port, err := parsePlan9Addr(string(buf[:n]))
82 if err != nil {
83 return
85 switch proto {
86 case "tcp":
87 addr = &TCPAddr{IP: ip, Port: port}
88 case "udp":
89 addr = &UDPAddr{IP: ip, Port: port}
90 default:
91 return nil, UnknownNetworkError(proto)
93 return addr, nil
96 func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
97 var (
98 ip IP
99 port int
101 switch a := addr.(type) {
102 case *TCPAddr:
103 proto = "tcp"
104 ip = a.IP
105 port = a.Port
106 case *UDPAddr:
107 proto = "udp"
108 ip = a.IP
109 port = a.Port
110 default:
111 err = UnknownNetworkError(net)
112 return
115 if port > 65535 {
116 err = InvalidAddrError("port should be < 65536")
117 return
120 clone, dest, err := queryCS1(ctx, proto, ip, port)
121 if err != nil {
122 return
124 f, err := os.OpenFile(clone, os.O_RDWR, 0)
125 if err != nil {
126 return
128 var buf [16]byte
129 n, err := f.Read(buf[:])
130 if err != nil {
131 f.Close()
132 return
134 return f, dest, proto, string(buf[:n]), nil
137 func fixErr(err error) {
138 oe, ok := err.(*OpError)
139 if !ok {
140 return
142 nonNilInterface := func(a Addr) bool {
143 switch a := a.(type) {
144 case *TCPAddr:
145 return a == nil
146 case *UDPAddr:
147 return a == nil
148 case *IPAddr:
149 return a == nil
150 default:
151 return false
154 if nonNilInterface(oe.Source) {
155 oe.Source = nil
157 if nonNilInterface(oe.Addr) {
158 oe.Addr = nil
160 if pe, ok := oe.Err.(*os.PathError); ok {
161 if _, ok = pe.Err.(syscall.ErrorString); ok {
162 oe.Err = pe.Err
167 func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
168 defer func() { fixErr(err) }()
169 type res struct {
170 fd *netFD
171 err error
173 resc := make(chan res)
174 go func() {
175 testHookDialChannel()
176 fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
177 select {
178 case resc <- res{fd, err}:
179 case <-ctx.Done():
180 if fd != nil {
181 fd.Close()
185 select {
186 case res := <-resc:
187 return res.fd, res.err
188 case <-ctx.Done():
189 return nil, mapErr(ctx.Err())
193 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
194 if isWildcard(raddr) {
195 raddr = toLocal(raddr, net)
197 f, dest, proto, name, err := startPlan9(ctx, net, raddr)
198 if err != nil {
199 return nil, err
201 _, err = f.WriteString("connect " + dest)
202 if err != nil {
203 f.Close()
204 return nil, err
206 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
207 if err != nil {
208 f.Close()
209 return nil, err
211 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
212 if err != nil {
213 data.Close()
214 f.Close()
215 return nil, err
217 return newFD(proto, name, nil, f, data, laddr, raddr)
220 func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
221 defer func() { fixErr(err) }()
222 f, dest, proto, name, err := startPlan9(ctx, net, laddr)
223 if err != nil {
224 return nil, err
226 _, err = f.WriteString("announce " + dest)
227 if err != nil {
228 f.Close()
229 return nil, err
231 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
232 if err != nil {
233 f.Close()
234 return nil, err
236 return newFD(proto, name, nil, f, nil, laddr, nil)
239 func (fd *netFD) netFD() (*netFD, error) {
240 return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
243 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
244 defer func() { fixErr(err) }()
245 if err := fd.pfd.ReadLock(); err != nil {
246 return nil, err
248 defer fd.pfd.ReadUnlock()
249 listen, err := os.Open(fd.dir + "/listen")
250 if err != nil {
251 return nil, err
253 var buf [16]byte
254 n, err := listen.Read(buf[:])
255 if err != nil {
256 listen.Close()
257 return nil, err
259 name := string(buf[:n])
260 ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
261 if err != nil {
262 listen.Close()
263 return nil, err
265 data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
266 if err != nil {
267 listen.Close()
268 ctl.Close()
269 return nil, err
271 raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
272 if err != nil {
273 listen.Close()
274 ctl.Close()
275 data.Close()
276 return nil, err
278 return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
281 func isWildcard(a Addr) bool {
282 var wildcard bool
283 switch a := a.(type) {
284 case *TCPAddr:
285 wildcard = a.isWildcard()
286 case *UDPAddr:
287 wildcard = a.isWildcard()
288 case *IPAddr:
289 wildcard = a.isWildcard()
291 return wildcard
294 func toLocal(a Addr, net string) Addr {
295 switch a := a.(type) {
296 case *TCPAddr:
297 a.IP = loopbackIP(net)
298 case *UDPAddr:
299 a.IP = loopbackIP(net)
300 case *IPAddr:
301 a.IP = loopbackIP(net)
303 return a