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