Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgo / go / net / lookup_plan9.go
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.
4
5 package net
6
7 import (
8         "errors"
9         "os"
10         "syscall"
11 )
12
13 func query(filename, query string, bufSize int) (res []string, err error) {
14         file, err := os.OpenFile(filename, os.O_RDWR, 0)
15         if err != nil {
16                 return
17         }
18         defer file.Close()
19
20         _, err = file.WriteString(query)
21         if err != nil {
22                 return
23         }
24         _, err = file.Seek(0, 0)
25         if err != nil {
26                 return
27         }
28         buf := make([]byte, bufSize)
29         for {
30                 n, _ := file.Read(buf)
31                 if n <= 0 {
32                         break
33                 }
34                 res = append(res, string(buf[:n]))
35         }
36         return
37 }
38
39 func queryCS(net, host, service string) (res []string, err error) {
40         switch net {
41         case "tcp4", "tcp6":
42                 net = "tcp"
43         case "udp4", "udp6":
44                 net = "udp"
45         }
46         if host == "" {
47                 host = "*"
48         }
49         return query("/net/cs", net+"!"+host+"!"+service, 128)
50 }
51
52 func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
53         ips := "*"
54         if len(ip) != 0 && !ip.IsUnspecified() {
55                 ips = ip.String()
56         }
57         lines, err := queryCS(net, ips, itoa(port))
58         if err != nil {
59                 return
60         }
61         f := getFields(lines[0])
62         if len(f) < 2 {
63                 return "", "", errors.New("net: bad response from ndb/cs")
64         }
65         clone, dest = f[0], f[1]
66         return
67 }
68
69 func queryDNS(addr string, typ string) (res []string, err error) {
70         return query("/net/dns", addr+" "+typ, 1024)
71 }
72
73 func lookupProtocol(name string) (proto int, err error) {
74         // TODO: Implement this
75         return 0, syscall.EPLAN9
76 }
77
78 func lookupHost(host string) (addrs []string, err error) {
79         // Use /net/cs instead of /net/dns because cs knows about
80         // host names in local network (e.g. from /lib/ndb/local)
81         lines, err := queryCS("tcp", host, "1")
82         if err != nil {
83                 return
84         }
85         for _, line := range lines {
86                 f := getFields(line)
87                 if len(f) < 2 {
88                         continue
89                 }
90                 addr := f[1]
91                 if i := byteIndex(addr, '!'); i >= 0 {
92                         addr = addr[:i] // remove port
93                 }
94                 if ParseIP(addr) == nil {
95                         continue
96                 }
97                 addrs = append(addrs, addr)
98         }
99         return
100 }
101
102 func lookupIP(host string) (ips []IP, err error) {
103         addrs, err := LookupHost(host)
104         if err != nil {
105                 return
106         }
107         for _, addr := range addrs {
108                 if ip := ParseIP(addr); ip != nil {
109                         ips = append(ips, ip)
110                 }
111         }
112         return
113 }
114
115 func lookupPort(network, service string) (port int, err error) {
116         switch network {
117         case "tcp4", "tcp6":
118                 network = "tcp"
119         case "udp4", "udp6":
120                 network = "udp"
121         }
122         lines, err := queryCS(network, "127.0.0.1", service)
123         if err != nil {
124                 return
125         }
126         unknownPortError := &AddrError{"unknown port", network + "/" + service}
127         if len(lines) == 0 {
128                 return 0, unknownPortError
129         }
130         f := getFields(lines[0])
131         if len(f) < 2 {
132                 return 0, unknownPortError
133         }
134         s := f[1]
135         if i := byteIndex(s, '!'); i >= 0 {
136                 s = s[i+1:] // remove address
137         }
138         if n, _, ok := dtoi(s, 0); ok {
139                 return n, nil
140         }
141         return 0, unknownPortError
142 }
143
144 func lookupCNAME(name string) (cname string, err error) {
145         lines, err := queryDNS(name, "cname")
146         if err != nil {
147                 return
148         }
149         if len(lines) > 0 {
150                 if f := getFields(lines[0]); len(f) >= 3 {
151                         return f[2] + ".", nil
152                 }
153         }
154         return "", errors.New("net: bad response from ndb/dns")
155 }
156
157 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
158         var target string
159         if service == "" && proto == "" {
160                 target = name
161         } else {
162                 target = "_" + service + "._" + proto + "." + name
163         }
164         lines, err := queryDNS(target, "srv")
165         if err != nil {
166                 return
167         }
168         for _, line := range lines {
169                 f := getFields(line)
170                 if len(f) < 6 {
171                         continue
172                 }
173                 port, _, portOk := dtoi(f[2], 0)
174                 priority, _, priorityOk := dtoi(f[3], 0)
175                 weight, _, weightOk := dtoi(f[4], 0)
176                 if !(portOk && priorityOk && weightOk) {
177                         continue
178                 }
179                 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
180                 cname = f[0]
181         }
182         byPriorityWeight(addrs).sort()
183         return
184 }
185
186 func lookupMX(name string) (mx []*MX, err error) {
187         lines, err := queryDNS(name, "mx")
188         if err != nil {
189                 return
190         }
191         for _, line := range lines {
192                 f := getFields(line)
193                 if len(f) < 4 {
194                         continue
195                 }
196                 if pref, _, ok := dtoi(f[2], 0); ok {
197                         mx = append(mx, &MX{f[3], uint16(pref)})
198                 }
199         }
200         byPref(mx).sort()
201         return
202 }
203
204 func lookupTXT(name string) (txt []string, err error) {
205         lines, err := queryDNS(name, "txt")
206         if err != nil {
207                 return
208         }
209         for _, line := range lines {
210                 if i := byteIndex(line, '\t'); i >= 0 {
211                         txt = append(txt, line[i+1:])
212                 }
213         }
214         return
215 }
216
217 func lookupAddr(addr string) (name []string, err error) {
218         arpa, err := reverseaddr(addr)
219         if err != nil {
220                 return
221         }
222         lines, err := queryDNS(arpa, "ptr")
223         if err != nil {
224                 return
225         }
226         for _, line := range lines {
227                 f := getFields(line)
228                 if len(f) < 3 {
229                         continue
230                 }
231                 name = append(name, f[2])
232         }
233         return
234 }