...

Source file src/net/ipsock_plan9.go

     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		"os"
    11		"syscall"
    12	)
    13	
    14	// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
    15	// capabilities.
    16	//
    17	// Plan 9 uses IPv6 natively, see ip(3).
    18	func (p *ipStackCapabilities) probe() {
    19		p.ipv4Enabled = probe(netdir+"/iproute", "4i")
    20		p.ipv6Enabled = probe(netdir+"/iproute", "6i")
    21		if p.ipv4Enabled && p.ipv6Enabled {
    22			p.ipv4MappedIPv6Enabled = true
    23		}
    24	}
    25	
    26	func probe(filename, query string) bool {
    27		var file *file
    28		var err error
    29		if file, err = open(filename); err != nil {
    30			return false
    31		}
    32		defer file.close()
    33	
    34		r := false
    35		for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
    36			f := getFields(line)
    37			if len(f) < 3 {
    38				continue
    39			}
    40			for i := 0; i < len(f); i++ {
    41				if query == f[i] {
    42					r = true
    43					break
    44				}
    45			}
    46		}
    47		return r
    48	}
    49	
    50	// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
    51	func parsePlan9Addr(s string) (ip IP, iport int, err error) {
    52		addr := IPv4zero // address contains port only
    53		i := bytealg.IndexByteString(s, '!')
    54		if i >= 0 {
    55			addr = ParseIP(s[:i])
    56			if addr == nil {
    57				return nil, 0, &ParseError{Type: "IP address", Text: s}
    58			}
    59		}
    60		p, _, ok := dtoi(s[i+1:])
    61		if !ok {
    62			return nil, 0, &ParseError{Type: "port", Text: s}
    63		}
    64		if p < 0 || p > 0xFFFF {
    65			return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
    66		}
    67		return addr, p, nil
    68	}
    69	
    70	func readPlan9Addr(proto, filename string) (addr Addr, err error) {
    71		var buf [128]byte
    72	
    73		f, err := os.Open(filename)
    74		if err != nil {
    75			return
    76		}
    77		defer f.Close()
    78		n, err := f.Read(buf[:])
    79		if err != nil {
    80			return
    81		}
    82		ip, port, err := parsePlan9Addr(string(buf[:n]))
    83		if err != nil {
    84			return
    85		}
    86		switch proto {
    87		case "tcp":
    88			addr = &TCPAddr{IP: ip, Port: port}
    89		case "udp":
    90			addr = &UDPAddr{IP: ip, Port: port}
    91		default:
    92			return nil, UnknownNetworkError(proto)
    93		}
    94		return addr, nil
    95	}
    96	
    97	func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
    98		var (
    99			ip   IP
   100			port int
   101		)
   102		switch a := addr.(type) {
   103		case *TCPAddr:
   104			proto = "tcp"
   105			ip = a.IP
   106			port = a.Port
   107		case *UDPAddr:
   108			proto = "udp"
   109			ip = a.IP
   110			port = a.Port
   111		default:
   112			err = UnknownNetworkError(net)
   113			return
   114		}
   115	
   116		if port > 65535 {
   117			err = InvalidAddrError("port should be < 65536")
   118			return
   119		}
   120	
   121		clone, dest, err := queryCS1(ctx, 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 fixErr(err error) {
   139		oe, ok := err.(*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(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   169		defer func() { fixErr(err) }()
   170		type res struct {
   171			fd  *netFD
   172			err error
   173		}
   174		resc := make(chan res)
   175		go func() {
   176			testHookDialChannel()
   177			fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
   178			select {
   179			case resc <- res{fd, err}:
   180			case <-ctx.Done():
   181				if fd != nil {
   182					fd.Close()
   183				}
   184			}
   185		}()
   186		select {
   187		case res := <-resc:
   188			return res.fd, res.err
   189		case <-ctx.Done():
   190			return nil, mapErr(ctx.Err())
   191		}
   192	}
   193	
   194	func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
   195		if isWildcard(raddr) {
   196			raddr = toLocal(raddr, net)
   197		}
   198		f, dest, proto, name, err := startPlan9(ctx, net, raddr)
   199		if err != nil {
   200			return nil, err
   201		}
   202		_, err = f.WriteString("connect " + dest)
   203		if err != nil {
   204			f.Close()
   205			return nil, err
   206		}
   207		data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
   208		if err != nil {
   209			f.Close()
   210			return nil, err
   211		}
   212		laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   213		if err != nil {
   214			data.Close()
   215			f.Close()
   216			return nil, err
   217		}
   218		return newFD(proto, name, nil, f, data, laddr, raddr)
   219	}
   220	
   221	func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
   222		defer func() { fixErr(err) }()
   223		f, dest, proto, name, err := startPlan9(ctx, net, laddr)
   224		if err != nil {
   225			return nil, err
   226		}
   227		_, err = f.WriteString("announce " + dest)
   228		if err != nil {
   229			f.Close()
   230			return nil, err
   231		}
   232		laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
   233		if err != nil {
   234			f.Close()
   235			return nil, err
   236		}
   237		return newFD(proto, name, nil, f, nil, laddr, nil)
   238	}
   239	
   240	func (fd *netFD) netFD() (*netFD, error) {
   241		return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
   242	}
   243	
   244	func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
   245		defer func() { fixErr(err) }()
   246		if err := fd.pfd.ReadLock(); err != nil {
   247			return nil, err
   248		}
   249		defer fd.pfd.ReadUnlock()
   250		listen, err := os.Open(fd.dir + "/listen")
   251		if err != nil {
   252			return nil, err
   253		}
   254		var buf [16]byte
   255		n, err := listen.Read(buf[:])
   256		if err != nil {
   257			listen.Close()
   258			return nil, err
   259		}
   260		name := string(buf[:n])
   261		ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
   262		if err != nil {
   263			listen.Close()
   264			return nil, err
   265		}
   266		data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
   267		if err != nil {
   268			listen.Close()
   269			ctl.Close()
   270			return nil, err
   271		}
   272		raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
   273		if err != nil {
   274			listen.Close()
   275			ctl.Close()
   276			data.Close()
   277			return nil, err
   278		}
   279		return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
   280	}
   281	
   282	func isWildcard(a Addr) bool {
   283		var wildcard bool
   284		switch a := a.(type) {
   285		case *TCPAddr:
   286			wildcard = a.isWildcard()
   287		case *UDPAddr:
   288			wildcard = a.isWildcard()
   289		case *IPAddr:
   290			wildcard = a.isWildcard()
   291		}
   292		return wildcard
   293	}
   294	
   295	func toLocal(a Addr, net string) Addr {
   296		switch a := a.(type) {
   297		case *TCPAddr:
   298			a.IP = loopbackIP(net)
   299		case *UDPAddr:
   300			a.IP = loopbackIP(net)
   301		case *IPAddr:
   302			a.IP = loopbackIP(net)
   303		}
   304		return a
   305	}
   306	

View as plain text