github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/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  	"github.com/x04/go/src/context"
     9  	"github.com/x04/go/src/internal/bytealg"
    10  	"github.com/x04/go/src/os"
    11  	"github.com/x04/go/src/syscall"
    12  )
    13  
    14  // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
    15  // capabilities.
    16  //
    17  // Plan 9 uses IPv6 natively, see ip(3).
    18  func (p *ipStackCapabilities) probe() {
    19  	p.ipv4Enabled = probe(netdir+"/iproute", "4i")
    20  	p.ipv6Enabled = probe(netdir+"/iproute", "6i")
    21  	if p.ipv4Enabled && p.ipv6Enabled {
    22  		p.ipv4MappedIPv6Enabled = true
    23  	}
    24  }
    25  
    26  func probe(filename, query string) bool {
    27  	var file *file
    28  	var err error
    29  	if file, err = open(filename); err != nil {
    30  		return false
    31  	}
    32  	defer file.close()
    33  
    34  	r := false
    35  	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
    36  		f := getFields(line)
    37  		if len(f) < 3 {
    38  			continue
    39  		}
    40  		for i := 0; i < len(f); i++ {
    41  			if query == f[i] {
    42  				r = true
    43  				break
    44  			}
    45  		}
    46  	}
    47  	return r
    48  }
    49  
    50  // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
    51  func parsePlan9Addr(s string) (ip IP, iport int, err error) {
    52  	addr := IPv4zero	// address contains port only
    53  	i := bytealg.IndexByteString(s, '!')
    54  	if i >= 0 {
    55  		addr = ParseIP(s[:i])
    56  		if addr == nil {
    57  			return nil, 0, &ParseError{Type: "IP address", Text: s}
    58  		}
    59  	}
    60  	p, _, ok := dtoi(s[i+1:])
    61  	if !ok {
    62  		return nil, 0, &ParseError{Type: "port", Text: s}
    63  	}
    64  	if p < 0 || p > 0xFFFF {
    65  		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
    66  	}
    67  	return addr, p, nil
    68  }
    69  
    70  func readPlan9Addr(proto, filename string) (addr Addr, err error) {
    71  	var buf [128]byte
    72  
    73  	f, err := os.Open(filename)
    74  	if err != nil {
    75  		return
    76  	}
    77  	defer f.Close()
    78  	n, err := f.Read(buf[:])
    79  	if err != nil {
    80  		return
    81  	}
    82  	ip, port, err := parsePlan9Addr(string(buf[:n]))
    83  	if err != nil {
    84  		return
    85  	}
    86  	switch proto {
    87  	case "tcp":
    88  		addr = &TCPAddr{IP: ip, Port: port}
    89  	case "udp":
    90  		addr = &UDPAddr{IP: ip, Port: port}
    91  	default:
    92  		return nil, UnknownNetworkError(proto)
    93  	}
    94  	return addr, nil
    95  }
    96  
    97  func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
    98  	var (
    99  		ip	IP
   100  		port	int
   101  	)
   102  	switch a := addr.(type) {
   103  	case *TCPAddr:
   104  		proto = "tcp"
   105  		ip = a.IP
   106  		port = a.Port
   107  	case *UDPAddr:
   108  		proto = "udp"
   109  		ip = a.IP
   110  		port = a.Port
   111  	default:
   112  		err = UnknownNetworkError(net)
   113  		return
   114  	}
   115  
   116  	if port > 65535 {
   117  		err = InvalidAddrError("port should be < 65536")
   118  		return
   119  	}
   120  
   121  	clone, dest, err := queryCS1(ctx, 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 fixErr(err error) {
   139  	oe, ok := err.(*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(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   169  	defer func() { fixErr(err) }()
   170  	type res struct {
   171  		fd	*netFD
   172  		err	error
   173  	}
   174  	resc := make(chan res)
   175  	go func() {
   176  		testHookDialChannel()
   177  		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
   178  		select {
   179  		case resc <- res{fd, err}:
   180  		case <-ctx.Done():
   181  			if fd != nil {
   182  				fd.Close()
   183  			}
   184  		}
   185  	}()
   186  	select {
   187  	case res := <-resc:
   188  		return res.fd, res.err
   189  	case <-ctx.Done():
   190  		return nil, mapErr(ctx.Err())
   191  	}
   192  }
   193  
   194  func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   195  	if isWildcard(raddr) {
   196  		raddr = toLocal(raddr, net)
   197  	}
   198  	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	_, err = f.WriteString("connect " + dest)
   203  	if err != nil {
   204  		f.Close()
   205  		return nil, err
   206  	}
   207  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   208  	if err != nil {
   209  		f.Close()
   210  		return nil, err
   211  	}
   212  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   213  	if err != nil {
   214  		data.Close()
   215  		f.Close()
   216  		return nil, err
   217  	}
   218  	return newFD(proto, name, nil, f, data, laddr, raddr)
   219  }
   220  
   221  func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
   222  	defer func() { fixErr(err) }()
   223  	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	_, err = f.WriteString("announce " + dest)
   228  	if err != nil {
   229  		f.Close()
   230  		return nil, &OpError{Op: "announce", Net: net, Source: laddr, Addr: nil, Err: err}
   231  	}
   232  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   233  	if err != nil {
   234  		f.Close()
   235  		return nil, err
   236  	}
   237  	return newFD(proto, name, nil, f, nil, laddr, nil)
   238  }
   239  
   240  func (fd *netFD) netFD() (*netFD, error) {
   241  	return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
   242  }
   243  
   244  func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   245  	defer func() { fixErr(err) }()
   246  	if err := fd.pfd.ReadLock(); err != nil {
   247  		return nil, err
   248  	}
   249  	defer fd.pfd.ReadUnlock()
   250  	listen, err := os.Open(fd.dir + "/listen")
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	var buf [16]byte
   255  	n, err := listen.Read(buf[:])
   256  	if err != nil {
   257  		listen.Close()
   258  		return nil, err
   259  	}
   260  	name := string(buf[:n])
   261  	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
   262  	if err != nil {
   263  		listen.Close()
   264  		return nil, err
   265  	}
   266  	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   267  	if err != nil {
   268  		listen.Close()
   269  		ctl.Close()
   270  		return nil, err
   271  	}
   272  	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   273  	if err != nil {
   274  		listen.Close()
   275  		ctl.Close()
   276  		data.Close()
   277  		return nil, err
   278  	}
   279  	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
   280  }
   281  
   282  func isWildcard(a Addr) bool {
   283  	var wildcard bool
   284  	switch a := a.(type) {
   285  	case *TCPAddr:
   286  		wildcard = a.isWildcard()
   287  	case *UDPAddr:
   288  		wildcard = a.isWildcard()
   289  	case *IPAddr:
   290  		wildcard = a.isWildcard()
   291  	}
   292  	return wildcard
   293  }
   294  
   295  func toLocal(a Addr, net string) Addr {
   296  	switch a := a.(type) {
   297  	case *TCPAddr:
   298  		a.IP = loopbackIP(net)
   299  	case *UDPAddr:
   300  		a.IP = loopbackIP(net)
   301  	case *IPAddr:
   302  		a.IP = loopbackIP(net)
   303  	}
   304  	return a
   305  }