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