ipsock_plan9.go 6.16 KB
Newer Older
1
// Copyright 2009 The Go Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
8
	"context"
9
	"os"
10
	"syscall"
11 12
)

13 14 15 16 17 18 19 20 21 22 23 24
// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
// capabilities.
//
// Plan 9 uses IPv6 natively, see ip(3).
func (p *ipStackCapabilities) probe() {
	p.ipv4Enabled = probe(netdir+"/iproute", "4i")
	p.ipv6Enabled = probe(netdir+"/iproute", "6i")
	if p.ipv4Enabled && p.ipv6Enabled {
		p.ipv4MappedIPv6Enabled = true
	}
}

25 26 27 28 29 30
func probe(filename, query string) bool {
	var file *file
	var err error
	if file, err = open(filename); err != nil {
		return false
	}
31
	defer file.close()
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

	r := false
	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
		f := getFields(line)
		if len(f) < 3 {
			continue
		}
		for i := 0; i < len(f); i++ {
			if query == f[i] {
				r = true
				break
			}
		}
	}
	return r
}

49
// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
50
func parsePlan9Addr(s string) (ip IP, iport int, err error) {
51 52
	addr := IPv4zero // address contains port only
	i := byteIndex(s, '!')
53 54 55
	if i >= 0 {
		addr = ParseIP(s[:i])
		if addr == nil {
56
			return nil, 0, &ParseError{Type: "IP address", Text: s}
57 58
		}
	}
59
	p, _, ok := dtoi(s[i+1:])
60
	if !ok {
61
		return nil, 0, &ParseError{Type: "port", Text: s}
62 63
	}
	if p < 0 || p > 0xFFFF {
64
		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
65 66 67 68
	}
	return addr, p, nil
}

69
func readPlan9Addr(proto, filename string) (addr Addr, err error) {
70 71 72 73 74 75
	var buf [128]byte

	f, err := os.Open(filename)
	if err != nil {
		return
	}
76
	defer f.Close()
77 78 79 80 81 82 83 84 85 86
	n, err := f.Read(buf[:])
	if err != nil {
		return
	}
	ip, port, err := parsePlan9Addr(string(buf[:n]))
	if err != nil {
		return
	}
	switch proto {
	case "tcp":
87
		addr = &TCPAddr{IP: ip, Port: port}
88
	case "udp":
89
		addr = &UDPAddr{IP: ip, Port: port}
90
	default:
91
		return nil, UnknownNetworkError(proto)
92 93 94 95
	}
	return addr, nil
}

96
func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	var (
		ip   IP
		port int
	)
	switch a := addr.(type) {
	case *TCPAddr:
		proto = "tcp"
		ip = a.IP
		port = a.Port
	case *UDPAddr:
		proto = "udp"
		ip = a.IP
		port = a.Port
	default:
		err = UnknownNetworkError(net)
		return
	}

115 116 117 118 119
	if port > 65535 {
		err = InvalidAddrError("port should be < 65536")
		return
	}

120
	clone, dest, err := queryCS1(ctx, proto, ip, port)
121 122 123 124 125 126 127 128 129 130
	if err != nil {
		return
	}
	f, err := os.OpenFile(clone, os.O_RDWR, 0)
	if err != nil {
		return
	}
	var buf [16]byte
	n, err := f.Read(buf[:])
	if err != nil {
131
		f.Close()
132 133 134 135 136
		return
	}
	return f, dest, proto, string(buf[:n]), nil
}

137 138
func fixErr(err error) {
	oe, ok := err.(*OpError)
139 140 141
	if !ok {
		return
	}
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	nonNilInterface := func(a Addr) bool {
		switch a := a.(type) {
		case *TCPAddr:
			return a == nil
		case *UDPAddr:
			return a == nil
		case *IPAddr:
			return a == nil
		default:
			return false
		}
	}
	if nonNilInterface(oe.Source) {
		oe.Source = nil
	}
	if nonNilInterface(oe.Addr) {
		oe.Addr = nil
	}
160 161 162 163 164 165 166
	if pe, ok := oe.Err.(*os.PathError); ok {
		if _, ok = pe.Err.(syscall.ErrorString); ok {
			oe.Err = pe.Err
		}
	}
}

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
	defer func() { fixErr(err) }()
	type res struct {
		fd  *netFD
		err error
	}
	resc := make(chan res)
	go func() {
		testHookDialChannel()
		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
		select {
		case resc <- res{fd, err}:
		case <-ctx.Done():
			if fd != nil {
				fd.Close()
			}
		}
	}()
	select {
	case res := <-resc:
		return res.fd, res.err
	case <-ctx.Done():
		return nil, mapErr(ctx.Err())
	}
}

func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
194 195 196
	if isWildcard(raddr) {
		raddr = toLocal(raddr, net)
	}
197
	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
198
	if err != nil {
199
		return nil, err
200 201 202
	}
	_, err = f.WriteString("connect " + dest)
	if err != nil {
203
		f.Close()
204
		return nil, err
205
	}
206
	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
207
	if err != nil {
208
		f.Close()
209
		return nil, err
210
	}
211
	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
212
	if err != nil {
213
		data.Close()
214
		f.Close()
215
		return nil, err
216
	}
217
	return newFD(proto, name, nil, f, data, laddr, raddr)
218 219
}

220 221 222
func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
	defer func() { fixErr(err) }()
	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
223
	if err != nil {
224
		return nil, err
225 226 227
	}
	_, err = f.WriteString("announce " + dest)
	if err != nil {
228
		f.Close()
229
		return nil, err
230
	}
231
	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
232
	if err != nil {
233
		f.Close()
234
		return nil, err
235
	}
236
	return newFD(proto, name, nil, f, nil, laddr, nil)
237 238
}

239
func (fd *netFD) netFD() (*netFD, error) {
240
	return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
241 242
}

243
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
244
	defer func() { fixErr(err) }()
245
	if err := fd.pfd.ReadLock(); err != nil {
246 247
		return nil, err
	}
248
	defer fd.pfd.ReadUnlock()
249
	listen, err := os.Open(fd.dir + "/listen")
250
	if err != nil {
251
		return nil, err
252 253
	}
	var buf [16]byte
254
	n, err := listen.Read(buf[:])
255
	if err != nil {
256
		listen.Close()
257
		return nil, err
258 259
	}
	name := string(buf[:n])
260 261 262 263 264
	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
	if err != nil {
		listen.Close()
		return nil, err
	}
265
	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
266
	if err != nil {
267 268
		listen.Close()
		ctl.Close()
269
		return nil, err
270
	}
271
	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
272
	if err != nil {
273 274
		listen.Close()
		ctl.Close()
275
		data.Close()
276
		return nil, err
277
	}
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
}

func isWildcard(a Addr) bool {
	var wildcard bool
	switch a := a.(type) {
	case *TCPAddr:
		wildcard = a.isWildcard()
	case *UDPAddr:
		wildcard = a.isWildcard()
	case *IPAddr:
		wildcard = a.isWildcard()
	}
	return wildcard
}

func toLocal(a Addr, net string) Addr {
	switch a := a.(type) {
	case *TCPAddr:
		a.IP = loopbackIP(net)
	case *UDPAddr:
		a.IP = loopbackIP(net)
	case *IPAddr:
		a.IP = loopbackIP(net)
	}
	return a
304
}