]> Cypherpunks repositories - gostls13.git/commitdiff
net: add netaddr interface
authorMikio Hara <mikioh.mikioh@gmail.com>
Fri, 30 Aug 2013 00:09:45 +0000 (09:09 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Fri, 30 Aug 2013 00:09:45 +0000 (09:09 +0900)
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 #3610
Update #5267

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/13368044

14 files changed:
src/pkg/net/dial.go
src/pkg/net/dial_gen.go
src/pkg/net/fd_unix.go
src/pkg/net/fd_windows.go
src/pkg/net/iprawsock.go
src/pkg/net/iprawsock_posix.go
src/pkg/net/ipsock.go
src/pkg/net/sock_posix.go
src/pkg/net/tcpsock.go
src/pkg/net/tcpsock_posix.go
src/pkg/net/udpsock.go
src/pkg/net/udpsock_posix.go
src/pkg/net/unixsock.go
src/pkg/net/unixsock_posix.go

index 8df4f77849902a67d9b81d7753855cbd1492f66f..f0f47b215527a66b151e3aa640836a34a0ff37b7 100644 (file)
@@ -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:
index 4fb1c7ad94c8429c5a67e42457f47b67d3cb0ed2..f051cdaa844653ed8eaa816ddd62ae6acaccc20a 100644 (file)
@@ -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 {
index bdc2861d55d28acfa34ef9a3807d9f67604956a7..457c1d18e28bca9b08e3596dfbff15df55dbddaa 100644 (file)
@@ -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) {
index 75f7a63caa2962bd201f4beafc7d4f249def7e1d..6f344057c7a82e978fbf3144bbc32f500b0aa8b6 100644 (file)
@@ -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.
index 0be94eb70eb35caa8cdc010d50c87e095e68beca..5cc361390ff56a94ba0ea3d8ab5bafbe1489c908 100644 (file)
@@ -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
 }
index d74068b39ef60e535b4bc6ecf16fe5e6ced4cc23..722853257616e67927e14fadab5eab730b4830df 100644 (file)
@@ -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 {
index 33b584db57962940a79046734e52503013ae2c5b..10a51f490d473cbf64340b7419a07701038d8f9e 100644 (file)
@@ -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 {
index a6a6b4e913e78aa54ff3376ca2dcd106be06d133..c2d343c5858076c5653c5b48b875b7ae0ca7adaa 100644 (file)
@@ -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
index 4d9ebd214e0e2986b6215138c30166cdb165c7a8..8614c74595e2bb0b2dd5fa21729dcc5c55c3fe70 100644 (file)
@@ -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
 }
index 512b74c3f84d5d6ab3b4410d185b13a0747de51b..d9e25e26e62d7be3a6c9257f60c24281d905aff1 100644 (file)
@@ -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 {
index 5ce7d6bea0f7935826249a8f22426e42dd15e2ad..edbb93be3c8c612eedd36dc6714241d920a01a9e 100644 (file)
@@ -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
 }
index 67af4de1882cc2bb563b9a841223e71e6af8c48f..142da8186f1634dd21907dfc176ba117ed06bdb3 100644 (file)
@@ -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 {
index 94c4c39ddc542cb7640888d528873b76f080abca..85955845b803d87ad55a20e10af642c062b433ef 100644 (file)
@@ -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".
index c71ee957e0866b449ba05aa76eeea18eedb0b236..fc061804c701a79cc42970f961ae6b1bf15fb47c 100644 (file)
@@ -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 {