Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Internet protocol family sockets | 5 // Internet protocol family sockets |
6 | 6 |
7 package net | 7 package net |
8 | 8 |
9 import "time" | 9 import "time" |
10 | 10 |
(...skipping 11 matching lines...) Expand all Loading... | |
22 // layer protocols. See RFC 4291, RFC 4038 and RFC 3493. | 22 // layer protocols. See RFC 4291, RFC 4038 and RFC 3493. |
23 supportsIPv4map bool | 23 supportsIPv4map bool |
24 ) | 24 ) |
25 | 25 |
26 func init() { | 26 func init() { |
27 sysInit() | 27 sysInit() |
28 supportsIPv4 = probeIPv4Stack() | 28 supportsIPv4 = probeIPv4Stack() |
29 supportsIPv6, supportsIPv4map = probeIPv6Stack() | 29 supportsIPv6, supportsIPv4map = probeIPv6Stack() |
30 } | 30 } |
31 | 31 |
32 func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) { | 32 // A netaddr represents a network endpoint address or a list of |
33 » if filter == nil { | 33 // network endpoint addresses. |
34 » » // We'll take any IP address, but since the dialing code | 34 type netaddr interface { |
35 » » // does not yet try multiple addresses, prefer to use | 35 » // toAddr returns the address represented in Addr interface. |
36 » » // an IPv4 address if possible. This is especially relevant | 36 » // It returns a nil interface when the address is nil. |
37 » » // if localhost resolves to [ipv6-localhost, ipv4-localhost]. | 37 » toAddr() Addr |
38 » » // Too much code assumes localhost == ipv4-localhost. | |
39 » » addr = firstSupportedAddr(ipv4only, addrs) | |
40 » » if addr == nil { | |
41 » » » addr = firstSupportedAddr(anyaddr, addrs) | |
42 » » } | |
43 » } else { | |
44 » » addr = firstSupportedAddr(filter, addrs) | |
45 » } | |
46 » return | |
47 } | 38 } |
48 | 39 |
49 func firstSupportedAddr(filter func(IP) IP, addrs []string) IP { | 40 // An addrList represents a list of network endpoint addresses. |
50 » for _, s := range addrs { | 41 type addrList []netaddr |
51 » » if addr := filter(ParseIP(s)); addr != nil { | 42 |
52 » » » return addr | 43 func (al addrList) toAddr() Addr { |
44 » switch len(al) { | |
45 » case 0: | |
46 » » return nil | |
47 » case 1: | |
48 » » return al[0].toAddr() | |
49 » default: | |
50 » » // For now, we'll roughly pick first one without | |
51 » » // considering dealing with any preferences such as | |
52 » » // DNS TTL, transport path quality, network routing | |
53 » » // information. | |
54 » » return al[0].toAddr() | |
55 » } | |
56 } | |
57 | |
58 func firstFavoriteAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) netaddr { | |
59 » if filter != nil { | |
60 » » return firstSupportedAddr(filter, ips, inetaddr) | |
61 » } | |
62 » var ( | |
63 » » ipv4, ipv6, swap bool | |
64 » » list addrList | |
65 » ) | |
66 » for _, ip := range ips { | |
67 » » // We'll take any IP address, but since the dialing | |
68 » » // code does not yet try multiple addresses | |
69 » » // effectively, prefer to use an IPv4 address if | |
70 » » // possible. This is especially relevant if localhost | |
71 » » // resolves to [ipv6-localhost, ipv4-localhost]. Too | |
72 » » // much code assumes localhost == ipv4-localhost. | |
73 » » if ip4 := ipv4only(ip); ip4 != nil && !ipv4 { | |
74 » » » list = append(list, inetaddr(ip4)) | |
75 » » » ipv4 = true | |
76 » » » if ipv6 { | |
77 » » » » swap = true | |
78 » » » } | |
79 » » } else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 { | |
80 » » » list = append(list, inetaddr(ip6)) | |
81 » » » ipv6 = true | |
82 » » } | |
83 » » if ipv4 && ipv6 { | |
84 » » » if swap { | |
85 » » » » list[0], list[1] = list[1], list[0] | |
86 » » » } | |
87 » » » break | |
88 » » } | |
89 » } | |
90 » switch len(list) { | |
91 » case 0: | |
92 » » return nil | |
bradfitz
2013/08/22 01:10:38
shouldn't this be addrList(nil) so .Addr() on it r
mikio
2013/08/23 12:29:51
resolveInternetAddr will take care, so no.
| |
93 » case 1: | |
94 » » return list[0] | |
95 » default: | |
96 » » return list | |
97 » } | |
98 } | |
99 | |
100 func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) netaddr { | |
101 » for _, ip := range ips { | |
102 » » if ip := filter(ip); ip != nil { | |
103 » » » return inetaddr(ip) | |
53 } | 104 } |
54 } | 105 } |
55 return nil | 106 return nil |
56 } | 107 } |
57 | 108 |
58 // anyaddr returns IP addresses that we can use with the current | |
59 // kernel configuration. It returns nil when ip is not suitable for | |
60 // the configuration and an IP address. | |
61 func anyaddr(ip IP) IP { | |
62 if ip4 := ipv4only(ip); ip4 != nil { | |
63 return ip4 | |
64 } | |
65 return ipv6only(ip) | |
66 } | |
67 | |
68 // ipv4only returns IPv4 addresses that we can use with the kernel's | 109 // ipv4only returns IPv4 addresses that we can use with the kernel's |
69 // IPv4 addressing modes. It returns IPv4-mapped IPv6 addresses as | 110 // IPv4 addressing modes. It returns IPv4-mapped IPv6 addresses as |
70 // IPv4 addresses and returns other IPv6 address types as nils. | 111 // IPv4 addresses and returns other IPv6 address types as nils. |
71 func ipv4only(ip IP) IP { | 112 func ipv4only(ip IP) IP { |
72 if supportsIPv4 { | 113 if supportsIPv4 { |
73 return ip.To4() | 114 return ip.To4() |
74 } | 115 } |
75 return nil | 116 return nil |
76 } | 117 } |
77 | 118 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 // form "host:port" or, if host contains a colon or a percent sign, | 212 // form "host:port" or, if host contains a colon or a percent sign, |
172 // "[host]:port". | 213 // "[host]:port". |
173 func JoinHostPort(host, port string) string { | 214 func JoinHostPort(host, port string) string { |
174 // If host has colons or a percent sign, have to bracket it. | 215 // If host has colons or a percent sign, have to bracket it. |
175 if byteIndex(host, ':') >= 0 || byteIndex(host, '%') >= 0 { | 216 if byteIndex(host, ':') >= 0 || byteIndex(host, '%') >= 0 { |
176 return "[" + host + "]:" + port | 217 return "[" + host + "]:" + port |
177 } | 218 } |
178 return host + ":" + port | 219 return host + ":" + port |
179 } | 220 } |
180 | 221 |
181 func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) { | 222 // resolveInternetAddr resolves addr that is either a literal IP |
223 // address or a DNS registered name and returns an internet protocol | |
224 // family address. It returns a list that contains a pair of | |
225 // different address family addresses when addr is a DNS registered | |
226 // name and the name has mutiple address family records. The result | |
227 // contains at least one address when error is nil. | |
228 func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) { | |
182 var ( | 229 var ( |
183 err error | 230 err error |
184 host, port, zone string | 231 host, port, zone string |
185 portnum int | 232 portnum int |
186 ) | 233 ) |
187 switch net { | 234 switch net { |
188 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": | 235 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": |
189 if addr != "" { | 236 if addr != "" { |
190 if host, port, err = SplitHostPort(addr); err != nil { | 237 if host, port, err = SplitHostPort(addr); err != nil { |
191 return nil, err | 238 return nil, err |
192 } | 239 } |
193 if portnum, err = parsePort(net, port); err != nil { | 240 if portnum, err = parsePort(net, port); err != nil { |
194 return nil, err | 241 return nil, err |
195 } | 242 } |
196 } | 243 } |
197 case "ip", "ip4", "ip6": | 244 case "ip", "ip4", "ip6": |
198 if addr != "" { | 245 if addr != "" { |
199 host = addr | 246 host = addr |
200 } | 247 } |
201 default: | 248 default: |
202 return nil, UnknownNetworkError(net) | 249 return nil, UnknownNetworkError(net) |
203 } | 250 } |
204 » inetaddr := func(net string, ip IP, port int, zone string) Addr { | 251 » inetaddr := func(ip IP) netaddr { |
205 switch net { | 252 switch net { |
206 case "tcp", "tcp4", "tcp6": | 253 case "tcp", "tcp4", "tcp6": |
207 » » » return &TCPAddr{IP: ip, Port: port, Zone: zone} | 254 » » » return &TCPAddr{IP: ip, Port: portnum, Zone: zone} |
208 case "udp", "udp4", "udp6": | 255 case "udp", "udp4", "udp6": |
209 » » » return &UDPAddr{IP: ip, Port: port, Zone: zone} | 256 » » » return &UDPAddr{IP: ip, Port: portnum, Zone: zone} |
210 case "ip", "ip4", "ip6": | 257 case "ip", "ip4", "ip6": |
211 return &IPAddr{IP: ip, Zone: zone} | 258 return &IPAddr{IP: ip, Zone: zone} |
259 default: | |
260 return nil // should not happen | |
212 } | 261 } |
213 return nil | |
214 } | 262 } |
215 if host == "" { | 263 if host == "" { |
216 » » return inetaddr(net, nil, portnum, zone), nil | 264 » » return inetaddr(nil), nil |
217 } | 265 } |
218 » // Try as an IP address. | 266 » // Try as a literal IP address. |
219 » if ip := parseIPv4(host); ip != nil { | 267 » var ip IP |
220 » » return inetaddr(net, ip, portnum, zone), nil | 268 » if ip = parseIPv4(host); ip != nil { |
269 » » return inetaddr(ip), nil | |
221 } | 270 } |
222 » if ip, zone := parseIPv6(host, true); ip != nil { | 271 » if ip, zone = parseIPv6(host, true); ip != nil { |
223 » » return inetaddr(net, ip, portnum, zone), nil | 272 » » return inetaddr(ip), nil |
224 } | 273 } |
225 » // Try as a domain name. | 274 » // Try as a DNS registered name. |
226 host, zone = splitHostZone(host) | 275 host, zone = splitHostZone(host) |
227 » addrs, err := lookupHostDeadline(host, deadline) | 276 » ips, err := lookupIPDeadline(host, deadline) |
228 if err != nil { | 277 if err != nil { |
229 return nil, err | 278 return nil, err |
230 } | 279 } |
231 var filter func(IP) IP | 280 var filter func(IP) IP |
232 if net != "" && net[len(net)-1] == '4' { | 281 if net != "" && net[len(net)-1] == '4' { |
233 filter = ipv4only | 282 filter = ipv4only |
234 } | 283 } |
235 if net != "" && net[len(net)-1] == '6' || zone != "" { | 284 if net != "" && net[len(net)-1] == '6' || zone != "" { |
236 filter = ipv6only | 285 filter = ipv6only |
237 } | 286 } |
238 » ip := firstFavoriteAddr(filter, addrs) | 287 » netaddr := firstFavoriteAddr(filter, ips, inetaddr) |
239 » if ip == nil { | 288 » if netaddr == nil { |
240 » » // should not happen | 289 » » return nil, &AddrError{"LookupIP returned no suitable address", addr} |
241 » » return nil, &AddrError{"LookupHost returned no suitable address" , addrs[0]} | |
242 } | 290 } |
243 » return inetaddr(net, ip, portnum, zone), nil | 291 » return netaddr, nil |
244 } | 292 } |
245 | 293 |
246 func zoneToString(zone int) string { | 294 func zoneToString(zone int) string { |
247 if zone == 0 { | 295 if zone == 0 { |
248 return "" | 296 return "" |
249 } | 297 } |
250 if ifi, err := InterfaceByIndex(zone); err == nil { | 298 if ifi, err := InterfaceByIndex(zone); err == nil { |
251 return ifi.Name | 299 return ifi.Name |
252 } | 300 } |
253 return itod(uint(zone)) | 301 return itod(uint(zone)) |
254 } | 302 } |
255 | 303 |
256 func zoneToInt(zone string) int { | 304 func zoneToInt(zone string) int { |
257 if zone == "" { | 305 if zone == "" { |
258 return 0 | 306 return 0 |
259 } | 307 } |
260 if ifi, err := InterfaceByName(zone); err == nil { | 308 if ifi, err := InterfaceByName(zone); err == nil { |
261 return ifi.Index | 309 return ifi.Index |
262 } | 310 } |
263 n, _, _ := dtoi(zone, 0) | 311 n, _, _ := dtoi(zone, 0) |
264 return n | 312 return n |
265 } | 313 } |
OLD | NEW |