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:
parent
f134742f24
commit
4f74bbd24c
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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":
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user