github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 "os" 11 "syscall" 12 ) 13 14 func probe(filename, query string) bool { 15 var file *file 16 var err error 17 if file, err = open(filename); err != nil { 18 return false 19 } 20 21 r := false 22 for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() { 23 f := getFields(line) 24 if len(f) < 3 { 25 continue 26 } 27 for i := 0; i < len(f); i++ { 28 if query == f[i] { 29 r = true 30 break 31 } 32 } 33 } 34 file.close() 35 return r 36 } 37 38 func probeIPv4Stack() bool { 39 return probe(netdir+"/iproute", "4i") 40 } 41 42 // probeIPv6Stack returns two boolean values. If the first boolean 43 // value is true, kernel supports basic IPv6 functionality. If the 44 // second boolean value is true, kernel supports IPv6 IPv4-mapping. 45 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { 46 // Plan 9 uses IPv6 natively, see ip(3). 47 r := probe(netdir+"/iproute", "6i") 48 v := false 49 if r { 50 v = probe(netdir+"/iproute", "4i") 51 } 52 return r, v 53 } 54 55 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80). 56 func parsePlan9Addr(s string) (ip IP, iport int, err error) { 57 addr := IPv4zero // address contains port only 58 i := byteIndex(s, '!') 59 if i >= 0 { 60 addr = ParseIP(s[:i]) 61 if addr == nil { 62 return nil, 0, &ParseError{Type: "IP address", Text: s} 63 } 64 } 65 p, _, ok := dtoi(s[i+1:], 0) 66 if !ok { 67 return nil, 0, &ParseError{Type: "port", Text: s} 68 } 69 if p < 0 || p > 0xFFFF { 70 return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)} 71 } 72 return addr, p, nil 73 } 74 75 func readPlan9Addr(proto, filename string) (addr Addr, err error) { 76 var buf [128]byte 77 78 f, err := os.Open(filename) 79 if err != nil { 80 return 81 } 82 defer f.Close() 83 n, err := f.Read(buf[:]) 84 if err != nil { 85 return 86 } 87 ip, port, err := parsePlan9Addr(string(buf[:n])) 88 if err != nil { 89 return 90 } 91 switch proto { 92 case "tcp": 93 addr = &TCPAddr{IP: ip, Port: port} 94 case "udp": 95 addr = &UDPAddr{IP: ip, Port: port} 96 default: 97 return nil, UnknownNetworkError(proto) 98 } 99 return addr, nil 100 } 101 102 func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) { 103 var ( 104 ip IP 105 port int 106 ) 107 switch a := addr.(type) { 108 case *TCPAddr: 109 proto = "tcp" 110 ip = a.IP 111 port = a.Port 112 case *UDPAddr: 113 proto = "udp" 114 ip = a.IP 115 port = a.Port 116 default: 117 err = UnknownNetworkError(net) 118 return 119 } 120 121 clone, dest, err := queryCS1(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 netErr(e error) { 139 oe, ok := e.(*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(net string, laddr, raddr Addr) (fd *netFD, err error) { 169 defer func() { netErr(err) }() 170 f, dest, proto, name, err := startPlan9(net, raddr) 171 if err != nil { 172 return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err} 173 } 174 _, err = f.WriteString("connect " + dest) 175 if err != nil { 176 f.Close() 177 return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err} 178 } 179 data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0) 180 if err != nil { 181 f.Close() 182 return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err} 183 } 184 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") 185 if err != nil { 186 data.Close() 187 f.Close() 188 return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err} 189 } 190 return newFD(proto, name, f, data, laddr, raddr) 191 } 192 193 func listenPlan9(net string, laddr Addr) (fd *netFD, err error) { 194 defer func() { netErr(err) }() 195 f, dest, proto, name, err := startPlan9(net, laddr) 196 if err != nil { 197 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} 198 } 199 _, err = f.WriteString("announce " + dest) 200 if err != nil { 201 f.Close() 202 return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err} 203 } 204 laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") 205 if err != nil { 206 f.Close() 207 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} 208 } 209 return newFD(proto, name, f, nil, laddr, nil) 210 } 211 212 func (fd *netFD) netFD() (*netFD, error) { 213 return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr) 214 } 215 216 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) { 217 defer func() { netErr(err) }() 218 if err := fd.readLock(); err != nil { 219 return nil, err 220 } 221 defer fd.readUnlock() 222 f, err := os.Open(fd.dir + "/listen") 223 if err != nil { 224 return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err} 225 } 226 var buf [16]byte 227 n, err := f.Read(buf[:]) 228 if err != nil { 229 f.Close() 230 return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err} 231 } 232 name := string(buf[:n]) 233 data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0) 234 if err != nil { 235 f.Close() 236 return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err} 237 } 238 raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote") 239 if err != nil { 240 data.Close() 241 f.Close() 242 return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err} 243 } 244 return newFD(fd.net, name, f, data, fd.laddr, raddr) 245 }