Commit 41f93a43 authored by Russ Cox's avatar Russ Cox

net: drop laddr from Dial, cname from LookupHost; new functions

Drop laddr argument from Dial.

Drop cname return from LookupHost.

Add LookupIP, LookupCNAME, ParseCIDR, IP.Equal.
Export SplitHostPort, JoinHostPort.
Add AAAA (IPv6) support to host lookups.

Preparations for implementing some of the
lookups using cgo.

ParseCIDR and IP.Equal are logically new in this CL
but accidentally snuck into an earlier CL about unused
labels that was in the same client.

In crypto/tls, drop laddr from Dial to match net.

R=golang-dev, dsymonds, adg, rh
CC=golang-dev
https://golang.org/cl/4244055
parent 188a17db
......@@ -50,7 +50,7 @@ func TestRunClient(t *testing.T) {
testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig)
conn, err := Dial("tcp", "127.0.0.1:10443", testConfig)
if err != nil {
t.Fatal(err)
}
......
......@@ -87,8 +87,9 @@ func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
// Dial interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config
// for the defaults.
func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) {
c, err := net.Dial(network, laddr, raddr)
func Dial(network, addr string, config *Config) (*Conn, os.Error) {
raddr := addr
c, err := net.Dial(network, raddr)
if err != nil {
return nil, err
}
......
......@@ -6,6 +6,7 @@ include ../../Make.inc
TARG=net
GOFILES=\
cgo_stub.go\
dial.go\
dnsmsg.go\
fd_$(GOOS).go\
......@@ -13,6 +14,7 @@ GOFILES=\
ip.go\
ipsock.go\
iprawsock.go\
lookup.go\
net.go\
parse.go\
pipe.go\
......
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Stub cgo routines for systems that do not use cgo to do network lookups.
package net
import "os"
func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
return nil, nil, false
}
func cgoLookupPort(network, service string) (port int, err os.Error, completed bool) {
return 0, nil, false
}
func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
return nil, nil, false
}
......@@ -6,9 +6,7 @@ package net
import "os"
// Dial connects to the remote address raddr on the network net.
// If the string laddr is not empty, it is used as the local address
// for the connection.
// Dial connects to the address addr on the network net.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
......@@ -16,79 +14,56 @@ import "os"
//
// For IP networks, addresses have the form host:port. If host is
// a literal IPv6 address, it must be enclosed in square brackets.
// The functions JoinHostPort and SplitHostPort manipulate
// addresses in this form.
//
// Examples:
// Dial("tcp", "", "12.34.56.78:80")
// Dial("tcp", "", "google.com:80")
// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
// Dial("tcp", "12.34.56.78:80")
// Dial("tcp", "google.com:80")
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
//
func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
func Dial(net, addr string) (c Conn, err os.Error) {
raddr := addr
if raddr == "" {
return nil, &OpError{"dial", net, nil, errMissingAddress}
}
switch net {
case "tcp", "tcp4", "tcp6":
var la, ra *TCPAddr
if laddr != "" {
if la, err = ResolveTCPAddr(laddr); err != nil {
goto Error
}
}
if raddr != "" {
if ra, err = ResolveTCPAddr(raddr); err != nil {
goto Error
}
var ra *TCPAddr
if ra, err = ResolveTCPAddr(raddr); err != nil {
goto Error
}
c, err := DialTCP(net, la, ra)
c, err := DialTCP(net, nil, ra)
if err != nil {
return nil, err
}
return c, nil
case "udp", "udp4", "udp6":
var la, ra *UDPAddr
if laddr != "" {
if la, err = ResolveUDPAddr(laddr); err != nil {
goto Error
}
}
if raddr != "" {
if ra, err = ResolveUDPAddr(raddr); err != nil {
goto Error
}
var ra *UDPAddr
if ra, err = ResolveUDPAddr(raddr); err != nil {
goto Error
}
c, err := DialUDP(net, la, ra)
c, err := DialUDP(net, nil, ra)
if err != nil {
return nil, err
}
return c, nil
case "unix", "unixgram", "unixpacket":
var la, ra *UnixAddr
if raddr != "" {
if ra, err = ResolveUnixAddr(net, raddr); err != nil {
goto Error
}
}
if laddr != "" {
if la, err = ResolveUnixAddr(net, laddr); err != nil {
goto Error
}
var ra *UnixAddr
if ra, err = ResolveUnixAddr(net, raddr); err != nil {
goto Error
}
c, err = DialUnix(net, la, ra)
c, err = DialUnix(net, nil, ra)
if err != nil {
return nil, err
}
return c, nil
case "ip", "ip4", "ip6":
var la, ra *IPAddr
if laddr != "" {
if la, err = ResolveIPAddr(laddr); err != nil {
goto Error
}
}
if raddr != "" {
if ra, err = ResolveIPAddr(raddr); err != nil {
goto Error
}
var ra *IPAddr
if ra, err = ResolveIPAddr(raddr); err != nil {
goto Error
}
c, err := DialIP(net, la, ra)
c, err := DialIP(net, nil, ra)
if err != nil {
return nil, err
}
......
......@@ -32,7 +32,7 @@ func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
}
func doDial(t *testing.T, network, addr string) {
fd, err := Dial(network, "", addr)
fd, err := Dial(network, addr)
if err != nil {
t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
return
......@@ -55,6 +55,13 @@ var googleaddrs = []string{
"[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set
}
func TestLookupCNAME(t *testing.T) {
cname, err := LookupCNAME("www.google.com")
if cname != "www.l.google.com." || err != nil {
t.Errorf(`LookupCNAME("www.google.com.") = %q, %v, want "www.l.google.com.", nil`, cname, err)
}
}
func TestDialGoogle(t *testing.T) {
// If no ipv6 tunnel, don't try the last address.
if !*ipv6 {
......@@ -64,14 +71,14 @@ func TestDialGoogle(t *testing.T) {
// Insert an actual IP address for google.com
// into the table.
_, addrs, err := LookupHost("www.google.com")
addrs, err := LookupIP("www.google.com")
if err != nil {
t.Fatalf("lookup www.google.com: %v", err)
}
if len(addrs) == 0 {
t.Fatalf("no addresses for www.google.com")
}
ip := ParseIP(addrs[0]).To4()
ip := addrs[0].To4()
for i, s := range googleaddrs {
if strings.Contains(s, "%") {
......
......@@ -159,7 +159,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
// all the cfg.servers[i] are IP addresses, which
// Dial will use without a DNS lookup.
server := cfg.servers[i] + ":53"
c, cerr := Dial("udp", "", server)
c, cerr := Dial("udp", server)
if cerr != nil {
err = cerr
continue
......@@ -178,12 +178,23 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
return
}
func convertRR_A(records []dnsRR) []string {
addrs := make([]string, len(records))
func convertRR_A(records []dnsRR) []IP {
addrs := make([]IP, len(records))
for i := 0; i < len(records); i++ {
rr := records[i]
a := rr.(*dnsRR_A).A
addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
}
return addrs
}
func convertRR_AAAA(records []dnsRR) []IP {
addrs := make([]IP, len(records))
for i := 0; i < len(records); i++ {
rr := records[i]
a := make(IP, 16)
copy(a, rr.(*dnsRR_AAAA).AAAA[:])
addrs[i] = a
}
return addrs
}
......@@ -294,10 +305,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
return
}
// LookupHost looks for name using the local hosts file and DNS resolver.
// It returns the canonical name for the host and an array of that
// host's addresses.
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
// goLookupHost is the native Go implementation of LookupHost.
func goLookupHost(name string) (addrs []string, err os.Error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
......@@ -306,18 +315,69 @@ func LookupHost(name string) (cname string, addrs []string, err os.Error) {
// Use entries from /etc/hosts if they match.
addrs = lookupStaticHost(name)
if len(addrs) > 0 {
cname = name
return
}
ips, err := goLookupIP(name)
if err != nil {
return
}
addrs = make([]string, 0, len(ips))
for _, ip := range ips {
addrs = append(addrs, ip.String())
}
return
}
// goLookupIP is the native Go implementation of LookupIP.
func goLookupIP(name string) (addrs []IP, err os.Error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
}
var records []dnsRR
var cname string
cname, records, err = lookup(name, dnsTypeA)
if err != nil {
return
}
addrs = convertRR_A(records)
if cname != "" {
name = cname
}
_, records, err = lookup(name, dnsTypeAAAA)
if err != nil && len(addrs) > 0 {
// Ignore error because A lookup succeeded.
err = nil
}
if err != nil {
return
}
addrs = append(addrs, convertRR_AAAA(records)...)
return
}
// LookupCNAME returns the canonical DNS host for the given name.
// Callers that do not care about the canonical name can call
// LookupHost or LookupIP directly; both take care of resolving
// the canonical name as part of the lookup.
func LookupCNAME(name string) (cname string, err os.Error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
}
_, rr, err := lookup(name, dnsTypeCNAME)
if err != nil {
return
}
if len(rr) >= 0 {
cname = rr[0].(*dnsRR_CNAME).Cname
}
return
}
// An SRV represents a single DNS SRV record.
type SRV struct {
Target string
Port uint16
......@@ -344,11 +404,13 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return
}
// An MX represents a single DNS MX record.
type MX struct {
Host string
Pref uint16
}
// LookupMX returns the DNS MX records associated with name.
func LookupMX(name string) (entries []*MX, err os.Error) {
var records []dnsRR
_, records, err = lookup(name, dnsTypeMX)
......
......@@ -50,6 +50,7 @@ const (
dnsTypeMINFO = 14
dnsTypeMX = 15
dnsTypeTXT = 16
dnsTypeAAAA = 28
dnsTypeSRV = 33
// valid dnsQuestion.qtype only
......@@ -244,8 +245,18 @@ type dnsRR_A struct {
A uint32 "ipv4"
}
func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr }
func (rr *dnsRR_A) Header() *dnsRR_Header {
return &rr.Hdr
}
type dnsRR_AAAA struct {
Hdr dnsRR_Header
AAAA [16]byte "ipv6"
}
func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
return &rr.Hdr
}
// Packing and unpacking.
//
......@@ -270,6 +281,7 @@ var rr_mk = map[int]func() dnsRR{
dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
dnsTypeA: func() dnsRR { return new(dnsRR_A) },
dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
}
// Pack a domain name s into msg[off:].
......@@ -377,7 +389,7 @@ Loop:
// TODO(rsc): Move into generic library?
// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
// and other (often anonymous) structs.
// [n]byte, and other (often anonymous) structs.
func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
for i := 0; i < val.NumField(); i++ {
f := val.Type().(*reflect.StructType).Field(i)
......@@ -410,6 +422,16 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
msg[off+3] = byte(i)
off += 4
}
case *reflect.ArrayValue:
if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
goto BadType
}
n := fv.Len()
if off+n > len(msg) {
return len(msg), false
}
reflect.Copy(reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue), fv)
off += n
case *reflect.StringValue:
// There are multiple string encodings.
// The tag distinguishes ordinary strings from domain names.
......@@ -478,6 +500,16 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
fv.Set(uint64(i))
off += 4
}
case *reflect.ArrayValue:
if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
goto BadType
}
n := fv.Len()
if off+n > len(msg) {
return len(msg), false
}
reflect.Copy(fv, reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue))
off += n
case *reflect.StringValue:
var s string
switch f.Tag {
......@@ -515,7 +547,8 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
// Generic struct printer.
// Doesn't care about the string tag "domain-name",
// but does look for an "ipv4" tag on uint32 variables,
// but does look for an "ipv4" tag on uint32 variables
// and the "ipv6" tag on array variables,
// printing them as IP addresses.
func printStructValue(val *reflect.StructValue) string {
s := "{"
......@@ -533,6 +566,9 @@ func printStructValue(val *reflect.StructValue) string {
} else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
i := fv.Get()
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
} else if fv, ok := fval.(*reflect.ArrayValue); ok && f.Tag == "ipv6" {
i := fv.Interface().([]byte)
s += IP(i).String()
} else {
s += fmt.Sprint(fval.Interface())
}
......
......@@ -13,7 +13,6 @@ type hostTest struct {
ips []IP
}
var hosttests = []hostTest{
{"odin", []IP{
IPv4(127, 0, 0, 2),
......
......@@ -474,13 +474,13 @@ func parseIPv6(s string) IP {
return p
}
// A SyntaxError represents a malformed text string and the type of string that was expected.
type SyntaxError struct {
// A ParseError represents a malformed text string and the type of string that was expected.
type ParseError struct {
Type string
Text string
}
func (e *SyntaxError) String() string {
func (e *ParseError) String() string {
return "invalid " + e.Type + ": " + e.Text
}
......@@ -507,33 +507,46 @@ func ParseIP(s string) IP {
}
// ParseCIDR parses s as a CIDR notation IP address and mask,
// like "192.168.100.1/24" or "2001:DB8::/48".
// like "192.168.100.1/24", "2001:DB8::/48", as defined in
// RFC 4632 and RFC 4291.
func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
i := byteIndex(s, '/')
if i < 0 {
return nil, nil, &SyntaxError{"CIDR address", s}
return nil, nil, &ParseError{"CIDR address", s}
}
ipstr, maskstr := s[:i], s[i+1:]
ip = ParseIP(ipstr)
iplen := 4
ip = parseIPv4(ipstr)
if ip == nil {
iplen = 16
ip = parseIPv6(ipstr)
}
nn, i, ok := dtoi(maskstr, 0)
if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*len(ip) {
return nil, nil, &SyntaxError{"CIDR address", s}
if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*iplen {
return nil, nil, &ParseError{"CIDR address", s}
}
n := uint(nn)
if len(ip) == 4 {
if iplen == 4 {
v4mask := ^uint32(0xffffffff >> n)
mask = IPMask(IPv4(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask)))
return ip, mask, nil
}
mask = make(IPMask, 16)
for i := 0; i < 16; i++ {
if n >= 8 {
mask[i] = 0xff
n -= 8
continue
mask = IPv4Mask(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))
} else {
mask = make(IPMask, 16)
for i := 0; i < 16; i++ {
if n >= 8 {
mask[i] = 0xff
n -= 8
continue
}
mask[i] = ^byte(0xff >> n)
n = 0
}
}
// address must not have any bits not in mask
for i := range ip {
if ip[i]&^mask[i] != 0 {
return nil, nil, &ParseError{"CIDR address", s}
}
mask[i] = ^byte(0xff >> n)
n = 0
}
return ip, mask, nil
}
......@@ -5,30 +5,26 @@
package net
import (
"bytes"
"reflect"
"testing"
"os"
)
func isEqual(a, b IP) bool {
func isEqual(a, b []byte) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil || len(a) != len(b) {
if a == nil || b == nil {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
return bytes.Equal(a, b)
}
type parseIPTest struct {
var parseiptests = []struct {
in string
out IP
}
var parseiptests = []parseIPTest{
}{
{"127.0.1.2", IPv4(127, 0, 1, 2)},
{"127.0.0.1", IPv4(127, 0, 0, 1)},
{"127.0.0.256", nil},
......@@ -43,20 +39,17 @@ var parseiptests = []parseIPTest{
}
func TestParseIP(t *testing.T) {
for i := 0; i < len(parseiptests); i++ {
tt := parseiptests[i]
for _, tt := range parseiptests {
if out := ParseIP(tt.in); !isEqual(out, tt.out) {
t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
}
}
}
type ipStringTest struct {
var ipstringtests = []struct {
in IP
out string
}
var ipstringtests = []ipStringTest{
}{
// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
......@@ -85,10 +78,67 @@ var ipstringtests = []ipStringTest{
}
func TestIPString(t *testing.T) {
for i := 0; i < len(ipstringtests); i++ {
tt := ipstringtests[i]
for _, tt := range ipstringtests {
if out := tt.in.String(); out != tt.out {
t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
}
}
}
var parsecidrtests = []struct {
in string
ip IP
mask IPMask
err os.Error
}{
{"135.104.0.0/32", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255), nil},
{"0.0.0.0/24", IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
{"135.104.0.0/24", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
{"135.104.0.1/32", IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255), nil},
{"135.104.0.1/24", nil, nil, &ParseError{"CIDR address", "135.104.0.1/24"}},
{"::1/128", ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")), nil},
{"abcd:2345::/127", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")), nil},
{"abcd:2345::/65", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::")), nil},
{"abcd:2345::/64", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::")), nil},
{"abcd:2345::/63", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::")), nil},
{"abcd:2345::/33", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::")), nil},
{"abcd:2345::/32", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::")), nil},
{"abcd:2344::/31", ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::")), nil},
{"abcd:2300::/24", ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::")), nil},
{"abcd:2345::/24", nil, nil, &ParseError{"CIDR address", "abcd:2345::/24"}},
{"2001:DB8::/48", ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::")), nil},
}
func TestParseCIDR(t *testing.T) {
for _, tt := range parsecidrtests {
if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
}
}
}
var splitjointests = []struct {
Host string
Port string
Join string
}{
{"www.google.com", "80", "www.google.com:80"},
{"127.0.0.1", "1234", "127.0.0.1:1234"},
{"::1", "80", "[::1]:80"},
}
func TestSplitHostPort(t *testing.T) {
for _, tt := range splitjointests {
if host, port, err := SplitHostPort(tt.Join); host != tt.Host || port != tt.Port || err != nil {
t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.Join, host, port, err, tt.Host, tt.Port)
}
}
}
func TestJoinHostPort(t *testing.T) {
for _, tt := range splitjointests {
if join := JoinHostPort(tt.Host, tt.Port); join != tt.Join {
t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.Host, tt.Port, join, tt.Join)
}
}
}
......@@ -240,7 +240,7 @@ func hostToIP(host string) (ip IP, err os.Error) {
addr = ParseIP(host)
if addr == nil {
// Not an IP address. Try as a DNS name.
_, addrs, err1 := LookupHost(host)
addrs, err1 := LookupHost(host)
if err1 != nil {
err = err1
goto Error
......
......@@ -170,9 +170,10 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
return nil, InvalidAddrError("unexpected socket family")
}
// Split "host:port" into "host" and "port".
// Host cannot contain colons unless it is bracketed.
func splitHostPort(hostport string) (host, port string, err os.Error) {
// SplitHostPort splits a network address of the form
// "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 os.Error) {
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
......@@ -195,9 +196,9 @@ func splitHostPort(hostport string) (host, port string, err os.Error) {
return
}
// Join "host" and "port" into "host:port".
// If host contains colons, will join into "[host]:port".
func joinHostPort(host, port string) string {
// JoinHostPort combines host and port into a network address
// of the form "host:port" or, if host contains a colon, "[host]:port".
func JoinHostPort(host, port string) string {
// If host has colons, have to bracket it.
if byteIndex(host, ':') >= 0 {
return "[" + host + "]:" + port
......@@ -207,7 +208,7 @@ func joinHostPort(host, port string) string {
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
host, port, err := splitHostPort(hostport)
host, port, err := SplitHostPort(hostport)
if err != nil {
goto Error
}
......@@ -218,7 +219,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
addr = ParseIP(host)
if addr == nil {
// Not an IP address. Try as a DNS name.
_, addrs, err1 := LookupHost(host)
addrs, err1 := LookupHost(host)
if err1 != nil {
err = err1
goto Error
......
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
"os"
)
// LookupHost looks up the given host using the local resolver.
// It returns an array of that host's addresses.
func LookupHost(host string) (addrs []string, err os.Error) {
addrs, err, ok := cgoLookupHost(host)
if !ok {
addrs, err = goLookupHost(host)
}
return
}
// LookupIP looks up host using the local resolver.
// It returns an array of that host's IPv4 and IPv6 addresses.
func LookupIP(host string) (addrs []IP, err os.Error) {
addrs, err, ok := cgoLookupIP(host)
if !ok {
addrs, err = goLookupIP(host)
}
return
}
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err os.Error) {
port, err, ok := cgoLookupPort(network, service)
if !ok {
port, err = goLookupPort(network, service)
}
return
}
......@@ -15,50 +15,49 @@ var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check f
type DialErrorTest struct {
Net string
Laddr string
Raddr string
Pattern string
}
var dialErrorTests = []DialErrorTest{
{
"datakit", "", "mh/astro/r70",
"datakit", "mh/astro/r70",
"dial datakit mh/astro/r70: unknown network datakit",
},
{
"tcp", "", "127.0.0.1:☺",
"tcp", "127.0.0.1:☺",
"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
},
{
"tcp", "", "no-such-name.google.com.:80",
"tcp", "no-such-name.google.com.:80",
"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
},
{
"tcp", "", "no-such-name.no-such-top-level-domain.:80",
"tcp", "no-such-name.no-such-top-level-domain.:80",
"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
},
{
"tcp", "", "no-such-name:80",
"tcp", "no-such-name:80",
`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
},
{
"tcp", "", "mh/astro/r70:http",
"tcp", "mh/astro/r70:http",
"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
},
{
"unix", "", "/etc/file-not-found",
"unix", "/etc/file-not-found",
"dial unix /etc/file-not-found: no such file or directory",
},
{
"unix", "", "/etc/",
"unix", "/etc/",
"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
},
{
"unixpacket", "", "/etc/file-not-found",
"unixpacket", "/etc/file-not-found",
"dial unixpacket /etc/file-not-found: no such file or directory",
},
{
"unixpacket", "", "/etc/",
"unixpacket", "/etc/",
"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
},
}
......@@ -69,7 +68,7 @@ func TestDialError(t *testing.T) {
return
}
for i, tt := range dialErrorTests {
c, e := Dial(tt.Net, tt.Laddr, tt.Raddr)
c, e := Dial(tt.Net, tt.Raddr)
if c != nil {
c.Close()
}
......
......@@ -50,8 +50,8 @@ func readServices() {
file.close()
}
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err os.Error) {
// goLookupPort is the native Go implementation of LookupPort.
func goLookupPort(network, service string) (port int, err os.Error) {
onceReadServices.Do(readServices)
switch network {
......
......@@ -54,13 +54,15 @@ func runServe(t *testing.T, network, addr string, listening chan<- string, done
}
func connect(t *testing.T, network, addr string, isEmpty bool) {
var laddr string
var fd Conn
var err os.Error
if network == "unixgram" {
laddr = addr + ".local"
fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
} else {
fd, err = Dial(network, addr)
}
fd, err := Dial(network, laddr, addr)
if err != nil {
t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
}
fd.SetReadTimeout(1e9) // 1s
......
......@@ -167,9 +167,9 @@ func (e *UnknownSocketError) String() string {
func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
switch a := sa.(type) {
case *syscall.SockaddrInet4:
return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
case *syscall.SockaddrInet6:
return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
case *syscall.SockaddrUnix:
return a.Name, nil
}
......
......@@ -34,7 +34,7 @@ func (a *TCPAddr) String() string {
if a == nil {
return "<nil>"
}
return joinHostPort(a.IP.String(), itoa(a.Port))
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
func (a *TCPAddr) family() int {
......@@ -213,8 +213,9 @@ func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
// Closing c does not affect f, and closing f does not affect c.
func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
// DialTCP is like Dial but can only connect to TCP networks
// and returns a TCPConn structure.
// DialTCP connects to the remote address raddr on the network net,
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
// as the local address for the connection.
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
if raddr == nil {
return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
......
......@@ -78,7 +78,7 @@ func (c *Conn) Close() os.Error {
// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, os.Error) {
c, err := net.Dial(network, "", addr)
c, err := net.Dial(network, addr)
if err != nil {
return nil, err
}
......
......@@ -11,7 +11,7 @@ import (
)
func testTimeout(t *testing.T, network, addr string, readFrom bool) {
fd, err := Dial(network, "", addr)
fd, err := Dial(network, addr)
if err != nil {
t.Errorf("dial %s %s failed: %v", network, addr, err)
return
......
......@@ -34,7 +34,7 @@ func (a *UDPAddr) String() string {
if a == nil {
return "<nil>"
}
return joinHostPort(a.IP.String(), itoa(a.Port))
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
func (a *UDPAddr) family() int {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment