* gcc-interface/decl.c (warn_on_field_placement): Issue the warning
[official-gcc.git] / libgo / go / net / ipsock_plan9.go
blobb7fd344c8ad4a931fce68286f3b58e56a9101807
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 // Internet protocol family sockets for Plan 9
7 package net
9 import (
10 "context"
11 "os"
12 "syscall"
15 func probe(filename, query string) bool {
16 var file *file
17 var err error
18 if file, err = open(filename); err != nil {
19 return false
22 r := false
23 for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
24 f := getFields(line)
25 if len(f) < 3 {
26 continue
28 for i := 0; i < len(f); i++ {
29 if query == f[i] {
30 r = true
31 break
35 file.close()
36 return r
39 func probeIPv4Stack() bool {
40 return probe(netdir+"/iproute", "4i")
43 // probeIPv6Stack returns two boolean values. If the first boolean
44 // value is true, kernel supports basic IPv6 functionality. If the
45 // second boolean value is true, kernel supports IPv6 IPv4-mapping.
46 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
47 // Plan 9 uses IPv6 natively, see ip(3).
48 r := probe(netdir+"/iproute", "6i")
49 v := false
50 if r {
51 v = probe(netdir+"/iproute", "4i")
53 return r, v
56 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
57 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
58 addr := IPv4zero // address contains port only
59 i := byteIndex(s, '!')
60 if i >= 0 {
61 addr = ParseIP(s[:i])
62 if addr == nil {
63 return nil, 0, &ParseError{Type: "IP address", Text: s}
66 p, _, ok := dtoi(s[i+1:])
67 if !ok {
68 return nil, 0, &ParseError{Type: "port", Text: s}
70 if p < 0 || p > 0xFFFF {
71 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
73 return addr, p, nil
76 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
77 var buf [128]byte
79 f, err := os.Open(filename)
80 if err != nil {
81 return
83 defer f.Close()
84 n, err := f.Read(buf[:])
85 if err != nil {
86 return
88 ip, port, err := parsePlan9Addr(string(buf[:n]))
89 if err != nil {
90 return
92 switch proto {
93 case "tcp":
94 addr = &TCPAddr{IP: ip, Port: port}
95 case "udp":
96 addr = &UDPAddr{IP: ip, Port: port}
97 default:
98 return nil, UnknownNetworkError(proto)
100 return addr, nil
103 func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
104 var (
105 ip IP
106 port int
108 switch a := addr.(type) {
109 case *TCPAddr:
110 proto = "tcp"
111 ip = a.IP
112 port = a.Port
113 case *UDPAddr:
114 proto = "udp"
115 ip = a.IP
116 port = a.Port
117 default:
118 err = UnknownNetworkError(net)
119 return
122 if port > 65535 {
123 err = InvalidAddrError("port should be < 65536")
124 return
127 clone, dest, err := queryCS1(ctx, proto, ip, port)
128 if err != nil {
129 return
131 f, err := os.OpenFile(clone, os.O_RDWR, 0)
132 if err != nil {
133 return
135 var buf [16]byte
136 n, err := f.Read(buf[:])
137 if err != nil {
138 f.Close()
139 return
141 return f, dest, proto, string(buf[:n]), nil
144 func fixErr(err error) {
145 oe, ok := err.(*OpError)
146 if !ok {
147 return
149 nonNilInterface := func(a Addr) bool {
150 switch a := a.(type) {
151 case *TCPAddr:
152 return a == nil
153 case *UDPAddr:
154 return a == nil
155 case *IPAddr:
156 return a == nil
157 default:
158 return false
161 if nonNilInterface(oe.Source) {
162 oe.Source = nil
164 if nonNilInterface(oe.Addr) {
165 oe.Addr = nil
167 if pe, ok := oe.Err.(*os.PathError); ok {
168 if _, ok = pe.Err.(syscall.ErrorString); ok {
169 oe.Err = pe.Err
174 func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
175 defer func() { fixErr(err) }()
176 type res struct {
177 fd *netFD
178 err error
180 resc := make(chan res)
181 go func() {
182 testHookDialChannel()
183 fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
184 select {
185 case resc <- res{fd, err}:
186 case <-ctx.Done():
187 if fd != nil {
188 fd.Close()
192 select {
193 case res := <-resc:
194 return res.fd, res.err
195 case <-ctx.Done():
196 return nil, mapErr(ctx.Err())
200 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
201 if isWildcard(raddr) {
202 raddr = toLocal(raddr, net)
204 f, dest, proto, name, err := startPlan9(ctx, net, raddr)
205 if err != nil {
206 return nil, err
208 _, err = f.WriteString("connect " + dest)
209 if err != nil {
210 f.Close()
211 return nil, err
213 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
214 if err != nil {
215 f.Close()
216 return nil, err
218 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
219 if err != nil {
220 data.Close()
221 f.Close()
222 return nil, err
224 return newFD(proto, name, nil, f, data, laddr, raddr)
227 func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
228 defer func() { fixErr(err) }()
229 f, dest, proto, name, err := startPlan9(ctx, net, laddr)
230 if err != nil {
231 return nil, err
233 _, err = f.WriteString("announce " + dest)
234 if err != nil {
235 f.Close()
236 return nil, err
238 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
239 if err != nil {
240 f.Close()
241 return nil, err
243 return newFD(proto, name, nil, f, nil, laddr, nil)
246 func (fd *netFD) netFD() (*netFD, error) {
247 return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
250 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
251 defer func() { fixErr(err) }()
252 if err := fd.readLock(); err != nil {
253 return nil, err
255 defer fd.readUnlock()
256 listen, err := os.Open(fd.dir + "/listen")
257 if err != nil {
258 return nil, err
260 var buf [16]byte
261 n, err := listen.Read(buf[:])
262 if err != nil {
263 listen.Close()
264 return nil, err
266 name := string(buf[:n])
267 ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
268 if err != nil {
269 listen.Close()
270 return nil, err
272 data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
273 if err != nil {
274 listen.Close()
275 ctl.Close()
276 return nil, err
278 raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
279 if err != nil {
280 listen.Close()
281 ctl.Close()
282 data.Close()
283 return nil, err
285 return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
288 func isWildcard(a Addr) bool {
289 var wildcard bool
290 switch a := a.(type) {
291 case *TCPAddr:
292 wildcard = a.isWildcard()
293 case *UDPAddr:
294 wildcard = a.isWildcard()
295 case *IPAddr:
296 wildcard = a.isWildcard()
298 return wildcard
301 func toLocal(a Addr, net string) Addr {
302 switch a := a.(type) {
303 case *TCPAddr:
304 a.IP = loopbackIP(net)
305 case *UDPAddr:
306 a.IP = loopbackIP(net)
307 case *IPAddr:
308 a.IP = loopbackIP(net)
310 return a