mirror of
https://github.com/golang/go
synced 2024-11-24 22:00:09 -07:00
net: make resolveInternetAddr return a list of addresses
This CL makes resolveInternetAddr return a list of addresses that contain a pair of different address family IP addresses if possible, but doesn't contain any API behavioral changes yet. A simple IP address selection mechanism for Resolve{TCP,UDP,IP}Addr and Dial API still prefers IPv4. This is in preparation for TCP connection setup with fast failover on dual IP stack node as described in RFC 6555. Update #3610 Update #5267 R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/13374043
This commit is contained in:
parent
379096de05
commit
7c59c8bdee
@ -16,6 +16,31 @@ import (
|
|||||||
// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
|
// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
|
||||||
var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
|
var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
|
||||||
|
|
||||||
|
func TestResolveGoogle(t *testing.T) {
|
||||||
|
if testing.Short() || !*testExternal {
|
||||||
|
t.Skip("skipping test to avoid external network")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, network := range []string{"tcp", "tcp4", "tcp6"} {
|
||||||
|
addr, err := ResolveTCPAddr(network, "www.google.com:http")
|
||||||
|
if err != nil {
|
||||||
|
if (network == "tcp" || network == "tcp4") && !supportsIPv4 {
|
||||||
|
t.Logf("ipv4 is not supported: %v", err)
|
||||||
|
} else if network == "tcp6" && !supportsIPv6 {
|
||||||
|
t.Logf("ipv6 is not supported: %v", err)
|
||||||
|
} else {
|
||||||
|
t.Errorf("ResolveTCPAddr failed: %v", err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (network == "tcp" || network == "tcp4") && addr.IP.To4() == nil {
|
||||||
|
t.Errorf("got %v; expected an IPv4 address on %v", addr, network)
|
||||||
|
} else if network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil) {
|
||||||
|
t.Errorf("got %v; expected an IPv6 address on %v", addr, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fd is already connected to the destination, port 80.
|
// fd is already connected to the destination, port 80.
|
||||||
// Run an HTTP request to fetch the appropriate page.
|
// Run an HTTP request to fetch the appropriate page.
|
||||||
func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
|
func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
|
||||||
|
@ -16,10 +16,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type resolveIPAddrTest struct {
|
type resolveIPAddrTest struct {
|
||||||
net string
|
net string
|
||||||
litAddr string
|
litAddrOrName string
|
||||||
addr *IPAddr
|
addr *IPAddr
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolveIPAddrTests = []resolveIPAddrTest{
|
var resolveIPAddrTests = []resolveIPAddrTest{
|
||||||
@ -51,13 +51,20 @@ func init() {
|
|||||||
{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
|
{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
|
||||||
|
resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
|
||||||
|
{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}, nil},
|
||||||
|
{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}, nil},
|
||||||
|
{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveIPAddr(t *testing.T) {
|
func TestResolveIPAddr(t *testing.T) {
|
||||||
for _, tt := range resolveIPAddrTests {
|
for _, tt := range resolveIPAddrTests {
|
||||||
addr, err := ResolveIPAddr(tt.net, tt.litAddr)
|
addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
|
||||||
if err != tt.err {
|
if err != tt.err {
|
||||||
t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
|
t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err)
|
||||||
} else if !reflect.DeepEqual(addr, tt.addr) {
|
} else if !reflect.DeepEqual(addr, tt.addr) {
|
||||||
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
||||||
}
|
}
|
||||||
|
@ -60,44 +60,61 @@ func (al addrList) toAddr() Addr {
|
|||||||
|
|
||||||
var errNoSuitableAddress = errors.New("no suitable address found")
|
var errNoSuitableAddress = errors.New("no suitable address found")
|
||||||
|
|
||||||
// firstFavoriteAddr returns an address that implemets netaddr
|
// firstFavoriteAddr returns an address or a list of addresses that
|
||||||
// interface.
|
// implement the netaddr interface. Known filters are nil, ipv4only
|
||||||
func firstFavoriteAddr(filter func(IP) IP, addrs []string, inetaddr func(IP) netaddr) (netaddr, error) {
|
// and ipv6only. It returns any address when filter is nil. The result
|
||||||
if filter == nil {
|
// contains at least one address when error is nil.
|
||||||
// We'll take any IP address, but since the dialing code
|
func firstFavoriteAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
|
||||||
// does not yet try multiple addresses, prefer to use
|
if filter != nil {
|
||||||
// an IPv4 address if possible. This is especially relevant
|
return firstSupportedAddr(filter, ips, inetaddr)
|
||||||
// if localhost resolves to [ipv6-localhost, ipv4-localhost].
|
}
|
||||||
// Too much code assumes localhost == ipv4-localhost.
|
var (
|
||||||
addr, err := firstSupportedAddr(ipv4only, addrs, inetaddr)
|
ipv4, ipv6, swap bool
|
||||||
if err != nil {
|
list addrList
|
||||||
addr, err = firstSupportedAddr(anyaddr, addrs, inetaddr)
|
)
|
||||||
|
for _, ip := range ips {
|
||||||
|
// We'll take any IP address, but since the dialing
|
||||||
|
// code does not yet try multiple addresses
|
||||||
|
// effectively, prefer to use an IPv4 address if
|
||||||
|
// possible. This is especially relevant if localhost
|
||||||
|
// resolves to [ipv6-localhost, ipv4-localhost]. Too
|
||||||
|
// much code assumes localhost == ipv4-localhost.
|
||||||
|
if ip4 := ipv4only(ip); ip4 != nil && !ipv4 {
|
||||||
|
list = append(list, inetaddr(ip4))
|
||||||
|
ipv4 = true
|
||||||
|
if ipv6 {
|
||||||
|
swap = true
|
||||||
|
}
|
||||||
|
} else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 {
|
||||||
|
list = append(list, inetaddr(ip6))
|
||||||
|
ipv6 = true
|
||||||
}
|
}
|
||||||
return addr, err
|
if ipv4 && ipv6 {
|
||||||
} else {
|
if swap {
|
||||||
return firstSupportedAddr(filter, addrs, inetaddr)
|
list[0], list[1] = list[1], list[0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch len(list) {
|
||||||
|
case 0:
|
||||||
|
return nil, errNoSuitableAddress
|
||||||
|
case 1:
|
||||||
|
return list[0], nil
|
||||||
|
default:
|
||||||
|
return list, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstSupportedAddr(filter func(IP) IP, addrs []string, inetaddr func(IP) netaddr) (netaddr, error) {
|
func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
|
||||||
for _, s := range addrs {
|
for _, ip := range ips {
|
||||||
if ip := filter(ParseIP(s)); ip != nil {
|
if ip := filter(ip); ip != nil {
|
||||||
return inetaddr(ip), nil
|
return inetaddr(ip), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errNoSuitableAddress
|
return nil, errNoSuitableAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// anyaddr returns IP addresses that we can use with the current
|
|
||||||
// kernel configuration. It returns nil when ip is not suitable for
|
|
||||||
// the configuration and an IP address.
|
|
||||||
func anyaddr(ip IP) IP {
|
|
||||||
if ip4 := ipv4only(ip); ip4 != nil {
|
|
||||||
return ip4
|
|
||||||
}
|
|
||||||
return ipv6only(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ipv4only returns IPv4 addresses that we can use with the kernel's
|
// ipv4only returns IPv4 addresses that we can use with the kernel's
|
||||||
// IPv4 addressing modes. It returns IPv4-mapped IPv6 addresses as
|
// IPv4 addressing modes. It returns IPv4-mapped IPv6 addresses as
|
||||||
// IPv4 addresses and returns other IPv6 address types as nils.
|
// IPv4 addresses and returns other IPv6 address types as nils.
|
||||||
@ -212,8 +229,11 @@ func JoinHostPort(host, port string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resolveInternetAddr resolves addr that is either a literal IP
|
// resolveInternetAddr resolves addr that is either a literal IP
|
||||||
// address or a DNS registered name and returns an internet protocol
|
// address or a DNS name and returns an internet protocol family
|
||||||
// family address.
|
// address. It returns a list that contains a pair of different
|
||||||
|
// address family addresses when addr is a DNS name and the name has
|
||||||
|
// mutiple address family records. The result contains at least one
|
||||||
|
// address when error is nil.
|
||||||
func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
|
func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
@ -260,9 +280,9 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error)
|
|||||||
if ip, zone = parseIPv6(host, true); ip != nil {
|
if ip, zone = parseIPv6(host, true); ip != nil {
|
||||||
return inetaddr(ip), nil
|
return inetaddr(ip), nil
|
||||||
}
|
}
|
||||||
// Try as a DNS registered name.
|
// Try as a DNS name.
|
||||||
host, zone = splitHostZone(host)
|
host, zone = splitHostZone(host)
|
||||||
addrs, err := lookupHostDeadline(host, deadline)
|
ips, err := lookupIPDeadline(host, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -273,7 +293,7 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error)
|
|||||||
if net != "" && net[len(net)-1] == '6' || zone != "" {
|
if net != "" && net[len(net)-1] == '6' || zone != "" {
|
||||||
filter = ipv6only
|
filter = ipv6only
|
||||||
}
|
}
|
||||||
return firstFavoriteAddr(filter, addrs, inetaddr)
|
return firstFavoriteAddr(filter, ips, inetaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func zoneToString(zone int) string {
|
func zoneToString(zone int) string {
|
||||||
|
189
src/pkg/net/ipsock_test.go
Normal file
189
src/pkg/net/ipsock_test.go
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testInetaddr = func(ip IP) netaddr { return &TCPAddr{IP: ip, Port: 5682} }
|
||||||
|
|
||||||
|
var firstFavoriteAddrTests = []struct {
|
||||||
|
filter func(IP) IP
|
||||||
|
ips []IP
|
||||||
|
inetaddr func(IP) netaddr
|
||||||
|
addr netaddr
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv6loopback,
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv4(192, 168, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
ParseIP("fe80::1"),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv4(192, 168, 0, 1),
|
||||||
|
IPv6loopback,
|
||||||
|
ParseIP("fe80::1"),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
ParseIP("fe80::1"),
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv4(192, 168, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv6loopback,
|
||||||
|
IPv4(192, 168, 0, 1),
|
||||||
|
ParseIP("fe80::1"),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
ParseIP("fe80::1"),
|
||||||
|
IPv4(192, 168, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
addrList{
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ipv4only,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv6loopback,
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ipv4only,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ipv6only,
|
||||||
|
[]IP{
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
IPv6loopback,
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ipv6only,
|
||||||
|
[]IP{
|
||||||
|
IPv6loopback,
|
||||||
|
IPv4(127, 0, 0, 1),
|
||||||
|
},
|
||||||
|
testInetaddr,
|
||||||
|
&TCPAddr{IP: IPv6loopback, Port: 5682},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
{nil, nil, testInetaddr, nil, errNoSuitableAddress},
|
||||||
|
|
||||||
|
{ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
|
||||||
|
{ipv4only, []IP{IPv6loopback}, testInetaddr, nil, errNoSuitableAddress},
|
||||||
|
|
||||||
|
{ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
|
||||||
|
{ipv6only, []IP{IPv4(127, 0, 0, 1)}, testInetaddr, nil, errNoSuitableAddress},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFirstFavoriteAddr(t *testing.T) {
|
||||||
|
for i, tt := range firstFavoriteAddrTests {
|
||||||
|
addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr)
|
||||||
|
if err != tt.err {
|
||||||
|
t.Errorf("#%v: got %v; expected %v", i, err, tt.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(addr, tt.addr) {
|
||||||
|
t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,19 +23,19 @@ var protocols = map[string]int{
|
|||||||
|
|
||||||
var lookupGroup singleflight
|
var lookupGroup singleflight
|
||||||
|
|
||||||
// lookupHostMerge wraps lookupHost, but makes sure that for any given
|
// lookupIPMerge wraps lookupIP, but makes sure that for any given
|
||||||
// host, only one lookup is in-flight at a time. The returned memory
|
// host, only one lookup is in-flight at a time. The returned memory
|
||||||
// is always owned by the caller.
|
// is always owned by the caller.
|
||||||
func lookupHostMerge(host string) (addrs []string, err error) {
|
func lookupIPMerge(host string) (addrs []IP, err error) {
|
||||||
addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
|
addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
|
||||||
return lookupHost(host)
|
return lookupIP(host)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
addrs = addrsi.([]string)
|
addrs = addrsi.([]IP)
|
||||||
if shared {
|
if shared {
|
||||||
clone := make([]string, len(addrs))
|
clone := make([]IP, len(addrs))
|
||||||
copy(clone, addrs)
|
copy(clone, addrs)
|
||||||
addrs = clone
|
addrs = clone
|
||||||
}
|
}
|
||||||
@ -45,12 +45,12 @@ func lookupHostMerge(host string) (addrs []string, err error) {
|
|||||||
// LookupHost looks up the given host using the local resolver.
|
// LookupHost looks up the given host using the local resolver.
|
||||||
// It returns an array of that host's addresses.
|
// It returns an array of that host's addresses.
|
||||||
func LookupHost(host string) (addrs []string, err error) {
|
func LookupHost(host string) (addrs []string, err error) {
|
||||||
return lookupHostMerge(host)
|
return lookupHost(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupHostDeadline(host string, deadline time.Time) (addrs []string, err error) {
|
func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
|
||||||
if deadline.IsZero() {
|
if deadline.IsZero() {
|
||||||
return lookupHostMerge(host)
|
return lookupIPMerge(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bradfitz): consider pushing the deadline down into the
|
// TODO(bradfitz): consider pushing the deadline down into the
|
||||||
@ -68,12 +68,12 @@ func lookupHostDeadline(host string, deadline time.Time) (addrs []string, err er
|
|||||||
t := time.NewTimer(timeout)
|
t := time.NewTimer(timeout)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
type res struct {
|
type res struct {
|
||||||
addrs []string
|
addrs []IP
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
resc := make(chan res, 1)
|
resc := make(chan res, 1)
|
||||||
go func() {
|
go func() {
|
||||||
a, err := lookupHostMerge(host)
|
a, err := lookupIPMerge(host)
|
||||||
resc <- res{a, err}
|
resc <- res{a, err}
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
@ -88,7 +88,7 @@ func lookupHostDeadline(host string, deadline time.Time) (addrs []string, err er
|
|||||||
// LookupIP looks up host using the local resolver.
|
// LookupIP looks up host using the local resolver.
|
||||||
// It returns an array of that host's IPv4 and IPv6 addresses.
|
// It returns an array of that host's IPv4 and IPv6 addresses.
|
||||||
func LookupIP(host string) (addrs []IP, err error) {
|
func LookupIP(host string) (addrs []IP, err error) {
|
||||||
return lookupIP(host)
|
return lookupIPMerge(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupPort looks up the port for the given network and service.
|
// LookupPort looks up the port for the given network and service.
|
||||||
|
@ -273,10 +273,10 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type resolveTCPAddrTest struct {
|
type resolveTCPAddrTest struct {
|
||||||
net string
|
net string
|
||||||
litAddr string
|
litAddrOrName string
|
||||||
addr *TCPAddr
|
addr *TCPAddr
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolveTCPAddrTests = []resolveTCPAddrTest{
|
var resolveTCPAddrTests = []resolveTCPAddrTest{
|
||||||
@ -303,13 +303,20 @@ func init() {
|
|||||||
{"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
|
{"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
|
||||||
|
resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
|
||||||
|
{"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5}, nil},
|
||||||
|
{"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 6}, nil},
|
||||||
|
{"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveTCPAddr(t *testing.T) {
|
func TestResolveTCPAddr(t *testing.T) {
|
||||||
for _, tt := range resolveTCPAddrTests {
|
for _, tt := range resolveTCPAddrTests {
|
||||||
addr, err := ResolveTCPAddr(tt.net, tt.litAddr)
|
addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName)
|
||||||
if err != tt.err {
|
if err != tt.err {
|
||||||
t.Fatalf("ResolveTCPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
|
t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(addr, tt.addr) {
|
if !reflect.DeepEqual(addr, tt.addr) {
|
||||||
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type resolveUDPAddrTest struct {
|
type resolveUDPAddrTest struct {
|
||||||
net string
|
net string
|
||||||
litAddr string
|
litAddrOrName string
|
||||||
addr *UDPAddr
|
addr *UDPAddr
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolveUDPAddrTests = []resolveUDPAddrTest{
|
var resolveUDPAddrTests = []resolveUDPAddrTest{
|
||||||
@ -42,13 +42,20 @@ func init() {
|
|||||||
{"udp6", "[fe80::1%" + index + "]:4", &UDPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
|
{"udp6", "[fe80::1%" + index + "]:4", &UDPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
|
||||||
|
resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
|
||||||
|
{"udp", "localhost:5", &UDPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 5}, nil},
|
||||||
|
{"udp4", "localhost:6", &UDPAddr{IP: IPv4(127, 0, 0, 1).To4(), Port: 6}, nil},
|
||||||
|
{"udp6", "localhost:7", &UDPAddr{IP: IPv6loopback, Port: 7}, nil},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveUDPAddr(t *testing.T) {
|
func TestResolveUDPAddr(t *testing.T) {
|
||||||
for _, tt := range resolveUDPAddrTests {
|
for _, tt := range resolveUDPAddrTests {
|
||||||
addr, err := ResolveUDPAddr(tt.net, tt.litAddr)
|
addr, err := ResolveUDPAddr(tt.net, tt.litAddrOrName)
|
||||||
if err != tt.err {
|
if err != tt.err {
|
||||||
t.Fatalf("ResolveUDPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
|
t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(addr, tt.addr) {
|
if !reflect.DeepEqual(addr, tt.addr) {
|
||||||
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
|
||||||
|
Loading…
Reference in New Issue
Block a user