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 package net
      6 
      7 import (
      8 	"context"
      9 	"os"
     10 	"syscall"
     11 )
     12 
     13 // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
     14 // capabilities.
     15 //
     16 // Plan 9 uses IPv6 natively, see ip(3).
     17 func (p *ipStackCapabilities) probe() {
     18 	p.ipv4Enabled = probe(netdir+"/iproute", "4i")
     19 	p.ipv6Enabled = probe(netdir+"/iproute", "6i")
     20 	if p.ipv4Enabled && p.ipv6Enabled {
     21 		p.ipv4MappedIPv6Enabled = true
     22 	}
     23 }
     24 
     25 func probe(filename, query string) bool {
     26 	var file *file
     27 	var err error
     28 	if file, err = open(filename); err != nil {
     29 		return false
     30 	}
     31 	defer file.close()
     32 
     33 	r := false
     34 	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
     35 		f := getFields(line)
     36 		if len(f) < 3 {
     37 			continue
     38 		}
     39 		for i := 0; i < len(f); i++ {
     40 			if query == f[i] {
     41 				r = true
     42 				break
     43 			}
     44 		}
     45 	}
     46 	return r
     47 }
     48 
     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 	addr := IPv4zero // address contains port only
     52 	i := byteIndex(s, '!')
     53 	if i >= 0 {
     54 		addr = ParseIP(s[:i])
     55 		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 	return addr, p, nil
     67 }
     68 
     69 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
     70 	var buf [128]byte
     71 
     72 	f, err := os.Open(filename)
     73 	if err != nil {
     74 		return
     75 	}
     76 	defer f.Close()
     77 	n, err := f.Read(buf[:])
     78 	if err != nil {
     79 		return
     80 	}
     81 	ip, port, err := parsePlan9Addr(string(buf[:n]))
     82 	if err != nil {
     83 		return
     84 	}
     85 	switch proto {
     86 	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 	return addr, nil
     94 }
     95 
     96 func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
     97 	var (
     98 		ip   IP
     99 		port int
    100 	)
    101 	switch a := addr.(type) {
    102 	case *TCPAddr:
    103 		proto = "tcp"
    104 		ip = a.IP
    105 		port = a.Port
    106 	case *UDPAddr:
    107 		proto = "udp"
    108 		ip = a.IP
    109 		port = a.Port
    110 	default:
    111 		err = UnknownNetworkError(net)
    112 		return
    113 	}
    114 
    115 	if port > 65535 {
    116 		err = InvalidAddrError("port should be < 65536")
    117 		return
    118 	}
    119 
    120 	clone, dest, err := queryCS1(ctx, proto, ip, port)
    121 	if err != nil {
    122 		return
    123 	}
    124 	f, err := os.OpenFile(clone, os.O_RDWR, 0)
    125 	if err != nil {
    126 		return
    127 	}
    128 	var buf [16]byte
    129 	n, err := f.Read(buf[:])
    130 	if err != nil {
    131 		f.Close()
    132 		return
    133 	}
    134 	return f, dest, proto, string(buf[:n]), nil
    135 }
    136 
    137 func fixErr(err error) {
    138 	oe, ok := err.(*OpError)
    139 	if !ok {
    140 		return
    141 	}
    142 	nonNilInterface := func(a Addr) bool {
    143 		switch a := a.(type) {
    144 		case *TCPAddr:
    145 			return a == nil
    146 		case *UDPAddr:
    147 			return a == nil
    148 		case *IPAddr:
    149 			return a == nil
    150 		default:
    151 			return false
    152 		}
    153 	}
    154 	if nonNilInterface(oe.Source) {
    155 		oe.Source = nil
    156 	}
    157 	if nonNilInterface(oe.Addr) {
    158 		oe.Addr = nil
    159 	}
    160 	if pe, ok := oe.Err.(*os.PathError); ok {
    161 		if _, ok = pe.Err.(syscall.ErrorString); ok {
    162 			oe.Err = pe.Err
    163 		}
    164 	}
    165 }
    166 
    167 func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
    168 	defer func() { fixErr(err) }()
    169 	type res struct {
    170 		fd  *netFD
    171 		err error
    172 	}
    173 	resc := make(chan res)
    174 	go func() {
    175 		testHookDialChannel()
    176 		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
    177 		select {
    178 		case resc <- res{fd, err}:
    179 		case <-ctx.Done():
    180 			if fd != nil {
    181 				fd.Close()
    182 			}
    183 		}
    184 	}()
    185 	select {
    186 	case res := <-resc:
    187 		return res.fd, res.err
    188 	case <-ctx.Done():
    189 		return nil, mapErr(ctx.Err())
    190 	}
    191 }
    192 
    193 func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
    194 	if isWildcard(raddr) {
    195 		raddr = toLocal(raddr, net)
    196 	}
    197 	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
    198 	if err != nil {
    199 		return nil, err
    200 	}
    201 	_, err = f.WriteString("connect " + dest)
    202 	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 func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
    221 	defer func() { fixErr(err) }()
    222 	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
    223 	if err != nil {
    224 		return nil, err
    225 	}
    226 	_, err = f.WriteString("announce " + dest)
    227 	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 		return nil, err
    247 	}
    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 	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
    261 	if err != nil {
    262 		listen.Close()
    263 		return nil, err
    264 	}
    265 	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
    266 	if err != nil {
    267 		listen.Close()
    268 		ctl.Close()
    269 		return nil, err
    270 	}
    271 	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
    272 	if err != nil {
    273 		listen.Close()
    274 		ctl.Close()
    275 		data.Close()
    276 		return nil, err
    277 	}
    278 	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
    279 }
    280 
    281 func isWildcard(a Addr) bool {
    282 	var wildcard bool
    283 	switch a := a.(type) {
    284 	case *TCPAddr:
    285 		wildcard = a.isWildcard()
    286 	case *UDPAddr:
    287 		wildcard = a.isWildcard()
    288 	case *IPAddr:
    289 		wildcard = a.isWildcard()
    290 	}
    291 	return wildcard
    292 }
    293 
    294 func toLocal(a Addr, net string) Addr {
    295 	switch a := a.(type) {
    296 	case *TCPAddr:
    297 		a.IP = loopbackIP(net)
    298 	case *UDPAddr:
    299 		a.IP = loopbackIP(net)
    300 	case *IPAddr:
    301 		a.IP = loopbackIP(net)
    302 	}
    303 	return a
    304 }
    305