github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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  	"os"
    11  	"syscall"
    12  )
    13  
    14  func probe(filename, query string) bool {
    15  	var file *file
    16  	var err error
    17  	if file, err = open(filename); err != nil {
    18  		return false
    19  	}
    20  
    21  	r := false
    22  	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
    23  		f := getFields(line)
    24  		if len(f) < 3 {
    25  			continue
    26  		}
    27  		for i := 0; i < len(f); i++ {
    28  			if query == f[i] {
    29  				r = true
    30  				break
    31  			}
    32  		}
    33  	}
    34  	file.close()
    35  	return r
    36  }
    37  
    38  func probeIPv4Stack() bool {
    39  	return probe(netdir+"/iproute", "4i")
    40  }
    41  
    42  // probeIPv6Stack returns two boolean values.  If the first boolean
    43  // value is true, kernel supports basic IPv6 functionality.  If the
    44  // second boolean value is true, kernel supports IPv6 IPv4-mapping.
    45  func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
    46  	// Plan 9 uses IPv6 natively, see ip(3).
    47  	r := probe(netdir+"/iproute", "6i")
    48  	v := false
    49  	if r {
    50  		v = probe(netdir+"/iproute", "4i")
    51  	}
    52  	return r, v
    53  }
    54  
    55  // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
    56  func parsePlan9Addr(s string) (ip IP, iport int, err error) {
    57  	addr := IPv4zero // address contains port only
    58  	i := byteIndex(s, '!')
    59  	if i >= 0 {
    60  		addr = ParseIP(s[:i])
    61  		if addr == nil {
    62  			return nil, 0, &ParseError{Type: "IP address", Text: s}
    63  		}
    64  	}
    65  	p, _, ok := dtoi(s[i+1:], 0)
    66  	if !ok {
    67  		return nil, 0, &ParseError{Type: "port", Text: s}
    68  	}
    69  	if p < 0 || p > 0xFFFF {
    70  		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
    71  	}
    72  	return addr, p, nil
    73  }
    74  
    75  func readPlan9Addr(proto, filename string) (addr Addr, err error) {
    76  	var buf [128]byte
    77  
    78  	f, err := os.Open(filename)
    79  	if err != nil {
    80  		return
    81  	}
    82  	defer f.Close()
    83  	n, err := f.Read(buf[:])
    84  	if err != nil {
    85  		return
    86  	}
    87  	ip, port, err := parsePlan9Addr(string(buf[:n]))
    88  	if err != nil {
    89  		return
    90  	}
    91  	switch proto {
    92  	case "tcp":
    93  		addr = &TCPAddr{IP: ip, Port: port}
    94  	case "udp":
    95  		addr = &UDPAddr{IP: ip, Port: port}
    96  	default:
    97  		return nil, UnknownNetworkError(proto)
    98  	}
    99  	return addr, nil
   100  }
   101  
   102  func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
   103  	var (
   104  		ip   IP
   105  		port int
   106  	)
   107  	switch a := addr.(type) {
   108  	case *TCPAddr:
   109  		proto = "tcp"
   110  		ip = a.IP
   111  		port = a.Port
   112  	case *UDPAddr:
   113  		proto = "udp"
   114  		ip = a.IP
   115  		port = a.Port
   116  	default:
   117  		err = UnknownNetworkError(net)
   118  		return
   119  	}
   120  
   121  	clone, dest, err := queryCS1(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 netErr(e error) {
   139  	oe, ok := e.(*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(net string, laddr, raddr Addr) (fd *netFD, err error) {
   169  	defer func() { netErr(err) }()
   170  	f, dest, proto, name, err := startPlan9(net, raddr)
   171  	if err != nil {
   172  		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
   173  	}
   174  	_, err = f.WriteString("connect " + dest)
   175  	if err != nil {
   176  		f.Close()
   177  		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
   178  	}
   179  	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   180  	if err != nil {
   181  		f.Close()
   182  		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
   183  	}
   184  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   185  	if err != nil {
   186  		data.Close()
   187  		f.Close()
   188  		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
   189  	}
   190  	return newFD(proto, name, f, data, laddr, raddr)
   191  }
   192  
   193  func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
   194  	defer func() { netErr(err) }()
   195  	f, dest, proto, name, err := startPlan9(net, laddr)
   196  	if err != nil {
   197  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
   198  	}
   199  	_, err = f.WriteString("announce " + dest)
   200  	if err != nil {
   201  		f.Close()
   202  		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
   203  	}
   204  	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   205  	if err != nil {
   206  		f.Close()
   207  		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
   208  	}
   209  	return newFD(proto, name, f, nil, laddr, nil)
   210  }
   211  
   212  func (fd *netFD) netFD() (*netFD, error) {
   213  	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
   214  }
   215  
   216  func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   217  	defer func() { netErr(err) }()
   218  	if err := fd.readLock(); err != nil {
   219  		return nil, err
   220  	}
   221  	defer fd.readUnlock()
   222  	f, err := os.Open(fd.dir + "/listen")
   223  	if err != nil {
   224  		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
   225  	}
   226  	var buf [16]byte
   227  	n, err := f.Read(buf[:])
   228  	if err != nil {
   229  		f.Close()
   230  		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
   231  	}
   232  	name := string(buf[:n])
   233  	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   234  	if err != nil {
   235  		f.Close()
   236  		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
   237  	}
   238  	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   239  	if err != nil {
   240  		data.Close()
   241  		f.Close()
   242  		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
   243  	}
   244  	return newFD(fd.net, name, f, data, fd.laddr, raddr)
   245  }