github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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  // Internet protocol family sockets for Plan 9
     6  
     7  package net
     8  
     9  import (
    10  	"context"
    11  	"os"
    12  	"syscall"
    13  )
    14  
    15  func probe(filename, query string) bool {
    16  	var file *file
    17  	var err error
    18  	if file, err = open(filename); err != nil {
    19  		return false
    20  	}
    21  
    22  	r := false
    23  	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
    24  		f := getFields(line)
    25  		if len(f) < 3 {
    26  			continue
    27  		}
    28  		for i := 0; i < len(f); i++ {
    29  			if query == f[i] {
    30  				r = true
    31  				break
    32  			}
    33  		}
    34  	}
    35  	file.close()
    36  	return r
    37  }
    38  
    39  func probeIPv4Stack() bool {
    40  	return probe(netdir+"/iproute", "4i")
    41  }
    42  
    43  // probeIPv6Stack returns two boolean values. If the first boolean
    44  // value is true, kernel supports basic IPv6 functionality. If the
    45  // second boolean value is true, kernel supports IPv6 IPv4-mapping.
    46  func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
    47  	// Plan 9 uses IPv6 natively, see ip(3).
    48  	r := probe(netdir+"/iproute", "6i")
    49  	v := false
    50  	if r {
    51  		v = probe(netdir+"/iproute", "4i")
    52  	}
    53  	return r, v
    54  }
    55  
    56  // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
    57  func parsePlan9Addr(s string) (ip IP, iport int, err error) {
    58  	addr := IPv4zero // address contains port only
    59  	i := byteIndex(s, '!')
    60  	if i >= 0 {
    61  		addr = ParseIP(s[:i])
    62  		if addr == nil {
    63  			return nil, 0, &ParseError{Type: "IP address", Text: s}
    64  		}
    65  	}
    66  	p, _, ok := dtoi(s[i+1:])
    67  	if !ok {
    68  		return nil, 0, &ParseError{Type: "port", Text: s}
    69  	}
    70  	if p < 0 || p > 0xFFFF {
    71  		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
    72  	}
    73  	return addr, p, nil
    74  }
    75  
    76  func readPlan9Addr(proto, filename string) (addr Addr, err error) {
    77  	var buf [128]byte
    78  
    79  	f, err := os.Open(filename)
    80  	if err != nil {
    81  		return
    82  	}
    83  	defer f.Close()
    84  	n, err := f.Read(buf[:])
    85  	if err != nil {
    86  		return
    87  	}
    88  	ip, port, err := parsePlan9Addr(string(buf[:n]))
    89  	if err != nil {
    90  		return
    91  	}
    92  	switch proto {
    93  	case "tcp":
    94  		addr = &TCPAddr{IP: ip, Port: port}
    95  	case "udp":
    96  		addr = &UDPAddr{IP: ip, Port: port}
    97  	default:
    98  		return nil, UnknownNetworkError(proto)
    99  	}
   100  	return addr, nil
   101  }
   102  
   103  func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
   104  	var (
   105  		ip   IP
   106  		port int
   107  	)
   108  	switch a := addr.(type) {
   109  	case *TCPAddr:
   110  		proto = "tcp"
   111  		ip = a.IP
   112  		port = a.Port
   113  	case *UDPAddr:
   114  		proto = "udp"
   115  		ip = a.IP
   116  		port = a.Port
   117  	default:
   118  		err = UnknownNetworkError(net)
   119  		return
   120  	}
   121  
   122  	if port > 65535 {
   123  		err = InvalidAddrError("port should be < 65536")
   124  		return
   125  	}
   126  
   127  	clone, dest, err := queryCS1(ctx, proto, ip, port)
   128  	if err != nil {
   129  		return
   130  	}
   131  	f, err := os.OpenFile(clone, os.O_RDWR, 0)
   132  	if err != nil {
   133  		return
   134  	}
   135  	var buf [16]byte
   136  	n, err := f.Read(buf[:])
   137  	if err != nil {
   138  		f.Close()
   139  		return
   140  	}
   141  	return f, dest, proto, string(buf[:n]), nil
   142  }
   143  
   144  func fixErr(err error) {
   145  	oe, ok := err.(*OpError)
   146  	if !ok {
   147  		return
   148  	}
   149  	nonNilInterface := func(a Addr) bool {
   150  		switch a := a.(type) {
   151  		case *TCPAddr:
   152  			return a == nil
   153  		case *UDPAddr:
   154  			return a == nil
   155  		case *IPAddr:
   156  			return a == nil
   157  		default:
   158  			return false
   159  		}
   160  	}
   161  	if nonNilInterface(oe.Source) {
   162  		oe.Source = nil
   163  	}
   164  	if nonNilInterface(oe.Addr) {
   165  		oe.Addr = nil
   166  	}
   167  	if pe, ok := oe.Err.(*os.PathError); ok {
   168  		if _, ok = pe.Err.(syscall.ErrorString); ok {
   169  			oe.Err = pe.Err
   170  		}
   171  	}
   172  }
   173  
   174  func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   175  	defer func() { fixErr(err) }()
   176  	type res struct {
   177  		fd  *netFD
   178  		err error
   179  	}
   180  	resc := make(chan res)
   181  	go func() {
   182  		testHookDialChannel()
   183  		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
   184  		select {
   185  		case resc <- res{fd, err}:
   186  		case <-ctx.Done():
   187  			if fd != nil {
   188  				fd.Close()
   189  			}
   190  		}
   191  	}()
   192  	select {
   193  	case res := <-resc:
   194  		return res.fd, res.err
   195  	case <-ctx.Done():
   196  		return nil, mapErr(ctx.Err())
   197  	}
   198  }
   199  
   200  func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   201  	if isWildcard(raddr) {
   202  		raddr = toLocal(raddr, net)
   203  	}
   204  	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	_, err = f.WriteString("connect " + dest)
   209  	if err != nil {
   210  		f.Close()
   211  		return nil, err
   212  	}
   213  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   214  	if err != nil {
   215  		f.Close()
   216  		return nil, err
   217  	}
   218  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   219  	if err != nil {
   220  		data.Close()
   221  		f.Close()
   222  		return nil, err
   223  	}
   224  	return newFD(proto, name, nil, f, data, laddr, raddr)
   225  }
   226  
   227  func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
   228  	defer func() { fixErr(err) }()
   229  	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  	_, err = f.WriteString("announce " + dest)
   234  	if err != nil {
   235  		f.Close()
   236  		return nil, err
   237  	}
   238  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   239  	if err != nil {
   240  		f.Close()
   241  		return nil, err
   242  	}
   243  	return newFD(proto, name, nil, f, nil, laddr, nil)
   244  }
   245  
   246  func (fd *netFD) netFD() (*netFD, error) {
   247  	return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
   248  }
   249  
   250  func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   251  	defer func() { fixErr(err) }()
   252  	if err := fd.readLock(); err != nil {
   253  		return nil, err
   254  	}
   255  	defer fd.readUnlock()
   256  	listen, err := os.Open(fd.dir + "/listen")
   257  	if err != nil {
   258  		return nil, err
   259  	}
   260  	var buf [16]byte
   261  	n, err := listen.Read(buf[:])
   262  	if err != nil {
   263  		listen.Close()
   264  		return nil, err
   265  	}
   266  	name := string(buf[:n])
   267  	ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
   268  	if err != nil {
   269  		listen.Close()
   270  		return nil, err
   271  	}
   272  	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   273  	if err != nil {
   274  		listen.Close()
   275  		ctl.Close()
   276  		return nil, err
   277  	}
   278  	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   279  	if err != nil {
   280  		listen.Close()
   281  		ctl.Close()
   282  		data.Close()
   283  		return nil, err
   284  	}
   285  	return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
   286  }
   287  
   288  func isWildcard(a Addr) bool {
   289  	var wildcard bool
   290  	switch a := a.(type) {
   291  	case *TCPAddr:
   292  		wildcard = a.isWildcard()
   293  	case *UDPAddr:
   294  		wildcard = a.isWildcard()
   295  	case *IPAddr:
   296  		wildcard = a.isWildcard()
   297  	}
   298  	return wildcard
   299  }
   300  
   301  func toLocal(a Addr, net string) Addr {
   302  	switch a := a.(type) {
   303  	case *TCPAddr:
   304  		a.IP = loopbackIP(net)
   305  	case *UDPAddr:
   306  		a.IP = loopbackIP(net)
   307  	case *IPAddr:
   308  		a.IP = loopbackIP(net)
   309  	}
   310  	return a
   311  }