Home | History | Annotate | Download | only in net
      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 // Internet protocol family sockets for Plan 9
      6 
      7 package net
      8 
      9 import (
     10 	"context"
     11 	"os"
     12 	"syscall"
     13 )
     14 
     15 func probe(filename, query string) bool {
     16 	var file *file
     17 	var err error
     18 	if file, err = open(filename); err != nil {
     19 		return false
     20 	}
     21 
     22 	r := false
     23 	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
     24 		f := getFields(line)
     25 		if len(f) < 3 {
     26 			continue
     27 		}
     28 		for i := 0; i < len(f); i++ {
     29 			if query == f[i] {
     30 				r = true
     31 				break
     32 			}
     33 		}
     34 	}
     35 	file.close()
     36 	return r
     37 }
     38 
     39 func probeIPv4Stack() bool {
     40 	return probe(netdir+"/iproute", "4i")
     41 }
     42 
     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")
     49 	v := false
     50 	if r {
     51 		v = probe(netdir+"/iproute", "4i")
     52 	}
     53 	return r, v
     54 }
     55 
     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, '!')
     60 	if i >= 0 {
     61 		addr = ParseIP(s[:i])
     62 		if addr == nil {
     63 			return nil, 0, &ParseError{Type: "IP address", Text: s}
     64 		}
     65 	}
     66 	p, _, ok := dtoi(s[i+1:])
     67 	if !ok {
     68 		return nil, 0, &ParseError{Type: "port", Text: s}
     69 	}
     70 	if p < 0 || p > 0xFFFF {
     71 		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
     72 	}
     73 	return addr, p, nil
     74 }
     75 
     76 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
     77 	var buf [128]byte
     78 
     79 	f, err := os.Open(filename)
     80 	if err != nil {
     81 		return
     82 	}
     83 	defer f.Close()
     84 	n, err := f.Read(buf[:])
     85 	if err != nil {
     86 		return
     87 	}
     88 	ip, port, err := parsePlan9Addr(string(buf[:n]))
     89 	if err != nil {
     90 		return
     91 	}
     92 	switch proto {
     93 	case "tcp":
     94 		addr = &TCPAddr{IP: ip, Port: port}
     95 	case "udp":
     96 		addr = &UDPAddr{IP: ip, Port: port}
     97 	default:
     98 		return nil, UnknownNetworkError(proto)
     99 	}
    100 	return addr, nil
    101 }
    102 
    103 func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
    104 	var (
    105 		ip   IP
    106 		port int
    107 	)
    108 	switch a := addr.(type) {
    109 	case *TCPAddr:
    110 		proto = "tcp"
    111 		ip = a.IP
    112 		port = a.Port
    113 	case *UDPAddr:
    114 		proto = "udp"
    115 		ip = a.IP
    116 		port = a.Port
    117 	default:
    118 		err = UnknownNetworkError(net)
    119 		return
    120 	}
    121 
    122 	if port > 65535 {
    123 		err = InvalidAddrError("port should be < 65536")
    124 		return
    125 	}
    126 
    127 	clone, dest, err := queryCS1(ctx, proto, ip, port)
    128 	if err != nil {
    129 		return
    130 	}
    131 	f, err := os.OpenFile(clone, os.O_RDWR, 0)
    132 	if err != nil {
    133 		return
    134 	}
    135 	var buf [16]byte
    136 	n, err := f.Read(buf[:])
    137 	if err != nil {
    138 		f.Close()
    139 		return
    140 	}
    141 	return f, dest, proto, string(buf[:n]), nil
    142 }
    143 
    144 func fixErr(err error) {
    145 	oe, ok := err.(*OpError)
    146 	if !ok {
    147 		return
    148 	}
    149 	nonNilInterface := func(a Addr) bool {
    150 		switch a := a.(type) {
    151 		case *TCPAddr:
    152 			return a == nil
    153 		case *UDPAddr:
    154 			return a == nil
    155 		case *IPAddr:
    156 			return a == nil
    157 		default:
    158 			return false
    159 		}
    160 	}
    161 	if nonNilInterface(oe.Source) {
    162 		oe.Source = nil
    163 	}
    164 	if nonNilInterface(oe.Addr) {
    165 		oe.Addr = nil
    166 	}
    167 	if pe, ok := oe.Err.(*os.PathError); ok {
    168 		if _, ok = pe.Err.(syscall.ErrorString); ok {
    169 			oe.Err = pe.Err
    170 		}
    171 	}
    172 }
    173 
    174 func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
    175 	defer func() { fixErr(err) }()
    176 	type res struct {
    177 		fd  *netFD
    178 		err error
    179 	}
    180 	resc := make(chan res)
    181 	go func() {
    182 		testHookDialChannel()
    183 		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
    184 		select {
    185 		case resc <- res{fd, err}:
    186 		case <-ctx.Done():
    187 			if fd != nil {
    188 				fd.Close()
    189 			}
    190 		}
    191 	}()
    192 	select {
    193 	case res := <-resc:
    194 		return res.fd, res.err
    195 	case <-ctx.Done():
    196 		return nil, mapErr(ctx.Err())
    197 	}
    198 }
    199 
    200 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
    201 	if isWildcard(raddr) {
    202 		raddr = toLocal(raddr, net)
    203 	}
    204 	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
    205 	if err != nil {
    206 		return nil, err
    207 	}
    208 	_, err = f.WriteString("connect " + dest)
    209 	if err != nil {
    210 		f.Close()
    211 		return nil, err
    212 	}
    213 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
    214 	if err != nil {
    215 		f.Close()
    216 		return nil, err
    217 	}
    218 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
    219 	if err != nil {
    220 		data.Close()
    221 		f.Close()
    222 		return nil, err
    223 	}
    224 	return newFD(proto, name, nil, f, data, laddr, raddr)
    225 }
    226 
    227 func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
    228 	defer func() { fixErr(err) }()
    229 	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
    230 	if err != nil {
    231 		return nil, err
    232 	}
    233 	_, err = f.WriteString("announce " + dest)
    234 	if err != nil {
    235 		f.Close()
    236 		return nil, err
    237 	}
    238 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
    239 	if err != nil {
    240 		f.Close()
    241 		return nil, err
    242 	}
    243 	return newFD(proto, name, nil, f, nil, laddr, nil)
    244 }
    245 
    246 func (fd *netFD) netFD() (*netFD, error) {
    247 	return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
    248 }
    249 
    250 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
    251 	defer func() { fixErr(err) }()
    252 	if err := fd.readLock(); err != nil {
    253 		return nil, err
    254 	}
    255 	defer fd.readUnlock()
    256 	listen, err := os.Open(fd.dir + "/listen")
    257 	if err != nil {
    258 		return nil, err
    259 	}
    260 	var buf [16]byte
    261 	n, err := listen.Read(buf[:])
    262 	if err != nil {
    263 		listen.Close()
    264 		return nil, err
    265 	}
    266 	name := string(buf[:n])
    267 	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
    268 	if err != nil {
    269 		listen.Close()
    270 		return nil, err
    271 	}
    272 	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
    273 	if err != nil {
    274 		listen.Close()
    275 		ctl.Close()
    276 		return nil, err
    277 	}
    278 	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
    279 	if err != nil {
    280 		listen.Close()
    281 		ctl.Close()
    282 		data.Close()
    283 		return nil, err
    284 	}
    285 	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
    286 }
    287 
    288 func isWildcard(a Addr) bool {
    289 	var wildcard bool
    290 	switch a := a.(type) {
    291 	case *TCPAddr:
    292 		wildcard = a.isWildcard()
    293 	case *UDPAddr:
    294 		wildcard = a.isWildcard()
    295 	case *IPAddr:
    296 		wildcard = a.isWildcard()
    297 	}
    298 	return wildcard
    299 }
    300 
    301 func toLocal(a Addr, net string) Addr {
    302 	switch a := a.(type) {
    303 	case *TCPAddr:
    304 		a.IP = loopbackIP(net)
    305 	case *UDPAddr:
    306 		a.IP = loopbackIP(net)
    307 	case *IPAddr:
    308 		a.IP = loopbackIP(net)
    309 	}
    310 	return a
    311 }
    312