Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1399)

Side by Side Diff: src/pkg/net/ipsock.go

Issue 12414043: code review 12414043: net: pick a pair of different address family IP address... (Closed)
Patch Set: diff -r 9b8afda16f02 https://code.google.com/p/go Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pkg/net/iprawsock_posix.go ('k') | src/pkg/net/lookup.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « src/pkg/net/iprawsock_posix.go ('k') | src/pkg/net/lookup.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b