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 }