github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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:], 0)
    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  	clone, dest, err := queryCS1(ctx, 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 fixErr(err error) {
   140  	oe, ok := err.(*OpError)
   141  	if !ok {
   142  		return
   143  	}
   144  	nonNilInterface := func(a Addr) bool {
   145  		switch a := a.(type) {
   146  		case *TCPAddr:
   147  			return a == nil
   148  		case *UDPAddr:
   149  			return a == nil
   150  		case *IPAddr:
   151  			return a == nil
   152  		default:
   153  			return false
   154  		}
   155  	}
   156  	if nonNilInterface(oe.Source) {
   157  		oe.Source = nil
   158  	}
   159  	if nonNilInterface(oe.Addr) {
   160  		oe.Addr = nil
   161  	}
   162  	if pe, ok := oe.Err.(*os.PathError); ok {
   163  		if _, ok = pe.Err.(syscall.ErrorString); ok {
   164  			oe.Err = pe.Err
   165  		}
   166  	}
   167  }
   168  
   169  func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   170  	defer func() { fixErr(err) }()
   171  	type res struct {
   172  		fd  *netFD
   173  		err error
   174  	}
   175  	resc := make(chan res)
   176  	go func() {
   177  		testHookDialChannel()
   178  		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
   179  		select {
   180  		case resc <- res{fd, err}:
   181  		case <-ctx.Done():
   182  			if fd != nil {
   183  				fd.Close()
   184  			}
   185  		}
   186  	}()
   187  	select {
   188  	case res := <-resc:
   189  		return res.fd, res.err
   190  	case <-ctx.Done():
   191  		return nil, mapErr(ctx.Err())
   192  	}
   193  }
   194  
   195  func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   196  	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	_, err = f.WriteString("connect " + dest)
   201  	if err != nil {
   202  		f.Close()
   203  		return nil, err
   204  	}
   205  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   206  	if err != nil {
   207  		f.Close()
   208  		return nil, err
   209  	}
   210  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   211  	if err != nil {
   212  		data.Close()
   213  		f.Close()
   214  		return nil, err
   215  	}
   216  	return newFD(proto, name, f, data, laddr, raddr)
   217  }
   218  
   219  func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
   220  	defer func() { fixErr(err) }()
   221  	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  	_, err = f.WriteString("announce " + dest)
   226  	if err != nil {
   227  		f.Close()
   228  		return nil, err
   229  	}
   230  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   231  	if err != nil {
   232  		f.Close()
   233  		return nil, err
   234  	}
   235  	return newFD(proto, name, f, nil, laddr, nil)
   236  }
   237  
   238  func (fd *netFD) netFD() (*netFD, error) {
   239  	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
   240  }
   241  
   242  func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   243  	defer func() { fixErr(err) }()
   244  	if err := fd.readLock(); err != nil {
   245  		return nil, err
   246  	}
   247  	defer fd.readUnlock()
   248  	f, err := os.Open(fd.dir + "/listen")
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	var buf [16]byte
   253  	n, err := f.Read(buf[:])
   254  	if err != nil {
   255  		f.Close()
   256  		return nil, err
   257  	}
   258  	name := string(buf[:n])
   259  	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   260  	if err != nil {
   261  		f.Close()
   262  		return nil, err
   263  	}
   264  	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   265  	if err != nil {
   266  		data.Close()
   267  		f.Close()
   268  		return nil, err
   269  	}
   270  	return newFD(fd.net, name, f, data, fd.laddr, raddr)
   271  }