github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 "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 }