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