summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikio Hara <mikioh.mikioh@gmail.com>2013-08-30 09:09:45 +0900
committerMikio Hara <mikioh.mikioh@gmail.com>2013-08-30 09:09:45 +0900
commit5b8e479cc9ef2ff79f4c6378ee71a493164f7890 (patch)
tree014d0111ec3cdae1131c217bf572a638a095019d
parentee31d1156545b6cc78726d449b879486ca453096 (diff)
downloadgo-5b8e479cc9ef2ff79f4c6378ee71a493164f7890.tar.gz
net: add netaddr interface
This CL adds the netaddr interface that will carry a single network endpoint address or a short list of IP addresses to dial helper functions in the upcoming CLs. This is in preparation for TCP connection setup with fast failover on dual IP stack node as described in RFC 6555. Update issue 3610 Update issue 5267 R=golang-dev, bradfitz CC=golang-dev https://codereview.appspot.com/13368044
-rw-r--r--src/pkg/net/dial.go6
-rw-r--r--src/pkg/net/dial_gen.go6
-rw-r--r--src/pkg/net/fd_unix.go2
-rw-r--r--src/pkg/net/fd_windows.go2
-rw-r--r--src/pkg/net/iprawsock.go9
-rw-r--r--src/pkg/net/iprawsock_posix.go7
-rw-r--r--src/pkg/net/ipsock.go73
-rw-r--r--src/pkg/net/sock_posix.go7
-rw-r--r--src/pkg/net/tcpsock.go9
-rw-r--r--src/pkg/net/tcpsock_posix.go7
-rw-r--r--src/pkg/net/udpsock.go9
-rw-r--r--src/pkg/net/udpsock_posix.go7
-rw-r--r--src/pkg/net/unixsock.go7
-rw-r--r--src/pkg/net/unixsock_posix.go7
14 files changed, 85 insertions, 73 deletions
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 8df4f7784..f0f47b215 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -82,7 +82,7 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
return "", 0, UnknownNetworkError(net)
}
-func resolveAddr(op, net, addr string, deadline time.Time) (Addr, error) {
+func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
afnet, _, err := parseNetwork(net)
if err != nil {
return nil, err
@@ -184,7 +184,7 @@ func Listen(net, laddr string) (Listener, error) {
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
- switch la := la.(type) {
+ switch la := la.toAddr().(type) {
case *TCPAddr:
return ListenTCP(net, la)
case *UnixAddr:
@@ -203,7 +203,7 @@ func ListenPacket(net, laddr string) (PacketConn, error) {
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
- switch la := la.(type) {
+ switch la := la.toAddr().(type) {
case *UDPAddr:
return ListenUDP(net, la)
case *IPAddr:
diff --git a/src/pkg/net/dial_gen.go b/src/pkg/net/dial_gen.go
index 4fb1c7ad9..f051cdaa8 100644
--- a/src/pkg/net/dial_gen.go
+++ b/src/pkg/net/dial_gen.go
@@ -26,7 +26,7 @@ func resolveAndDialChannel(net, addr string, localAddr Addr, deadline time.Time)
if err != nil {
return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: err}
}
- return dial(net, addr, localAddr, ra, noDeadline)
+ return dial(net, addr, localAddr, ra.toAddr(), noDeadline)
}
t := time.NewTimer(timeout)
defer t.Stop()
@@ -45,8 +45,8 @@ func resolveAndDialChannel(net, addr string, localAddr Addr, deadline time.Time)
ch <- pair{nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: err}}
return
}
- resolvedAddr <- ra // in case we need it for OpError
- c, err := dial(net, addr, localAddr, ra, noDeadline)
+ resolvedAddr <- ra.toAddr() // in case we need it for OpError
+ c, err := dial(net, addr, localAddr, ra.toAddr(), noDeadline)
ch <- pair{c, err}
}()
select {
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index bdc2861d5..457c1d18e 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -41,7 +41,7 @@ func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn,
if err != nil {
return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: err}
}
- return dial(net, addr, localAddr, ra, deadline)
+ return dial(net, addr, localAddr, ra.toAddr(), deadline)
}
func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 75f7a63ca..6f344057c 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -93,7 +93,7 @@ func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn,
if err != nil {
return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: err}
}
- return dial(net, addr, localAddr, ra, deadline)
+ return dial(net, addr, localAddr, ra.toAddr(), deadline)
}
// operation contains superset of data necessary to perform all async IO.
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
index 0be94eb70..5cc361390 100644
--- a/src/pkg/net/iprawsock.go
+++ b/src/pkg/net/iprawsock.go
@@ -23,6 +23,13 @@ func (a *IPAddr) String() string {
return a.IP.String()
}
+func (a *IPAddr) toAddr() Addr {
+ if a == nil {
+ return nil
+ }
+ return a
+}
+
// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
@@ -43,5 +50,5 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
if err != nil {
return nil, err
}
- return a.(*IPAddr), nil
+ return a.toAddr().(*IPAddr), nil
}
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index d74068b39..722853257 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -57,13 +57,6 @@ func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0, a.Zone)
}
-func (a *IPAddr) toAddr() sockaddr {
- if a == nil {
- return nil
- }
- return a
-}
-
// IPConn is the implementation of the Conn and PacketConn interfaces
// for IP network connections.
type IPConn struct {
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 33b584db5..10a51f490 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -6,7 +6,10 @@
package net
-import "time"
+import (
+ "errors"
+ "time"
+)
var (
// supportsIPv4 reports whether the platform supports IPv4
@@ -29,30 +32,42 @@ func init() {
supportsIPv6, supportsIPv4map = probeIPv6Stack()
}
-func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
+// A netaddr represents a network endpoint address or a list of
+// network endpoint addresses.
+type netaddr interface {
+ // toAddr returns the address represented in Addr interface.
+ // It returns a nil interface when the address is nil.
+ toAddr() Addr
+}
+
+var errNoSuitableAddress = errors.New("no suitable address found")
+
+// firstFavoriteAddr returns an address that implemets netaddr
+// interface.
+func firstFavoriteAddr(filter func(IP) IP, addrs []string, inetaddr func(IP) netaddr) (netaddr, error) {
if filter == nil {
// We'll take any IP address, but since the dialing code
// does not yet try multiple addresses, 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.
- addr = firstSupportedAddr(ipv4only, addrs)
- if addr == nil {
- addr = firstSupportedAddr(anyaddr, addrs)
+ addr, err := firstSupportedAddr(ipv4only, addrs, inetaddr)
+ if err != nil {
+ addr, err = firstSupportedAddr(anyaddr, addrs, inetaddr)
}
+ return addr, err
} else {
- addr = firstSupportedAddr(filter, addrs)
+ return firstSupportedAddr(filter, addrs, inetaddr)
}
- return
}
-func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
+func firstSupportedAddr(filter func(IP) IP, addrs []string, inetaddr func(IP) netaddr) (netaddr, error) {
for _, s := range addrs {
- if addr := filter(ParseIP(s)); addr != nil {
- return addr
+ if ip := filter(ParseIP(s)); ip != nil {
+ return inetaddr(ip), nil
}
}
- return nil
+ return nil, errNoSuitableAddress
}
// anyaddr returns IP addresses that we can use with the current
@@ -178,7 +193,10 @@ func JoinHostPort(host, port string) string {
return host + ":" + port
}
-func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
+// resolveInternetAddr resolves addr that is either a literal IP
+// address or a DNS registered name and returns an internet protocol
+// family address.
+func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
var (
err error
host, port, zone string
@@ -201,28 +219,30 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
default:
return nil, UnknownNetworkError(net)
}
- inetaddr := func(net string, ip IP, port int, zone string) Addr {
+ inetaddr := func(ip IP) netaddr {
switch net {
case "tcp", "tcp4", "tcp6":
- return &TCPAddr{IP: ip, Port: port, Zone: zone}
+ return &TCPAddr{IP: ip, Port: portnum, Zone: zone}
case "udp", "udp4", "udp6":
- return &UDPAddr{IP: ip, Port: port, Zone: zone}
+ return &UDPAddr{IP: ip, Port: portnum, Zone: zone}
case "ip", "ip4", "ip6":
return &IPAddr{IP: ip, Zone: zone}
+ default:
+ panic("unexpected network: " + net)
}
- return nil
}
if host == "" {
- return inetaddr(net, nil, portnum, zone), nil
+ return inetaddr(nil), nil
}
- // Try as an IP address.
- if ip := parseIPv4(host); ip != nil {
- return inetaddr(net, ip, portnum, zone), nil
+ // Try as a literal IP address.
+ var ip IP
+ if ip = parseIPv4(host); ip != nil {
+ return inetaddr(ip), nil
}
- if ip, zone := parseIPv6(host, true); ip != nil {
- return inetaddr(net, ip, portnum, zone), nil
+ if ip, zone = parseIPv6(host, true); ip != nil {
+ return inetaddr(ip), nil
}
- // Try as a domain name.
+ // Try as a DNS registered name.
host, zone = splitHostZone(host)
addrs, err := lookupHostDeadline(host, deadline)
if err != nil {
@@ -235,12 +255,7 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
if net != "" && net[len(net)-1] == '6' || zone != "" {
filter = ipv6only
}
- ip := firstFavoriteAddr(filter, addrs)
- if ip == nil {
- // should not happen
- return nil, &AddrError{"LookupHost returned no suitable address", addrs[0]}
- }
- return inetaddr(net, ip, portnum, zone), nil
+ return firstFavoriteAddr(filter, addrs, inetaddr)
}
func zoneToString(zone int) string {
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index a6a6b4e91..c2d343c58 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -17,6 +17,8 @@ import (
type sockaddr interface {
Addr
+ netaddr
+
// family returns the platform-dependent address family
// identifier.
family() int
@@ -30,11 +32,6 @@ type sockaddr interface {
// interface. It returns a nil interface when the address is
// nil.
sockaddr(family int) (syscall.Sockaddr, error)
-
- // toAddr returns the address represented in sockaddr
- // interface. It returns a nil interface when the address is
- // nil.
- toAddr() sockaddr
}
// socket returns a network file descriptor that is ready for
diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go
index 4d9ebd214..8614c7459 100644
--- a/src/pkg/net/tcpsock.go
+++ b/src/pkg/net/tcpsock.go
@@ -24,6 +24,13 @@ func (a *TCPAddr) String() string {
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
+func (a *TCPAddr) toAddr() Addr {
+ if a == nil {
+ return nil
+ }
+ return a
+}
+
// ResolveTCPAddr parses addr as a TCP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "tcp", "tcp4" or
@@ -42,5 +49,5 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
if err != nil {
return nil, err
}
- return a.(*TCPAddr), nil
+ return a.toAddr().(*TCPAddr), nil
}
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 512b74c3f..d9e25e26e 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -52,13 +52,6 @@ func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
-func (a *TCPAddr) toAddr() sockaddr {
- if a == nil {
- return nil
- }
- return a
-}
-
// TCPConn is an implementation of the Conn interface for TCP network
// connections.
type TCPConn struct {
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 5ce7d6bea..edbb93be3 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -28,6 +28,13 @@ func (a *UDPAddr) String() string {
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
+func (a *UDPAddr) toAddr() Addr {
+ if a == nil {
+ return nil
+ }
+ return a
+}
+
// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "udp", "udp4" or
@@ -46,5 +53,5 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
if err != nil {
return nil, err
}
- return a.(*UDPAddr), nil
+ return a.toAddr().(*UDPAddr), nil
}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 67af4de18..142da8186 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -45,13 +45,6 @@ func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
-func (a *UDPAddr) toAddr() sockaddr {
- if a == nil {
- return nil
- }
- return a
-}
-
// UDPConn is the implementation of the Conn and PacketConn interfaces
// for UDP network connections.
type UDPConn struct {
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
index 94c4c39dd..85955845b 100644
--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.go
@@ -23,6 +23,13 @@ func (a *UnixAddr) String() string {
return a.Name
}
+func (a *UnixAddr) toAddr() Addr {
+ if a == nil {
+ return nil
+ }
+ return a
+}
+
// ResolveUnixAddr parses addr as a Unix domain socket address.
// The string net gives the network name, "unix", "unixgram" or
// "unixpacket".
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index c71ee957e..fc061804c 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -105,13 +105,6 @@ func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return &syscall.SockaddrUnix{Name: a.Name}, nil
}
-func (a *UnixAddr) toAddr() sockaddr {
- if a == nil {
- return nil
- }
- return a
-}
-
// UnixConn is an implementation of the Conn interface for connections
// to Unix domain sockets.
type UnixConn struct {