github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/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  	"internal/bytealg"
    10  	"io/fs"
    11  	"os"
    12  	"syscall"
    13  )
    14  
    15  // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
    16  // capabilities.
    17  //
    18  // Plan 9 uses IPv6 natively, see ip(3).
    19  func (p *ipStackCapabilities) probe() {
    20  	p.ipv4Enabled = probe(netdir+"/iproute", "4i")
    21  	p.ipv6Enabled = probe(netdir+"/iproute", "6i")
    22  	if p.ipv4Enabled && p.ipv6Enabled {
    23  		p.ipv4MappedIPv6Enabled = true
    24  	}
    25  }
    26  
    27  func probe(filename, query string) bool {
    28  	var file *file
    29  	var err error
    30  	if file, err = open(filename); err != nil {
    31  		return false
    32  	}
    33  	defer file.close()
    34  
    35  	r := false
    36  	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
    37  		f := getFields(line)
    38  		if len(f) < 3 {
    39  			continue
    40  		}
    41  		for i := 0; i < len(f); i++ {
    42  			if query == f[i] {
    43  				r = true
    44  				break
    45  			}
    46  		}
    47  	}
    48  	return r
    49  }
    50  
    51  // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
    52  func parsePlan9Addr(s string) (ip IP, iport int, err error) {
    53  	addr := IPv4zero // address contains port only
    54  	i := bytealg.IndexByteString(s, '!')
    55  	if i >= 0 {
    56  		addr = ParseIP(s[:i])
    57  		if addr == nil {
    58  			return nil, 0, &ParseError{Type: "IP address", Text: s}
    59  		}
    60  	}
    61  	p, plen, ok := dtoi(s[i+1:])
    62  	if !ok {
    63  		return nil, 0, &ParseError{Type: "port", Text: s}
    64  	}
    65  	if p < 0 || p > 0xFFFF {
    66  		return nil, 0, &AddrError{Err: "invalid port", Addr: s[i+1 : i+1+plen]}
    67  	}
    68  	return addr, p, nil
    69  }
    70  
    71  func readPlan9Addr(net, filename string) (addr Addr, err error) {
    72  	var buf [128]byte
    73  
    74  	f, err := os.Open(filename)
    75  	if err != nil {
    76  		return
    77  	}
    78  	defer f.Close()
    79  	n, err := f.Read(buf[:])
    80  	if err != nil {
    81  		return
    82  	}
    83  	ip, port, err := parsePlan9Addr(string(buf[:n]))
    84  	if err != nil {
    85  		return
    86  	}
    87  	switch net {
    88  	case "tcp4", "udp4":
    89  		if ip.Equal(IPv6zero) {
    90  			ip = ip[:IPv4len]
    91  		}
    92  	}
    93  	switch net {
    94  	case "tcp", "tcp4", "tcp6":
    95  		addr = &TCPAddr{IP: ip, Port: port}
    96  	case "udp", "udp4", "udp6":
    97  		addr = &UDPAddr{IP: ip, Port: port}
    98  	default:
    99  		return nil, UnknownNetworkError(net)
   100  	}
   101  	return addr, nil
   102  }
   103  
   104  func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
   105  	var (
   106  		ip   IP
   107  		port int
   108  	)
   109  	switch a := addr.(type) {
   110  	case *TCPAddr:
   111  		proto = "tcp"
   112  		ip = a.IP
   113  		port = a.Port
   114  	case *UDPAddr:
   115  		proto = "udp"
   116  		ip = a.IP
   117  		port = a.Port
   118  	default:
   119  		err = UnknownNetworkError(net)
   120  		return
   121  	}
   122  
   123  	if port > 65535 {
   124  		err = InvalidAddrError("port should be < 65536")
   125  		return
   126  	}
   127  
   128  	clone, dest, err := queryCS1(ctx, proto, ip, port)
   129  	if err != nil {
   130  		return
   131  	}
   132  	f, err := os.OpenFile(clone, os.O_RDWR, 0)
   133  	if err != nil {
   134  		return
   135  	}
   136  	var buf [16]byte
   137  	n, err := f.Read(buf[:])
   138  	if err != nil {
   139  		f.Close()
   140  		return
   141  	}
   142  	return f, dest, proto, string(buf[:n]), nil
   143  }
   144  
   145  func fixErr(err error) {
   146  	oe, ok := err.(*OpError)
   147  	if !ok {
   148  		return
   149  	}
   150  	nonNilInterface := func(a Addr) bool {
   151  		switch a := a.(type) {
   152  		case *TCPAddr:
   153  			return a == nil
   154  		case *UDPAddr:
   155  			return a == nil
   156  		case *IPAddr:
   157  			return a == nil
   158  		default:
   159  			return false
   160  		}
   161  	}
   162  	if nonNilInterface(oe.Source) {
   163  		oe.Source = nil
   164  	}
   165  	if nonNilInterface(oe.Addr) {
   166  		oe.Addr = nil
   167  	}
   168  	if pe, ok := oe.Err.(*fs.PathError); ok {
   169  		if _, ok = pe.Err.(syscall.ErrorString); ok {
   170  			oe.Err = pe.Err
   171  		}
   172  	}
   173  }
   174  
   175  func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   176  	defer func() { fixErr(err) }()
   177  	type res struct {
   178  		fd  *netFD
   179  		err error
   180  	}
   181  	resc := make(chan res)
   182  	go func() {
   183  		testHookDialChannel()
   184  		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
   185  		select {
   186  		case resc <- res{fd, err}:
   187  		case <-ctx.Done():
   188  			if fd != nil {
   189  				fd.Close()
   190  			}
   191  		}
   192  	}()
   193  	select {
   194  	case res := <-resc:
   195  		return res.fd, res.err
   196  	case <-ctx.Done():
   197  		return nil, mapErr(ctx.Err())
   198  	}
   199  }
   200  
   201  func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   202  	if isWildcard(raddr) {
   203  		raddr = toLocal(raddr, net)
   204  	}
   205  	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	if la := plan9LocalAddr(laddr); la == "" {
   210  		err = hangupCtlWrite(ctx, proto, f, "connect "+dest)
   211  	} else {
   212  		err = hangupCtlWrite(ctx, proto, f, "connect "+dest+" "+la)
   213  	}
   214  	if err != nil {
   215  		f.Close()
   216  		return nil, err
   217  	}
   218  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   219  	if err != nil {
   220  		f.Close()
   221  		return nil, err
   222  	}
   223  	laddr, err = readPlan9Addr(net, netdir+"/"+proto+"/"+name+"/local")
   224  	if err != nil {
   225  		data.Close()
   226  		f.Close()
   227  		return nil, err
   228  	}
   229  	return newFD(proto, name, nil, f, data, laddr, raddr)
   230  }
   231  
   232  func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
   233  	defer func() { fixErr(err) }()
   234  	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  	_, err = f.WriteString("announce " + dest)
   239  	if err != nil {
   240  		f.Close()
   241  		return nil, &OpError{Op: "announce", Net: net, Source: laddr, Addr: nil, Err: err}
   242  	}
   243  	laddr, err = readPlan9Addr(net, netdir+"/"+proto+"/"+name+"/local")
   244  	if err != nil {
   245  		f.Close()
   246  		return nil, err
   247  	}
   248  	return newFD(proto, name, nil, f, nil, laddr, nil)
   249  }
   250  
   251  func (fd *netFD) netFD() (*netFD, error) {
   252  	return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
   253  }
   254  
   255  func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   256  	defer func() { fixErr(err) }()
   257  	if err := fd.pfd.ReadLock(); err != nil {
   258  		return nil, err
   259  	}
   260  	defer fd.pfd.ReadUnlock()
   261  	listen, err := os.Open(fd.dir + "/listen")
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	var buf [16]byte
   266  	n, err := listen.Read(buf[:])
   267  	if err != nil {
   268  		listen.Close()
   269  		return nil, err
   270  	}
   271  	name := string(buf[:n])
   272  	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
   273  	if err != nil {
   274  		listen.Close()
   275  		return nil, err
   276  	}
   277  	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   278  	if err != nil {
   279  		listen.Close()
   280  		ctl.Close()
   281  		return nil, err
   282  	}
   283  	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   284  	if err != nil {
   285  		listen.Close()
   286  		ctl.Close()
   287  		data.Close()
   288  		return nil, err
   289  	}
   290  	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
   291  }
   292  
   293  func isWildcard(a Addr) bool {
   294  	var wildcard bool
   295  	switch a := a.(type) {
   296  	case *TCPAddr:
   297  		wildcard = a.isWildcard()
   298  	case *UDPAddr:
   299  		wildcard = a.isWildcard()
   300  	case *IPAddr:
   301  		wildcard = a.isWildcard()
   302  	}
   303  	return wildcard
   304  }
   305  
   306  func toLocal(a Addr, net string) Addr {
   307  	switch a := a.(type) {
   308  	case *TCPAddr:
   309  		a.IP = loopbackIP(net)
   310  	case *UDPAddr:
   311  		a.IP = loopbackIP(net)
   312  	case *IPAddr:
   313  		a.IP = loopbackIP(net)
   314  	}
   315  	return a
   316  }
   317  
   318  // plan9LocalAddr returns a Plan 9 local address string.
   319  // See setladdrport at https://9p.io/sources/plan9/sys/src/9/ip/devip.c.
   320  func plan9LocalAddr(addr Addr) string {
   321  	var ip IP
   322  	port := 0
   323  	switch a := addr.(type) {
   324  	case *TCPAddr:
   325  		if a != nil {
   326  			ip = a.IP
   327  			port = a.Port
   328  		}
   329  	case *UDPAddr:
   330  		if a != nil {
   331  			ip = a.IP
   332  			port = a.Port
   333  		}
   334  	}
   335  	if len(ip) == 0 || ip.IsUnspecified() {
   336  		if port == 0 {
   337  			return ""
   338  		}
   339  		return itoa(port)
   340  	}
   341  	return ip.String() + "!" + itoa(port)
   342  }
   343  
   344  func hangupCtlWrite(ctx context.Context, proto string, ctl *os.File, msg string) error {
   345  	if proto != "tcp" {
   346  		_, err := ctl.WriteString(msg)
   347  		return err
   348  	}
   349  	written := make(chan struct{})
   350  	errc := make(chan error)
   351  	go func() {
   352  		select {
   353  		case <-ctx.Done():
   354  			ctl.WriteString("hangup")
   355  			errc <- mapErr(ctx.Err())
   356  		case <-written:
   357  			errc <- nil
   358  		}
   359  	}()
   360  	_, err := ctl.WriteString(msg)
   361  	close(written)
   362  	if e := <-errc; err == nil && e != nil { // we hung up
   363  		return e
   364  	}
   365  	return err
   366  }