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
14 func probe(filename
, query
string) bool {
17 if file
, err
= open(filename
); err
!= nil {
22 for line
, ok
:= file
.readLine(); ok
&& !r
; line
, ok
= file
.readLine() {
27 for i
:= 0; i
< len(f
); i
++ {
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")
50 v
= probe(netdir
+"/iproute", "4i")
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
, '!')
62 return nil, 0, &ParseError
{Type
: "IP address", Text
: s
}
65 p
, _
, ok
:= dtoi(s
[i
+1:], 0)
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
)}
75 func readPlan9Addr(proto
, filename
string) (addr Addr
, err error
) {
78 f
, err
:= os
.Open(filename
)
83 n
, err
:= f
.Read(buf
[:])
87 ip
, port
, err
:= parsePlan9Addr(string(buf
[:n
]))
93 addr
= &TCPAddr
{IP
: ip
, Port
: port
}
95 addr
= &UDPAddr
{IP
: ip
, Port
: port
}
97 return nil, UnknownNetworkError(proto
)
102 func startPlan9(net
string, addr Addr
) (ctl
*os
.File
, dest
, proto
, name
string, err error
) {
107 switch a
:= addr
.(type) {
117 err
= UnknownNetworkError(net
)
121 clone
, dest
, err
:= queryCS1(proto
, ip
, port
)
125 f
, err
:= os
.OpenFile(clone
, os
.O_RDWR
, 0)
130 n
, err
:= f
.Read(buf
[:])
135 return f
, dest
, proto
, string(buf
[:n
]), nil
138 func netErr(e error
) {
139 oe
, ok
:= e
.(*OpError
)
143 nonNilInterface
:= func(a Addr
) bool {
144 switch a
:= a
.(type) {
155 if nonNilInterface(oe
.Source
) {
158 if nonNilInterface(oe
.Addr
) {
161 if pe
, ok
:= oe
.Err
.(*os
.PathError
); ok
{
162 if _
, ok
= pe
.Err
.(syscall
.ErrorString
); ok
{
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
)
172 return nil, &OpError
{Op
: "dial", Net
: net
, Source
: laddr
, Addr
: raddr
, Err
: err
}
174 _
, err
= f
.WriteString("connect " + dest
)
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)
182 return nil, &OpError
{Op
: "dial", Net
: net
, Source
: laddr
, Addr
: raddr
, Err
: err
}
184 laddr
, err
= readPlan9Addr(proto
, netdir
+"/"+proto
+"/"+name
+"/local")
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
)
197 return nil, &OpError
{Op
: "listen", Net
: net
, Source
: nil, Addr
: laddr
, Err
: err
}
199 _
, err
= f
.WriteString("announce " + dest
)
202 return nil, &OpError
{Op
: "announce", Net
: proto
, Source
: nil, Addr
: laddr
, Err
: err
}
204 laddr
, err
= readPlan9Addr(proto
, netdir
+"/"+proto
+"/"+name
+"/local")
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 {
221 defer fd
.readUnlock()
222 f
, err
:= os
.Open(fd
.dir
+ "/listen")
224 return nil, &OpError
{Op
: "accept", Net
: fd
.dir
+ "/listen", Source
: nil, Addr
: fd
.laddr
, Err
: err
}
227 n
, err
:= f
.Read(buf
[:])
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)
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")
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
)