github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/net/ipsock_plan9.go (about)

     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  }