Add gcc.dg/parloops-exit-first-loop-alt-4.c
[official-gcc.git] / libgo / go / net / ipsock_plan9.go
blob94ceea31b0350c645f524ed626f4f42d1f46ee74
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 "errors"
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, errors.New("parsing IP failed")
66 p, _, ok := dtoi(s[i+1:], 0)
67 if !ok {
68 return nil, 0, errors.New("parsing port failed")
70 if p < 0 || p > 0xFFFF {
71 return nil, 0, &AddrError{"invalid port", 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, errors.New("unknown protocol " + proto)
100 return addr, nil
103 func startPlan9(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 clone, dest, err := queryCS1(proto, ip, port)
123 if err != nil {
124 return
126 f, err := os.OpenFile(clone, os.O_RDWR, 0)
127 if err != nil {
128 return
130 var buf [16]byte
131 n, err := f.Read(buf[:])
132 if err != nil {
133 f.Close()
134 return
136 return f, dest, proto, string(buf[:n]), nil
139 func netErr(e error) {
140 oe, ok := e.(*OpError)
141 if !ok {
142 return
144 if pe, ok := oe.Err.(*os.PathError); ok {
145 if _, ok = pe.Err.(syscall.ErrorString); ok {
146 oe.Err = pe.Err
151 func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
152 defer func() { netErr(err) }()
153 f, dest, proto, name, err := startPlan9(net, raddr)
154 if err != nil {
155 return nil, &OpError{"dial", net, raddr, err}
157 _, err = f.WriteString("connect " + dest)
158 if err != nil {
159 f.Close()
160 return nil, &OpError{"dial", f.Name(), raddr, err}
162 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
163 if err != nil {
164 f.Close()
165 return nil, &OpError{"dial", net, raddr, err}
167 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
168 if err != nil {
169 data.Close()
170 f.Close()
171 return nil, &OpError{"dial", proto, raddr, err}
173 return newFD(proto, name, f, data, laddr, raddr)
176 func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
177 defer func() { netErr(err) }()
178 f, dest, proto, name, err := startPlan9(net, laddr)
179 if err != nil {
180 return nil, &OpError{"listen", net, laddr, err}
182 _, err = f.WriteString("announce " + dest)
183 if err != nil {
184 f.Close()
185 return nil, &OpError{"announce", proto, laddr, err}
187 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
188 if err != nil {
189 f.Close()
190 return nil, &OpError{Op: "listen", Net: net, Err: err}
192 return newFD(proto, name, f, nil, laddr, nil)
195 func (l *netFD) netFD() (*netFD, error) {
196 return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
199 func (l *netFD) acceptPlan9() (fd *netFD, err error) {
200 defer func() { netErr(err) }()
201 if err := l.readLock(); err != nil {
202 return nil, err
204 defer l.readUnlock()
205 f, err := os.Open(l.dir + "/listen")
206 if err != nil {
207 return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
209 var buf [16]byte
210 n, err := f.Read(buf[:])
211 if err != nil {
212 f.Close()
213 return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
215 name := string(buf[:n])
216 data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
217 if err != nil {
218 f.Close()
219 return nil, &OpError{"accept", l.proto, l.laddr, err}
221 raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
222 if err != nil {
223 data.Close()
224 f.Close()
225 return nil, &OpError{"accept", l.proto, l.laddr, err}
227 return newFD(l.proto, name, f, data, l.laddr, raddr)