libgo: Update to Go 1.3 release.
[official-gcc.git] / libgo / go / net / lookup_plan9.go
blobb80ac10e0d9d0ef155c123e11fc26a031f200873
1 // Copyright 2011 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.
5 package net
7 import (
8 "errors"
9 "os"
12 func query(filename, query string, bufSize int) (res []string, err error) {
13 file, err := os.OpenFile(filename, os.O_RDWR, 0)
14 if err != nil {
15 return
17 defer file.Close()
19 _, err = file.Seek(0, 0)
20 if err != nil {
21 return
23 _, err = file.WriteString(query)
24 if err != nil {
25 return
27 _, err = file.Seek(0, 0)
28 if err != nil {
29 return
31 buf := make([]byte, bufSize)
32 for {
33 n, _ := file.Read(buf)
34 if n <= 0 {
35 break
37 res = append(res, string(buf[:n]))
39 return
42 func queryCS(net, host, service string) (res []string, err error) {
43 switch net {
44 case "tcp4", "tcp6":
45 net = "tcp"
46 case "udp4", "udp6":
47 net = "udp"
49 if host == "" {
50 host = "*"
52 return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
55 func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
56 ips := "*"
57 if len(ip) != 0 && !ip.IsUnspecified() {
58 ips = ip.String()
60 lines, err := queryCS(net, ips, itoa(port))
61 if err != nil {
62 return
64 f := getFields(lines[0])
65 if len(f) < 2 {
66 return "", "", errors.New("bad response from ndb/cs")
68 clone, dest = f[0], f[1]
69 return
72 func queryDNS(addr string, typ string) (res []string, err error) {
73 return query(netdir+"/dns", addr+" "+typ, 1024)
76 // toLower returns a lower-case version of in. Restricting us to
77 // ASCII is sufficient to handle the IP protocol names and allow
78 // us to not depend on the strings and unicode packages.
79 func toLower(in string) string {
80 for _, c := range in {
81 if 'A' <= c && c <= 'Z' {
82 // Has upper case; need to fix.
83 out := []byte(in)
84 for i := 0; i < len(in); i++ {
85 c := in[i]
86 if 'A' <= c && c <= 'Z' {
87 c += 'a' - 'A'
89 out[i] = c
91 return string(out)
94 return in
97 // lookupProtocol looks up IP protocol name and returns
98 // the corresponding protocol number.
99 func lookupProtocol(name string) (proto int, err error) {
100 lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
101 if err != nil {
102 return 0, err
104 unknownProtoError := errors.New("unknown IP protocol specified: " + name)
105 if len(lines) == 0 {
106 return 0, unknownProtoError
108 f := getFields(lines[0])
109 if len(f) < 2 {
110 return 0, unknownProtoError
112 s := f[1]
113 if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
114 return n, nil
116 return 0, unknownProtoError
119 func lookupHost(host string) (addrs []string, err error) {
120 // Use netdir/cs instead of netdir/dns because cs knows about
121 // host names in local network (e.g. from /lib/ndb/local)
122 lines, err := queryCS("net", host, "1")
123 if err != nil {
124 return
126 loop:
127 for _, line := range lines {
128 f := getFields(line)
129 if len(f) < 2 {
130 continue
132 addr := f[1]
133 if i := byteIndex(addr, '!'); i >= 0 {
134 addr = addr[:i] // remove port
136 if ParseIP(addr) == nil {
137 continue
139 // only return unique addresses
140 for _, a := range addrs {
141 if a == addr {
142 continue loop
145 addrs = append(addrs, addr)
147 return
150 func lookupIP(host string) (ips []IP, err error) {
151 addrs, err := LookupHost(host)
152 if err != nil {
153 return
155 for _, addr := range addrs {
156 if ip := ParseIP(addr); ip != nil {
157 ips = append(ips, ip)
160 return
163 func lookupPort(network, service string) (port int, err error) {
164 switch network {
165 case "tcp4", "tcp6":
166 network = "tcp"
167 case "udp4", "udp6":
168 network = "udp"
170 lines, err := queryCS(network, "127.0.0.1", service)
171 if err != nil {
172 return
174 unknownPortError := &AddrError{"unknown port", network + "/" + service}
175 if len(lines) == 0 {
176 return 0, unknownPortError
178 f := getFields(lines[0])
179 if len(f) < 2 {
180 return 0, unknownPortError
182 s := f[1]
183 if i := byteIndex(s, '!'); i >= 0 {
184 s = s[i+1:] // remove address
186 if n, _, ok := dtoi(s, 0); ok {
187 return n, nil
189 return 0, unknownPortError
192 func lookupCNAME(name string) (cname string, err error) {
193 lines, err := queryDNS(name, "cname")
194 if err != nil {
195 return
197 if len(lines) > 0 {
198 if f := getFields(lines[0]); len(f) >= 3 {
199 return f[2] + ".", nil
202 return "", errors.New("bad response from ndb/dns")
205 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
206 var target string
207 if service == "" && proto == "" {
208 target = name
209 } else {
210 target = "_" + service + "._" + proto + "." + name
212 lines, err := queryDNS(target, "srv")
213 if err != nil {
214 return
216 for _, line := range lines {
217 f := getFields(line)
218 if len(f) < 6 {
219 continue
221 port, _, portOk := dtoi(f[4], 0)
222 priority, _, priorityOk := dtoi(f[3], 0)
223 weight, _, weightOk := dtoi(f[2], 0)
224 if !(portOk && priorityOk && weightOk) {
225 continue
227 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
228 cname = f[0]
230 byPriorityWeight(addrs).sort()
231 return
234 func lookupMX(name string) (mx []*MX, err error) {
235 lines, err := queryDNS(name, "mx")
236 if err != nil {
237 return
239 for _, line := range lines {
240 f := getFields(line)
241 if len(f) < 4 {
242 continue
244 if pref, _, ok := dtoi(f[2], 0); ok {
245 mx = append(mx, &MX{f[3], uint16(pref)})
248 byPref(mx).sort()
249 return
252 func lookupNS(name string) (ns []*NS, err error) {
253 lines, err := queryDNS(name, "ns")
254 if err != nil {
255 return
257 for _, line := range lines {
258 f := getFields(line)
259 if len(f) < 3 {
260 continue
262 ns = append(ns, &NS{f[2]})
264 return
267 func lookupTXT(name string) (txt []string, err error) {
268 lines, err := queryDNS(name, "txt")
269 if err != nil {
270 return
272 for _, line := range lines {
273 if i := byteIndex(line, '\t'); i >= 0 {
274 txt = append(txt, line[i+1:])
277 return
280 func lookupAddr(addr string) (name []string, err error) {
281 arpa, err := reverseaddr(addr)
282 if err != nil {
283 return
285 lines, err := queryDNS(arpa, "ptr")
286 if err != nil {
287 return
289 for _, line := range lines {
290 f := getFields(line)
291 if len(f) < 3 {
292 continue
294 name = append(name, f[2])
296 return