github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/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  	"errors"
    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, errors.New("parsing IP failed")
    64  		}
    65  	}
    66  	p, _, ok := dtoi(s[i+1:], 0)
    67  	if !ok {
    68  		return nil, 0, errors.New("parsing port failed")
    69  	}
    70  	if p < 0 || p > 0xFFFF {
    71  		return nil, 0, &AddrError{"invalid port", 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, errors.New("unknown protocol " + proto)
    99  	}
   100  	return addr, nil
   101  }
   102  
   103  func startPlan9(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  	clone, dest, err := queryCS1(proto, ip, port)
   123  	if err != nil {
   124  		return
   125  	}
   126  	f, err := os.OpenFile(clone, os.O_RDWR, 0)
   127  	if err != nil {
   128  		return
   129  	}
   130  	var buf [16]byte
   131  	n, err := f.Read(buf[:])
   132  	if err != nil {
   133  		f.Close()
   134  		return
   135  	}
   136  	return f, dest, proto, string(buf[:n]), nil
   137  }
   138  
   139  func netErr(e error) {
   140  	oe, ok := e.(*OpError)
   141  	if !ok {
   142  		return
   143  	}
   144  	if pe, ok := oe.Err.(*os.PathError); ok {
   145  		if _, ok = pe.Err.(syscall.ErrorString); ok {
   146  			oe.Err = pe.Err
   147  		}
   148  	}
   149  }
   150  
   151  func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
   152  	defer func() { netErr(err) }()
   153  	f, dest, proto, name, err := startPlan9(net, raddr)
   154  	if err != nil {
   155  		return nil, &OpError{"dial", net, raddr, err}
   156  	}
   157  	_, err = f.WriteString("connect " + dest)
   158  	if err != nil {
   159  		f.Close()
   160  		return nil, &OpError{"dial", f.Name(), raddr, err}
   161  	}
   162  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   163  	if err != nil {
   164  		f.Close()
   165  		return nil, &OpError{"dial", net, raddr, err}
   166  	}
   167  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   168  	if err != nil {
   169  		data.Close()
   170  		f.Close()
   171  		return nil, &OpError{"dial", proto, raddr, err}
   172  	}
   173  	return newFD(proto, name, f, data, laddr, raddr)
   174  }
   175  
   176  func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
   177  	defer func() { netErr(err) }()
   178  	f, dest, proto, name, err := startPlan9(net, laddr)
   179  	if err != nil {
   180  		return nil, &OpError{"listen", net, laddr, err}
   181  	}
   182  	_, err = f.WriteString("announce " + dest)
   183  	if err != nil {
   184  		f.Close()
   185  		return nil, &OpError{"announce", proto, laddr, err}
   186  	}
   187  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   188  	if err != nil {
   189  		f.Close()
   190  		return nil, &OpError{Op: "listen", Net: net, Err: err}
   191  	}
   192  	return newFD(proto, name, f, nil, laddr, nil)
   193  }
   194  
   195  func (l *netFD) netFD() (*netFD, error) {
   196  	return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
   197  }
   198  
   199  func (l *netFD) acceptPlan9() (fd *netFD, err error) {
   200  	defer func() { netErr(err) }()
   201  	if err := l.readLock(); err != nil {
   202  		return nil, err
   203  	}
   204  	defer l.readUnlock()
   205  	f, err := os.Open(l.dir + "/listen")
   206  	if err != nil {
   207  		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
   208  	}
   209  	var buf [16]byte
   210  	n, err := f.Read(buf[:])
   211  	if err != nil {
   212  		f.Close()
   213  		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
   214  	}
   215  	name := string(buf[:n])
   216  	data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
   217  	if err != nil {
   218  		f.Close()
   219  		return nil, &OpError{"accept", l.proto, l.laddr, err}
   220  	}
   221  	raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
   222  	if err != nil {
   223  		data.Close()
   224  		f.Close()
   225  		return nil, &OpError{"accept", l.proto, l.laddr, err}
   226  	}
   227  	return newFD(l.proto, name, f, data, l.laddr, raddr)
   228  }