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
15 func probe(filename
, query
string) bool {
18 if file
, err
= open(filename
); err
!= nil {
23 for line
, ok
:= file
.readLine(); ok
&& !r
; line
, ok
= file
.readLine() {
28 for i
:= 0; i
< len(f
); i
++ {
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")
51 v
= probe(netdir
+"/iproute", "4i")
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
, '!')
63 return nil, 0, errors
.New("parsing IP failed")
66 p
, _
, ok
:= dtoi(s
[i
+1:], 0)
68 return nil, 0, errors
.New("parsing port failed")
70 if p
< 0 || p
> 0xFFFF {
71 return nil, 0, &AddrError
{"invalid port", string(p
)}
76 func readPlan9Addr(proto
, filename
string) (addr Addr
, err error
) {
79 f
, err
:= os
.Open(filename
)
84 n
, err
:= f
.Read(buf
[:])
88 ip
, port
, err
:= parsePlan9Addr(string(buf
[:n
]))
94 addr
= &TCPAddr
{IP
: ip
, Port
: port
}
96 addr
= &UDPAddr
{IP
: ip
, Port
: port
}
98 return nil, errors
.New("unknown protocol " + proto
)
103 func startPlan9(net
string, addr Addr
) (ctl
*os
.File
, dest
, proto
, name
string, err error
) {
108 switch a
:= addr
.(type) {
118 err
= UnknownNetworkError(net
)
122 clone
, dest
, err
:= queryCS1(proto
, ip
, port
)
126 f
, err
:= os
.OpenFile(clone
, os
.O_RDWR
, 0)
131 n
, err
:= f
.Read(buf
[:])
136 return f
, dest
, proto
, string(buf
[:n
]), nil
139 func netErr(e error
) {
140 oe
, ok
:= e
.(*OpError
)
144 if pe
, ok
:= oe
.Err
.(*os
.PathError
); ok
{
145 if _
, ok
= pe
.Err
.(syscall
.ErrorString
); ok
{
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
)
155 return nil, &OpError
{"dial", net
, raddr
, err
}
157 _
, err
= f
.WriteString("connect " + dest
)
160 return nil, &OpError
{"dial", f
.Name(), raddr
, err
}
162 data
, err
:= os
.OpenFile(netdir
+"/"+proto
+"/"+name
+"/data", os
.O_RDWR
, 0)
165 return nil, &OpError
{"dial", net
, raddr
, err
}
167 laddr
, err
= readPlan9Addr(proto
, netdir
+"/"+proto
+"/"+name
+"/local")
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
)
180 return nil, &OpError
{"listen", net
, laddr
, err
}
182 _
, err
= f
.WriteString("announce " + dest
)
185 return nil, &OpError
{"announce", proto
, laddr
, err
}
187 laddr
, err
= readPlan9Addr(proto
, netdir
+"/"+proto
+"/"+name
+"/local")
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 {
205 f
, err
:= os
.Open(l
.dir
+ "/listen")
207 return nil, &OpError
{"accept", l
.dir
+ "/listen", l
.laddr
, err
}
210 n
, err
:= f
.Read(buf
[:])
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)
219 return nil, &OpError
{"accept", l
.proto
, l
.laddr
, err
}
221 raddr
, err
:= readPlan9Addr(l
.proto
, netdir
+"/"+l
.proto
+"/"+name
+"/remote")
225 return nil, &OpError
{"accept", l
.proto
, l
.laddr
, err
}
227 return newFD(l
.proto
, name
, f
, data
, l
.laddr
, raddr
)