OSDN Git Service

Update Go library to r60.
[pf3gnuchains/gcc-fork.git] / libgo / go / net / ipsock_plan9.go
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.
4
5 // IP sockets stubs for Plan 9
6
7 package net
8
9 import (
10         "os"
11 )
12
13 // probeIPv6Stack returns two boolean values.  If the first boolean value is
14 // true, kernel supports basic IPv6 functionality.  If the second
15 // boolean value is true, kernel supports IPv6 IPv4-mapping.
16 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
17         return false, false
18 }
19
20 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
21 func parsePlan9Addr(s string) (ip IP, iport int, err os.Error) {
22         var (
23                 addr IP
24                 p, i int
25                 ok   bool
26         )
27         addr = IPv4zero // address contains port only
28         i = byteIndex(s, '!')
29         if i >= 0 {
30                 addr = ParseIP(s[:i])
31                 if addr == nil {
32                         err = os.NewError("net: parsing IP failed")
33                         goto Error
34                 }
35         }
36         p, _, ok = dtoi(s[i+1:], 0)
37         if !ok {
38                 err = os.NewError("net: parsing port failed")
39                 goto Error
40         }
41         if p < 0 || p > 0xFFFF {
42                 err = &AddrError{"invalid port", string(p)}
43                 goto Error
44         }
45         return addr, p, nil
46
47 Error:
48         return nil, 0, err
49 }
50
51 func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
52         var buf [128]byte
53
54         f, err := os.Open(filename)
55         if err != nil {
56                 return
57         }
58         n, err := f.Read(buf[:])
59         if err != nil {
60                 return
61         }
62         ip, port, err := parsePlan9Addr(string(buf[:n]))
63         if err != nil {
64                 return
65         }
66         switch proto {
67         case "tcp":
68                 addr = &TCPAddr{ip, port}
69         case "udp":
70                 addr = &UDPAddr{ip, port}
71         default:
72                 return nil, os.NewError("unknown protocol " + proto)
73         }
74         return addr, nil
75 }
76
77 type plan9Conn struct {
78         proto, name, dir string
79         ctl, data        *os.File
80         laddr, raddr     Addr
81 }
82
83 func newPlan9Conn(proto, name string, ctl *os.File, laddr, raddr Addr) *plan9Conn {
84         return &plan9Conn{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
85 }
86
87 func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
88
89 // Implementation of the Conn interface - see Conn for documentation.
90
91 // Read implements the net.Conn Read method.
92 func (c *plan9Conn) Read(b []byte) (n int, err os.Error) {
93         if !c.ok() {
94                 return 0, os.EINVAL
95         }
96         if c.data == nil {
97                 c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
98                 if err != nil {
99                         return 0, err
100                 }
101         }
102         n, err = c.data.Read(b)
103         if c.proto == "udp" && err == os.EOF {
104                 n = 0
105                 err = nil
106         }
107         return
108 }
109
110 // Write implements the net.Conn Write method.
111 func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
112         if !c.ok() {
113                 return 0, os.EINVAL
114         }
115         if c.data == nil {
116                 c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
117                 if err != nil {
118                         return 0, err
119                 }
120         }
121         return c.data.Write(b)
122 }
123
124 // Close closes the connection.
125 func (c *plan9Conn) Close() os.Error {
126         if !c.ok() {
127                 return os.EINVAL
128         }
129         err := c.ctl.Close()
130         if err != nil {
131                 return err
132         }
133         if c.data != nil {
134                 err = c.data.Close()
135         }
136         c.ctl = nil
137         c.data = nil
138         return err
139 }
140
141 // LocalAddr returns the local network address.
142 func (c *plan9Conn) LocalAddr() Addr {
143         if !c.ok() {
144                 return nil
145         }
146         return c.laddr
147 }
148
149 // RemoteAddr returns the remote network address.
150 func (c *plan9Conn) RemoteAddr() Addr {
151         if !c.ok() {
152                 return nil
153         }
154         return c.raddr
155 }
156
157 // SetTimeout implements the net.Conn SetTimeout method.
158 func (c *plan9Conn) SetTimeout(nsec int64) os.Error {
159         if !c.ok() {
160                 return os.EINVAL
161         }
162         return os.EPLAN9
163 }
164
165 // SetReadTimeout implements the net.Conn SetReadTimeout method.
166 func (c *plan9Conn) SetReadTimeout(nsec int64) os.Error {
167         if !c.ok() {
168                 return os.EINVAL
169         }
170         return os.EPLAN9
171 }
172
173 // SetWriteTimeout implements the net.Conn SetWriteTimeout method.
174 func (c *plan9Conn) SetWriteTimeout(nsec int64) os.Error {
175         if !c.ok() {
176                 return os.EINVAL
177         }
178         return os.EPLAN9
179 }
180
181 func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err os.Error) {
182         var (
183                 ip   IP
184                 port int
185         )
186         switch a := addr.(type) {
187         case *TCPAddr:
188                 proto = "tcp"
189                 ip = a.IP
190                 port = a.Port
191         case *UDPAddr:
192                 proto = "udp"
193                 ip = a.IP
194                 port = a.Port
195         default:
196                 err = UnknownNetworkError(net)
197                 return
198         }
199
200         clone, dest, err := queryCS1(proto, ip, port)
201         if err != nil {
202                 return
203         }
204         f, err := os.OpenFile(clone, os.O_RDWR, 0)
205         if err != nil {
206                 return
207         }
208         var buf [16]byte
209         n, err := f.Read(buf[:])
210         if err != nil {
211                 return
212         }
213         return f, dest, proto, string(buf[:n]), nil
214 }
215
216 func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err os.Error) {
217         f, dest, proto, name, err := startPlan9(net, raddr)
218         if err != nil {
219                 return
220         }
221         _, err = f.WriteString("connect " + dest)
222         if err != nil {
223                 return
224         }
225         laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
226         if err != nil {
227                 return
228         }
229         raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
230         if err != nil {
231                 return
232         }
233         return newPlan9Conn(proto, name, f, laddr, raddr), nil
234 }
235
236 type plan9Listener struct {
237         proto, name, dir string
238         ctl              *os.File
239         laddr            Addr
240 }
241
242 func listenPlan9(net string, laddr Addr) (l *plan9Listener, err os.Error) {
243         f, dest, proto, name, err := startPlan9(net, laddr)
244         if err != nil {
245                 return
246         }
247         _, err = f.WriteString("announce " + dest)
248         if err != nil {
249                 return
250         }
251         laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
252         if err != nil {
253                 return
254         }
255         l = new(plan9Listener)
256         l.proto = proto
257         l.name = name
258         l.dir = "/net/" + proto + "/" + name
259         l.ctl = f
260         l.laddr = laddr
261         return l, nil
262 }
263
264 func (l *plan9Listener) plan9Conn() *plan9Conn {
265         return newPlan9Conn(l.proto, l.name, l.ctl, l.laddr, nil)
266 }
267
268 func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err os.Error) {
269         f, err := os.Open(l.dir + "/listen")
270         if err != nil {
271                 return
272         }
273         var buf [16]byte
274         n, err := f.Read(buf[:])
275         if err != nil {
276                 return
277         }
278         name := string(buf[:n])
279         laddr, err := readPlan9Addr(l.proto, l.dir+"/local")
280         if err != nil {
281                 return
282         }
283         raddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
284         if err != nil {
285                 return
286         }
287         return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
288 }
289
290 func (l *plan9Listener) Accept() (c Conn, err os.Error) {
291         c1, err := l.acceptPlan9()
292         if err != nil {
293                 return
294         }
295         return c1, nil
296 }
297
298 func (l *plan9Listener) Close() os.Error {
299         if l == nil || l.ctl == nil {
300                 return os.EINVAL
301         }
302         return l.ctl.Close()
303 }
304
305 func (l *plan9Listener) Addr() Addr { return l.laddr }