diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-20 00:18:15 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-20 00:18:15 +0000 |
commit | 84911de8492fb75007eec6bfa4abb7905439f93c (patch) | |
tree | c891bdec1e6f073f73fedeef23718bc3ac30d499 /libgo/go/net | |
parent | ad33e6a8510b48571eaef50af339892925108830 (diff) | |
download | gcc-84911de8492fb75007eec6bfa4abb7905439f93c.tar.gz |
Update to current version of Go library.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@173931 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/net')
28 files changed, 709 insertions, 181 deletions
diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go new file mode 100644 index 00000000000..d9fef45de0a --- /dev/null +++ b/libgo/go/net/cgo_bsd.go @@ -0,0 +1,15 @@ +// 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 + +/* +#include <netdb.h> +*/ + +import "syscall" + +func cgoAddrInfoMask() C.int { + return syscall.AI_MASK +} diff --git a/libgo/go/net/cgo_linux.go b/libgo/go/net/cgo_linux.go new file mode 100644 index 00000000000..482435221e0 --- /dev/null +++ b/libgo/go/net/cgo_linux.go @@ -0,0 +1,15 @@ +// 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 + +/* +#include <netdb.h> +*/ + +import "syscall" + +func cgoAddrInfoMask() int { + return syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL +} diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go index e28f6622e93..c6277cb657c 100644 --- a/libgo/go/net/cgo_stub.go +++ b/libgo/go/net/cgo_stub.go @@ -19,3 +19,7 @@ func cgoLookupPort(network, service string) (port int, err os.Error, completed b func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) { return nil, nil, false } + +func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) { + return "", nil, false +} diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go new file mode 100644 index 00000000000..b8090181293 --- /dev/null +++ b/libgo/go/net/cgo_unix.go @@ -0,0 +1,149 @@ +// 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 + +/* +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +*/ + +import ( + "os" + "syscall" + "unsafe" +) + +func libc_getaddrinfo(node *byte, service *byte, hints *syscall.Addrinfo, res **syscall.Addrinfo) int __asm__ ("getaddrinfo") +func libc_freeaddrinfo(res *syscall.Addrinfo) __asm__ ("freeaddrinfo") +func libc_gai_strerror(errcode int) *byte __asm__ ("gai_strerror") + +func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) { + ip, err, completed := cgoLookupIP(name) + for _, p := range ip { + addrs = append(addrs, p.String()) + } + return +} + +func cgoLookupPort(net, service string) (port int, err os.Error, completed bool) { + var res *syscall.Addrinfo + var hints syscall.Addrinfo + + switch net { + case "": + // no hints + case "tcp", "tcp4", "tcp6": + hints.Ai_socktype = syscall.SOCK_STREAM + hints.Ai_protocol = syscall.IPPROTO_TCP + case "udp", "udp4", "udp6": + hints.Ai_socktype = syscall.SOCK_DGRAM + hints.Ai_protocol = syscall.IPPROTO_UDP + default: + return 0, UnknownNetworkError(net), true + } + if len(net) >= 4 { + switch net[3] { + case '4': + hints.Ai_family = syscall.AF_INET + case '6': + hints.Ai_family = syscall.AF_INET6 + } + } + + s := syscall.StringBytePtr(service) + if libc_getaddrinfo(nil, s, &hints, &res) == 0 { + defer libc_freeaddrinfo(res) + for r := res; r != nil; r = r.Ai_next { + switch r.Ai_family { + default: + continue + case syscall.AF_INET: + sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) + p := (*[2]byte)(unsafe.Pointer(&sa.Port)) + return int(p[0])<<8 | int(p[1]), nil, true + case syscall.AF_INET6: + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) + p := (*[2]byte)(unsafe.Pointer(&sa.Port)) + return int(p[0])<<8 | int(p[1]), nil, true + } + } + } + return 0, &AddrError{"unknown port", net + "/" + service}, true +} + +func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err os.Error, completed bool) { + var res *syscall.Addrinfo + var hints syscall.Addrinfo + + // NOTE(rsc): In theory there are approximately balanced + // arguments for and against including AI_ADDRCONFIG + // in the flags (it includes IPv4 results only on IPv4 systems, + // and similarly for IPv6), but in practice setting it causes + // getaddrinfo to return the wrong canonical name on Linux. + // So definitely leave it out. + hints.Ai_flags = int32((syscall.AI_ALL | syscall.AI_V4MAPPED | syscall.AI_CANONNAME) & cgoAddrInfoMask()) + + h := syscall.StringBytePtr(name) + gerrno := libc_getaddrinfo(h, nil, &hints, &res) + if gerrno != 0 { + var str string + if gerrno == syscall.EAI_NONAME { + str = noSuchHost + } else if gerrno == syscall.EAI_SYSTEM { + str = syscall.Errstr(syscall.GetErrno()) + } else { + str = syscall.BytePtrToString(libc_gai_strerror(gerrno)) + } + return nil, "", &DNSError{Error: str, Name: name}, true + } + defer libc_freeaddrinfo(res) + if res != nil { + cname = syscall.BytePtrToString((*byte)(unsafe.Pointer(res.Ai_canonname))) + if cname == "" { + cname = name + } + if len(cname) > 0 && cname[len(cname)-1] != '.' { + cname += "." + } + } + for r := res; r != nil; r = r.Ai_next { + // Everything comes back twice, once for UDP and once for TCP. + if r.Ai_socktype != syscall.SOCK_STREAM { + continue + } + switch r.Ai_family { + default: + continue + case syscall.AF_INET: + sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) + addrs = append(addrs, copyIP(sa.Addr[:])) + case syscall.AF_INET6: + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) + addrs = append(addrs, copyIP(sa.Addr[:])) + } + } + return addrs, cname, nil, true +} + +func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) { + addrs, _, err, completed = cgoLookupIPCNAME(name) + return +} + +func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) { + _, cname, err, completed = cgoLookupIPCNAME(name) + return +} + +func copyIP(x IP) IP { + y := make(IP, len(x)) + copy(y, x) + return y +} diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index 66cb09b19bb..16896b4269b 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -30,7 +30,7 @@ func Dial(net, addr string) (c Conn, err os.Error) { switch net { case "tcp", "tcp4", "tcp6": var ra *TCPAddr - if ra, err = ResolveTCPAddr(raddr); err != nil { + if ra, err = ResolveTCPAddr(net, raddr); err != nil { goto Error } c, err := DialTCP(net, nil, ra) @@ -40,7 +40,7 @@ func Dial(net, addr string) (c Conn, err os.Error) { return c, nil case "udp", "udp4", "udp6": var ra *UDPAddr - if ra, err = ResolveUDPAddr(raddr); err != nil { + if ra, err = ResolveUDPAddr(net, raddr); err != nil { goto Error } c, err := DialUDP(net, nil, ra) @@ -83,7 +83,7 @@ func Listen(net, laddr string) (l Listener, err os.Error) { case "tcp", "tcp4", "tcp6": var la *TCPAddr if laddr != "" { - if la, err = ResolveTCPAddr(laddr); err != nil { + if la, err = ResolveTCPAddr(net, laddr); err != nil { return nil, err } } @@ -116,7 +116,7 @@ func ListenPacket(net, laddr string) (c PacketConn, err os.Error) { case "udp", "udp4", "udp6": var la *UDPAddr if laddr != "" { - if la, err = ResolveUDPAddr(laddr); err != nil { + if la, err = ResolveUDPAddr(net, laddr); err != nil { return nil, err } } diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go index 9a9c02ebd71..e90c4f3f894 100644 --- a/libgo/go/net/dialgoogle_test.go +++ b/libgo/go/net/dialgoogle_test.go @@ -41,7 +41,19 @@ func doDial(t *testing.T, network, addr string) { fd.Close() } -var googleaddrs = []string{ +func TestLookupCNAME(t *testing.T) { + if testing.Short() { + // Don't use external network. + t.Logf("skipping external network test during -short") + return + } + cname, err := LookupCNAME("www.google.com") + if !strings.HasSuffix(cname, ".l.google.com.") || err != nil { + t.Errorf(`LookupCNAME("www.google.com.") = %q, %v, want "*.l.google.com.", nil`, cname, err) + } +} + +var googleaddrsipv4 = []string{ "%d.%d.%d.%d:80", "www.google.com:80", "%d.%d.%d.%d:http", @@ -52,42 +64,40 @@ var googleaddrs = []string{ "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80", "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80", "[0:0:0:0:0:ffff::%d.%d.%d.%d]:80", - "[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 { - googleaddrs[len(googleaddrs)-1] = "" +func TestDialGoogleIPv4(t *testing.T) { + if testing.Short() { + // Don't use external network. + t.Logf("skipping external network test during -short") + return } - // Insert an actual IP address for google.com + // Insert an actual IPv4 address for google.com // into the table. - 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") + var ip IP + for _, addr := range addrs { + if x := addr.To4(); x != nil { + ip = x + break + } + } + if ip == nil { + t.Fatalf("no IPv4 addresses for www.google.com") } - ip := addrs[0].To4() - for i, s := range googleaddrs { + for i, s := range googleaddrsipv4 { if strings.Contains(s, "%") { - googleaddrs[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3]) + googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3]) } } - for i := 0; i < len(googleaddrs); i++ { - addr := googleaddrs[i] + for i := 0; i < len(googleaddrsipv4); i++ { + addr := googleaddrsipv4[i] if addr == "" { continue } @@ -95,20 +105,67 @@ func TestDialGoogle(t *testing.T) { doDial(t, "tcp", addr) if addr[0] != '[' { doDial(t, "tcp4", addr) - if !preferIPv4 { // make sure preferIPv4 flag works. preferIPv4 = true syscall.SocketDisableIPv6 = true + doDial(t, "tcp", addr) doDial(t, "tcp4", addr) syscall.SocketDisableIPv6 = false preferIPv4 = false } } + } +} + +var googleaddrsipv6 = []string{ + "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80", + "ipv6.google.com:80", + "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http", + "ipv6.google.com:http", +} - // Only run tcp6 if the kernel will take it. - if kernelSupportsIPv6() { - doDial(t, "tcp6", addr) +func TestDialGoogleIPv6(t *testing.T) { + if testing.Short() { + // Don't use external network. + t.Logf("skipping external network test during -short") + return + } + // Only run tcp6 if the kernel will take it. + if !*ipv6 || !kernelSupportsIPv6() { + return + } + + // Insert an actual IPv6 address for ipv6.google.com + // into the table. + addrs, err := LookupIP("ipv6.google.com") + if err != nil { + t.Fatalf("lookup ipv6.google.com: %v", err) + } + var ip IP + for _, addr := range addrs { + if x := addr.To16(); x != nil { + ip = x + break + } + } + if ip == nil { + t.Fatalf("no IPv6 addresses for ipv6.google.com") + } + + for i, s := range googleaddrsipv6 { + if strings.Contains(s, "%") { + googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]) + } + } + + for i := 0; i < len(googleaddrsipv6); i++ { + addr := googleaddrsipv6[i] + if addr == "" { + continue } + t.Logf("-- %s --", addr) + doDial(t, "tcp", addr) + doDial(t, "tcp6", addr) } } diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go index 32cea6125eb..3466003fab8 100644 --- a/libgo/go/net/dnsclient.go +++ b/libgo/go/net/dnsclient.go @@ -21,6 +21,7 @@ import ( "rand" "sync" "time" + "sort" ) // DNSError represents a DNS lookup error. @@ -120,15 +121,19 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs Cname: for cnameloop := 0; cnameloop < 10; cnameloop++ { addrs = addrs[0:0] - for i := 0; i < len(dns.answer); i++ { - rr := dns.answer[i] + for _, rr := range dns.answer { + if _, justHeader := rr.(*dnsRR_Header); justHeader { + // Corrupt record: we only have a + // header. That header might say it's + // of type qtype, but we don't + // actually have it. Skip. + continue + } h := rr.Header() if h.Class == dnsClassINET && h.Name == name { switch h.Rrtype { case qtype: - n := len(addrs) - addrs = addrs[0 : n+1] - addrs[n] = rr + addrs = append(addrs, rr) case dnsTypeCNAME: // redirect to cname name = rr.(*dnsRR_CNAME).Cname @@ -180,8 +185,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs func convertRR_A(records []dnsRR) []IP { addrs := make([]IP, len(records)) - for i := 0; i < len(records); i++ { - rr := records[i] + for i, rr := range records { a := rr.(*dnsRR_A).A addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)) } @@ -190,8 +194,7 @@ func convertRR_A(records []dnsRR) []IP { func convertRR_AAAA(records []dnsRR) []IP { addrs := make([]IP, len(records)) - for i := 0; i < len(records); i++ { - rr := records[i] + for i, rr := range records { a := make(IP, 16) copy(a, rr.(*dnsRR_AAAA).AAAA[:]) addrs[i] = a @@ -306,17 +309,22 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro } // goLookupHost is the native Go implementation of LookupHost. +// Used only if cgoLookupHost refuses to handle the request +// (that is, only if cgoLookupHost is the stub in cgo_stub.go). +// Normally we let cgo use the C library resolver instead of +// depending on our lookup code, so that Go and C get the same +// answers. func goLookupHost(name string) (addrs []string, err os.Error) { - onceLoadConfig.Do(loadConfig) - if dnserr != nil || cfg == nil { - err = dnserr - return - } // Use entries from /etc/hosts if they match. addrs = lookupStaticHost(name) if len(addrs) > 0 { return } + onceLoadConfig.Do(loadConfig) + if dnserr != nil || cfg == nil { + err = dnserr + return + } ips, err := goLookupIP(name) if err != nil { return @@ -329,6 +337,11 @@ func goLookupHost(name string) (addrs []string, err os.Error) { } // goLookupIP is the native Go implementation of LookupIP. +// Used only if cgoLookupIP refuses to handle the request +// (that is, only if cgoLookupIP is the stub in cgo_stub.go). +// Normally we let cgo use the C library resolver instead of +// depending on our lookup code, so that Go and C get the same +// answers. func goLookupIP(name string) (addrs []IP, err os.Error) { onceLoadConfig.Do(loadConfig) if dnserr != nil || cfg == nil { @@ -357,11 +370,13 @@ func goLookupIP(name string) (addrs []IP, err os.Error) { 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) { +// goLookupCNAME is the native Go implementation of LookupCNAME. +// Used only if cgoLookupCNAME refuses to handle the request +// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go). +// Normally we let cgo use the C library resolver instead of +// depending on our lookup code, so that Go and C get the same +// answers. +func goLookupCNAME(name string) (cname string, err os.Error) { onceLoadConfig.Do(loadConfig) if dnserr != nil || cfg == nil { err = dnserr @@ -371,9 +386,7 @@ func LookupCNAME(name string) (cname string, err os.Error) { if err != nil { return } - if len(rr) >= 0 { - cname = rr[0].(*dnsRR_CNAME).Cname - } + cname = rr[0].(*dnsRR_CNAME).Cname return } @@ -397,8 +410,8 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os. return } addrs = make([]*SRV, len(records)) - for i := 0; i < len(records); i++ { - r := records[i].(*dnsRR_SRV) + for i, rr := range records { + r := rr.(*dnsRR_SRV) addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight} } return @@ -410,18 +423,32 @@ type MX struct { 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) +// byPref implements sort.Interface to sort MX records by preference +type byPref []*MX + +func (s byPref) Len() int { return len(s) } + +func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } + +func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// LookupMX returns the DNS MX records for the given domain name sorted by preference. +func LookupMX(name string) (mx []*MX, err os.Error) { + _, rr, err := lookup(name, dnsTypeMX) if err != nil { return } - entries = make([]*MX, len(records)) - for i := range records { - r := records[i].(*dnsRR_MX) - entries[i] = &MX{r.Mx, r.Pref} + mx = make([]*MX, len(rr)) + for i := range rr { + r := rr[i].(*dnsRR_MX) + mx[i] = &MX{r.Mx, r.Pref} + } + // Shuffle the records to match RFC 5321 when sorted + for i := range mx { + j := rand.Intn(i + 1) + mx[i], mx[j] = mx[j], mx[i] } + sort.Sort(byPref(mx)) return } diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go index 5209c1a06a5..731efe26a44 100644 --- a/libgo/go/net/dnsmsg.go +++ b/libgo/go/net/dnsmsg.go @@ -390,52 +390,48 @@ Loop: // TODO(rsc): Move into generic library? // Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string, // [n]byte, and other (often anonymous) structs. -func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { +func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) { for i := 0; i < val.NumField(); i++ { - f := val.Type().(*reflect.StructType).Field(i) - switch fv := val.Field(i).(type) { + f := val.Type().Field(i) + switch fv := val.Field(i); fv.Kind() { default: BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) return len(msg), false - case *reflect.StructValue: + case reflect.Struct: off, ok = packStructValue(fv, msg, off) - case *reflect.UintValue: - i := fv.Get() - switch fv.Type().Kind() { - default: - goto BadType - case reflect.Uint16: - if off+2 > len(msg) { - return len(msg), false - } - msg[off] = byte(i >> 8) - msg[off+1] = byte(i) - off += 2 - case reflect.Uint32: - if off+4 > len(msg) { - return len(msg), false - } - msg[off] = byte(i >> 24) - msg[off+1] = byte(i >> 16) - msg[off+2] = byte(i >> 8) - msg[off+3] = byte(i) - off += 4 + case reflect.Uint16: + if off+2 > len(msg) { + return len(msg), false } - case *reflect.ArrayValue: - if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 { + i := fv.Uint() + msg[off] = byte(i >> 8) + msg[off+1] = byte(i) + off += 2 + case reflect.Uint32: + if off+4 > len(msg) { + return len(msg), false + } + i := fv.Uint() + msg[off] = byte(i >> 24) + msg[off+1] = byte(i >> 16) + msg[off+2] = byte(i >> 8) + msg[off+3] = byte(i) + off += 4 + case reflect.Array: + if fv.Type().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) + reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv) off += n - case *reflect.StringValue: + case reflect.String: // There are multiple string encodings. // The tag distinguishes ordinary strings from domain names. - s := fv.Get() + s := fv.String() switch f.Tag { default: fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag) @@ -459,8 +455,8 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o return off, true } -func structValue(any interface{}) *reflect.StructValue { - return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue) +func structValue(any interface{}) reflect.Value { + return reflect.ValueOf(any).Elem() } func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { @@ -471,46 +467,41 @@ func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { // TODO(rsc): Move into generic library? // Unpack a reflect.StructValue from msg. // Same restrictions as packStructValue. -func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { +func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) { for i := 0; i < val.NumField(); i++ { - f := val.Type().(*reflect.StructType).Field(i) - switch fv := val.Field(i).(type) { + f := val.Type().Field(i) + switch fv := val.Field(i); fv.Kind() { default: BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) return len(msg), false - case *reflect.StructValue: + case reflect.Struct: off, ok = unpackStructValue(fv, msg, off) - case *reflect.UintValue: - switch fv.Type().Kind() { - default: - goto BadType - case reflect.Uint16: - if off+2 > len(msg) { - return len(msg), false - } - i := uint16(msg[off])<<8 | uint16(msg[off+1]) - fv.Set(uint64(i)) - off += 2 - case reflect.Uint32: - if off+4 > len(msg) { - return len(msg), false - } - i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) - fv.Set(uint64(i)) - off += 4 + case reflect.Uint16: + if off+2 > len(msg) { + return len(msg), false } - case *reflect.ArrayValue: - if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 { + i := uint16(msg[off])<<8 | uint16(msg[off+1]) + fv.SetUint(uint64(i)) + off += 2 + case reflect.Uint32: + if off+4 > len(msg) { + return len(msg), false + } + i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) + fv.SetUint(uint64(i)) + off += 4 + case reflect.Array: + if fv.Type().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)) + reflect.Copy(fv, reflect.ValueOf(msg[off:off+n])) off += n - case *reflect.StringValue: + case reflect.String: var s string switch f.Tag { default: @@ -534,7 +525,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, off += n s = string(b) } - fv.Set(s) + fv.SetString(s) } } return off, true @@ -550,23 +541,23 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { // 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 { +func printStructValue(val reflect.Value) string { s := "{" for i := 0; i < val.NumField(); i++ { if i > 0 { s += ", " } - f := val.Type().(*reflect.StructType).Field(i) + f := val.Type().Field(i) if !f.Anonymous { s += f.Name + "=" } fval := val.Field(i) - if fv, ok := fval.(*reflect.StructValue); ok { + if fv := fval; fv.Kind() == reflect.Struct { s += printStructValue(fv) - } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" { - i := fv.Get() + } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" { + i := fv.Uint() 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" { + } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" { i := fv.Interface().([]byte) s += IP(i).String() } else { @@ -724,24 +715,35 @@ func (dns *dnsMsg) Unpack(msg []byte) bool { // Arrays. dns.question = make([]dnsQuestion, dh.Qdcount) - dns.answer = make([]dnsRR, dh.Ancount) - dns.ns = make([]dnsRR, dh.Nscount) - dns.extra = make([]dnsRR, dh.Arcount) + dns.answer = make([]dnsRR, 0, dh.Ancount) + dns.ns = make([]dnsRR, 0, dh.Nscount) + dns.extra = make([]dnsRR, 0, dh.Arcount) + + var rec dnsRR for i := 0; i < len(dns.question); i++ { off, ok = unpackStruct(&dns.question[i], msg, off) } - for i := 0; i < len(dns.answer); i++ { - dns.answer[i], off, ok = unpackRR(msg, off) - } - for i := 0; i < len(dns.ns); i++ { - dns.ns[i], off, ok = unpackRR(msg, off) + for i := 0; i < int(dh.Ancount); i++ { + rec, off, ok = unpackRR(msg, off) + if !ok { + return false + } + dns.answer = append(dns.answer, rec) } - for i := 0; i < len(dns.extra); i++ { - dns.extra[i], off, ok = unpackRR(msg, off) + for i := 0; i < int(dh.Nscount); i++ { + rec, off, ok = unpackRR(msg, off) + if !ok { + return false + } + dns.ns = append(dns.ns, rec) } - if !ok { - return false + for i := 0; i < int(dh.Arcount); i++ { + rec, off, ok = unpackRR(msg, off) + if !ok { + return false + } + dns.extra = append(dns.extra, rec) } // if off != len(msg) { // println("extra bytes in dns packet", off, "<", len(msg)); diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go new file mode 100644 index 00000000000..20c9f02b0b4 --- /dev/null +++ b/libgo/go/net/dnsmsg_test.go @@ -0,0 +1,107 @@ +// 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 ( + "encoding/hex" + "runtime" + "testing" +) + +func TestDNSParseSRVReply(t *testing.T) { + if runtime.GOOS == "windows" { + return + } + data, err := hex.DecodeString(dnsSRVReply) + if err != nil { + t.Fatal(err) + } + msg := new(dnsMsg) + ok := msg.Unpack(data) + if !ok { + t.Fatalf("unpacking packet failed") + } + if g, e := len(msg.answer), 5; g != e { + t.Errorf("len(msg.answer) = %d; want %d", g, e) + } + for idx, rr := range msg.answer { + if g, e := rr.Header().Rrtype, uint16(dnsTypeSRV); g != e { + t.Errorf("rr[%d].Header().Rrtype = %d; want %d", idx, g, e) + } + if _, ok := rr.(*dnsRR_SRV); !ok { + t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr) + } + } + _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV)) + if err != nil { + t.Fatalf("answer: %v", err) + } + if g, e := len(addrs), 5; g != e { + t.Errorf("len(addrs) = %d; want %d", g, e) + t.Logf("addrs = %#v", addrs) + } +} + +func TestDNSParseCorruptSRVReply(t *testing.T) { + if runtime.GOOS == "windows" { + return + } + data, err := hex.DecodeString(dnsSRVCorruptReply) + if err != nil { + t.Fatal(err) + } + msg := new(dnsMsg) + ok := msg.Unpack(data) + if !ok { + t.Fatalf("unpacking packet failed") + } + if g, e := len(msg.answer), 5; g != e { + t.Errorf("len(msg.answer) = %d; want %d", g, e) + } + for idx, rr := range msg.answer { + if g, e := rr.Header().Rrtype, uint16(dnsTypeSRV); g != e { + t.Errorf("rr[%d].Header().Rrtype = %d; want %d", idx, g, e) + } + if idx == 4 { + if _, ok := rr.(*dnsRR_Header); !ok { + t.Errorf("answer[%d] = %T; want *dnsRR_Header", idx, rr) + } + } else { + if _, ok := rr.(*dnsRR_SRV); !ok { + t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr) + } + } + } + _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV)) + if err != nil { + t.Fatalf("answer: %v", err) + } + if g, e := len(addrs), 4; g != e { + t.Errorf("len(addrs) = %d; want %d", g, e) + t.Logf("addrs = %#v", addrs) + } +} + +// Valid DNS SRV reply +const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" + + "6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" + + "73657276657234016c06676f6f676c6503636f6d00c00c002100010000012c00210014" + + "000014950c786d70702d73657276657232016c06676f6f676c6503636f6d00c00c0021" + + "00010000012c00210014000014950c786d70702d73657276657233016c06676f6f676c" + + "6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" + + "72016c06676f6f676c6503636f6d00c00c002100010000012c00210014000014950c78" + + "6d70702d73657276657231016c06676f6f676c6503636f6d00" + +// Corrupt DNS SRV reply, with its final RR having a bogus length +// (perhaps it was truncated, or it's malicious) The mutation is the +// capital "FF" below, instead of the proper "21". +const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" + + "6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" + + "73657276657234016c06676f6f676c6503636f6d00c00c002100010000012c00210014" + + "000014950c786d70702d73657276657232016c06676f6f676c6503636f6d00c00c0021" + + "00010000012c00210014000014950c786d70702d73657276657233016c06676f6f676c" + + "6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" + + "72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" + + "6d70702d73657276657231016c06676f6f676c6503636f6d00" diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go index 470e35f7863..e5793eef2c7 100644 --- a/libgo/go/net/hosts_test.go +++ b/libgo/go/net/hosts_test.go @@ -5,6 +5,7 @@ package net import ( + "sort" "testing" ) @@ -51,3 +52,17 @@ func TestLookupStaticHost(t *testing.T) { } hostsPath = p } + +func TestLookupHost(t *testing.T) { + // Can't depend on this to return anything in particular, + // but if it does return something, make sure it doesn't + // duplicate addresses (a common bug due to the way + // getaddrinfo works). + addrs, _ := LookupHost("localhost") + sort.SortStrings(addrs) + for i := 0; i+1 < len(addrs); i++ { + if addrs[i] == addrs[i+1] { + t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs) + } + } +} diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go index 12bb6f351a1..61b2c687e2f 100644 --- a/libgo/go/net/ip.go +++ b/libgo/go/net/ip.go @@ -75,7 +75,8 @@ var ( // Well-known IPv6 addresses var ( - IPzero = make(IP, IPv6len) // all zeros + IPzero = make(IP, IPv6len) // all zeros + IPv6loopback = IP([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) ) // Is p all zeros? @@ -436,7 +437,7 @@ func parseIPv6(s string) IP { } // Otherwise must be followed by colon and more. - if s[i] != ':' && i+1 == len(s) { + if s[i] != ':' || i+1 == len(s) { return nil } i++ diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go index f1a4716d227..2008953ef38 100644 --- a/libgo/go/net/ip_test.go +++ b/libgo/go/net/ip_test.go @@ -29,6 +29,7 @@ var parseiptests = []struct { {"127.0.0.1", IPv4(127, 0, 0, 1)}, {"127.0.0.256", nil}, {"abc", nil}, + {"123:", nil}, {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)}, {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go index 562298bdf46..0c0b675f875 100644 --- a/libgo/go/net/ipraw_test.go +++ b/libgo/go/net/ipraw_test.go @@ -60,7 +60,8 @@ func parsePingReply(p []byte) (id, seq int) { } var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request") -var dsthost = flag.String("dsthost", "localhost", "Destination for the ICMP ECHO request") +// 127.0.0.1 because this is an IPv4-specific test. +var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request") // test (raw) IP socket using ICMP func TestICMP(t *testing.T) { @@ -69,9 +70,12 @@ func TestICMP(t *testing.T) { return } - var laddr *IPAddr + var ( + laddr *IPAddr + err os.Error + ) if *srchost != "" { - laddr, err := ResolveIPAddr(*srchost) + laddr, err = ResolveIPAddr(*srchost) if err != nil { t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err) } diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go index 60433303ae1..5be6fe4e0b9 100644 --- a/libgo/go/net/iprawsock.go +++ b/libgo/go/net/iprawsock.go @@ -245,7 +245,7 @@ func hostToIP(host string) (ip IP, err os.Error) { err = err1 goto Error } - addr = firstSupportedAddr(addrs) + addr = firstSupportedAddr(anyaddr, addrs) if addr == nil { // should not happen err = &AddrError{"LookupHost returned invalid address", addrs[0]} diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go index 80bc3eea5da..e8bcac64603 100644 --- a/libgo/go/net/ipsock.go +++ b/libgo/go/net/ipsock.go @@ -35,15 +35,28 @@ func kernelSupportsIPv6() bool { var preferIPv4 = !kernelSupportsIPv6() -func firstSupportedAddr(addrs []string) (addr IP) { +func firstSupportedAddr(filter func(IP) IP, addrs []string) IP { for _, s := range addrs { - addr = ParseIP(s) - if !preferIPv4 || addr.To4() != nil { - break + if addr := filter(ParseIP(s)); addr != nil { + return addr } - addr = nil } - return addr + return nil +} + +func anyaddr(x IP) IP { return x } +func ipv4only(x IP) IP { return x.To4() } + +func ipv6only(x IP) IP { + // Only return addresses that we can use + // with the kernel's IPv6 addressing modes. + // If preferIPv4 is set, it means the IPv6 stack + // cannot take IPv4 addresses directly (we prefer + // to use the IPv4 stack) so reject IPv4 addresses. + if x.To4() != nil && preferIPv4 { + return nil + } + return x } // TODO(rsc): if syscall.OS == "linux", we're supposd to read @@ -131,7 +144,6 @@ func (e InvalidAddrError) String() string { return string(e) } func (e InvalidAddrError) Timeout() bool { return false } func (e InvalidAddrError) Temporary() bool { return false } - func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) { switch family { case syscall.AF_INET: @@ -218,13 +230,31 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) { // Try as an IP address. addr = ParseIP(host) if addr == nil { + filter := anyaddr + if len(net) >= 4 && net[3] == '4' { + filter = ipv4only + } else if len(net) >= 4 && net[3] == '6' { + filter = ipv6only + } // Not an IP address. Try as a DNS name. addrs, err1 := LookupHost(host) if err1 != nil { err = err1 goto Error } - addr = firstSupportedAddr(addrs) + if filter == anyaddr { + // We'll take any IP address, but since the dialing code + // does not yet try multiple addresses, prefer to use + // an IPv4 address if possible. This is especially relevant + // if localhost resolves to [ipv6-localhost, ipv4-localhost]. + // Too much code assumes localhost == ipv4-localhost. + addr = firstSupportedAddr(ipv4only, addrs) + if addr == nil { + addr = firstSupportedAddr(anyaddr, addrs) + } + } else { + addr = firstSupportedAddr(filter, addrs) + } if addr == nil { // should not happen err = &AddrError{"LookupHost returned invalid address", addrs[0]} diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go index 7b2185ed419..eeb22a8ae3d 100644 --- a/libgo/go/net/lookup.go +++ b/libgo/go/net/lookup.go @@ -36,3 +36,15 @@ func LookupPort(network, service string) (port int, err os.Error) { } 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) { + cname, err, ok := cgoLookupCNAME(name) + if !ok { + cname, err = goLookupCNAME(name) + } + return +} diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go index 32fdec85bde..be6dbf2dc19 100644 --- a/libgo/go/net/multicast_test.go +++ b/libgo/go/net/multicast_test.go @@ -5,14 +5,21 @@ package net import ( + "flag" "runtime" "testing" ) +var multicast = flag.Bool("multicast", false, "enable multicast tests") + func TestMulticastJoinAndLeave(t *testing.T) { if runtime.GOOS == "windows" { return } + if !*multicast { + t.Logf("test disabled; use --multicast to enable") + return + } addr := &UDPAddr{ IP: IPv4zero, @@ -40,6 +47,10 @@ func TestMulticastJoinAndLeave(t *testing.T) { } func TestJoinFailureWithIPv6Address(t *testing.T) { + if !*multicast { + t.Logf("test disabled; use --multicast to enable") + return + } addr := &UDPAddr{ IP: IPv4zero, Port: 0, diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go index 04a898a9aac..51db1073954 100644 --- a/libgo/go/net/net.go +++ b/libgo/go/net/net.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The net package provides a portable interface to Unix -// networks sockets, including TCP/IP, UDP, domain name -// resolution, and Unix domain sockets. +// Package net provides a portable interface to Unix networks sockets, +// including TCP/IP, UDP, domain name resolution, and Unix domain sockets. package net // TODO(rsc): diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/resolv_windows.go index 000c3065911..f7c3f51bef1 100644 --- a/libgo/go/net/resolv_windows.go +++ b/libgo/go/net/resolv_windows.go @@ -47,7 +47,7 @@ func goLookupIP(name string) (addrs []IP, err os.Error) { return addrs, nil } -func LookupCNAME(name string) (cname string, err os.Error) { +func goLookupCNAME(name string) (cname string, err os.Error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil) if int(e) != 0 { @@ -113,6 +113,10 @@ func reverseaddr(addr string) (arpa string, err os.Error) { panic("unimplemented") } +func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) { + panic("unimplemented") +} + // DNSError represents a DNS lookup error. type DNSError struct { Error string // description of the error diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 37695a068d1..075748b83b0 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -108,12 +108,10 @@ func doTest(t *testing.T, network, listenaddr, dialaddr string) { } func TestTCPServer(t *testing.T) { - doTest(t, "tcp", "0.0.0.0", "127.0.0.1") - doTest(t, "tcp", "", "127.0.0.1") + doTest(t, "tcp", "127.0.0.1", "127.0.0.1") if kernelSupportsIPv6() { - doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]") - doTest(t, "tcp", "[::]", "127.0.0.1") - doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]") + doTest(t, "tcp", "[::1]", "[::1]") + doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]") } } diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index 933700af160..21bd5f03e89 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -32,17 +32,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() - // Allow reuse of recently-used addresses. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) - - // Allow broadcast. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) - - if f == syscall.AF_INET6 { - // using ip, tcp, udp, etc. - // allow both protocols even if the OS default is otherwise. - syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) - } + setKernelSpecificSockopt(s, f) if la != nil { e = syscall.Bind(s, la) @@ -161,7 +151,7 @@ type UnknownSocketError struct { } func (e *UnknownSocketError) String() string { - return "unknown socket address type " + reflect.Typeof(e.sa).String() + return "unknown socket address type " + reflect.TypeOf(e.sa).String() } func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) { diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go new file mode 100644 index 00000000000..5fd52074ad3 --- /dev/null +++ b/libgo/go/net/sock_bsd.go @@ -0,0 +1,31 @@ +// 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. + +// Sockets for BSD variants + +package net + +import ( + "syscall" +) + +func setKernelSpecificSockopt(s, f int) { + // Allow reuse of recently-used addresses. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + + // Allow reuse of recently-used ports. + // This option is supported only in descendants of 4.4BSD, + // to make an effective multicast application and an application + // that requires quick draw possible. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + + if f == syscall.AF_INET6 { + // using ip, tcp, udp, etc. + // allow both protocols even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } +} diff --git a/libgo/go/net/sock_linux.go b/libgo/go/net/sock_linux.go new file mode 100644 index 00000000000..ec31e803b6f --- /dev/null +++ b/libgo/go/net/sock_linux.go @@ -0,0 +1,25 @@ +// 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. + +// Sockets for Linux + +package net + +import ( + "syscall" +) + +func setKernelSpecificSockopt(s, f int) { + // Allow reuse of recently-used addresses. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + + if f == syscall.AF_INET6 { + // using ip, tcp, udp, etc. + // allow both protocols even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } +} diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go new file mode 100644 index 00000000000..e17c60b98b6 --- /dev/null +++ b/libgo/go/net/sock_windows.go @@ -0,0 +1,25 @@ +// 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. + +// Sockets for Windows + +package net + +import ( + "syscall" +) + +func setKernelSpecificSockopt(s, f int) { + // Allow reuse of recently-used addresses and ports. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + + if f == syscall.AF_INET6 { + // using ip, tcp, udp, etc. + // allow both protocols even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } +} diff --git a/libgo/go/net/srv_test.go b/libgo/go/net/srv_test.go index 4dd6089cdd2..f1c7a0ab498 100644 --- a/libgo/go/net/srv_test.go +++ b/libgo/go/net/srv_test.go @@ -8,10 +8,17 @@ package net import ( + "runtime" "testing" ) +var avoidMacFirewall = runtime.GOOS == "darwin" + func TestGoogleSRV(t *testing.T) { + if testing.Short() || avoidMacFirewall { + t.Logf("skipping test to avoid external network") + return + } _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com") if err != nil { t.Errorf("failed: %s", err) diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go index b484be20b46..d9aa7cf19a5 100644 --- a/libgo/go/net/tcpsock.go +++ b/libgo/go/net/tcpsock.go @@ -62,8 +62,8 @@ func (a *TCPAddr) toAddr() sockaddr { // host:port and resolves domain names or port names to // numeric addresses. A literal IPv6 host address must be // enclosed in square brackets, as in "[::]:80". -func ResolveTCPAddr(addr string) (*TCPAddr, os.Error) { - ip, port, err := hostPortToIP("tcp", addr) +func ResolveTCPAddr(network, addr string) (*TCPAddr, os.Error) { + ip, port, err := hostPortToIP(network, addr) if err != nil { return nil, err } diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go index fbfad9d61ce..9f19b5495d1 100644 --- a/libgo/go/net/textproto/textproto.go +++ b/libgo/go/net/textproto/textproto.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The textproto package implements generic support for -// text-based request/response protocols in the style of -// HTTP, NNTP, and SMTP. +// Package textproto implements generic support for text-based request/response +// protocols in the style of HTTP, NNTP, and SMTP. // // The package provides: // diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go index 44d618dab08..67684471b72 100644 --- a/libgo/go/net/udpsock.go +++ b/libgo/go/net/udpsock.go @@ -62,8 +62,8 @@ func (a *UDPAddr) toAddr() sockaddr { // host:port and resolves domain names or port names to // numeric addresses. A literal IPv6 host address must be // enclosed in square brackets, as in "[::]:80". -func ResolveUDPAddr(addr string) (*UDPAddr, os.Error) { - ip, port, err := hostPortToIP("udp", addr) +func ResolveUDPAddr(network, addr string) (*UDPAddr, os.Error) { + ip, port, err := hostPortToIP(network, addr) if err != nil { return nil, err } |