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