* da.po, sv.po: Update.
[official-gcc.git] / libgo / go / net / ipsock_plan9.go
blob9da6ec3053b4ee2a4cf554d1de6a50575c14b868
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 "os"
11 "syscall"
14 func probe(filename, query string) bool {
15 var file *file
16 var err error
17 if file, err = open(filename); err != nil {
18 return false
21 r := false
22 for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
23 f := getFields(line)
24 if len(f) < 3 {
25 continue
27 for i := 0; i < len(f); i++ {
28 if query == f[i] {
29 r = true
30 break
34 file.close()
35 return r
38 func probeIPv4Stack() bool {
39 return probe(netdir+"/iproute", "4i")
42 // probeIPv6Stack returns two boolean values. If the first boolean
43 // value is true, kernel supports basic IPv6 functionality. If the
44 // second boolean value is true, kernel supports IPv6 IPv4-mapping.
45 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
46 // Plan 9 uses IPv6 natively, see ip(3).
47 r := probe(netdir+"/iproute", "6i")
48 v := false
49 if r {
50 v = probe(netdir+"/iproute", "4i")
52 return r, v
55 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
56 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
57 addr := IPv4zero // address contains port only
58 i := byteIndex(s, '!')
59 if i >= 0 {
60 addr = ParseIP(s[:i])
61 if addr == nil {
62 return nil, 0, &ParseError{Type: "IP address", Text: s}
65 p, _, ok := dtoi(s[i+1:], 0)
66 if !ok {
67 return nil, 0, &ParseError{Type: "port", Text: s}
69 if p < 0 || p > 0xFFFF {
70 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
72 return addr, p, nil
75 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
76 var buf [128]byte
78 f, err := os.Open(filename)
79 if err != nil {
80 return
82 defer f.Close()
83 n, err := f.Read(buf[:])
84 if err != nil {
85 return
87 ip, port, err := parsePlan9Addr(string(buf[:n]))
88 if err != nil {
89 return
91 switch proto {
92 case "tcp":
93 addr = &TCPAddr{IP: ip, Port: port}
94 case "udp":
95 addr = &UDPAddr{IP: ip, Port: port}
96 default:
97 return nil, UnknownNetworkError(proto)
99 return addr, nil
102 func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
103 var (
104 ip IP
105 port int
107 switch a := addr.(type) {
108 case *TCPAddr:
109 proto = "tcp"
110 ip = a.IP
111 port = a.Port
112 case *UDPAddr:
113 proto = "udp"
114 ip = a.IP
115 port = a.Port
116 default:
117 err = UnknownNetworkError(net)
118 return
121 clone, dest, err := queryCS1(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 netErr(e error) {
139 oe, ok := e.(*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(net string, laddr, raddr Addr) (fd *netFD, err error) {
169 defer func() { netErr(err) }()
170 f, dest, proto, name, err := startPlan9(net, raddr)
171 if err != nil {
172 return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
174 _, err = f.WriteString("connect " + dest)
175 if err != nil {
176 f.Close()
177 return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
179 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
180 if err != nil {
181 f.Close()
182 return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
184 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
185 if err != nil {
186 data.Close()
187 f.Close()
188 return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
190 return newFD(proto, name, f, data, laddr, raddr)
193 func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
194 defer func() { netErr(err) }()
195 f, dest, proto, name, err := startPlan9(net, laddr)
196 if err != nil {
197 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
199 _, err = f.WriteString("announce " + dest)
200 if err != nil {
201 f.Close()
202 return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
204 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
205 if err != nil {
206 f.Close()
207 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
209 return newFD(proto, name, f, nil, laddr, nil)
212 func (fd *netFD) netFD() (*netFD, error) {
213 return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
216 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
217 defer func() { netErr(err) }()
218 if err := fd.readLock(); err != nil {
219 return nil, err
221 defer fd.readUnlock()
222 f, err := os.Open(fd.dir + "/listen")
223 if err != nil {
224 return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
226 var buf [16]byte
227 n, err := f.Read(buf[:])
228 if err != nil {
229 f.Close()
230 return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
232 name := string(buf[:n])
233 data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
234 if err != nil {
235 f.Close()
236 return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
238 raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
239 if err != nil {
240 data.Close()
241 f.Close()
242 return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
244 return newFD(fd.net, name, f, data, fd.laddr, raddr)