switch net {
case "tcp", "tcp4", "tcp6":
case "udp", "udp4", "udp6":
+ case "ip", "ip4", "ip6":
case "unix", "unixgram", "unixpacket":
default:
return "", 0, UnknownNetworkError(net)
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)
}
// 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
}
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
package net
-import (
- "time"
-)
-
// IPAddr represents the address of an IP end point.
type IPAddr struct {
IP IP
// "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
}
// "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]
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
- }
- 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
+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
}
- 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 {
package net
import (
+ "reflect"
"runtime"
"testing"
"time"
}
}
+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
package net
-import "time"
-
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
// "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
}
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":
package net
-import (
- "errors"
- "time"
-)
+import "errors"
var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
// "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
}