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 	"os"
     11 	"syscall"
     12 )
     13 
     14 func probe(filename, query string) bool {
     15 	var file *file
     16 	var err error
     17 	if file, err = open(filename); err != nil {
     18 		return false
     19 	}
     20 
     21 	r := false
     22 	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
     23 		f := getFields(line)
     24 		if len(f) < 3 {
     25 			continue
     26 		}
     27 		for i := 0; i < len(f); i++ {
     28 			if query == f[i] {
     29 				r = true
     30 				break
     31 			}
     32 		}
     33 	}
     34 	file.close()
     35 	return r
     36 }
     37 
     38 func probeIPv4Stack() bool {
     39 	return probe(netdir+"/iproute", "4i")
     40 }
     41 
     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")
     48 	v := false
     49 	if r {
     50 		v = probe(netdir+"/iproute", "4i")
     51 	}
     52 	return r, v
     53 }
     54 
     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, '!')
     59 	if i >= 0 {
     60 		addr = ParseIP(s[:i])
     61 		if addr == nil {
     62 			return nil, 0, &ParseError{Type: "IP address", Text: s}
     63 		}
     64 	}
     65 	p, _, ok := dtoi(s[i+1:], 0)
     66 	if !ok {
     67 		return nil, 0, &ParseError{Type: "port", Text: s}
     68 	}
     69 	if p < 0 || p > 0xFFFF {
     70 		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
     71 	}
     72 	return addr, p, nil
     73 }
     74 
     75 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
     76 	var buf [128]byte
     77 
     78 	f, err := os.Open(filename)
     79 	if err != nil {
     80 		return
     81 	}
     82 	defer f.Close()
     83 	n, err := f.Read(buf[:])
     84 	if err != nil {
     85 		return
     86 	}
     87 	ip, port, err := parsePlan9Addr(string(buf[:n]))
     88 	if err != nil {
     89 		return
     90 	}
     91 	switch proto {
     92 	case "tcp":
     93 		addr = &TCPAddr{IP: ip, Port: port}
     94 	case "udp":
     95 		addr = &UDPAddr{IP: ip, Port: port}
     96 	default:
     97 		return nil, UnknownNetworkError(proto)
     98 	}
     99 	return addr, nil
    100 }
    101 
    102 func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
    103 	var (
    104 		ip   IP
    105 		port int
    106 	)
    107 	switch a := addr.(type) {
    108 	case *TCPAddr:
    109 		proto = "tcp"
    110 		ip = a.IP
    111 		port = a.Port
    112 	case *UDPAddr:
    113 		proto = "udp"
    114 		ip = a.IP
    115 		port = a.Port
    116 	default:
    117 		err = UnknownNetworkError(net)
    118 		return
    119 	}
    120 
    121 	clone, dest, err := queryCS1(proto, ip, port)
    122 	if err != nil {
    123 		return
    124 	}
    125 	f, err := os.OpenFile(clone, os.O_RDWR, 0)
    126 	if err != nil {
    127 		return
    128 	}
    129 	var buf [16]byte
    130 	n, err := f.Read(buf[:])
    131 	if err != nil {
    132 		f.Close()
    133 		return
    134 	}
    135 	return f, dest, proto, string(buf[:n]), nil
    136 }
    137 
    138 func netErr(e error) {
    139 	oe, ok := e.(*OpError)
    140 	if !ok {
    141 		return
    142 	}
    143 	nonNilInterface := func(a Addr) bool {
    144 		switch a := a.(type) {
    145 		case *TCPAddr:
    146 			return a == nil
    147 		case *UDPAddr:
    148 			return a == nil
    149 		case *IPAddr:
    150 			return a == nil
    151 		default:
    152 			return false
    153 		}
    154 	}
    155 	if nonNilInterface(oe.Source) {
    156 		oe.Source = nil
    157 	}
    158 	if nonNilInterface(oe.Addr) {
    159 		oe.Addr = nil
    160 	}
    161 	if pe, ok := oe.Err.(*os.PathError); ok {
    162 		if _, ok = pe.Err.(syscall.ErrorString); ok {
    163 			oe.Err = pe.Err
    164 		}
    165 	}
    166 }
    167 
    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)
    171 	if err != nil {
    172 		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
    173 	}
    174 	_, err = f.WriteString("connect " + dest)
    175 	if err != nil {
    176 		f.Close()
    177 		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
    178 	}
    179 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
    180 	if err != nil {
    181 		f.Close()
    182 		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
    183 	}
    184 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
    185 	if err != nil {
    186 		data.Close()
    187 		f.Close()
    188 		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
    189 	}
    190 	return newFD(proto, name, f, data, laddr, raddr)
    191 }
    192 
    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)
    196 	if err != nil {
    197 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
    198 	}
    199 	_, err = f.WriteString("announce " + dest)
    200 	if err != nil {
    201 		f.Close()
    202 		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
    203 	}
    204 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
    205 	if err != nil {
    206 		f.Close()
    207 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
    208 	}
    209 	return newFD(proto, name, f, nil, laddr, nil)
    210 }
    211 
    212 func (fd *netFD) netFD() (*netFD, error) {
    213 	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
    214 }
    215 
    216 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
    217 	defer func() { netErr(err) }()
    218 	if err := fd.readLock(); err != nil {
    219 		return nil, err
    220 	}
    221 	defer fd.readUnlock()
    222 	f, err := os.Open(fd.dir + "/listen")
    223 	if err != nil {
    224 		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
    225 	}
    226 	var buf [16]byte
    227 	n, err := f.Read(buf[:])
    228 	if err != nil {
    229 		f.Close()
    230 		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
    231 	}
    232 	name := string(buf[:n])
    233 	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
    234 	if err != nil {
    235 		f.Close()
    236 		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
    237 	}
    238 	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
    239 	if err != nil {
    240 		data.Close()
    241 		f.Close()
    242 		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
    243 	}
    244 	return newFD(fd.net, name, f, data, fd.laddr, raddr)
    245 }
    246