mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
8 changed files with 174 additions and 101 deletions
|
|
@ -15,6 +15,7 @@ func parseDialNetwork(net string) (afnet string, proto int, err error) {
|
||||||
switch net {
|
switch net {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
|
case "ip", "ip4", "ip6":
|
||||||
case "unix", "unixgram", "unixpacket":
|
case "unix", "unixgram", "unixpacket":
|
||||||
default:
|
default:
|
||||||
return "", 0, UnknownNetworkError(net)
|
return "", 0, UnknownNetworkError(net)
|
||||||
|
|
@ -54,12 +55,8 @@ func resolveAfnetAddr(afnet, addr string, deadline time.Time) (Addr, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
switch afnet {
|
switch afnet {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6":
|
||||||
return resolveTCPAddr(afnet, addr, deadline)
|
return resolveInternetAddr(afnet, addr, deadline)
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
return resolveUDPAddr(afnet, addr, deadline)
|
|
||||||
case "ip", "ip4", "ip6":
|
|
||||||
return resolveIPAddr(afnet, addr, deadline)
|
|
||||||
case "unix", "unixgram", "unixpacket":
|
case "unix", "unixgram", "unixpacket":
|
||||||
return ResolveUnixAddr(afnet, addr)
|
return ResolveUnixAddr(afnet, addr)
|
||||||
}
|
}
|
||||||
|
|
@ -218,8 +215,8 @@ func Listen(net, laddr string) (Listener, error) {
|
||||||
// ListenPacket announces on the local network address laddr.
|
// ListenPacket announces on the local network address laddr.
|
||||||
// The network string net must be a packet-oriented network:
|
// The network string net must be a packet-oriented network:
|
||||||
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
|
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
|
||||||
func ListenPacket(net, addr string) (PacketConn, error) {
|
func ListenPacket(net, laddr string) (PacketConn, error) {
|
||||||
afnet, a, err := resolveNetAddr("listen", net, addr, noDeadline)
|
afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,43 @@ package net
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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 {
|
var icmpTests = []struct {
|
||||||
net string
|
net string
|
||||||
laddr string
|
laddr string
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,6 @@
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IPAddr represents the address of an IP end point.
|
// IPAddr represents the address of an IP end point.
|
||||||
type IPAddr struct {
|
type IPAddr struct {
|
||||||
IP IP
|
IP IP
|
||||||
|
|
@ -31,44 +27,15 @@ func (a *IPAddr) String() string {
|
||||||
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
|
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]".
|
// enclosed in square brackets, as in "[::]".
|
||||||
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
|
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
|
||||||
return resolveIPAddr(net, addr, noDeadline)
|
afnet, _, err := parseDialNetwork(net)
|
||||||
}
|
|
||||||
|
|
||||||
func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
|
|
||||||
ip, err := hostToIP(net, addr, deadline)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &IPAddr{IP: ip}, nil
|
switch afnet {
|
||||||
|
case "ip", "ip4", "ip6":
|
||||||
|
default:
|
||||||
|
return nil, UnknownNetworkError(net)
|
||||||
}
|
}
|
||||||
|
a, err := resolveInternetAddr(afnet, addr, noDeadline)
|
||||||
// Convert "host" into IP address.
|
return a.(*IPAddr), nil
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addr, nil
|
|
||||||
Error:
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,15 +72,18 @@ func (e InvalidAddrError) Temporary() bool { return false }
|
||||||
// "host:port" or "[host]:port" into host and port.
|
// "host:port" or "[host]:port" into host and port.
|
||||||
// The latter form must be used when host contains a colon.
|
// The latter form must be used when host contains a colon.
|
||||||
func SplitHostPort(hostport string) (host, port string, err error) {
|
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.
|
// The port starts after the last colon.
|
||||||
i := last(hostport, ':')
|
i := last(hostport, ':')
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
err = &AddrError{"missing port in address", hostport}
|
err = &AddrError{"missing port in address", hostport}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
host, port = hostport[:i], hostport[i+1:]
|
||||||
host, port = hostport[0:i], hostport[i+1:]
|
|
||||||
|
|
||||||
// Can put brackets around host ...
|
// Can put brackets around host ...
|
||||||
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
|
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
|
||||||
host = host[1 : len(host)-1]
|
host = host[1 : len(host)-1]
|
||||||
|
|
@ -104,18 +107,47 @@ func JoinHostPort(host, port string) string {
|
||||||
return host + ":" + port
|
return host + ":" + port
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert "host:port" into IP address and port.
|
func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
|
||||||
func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, err error) {
|
var (
|
||||||
host, port, err := SplitHostPort(hostport)
|
err error
|
||||||
if err != nil {
|
host, port, zone string
|
||||||
return nil, 0, err
|
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 portnum, err = parsePort(net, port); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "ip", "ip4", "ip6":
|
||||||
|
if addr != "" {
|
||||||
|
host = addr
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, UnknownNetworkError(net)
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr IP
|
|
||||||
if host != "" {
|
|
||||||
// Try as an IP address.
|
// Try as an IP address.
|
||||||
addr = ParseIP(host)
|
if ip := ParseIP(host); ip != nil {
|
||||||
if addr == nil {
|
return inetaddr(net, ip, portnum, zone), nil
|
||||||
|
}
|
||||||
var filter func(IP) IP
|
var filter func(IP) IP
|
||||||
if net != "" && net[len(net)-1] == '4' {
|
if net != "" && net[len(net)-1] == '4' {
|
||||||
filter = ipv4only
|
filter = ipv4only
|
||||||
|
|
@ -123,25 +155,17 @@ func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, e
|
||||||
if net != "" && net[len(net)-1] == '6' {
|
if net != "" && net[len(net)-1] == '6' {
|
||||||
filter = ipv6only
|
filter = ipv6only
|
||||||
}
|
}
|
||||||
// Not an IP address. Try as a DNS name.
|
// Try as a DNS name.
|
||||||
addrs, err := lookupHostDeadline(host, deadline)
|
addrs, err := lookupHostDeadline(host, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
addr = firstFavoriteAddr(filter, addrs)
|
ip := firstFavoriteAddr(filter, addrs)
|
||||||
if addr == nil {
|
if ip == nil {
|
||||||
// should not happen
|
// should not happen
|
||||||
return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
|
return nil, &AddrError{"LookupHost returned no suitable address", addrs[0]}
|
||||||
}
|
}
|
||||||
}
|
return inetaddr(net, ip, portnum, zone), nil
|
||||||
}
|
|
||||||
|
|
||||||
p, err := parsePort(net, port)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr, p, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func zoneToString(zone int) string {
|
func zoneToString(zone int) string {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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 {
|
var tcpListenerNameTests = []struct {
|
||||||
net string
|
net string
|
||||||
laddr *TCPAddr
|
laddr *TCPAddr
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// TCPAddr represents the address of a TCP end point.
|
// TCPAddr represents the address of a TCP end point.
|
||||||
type TCPAddr struct {
|
type TCPAddr struct {
|
||||||
IP IP
|
IP IP
|
||||||
|
|
@ -31,13 +29,14 @@ func (a *TCPAddr) String() string {
|
||||||
// "tcp4" or "tcp6". A literal IPv6 host address must be
|
// "tcp4" or "tcp6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]:80".
|
// enclosed in square brackets, as in "[::]:80".
|
||||||
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
|
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
|
||||||
return resolveTCPAddr(net, addr, noDeadline)
|
switch net {
|
||||||
|
case "tcp", "tcp4", "tcp6":
|
||||||
|
default:
|
||||||
|
return nil, UnknownNetworkError(net)
|
||||||
}
|
}
|
||||||
|
a, err := resolveInternetAddr(net, addr, noDeadline)
|
||||||
func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) {
|
|
||||||
ip, port, err := hostPortToIP(net, addr, deadline)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &TCPAddr{IP: ip, Port: port}, nil
|
return a.(*TCPAddr), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,38 @@
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"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) {
|
func TestWriteToUDP(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9":
|
case "plan9":
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,7 @@
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
|
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
|
// "udp4" or "udp6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]:80".
|
// enclosed in square brackets, as in "[::]:80".
|
||||||
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
|
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
|
||||||
return resolveUDPAddr(net, addr, noDeadline)
|
switch net {
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
default:
|
||||||
|
return nil, UnknownNetworkError(net)
|
||||||
}
|
}
|
||||||
|
a, err := resolveInternetAddr(net, addr, noDeadline)
|
||||||
func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) {
|
|
||||||
ip, port, err := hostPortToIP(net, addr, deadline)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &UDPAddr{IP: ip, Port: port}, nil
|
return a.(*UDPAddr), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue