1
0
mirror of https://github.com/golang/go synced 2024-11-26 17:56:55 -07:00

net: consoldate literal target address into IP address functions

This CL continues with introducing IPv6 scoped addressing capability
into the net package.

Update #4234.

R=rsc
CC=golang-dev
https://golang.org/cl/6842053
This commit is contained in:
Mikio Hara 2012-11-28 06:36:05 +09:00
parent f134742f24
commit 4f74bbd24c
8 changed files with 174 additions and 101 deletions

View File

@ -15,6 +15,7 @@ func parseDialNetwork(net string) (afnet string, proto int, err error) {
switch net {
case "tcp", "tcp4", "tcp6":
case "udp", "udp4", "udp6":
case "ip", "ip4", "ip6":
case "unix", "unixgram", "unixpacket":
default:
return "", 0, UnknownNetworkError(net)
@ -54,12 +55,8 @@ func resolveAfnetAddr(afnet, addr string, deadline time.Time) (Addr, error) {
return nil, nil
}
switch afnet {
case "tcp", "tcp4", "tcp6":
return resolveTCPAddr(afnet, addr, deadline)
case "udp", "udp4", "udp6":
return resolveUDPAddr(afnet, addr, deadline)
case "ip", "ip4", "ip6":
return resolveIPAddr(afnet, addr, deadline)
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6":
return resolveInternetAddr(afnet, addr, deadline)
case "unix", "unixgram", "unixpacket":
return ResolveUnixAddr(afnet, addr)
}
@ -218,8 +215,8 @@ func Listen(net, laddr string) (Listener, error) {
// ListenPacket announces on the local network address laddr.
// The network string net must be a packet-oriented network:
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
func ListenPacket(net, addr string) (PacketConn, error) {
afnet, a, err := resolveNetAddr("listen", net, addr, noDeadline)
func ListenPacket(net, laddr string) (PacketConn, error) {
afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
if err != nil {
return nil, err
}

View File

@ -9,11 +9,43 @@ package net
import (
"bytes"
"os"
"reflect"
"syscall"
"testing"
"time"
)
var resolveIPAddrTests = []struct {
net string
litAddr string
addr *IPAddr
err error
}{
{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"ip6:icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
}
func TestResolveIPAddr(t *testing.T) {
for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.net, tt.litAddr)
if err != tt.err {
t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
}
if !reflect.DeepEqual(addr, tt.addr) {
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
}
}
}
var icmpTests = []struct {
net string
laddr string

View File

@ -6,10 +6,6 @@
package net
import (
"time"
)
// IPAddr represents the address of an IP end point.
type IPAddr struct {
IP IP
@ -31,44 +27,15 @@ func (a *IPAddr) String() string {
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]".
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
return resolveIPAddr(net, addr, noDeadline)
}
func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
ip, err := hostToIP(net, addr, deadline)
afnet, _, err := parseDialNetwork(net)
if err != nil {
return nil, err
}
return &IPAddr{IP: ip}, nil
}
// Convert "host" into IP address.
func hostToIP(net, host string, deadline time.Time) (ip IP, err error) {
var addr IP
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
filter := anyaddr
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
addrs, err1 := lookupHostDeadline(host, deadline)
if err1 != nil {
err = err1
goto Error
}
addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
goto Error
}
switch afnet {
case "ip", "ip4", "ip6":
default:
return nil, UnknownNetworkError(net)
}
return addr, nil
Error:
return nil, err
a, err := resolveInternetAddr(afnet, addr, noDeadline)
return a.(*IPAddr), nil
}

View File

@ -72,15 +72,18 @@ func (e InvalidAddrError) Temporary() bool { return false }
// "host:port" or "[host]:port" into host and port.
// The latter form must be used when host contains a colon.
func SplitHostPort(hostport string) (host, port string, err error) {
host, port, _, err = splitHostPort(hostport)
return
}
func splitHostPort(hostport string) (host, port, zone string, err error) {
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
err = &AddrError{"missing port in address", hostport}
return
}
host, port = hostport[0:i], hostport[i+1:]
host, port = hostport[:i], hostport[i+1:]
// Can put brackets around host ...
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
@ -104,44 +107,65 @@ func JoinHostPort(host, port string) string {
return host + ":" + port
}
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, err error) {
host, port, err := SplitHostPort(hostport)
if err != nil {
return nil, 0, err
}
var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
var (
err error
host, port, zone string
portnum int
)
switch net {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
if addr != "" {
if host, port, zone, err = splitHostPort(addr); err != nil {
return nil, err
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
addrs, err := lookupHostDeadline(host, deadline)
if err != nil {
return nil, 0, err
}
addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
if portnum, err = parsePort(net, port); err != nil {
return nil, err
}
}
case "ip", "ip4", "ip6":
if addr != "" {
host = addr
}
default:
return nil, UnknownNetworkError(net)
}
p, err := parsePort(net, port)
inetaddr := func(net string, ip IP, port int, zone string) Addr {
switch net {
case "tcp", "tcp4", "tcp6":
return &TCPAddr{IP: ip, Port: port, Zone: zone}
case "udp", "udp4", "udp6":
return &UDPAddr{IP: ip, Port: port, Zone: zone}
case "ip", "ip4", "ip6":
return &IPAddr{IP: ip, Zone: zone}
}
return nil
}
if host == "" {
return inetaddr(net, nil, portnum, zone), nil
}
// Try as an IP address.
if ip := ParseIP(host); ip != nil {
return inetaddr(net, ip, portnum, zone), nil
}
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Try as a DNS name.
addrs, err := lookupHostDeadline(host, deadline)
if err != nil {
return nil, 0, err
return nil, err
}
return addr, p, nil
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
}
func zoneToString(zone int) string {

View File

@ -5,6 +5,7 @@
package net
import (
"reflect"
"runtime"
"testing"
"time"
@ -117,6 +118,33 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool) {
}
}
var resolveTCPAddrTests = []struct {
net string
litAddr string
addr *TCPAddr
err error
}{
{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
{"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
{"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
}
func TestResolveTCPAddr(t *testing.T) {
for _, tt := range resolveTCPAddrTests {
addr, err := ResolveTCPAddr(tt.net, tt.litAddr)
if err != tt.err {
t.Fatalf("ResolveTCPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
}
if !reflect.DeepEqual(addr, tt.addr) {
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
}
}
}
var tcpListenerNameTests = []struct {
net string
laddr *TCPAddr

View File

@ -6,8 +6,6 @@
package net
import "time"
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
@ -31,13 +29,14 @@ func (a *TCPAddr) String() string {
// "tcp4" or "tcp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
return resolveTCPAddr(net, addr, noDeadline)
}
func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) {
ip, port, err := hostPortToIP(net, addr, deadline)
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, UnknownNetworkError(net)
}
a, err := resolveInternetAddr(net, addr, noDeadline)
if err != nil {
return nil, err
}
return &TCPAddr{IP: ip, Port: port}, nil
return a.(*TCPAddr), nil
}

View File

@ -5,10 +5,38 @@
package net
import (
"reflect"
"runtime"
"testing"
)
var resolveUDPAddrTests = []struct {
net string
litAddr string
addr *UDPAddr
err error
}{
{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
{"udp", "[::1]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1}, nil},
{"udp6", "[::1]:65534", &UDPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
{"sip", "127.0.0.1:0", nil, UnknownNetworkError("sip")},
}
func TestResolveUDPAddr(t *testing.T) {
for _, tt := range resolveUDPAddrTests {
addr, err := ResolveUDPAddr(tt.net, tt.litAddr)
if err != tt.err {
t.Fatalf("ResolveUDPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
}
if !reflect.DeepEqual(addr, tt.addr) {
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
}
}
}
func TestWriteToUDP(t *testing.T) {
switch runtime.GOOS {
case "plan9":

View File

@ -6,10 +6,7 @@
package net
import (
"errors"
"time"
)
import "errors"
var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
@ -36,13 +33,14 @@ func (a *UDPAddr) String() string {
// "udp4" or "udp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
return resolveUDPAddr(net, addr, noDeadline)
}
func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) {
ip, port, err := hostPortToIP(net, addr, deadline)
switch net {
case "udp", "udp4", "udp6":
default:
return nil, UnknownNetworkError(net)
}
a, err := resolveInternetAddr(net, addr, noDeadline)
if err != nil {
return nil, err
}
return &UDPAddr{IP: ip, Port: port}, nil
return a.(*UDPAddr), nil
}