aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net')
-rw-r--r--libgo/go/net/dial_test.go19
-rw-r--r--libgo/go/net/dnsclient.go20
-rw-r--r--libgo/go/net/dnsmsg.go350
-rw-r--r--libgo/go/net/dnsmsg_test.go13
-rw-r--r--libgo/go/net/fd_linux.go3
-rw-r--r--libgo/go/net/file_test.go112
-rw-r--r--libgo/go/net/http/client_test.go6
-rw-r--r--libgo/go/net/http/request.go6
-rw-r--r--libgo/go/net/http/request_test.go19
-rw-r--r--libgo/go/net/http/server.go2
-rw-r--r--libgo/go/net/http/transport.go2
-rw-r--r--libgo/go/net/http/transport_test.go26
-rw-r--r--libgo/go/net/interface.go2
-rw-r--r--libgo/go/net/interface_linux.go10
-rw-r--r--libgo/go/net/iprawsock_posix.go7
-rw-r--r--libgo/go/net/ipsock_posix.go82
-rw-r--r--libgo/go/net/mac.go20
-rw-r--r--libgo/go/net/mac_test.go16
-rw-r--r--libgo/go/net/mail/message.go3
-rw-r--r--libgo/go/net/multicast_test.go8
-rw-r--r--libgo/go/net/net.go17
-rw-r--r--libgo/go/net/net_test.go1
-rw-r--r--libgo/go/net/parse_test.go4
-rw-r--r--libgo/go/net/rpc/client.go3
-rw-r--r--libgo/go/net/server_test.go547
-rw-r--r--libgo/go/net/sock.go4
-rw-r--r--libgo/go/net/sockopt.go3
-rw-r--r--libgo/go/net/sockopt_bsd.go13
-rw-r--r--libgo/go/net/sockopt_linux.go13
-rw-r--r--libgo/go/net/sockopt_windows.go13
-rw-r--r--libgo/go/net/tcpsock_posix.go10
-rw-r--r--libgo/go/net/timeout_test.go51
-rw-r--r--libgo/go/net/udp_test.go4
-rw-r--r--libgo/go/net/udpsock_posix.go7
-rw-r--r--libgo/go/net/unicast_test.go521
-rw-r--r--libgo/go/net/unixsock_posix.go14
36 files changed, 1482 insertions, 469 deletions
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
index 5f5aea1..7212087 100644
--- a/libgo/go/net/dial_test.go
+++ b/libgo/go/net/dial_test.go
@@ -6,6 +6,7 @@ package net
import (
"flag"
+ "fmt"
"regexp"
"runtime"
"testing"
@@ -32,7 +33,7 @@ func TestDialTimeout(t *testing.T) {
numConns := listenerBacklog + 10
// TODO(bradfitz): It's hard to test this in a portable
- // way. This is unforunate, but works for now.
+ // way. This is unfortunate, but works for now.
switch runtime.GOOS {
case "linux":
// The kernel will start accepting TCP connections before userspace
@@ -44,13 +45,25 @@ func TestDialTimeout(t *testing.T) {
errc <- err
}()
}
- case "darwin":
+ case "darwin", "windows":
// At least OS X 10.7 seems to accept any number of
// connections, ignoring listen's backlog, so resort
// to connecting to a hopefully-dead 127/8 address.
// Same for windows.
+ //
+ // Use an IANA reserved port (49151) instead of 80, because
+ // on our 386 builder, this Dial succeeds, connecting
+ // to an IIS web server somewhere. The data center
+ // or VM or firewall must be stealing the TCP connection.
+ //
+ // IANA Service Name and Transport Protocol Port Number Registry
+ // <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
go func() {
- _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
+ c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
+ if err == nil {
+ err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
+ c.Close()
+ }
errc <- err
}()
default:
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index f4ed8b8..e69cb31 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -5,8 +5,6 @@
package net
import (
- "bytes"
- "fmt"
"math/rand"
"sort"
)
@@ -45,20 +43,22 @@ func reverseaddr(addr string) (arpa string, err error) {
return "", &DNSError{Err: "unrecognized address", Name: addr}
}
if ip.To4() != nil {
- return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
+ return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
+ itoa(int(ip[12])) + ".in-addr.arpa.", nil
}
// Must be IPv6
- var buf bytes.Buffer
+ buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
// Add it, in reverse, to the buffer
for i := len(ip) - 1; i >= 0; i-- {
- s := fmt.Sprintf("%02x", ip[i])
- buf.WriteByte(s[1])
- buf.WriteByte('.')
- buf.WriteByte(s[0])
- buf.WriteByte('.')
+ v := ip[i]
+ buf = append(buf, hexDigit[v&0xF])
+ buf = append(buf, '.')
+ buf = append(buf, hexDigit[v>>4])
+ buf = append(buf, '.')
}
// Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
+ buf = append(buf, "ip6.arpa."...)
+ return string(buf), nil
}
// Find answer for name in dns message.
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
index 97c5062..b6ebe11 100644
--- a/libgo/go/net/dnsmsg.go
+++ b/libgo/go/net/dnsmsg.go
@@ -7,11 +7,10 @@
// This is intended to support name resolution during Dial.
// It doesn't have to be blazing fast.
//
-// Rather than write the usual handful of routines to pack and
-// unpack every message that can appear on the wire, we use
-// reflection to write a generic pack/unpack for structs and then
-// use it. Thus, if in the future we need to define new message
-// structs, no new pack/unpack/printing code needs to be written.
+// Each message structure has a Walk method that is used by
+// a generic pack/unpack routine. Thus, if in the future we need
+// to define new message structs, no new pack/unpack/printing code
+// needs to be written.
//
// The first half of this file defines the DNS message formats.
// The second half implements the conversion to and from wire format.
@@ -23,12 +22,6 @@
package net
-import (
- "fmt"
- "os"
- "reflect"
-)
-
// Packet formats
// Wire constants.
@@ -75,6 +68,20 @@ const (
dnsRcodeRefused = 5
)
+// A dnsStruct describes how to iterate over its fields to emulate
+// reflective marshalling.
+type dnsStruct interface {
+ // Walk iterates over fields of a structure and calls f
+ // with a reference to that field, the name of the field
+ // and a tag ("", "domain", "ipv4", "ipv6") specifying
+ // particular encodings. Possible concrete types
+ // for v are *uint16, *uint32, *string, or []byte, and
+ // *int, *bool in the case of dnsMsgHdr.
+ // Whenever f returns false, Walk must stop and return
+ // false, and otherwise return true.
+ Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool)
+}
+
// The wire format for the DNS packet header.
type dnsHeader struct {
Id uint16
@@ -82,6 +89,15 @@ type dnsHeader struct {
Qdcount, Ancount, Nscount, Arcount uint16
}
+func (h *dnsHeader) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Id, "Id", "") &&
+ f(&h.Bits, "Bits", "") &&
+ f(&h.Qdcount, "Qdcount", "") &&
+ f(&h.Ancount, "Ancount", "") &&
+ f(&h.Nscount, "Nscount", "") &&
+ f(&h.Arcount, "Arcount", "")
+}
+
const (
// dnsHeader.Bits
_QR = 1 << 15 // query/response (response=1)
@@ -98,6 +114,12 @@ type dnsQuestion struct {
Qclass uint16
}
+func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&q.Name, "Name", "domain") &&
+ f(&q.Qtype, "Qtype", "") &&
+ f(&q.Qclass, "Qclass", "")
+}
+
// DNS responses (resource records).
// There are many types of messages,
// but they all share the same header.
@@ -113,7 +135,16 @@ func (h *dnsRR_Header) Header() *dnsRR_Header {
return h
}
+func (h *dnsRR_Header) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Name, "Name", "domain") &&
+ f(&h.Rrtype, "Rrtype", "") &&
+ f(&h.Class, "Class", "") &&
+ f(&h.Ttl, "Ttl", "") &&
+ f(&h.Rdlength, "Rdlength", "")
+}
+
type dnsRR interface {
+ dnsStruct
Header() *dnsRR_Header
}
@@ -128,6 +159,10 @@ func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
+}
+
type dnsRR_HINFO struct {
Hdr dnsRR_Header
Cpu string
@@ -138,6 +173,10 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
+}
+
type dnsRR_MB struct {
Hdr dnsRR_Header
Mb string `net:"domain-name"`
@@ -147,6 +186,10 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
+}
+
type dnsRR_MG struct {
Hdr dnsRR_Header
Mg string `net:"domain-name"`
@@ -156,6 +199,10 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
+}
+
type dnsRR_MINFO struct {
Hdr dnsRR_Header
Rmail string `net:"domain-name"`
@@ -166,6 +213,10 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
+}
+
type dnsRR_MR struct {
Hdr dnsRR_Header
Mr string `net:"domain-name"`
@@ -175,6 +226,10 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
+}
+
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
@@ -185,6 +240,10 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
+}
+
type dnsRR_NS struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -194,6 +253,10 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
+}
+
type dnsRR_PTR struct {
Hdr dnsRR_Header
Ptr string `net:"domain-name"`
@@ -203,6 +266,10 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
+}
+
type dnsRR_SOA struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -218,6 +285,17 @@ func (rr *dnsRR_SOA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Ns, "Ns", "domain") &&
+ f(&rr.Mbox, "Mbox", "domain") &&
+ f(&rr.Serial, "Serial", "") &&
+ f(&rr.Refresh, "Refresh", "") &&
+ f(&rr.Retry, "Retry", "") &&
+ f(&rr.Expire, "Expire", "") &&
+ f(&rr.Minttl, "Minttl", "")
+}
+
type dnsRR_TXT struct {
Hdr dnsRR_Header
Txt string // not domain name
@@ -227,6 +305,10 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
+}
+
type dnsRR_SRV struct {
Hdr dnsRR_Header
Priority uint16
@@ -239,6 +321,14 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Priority, "Priority", "") &&
+ f(&rr.Weight, "Weight", "") &&
+ f(&rr.Port, "Port", "") &&
+ f(&rr.Target, "Target", "domain")
+}
+
type dnsRR_A struct {
Hdr dnsRR_Header
A uint32 `net:"ipv4"`
@@ -248,6 +338,10 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
+}
+
type dnsRR_AAAA struct {
Hdr dnsRR_Header
AAAA [16]byte `net:"ipv6"`
@@ -257,6 +351,10 @@ func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
+}
+
// Packing and unpacking.
//
// All the packers and unpackers take a (msg []byte, off int)
@@ -386,134 +484,107 @@ Loop:
return s, off1, true
}
-// 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.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// packStruct packs a structure into msg at specified offset off, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = packStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
+ i := *fv
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- 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()
+ case *uint32:
+ i := *fv
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 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
+ copy(msg[off:off+n], fv)
off += n
- case reflect.String:
- // There are multiple string encodings.
- // The tag distinguishes ordinary strings from domain names.
- s := fv.String()
- switch f.Tag {
+ case *string:
+ s := *fv
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
off, ok = packDomainName(s, msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
// Counted string: 1 byte length.
if len(s) > 255 || off+1+len(s) > len(msg) {
- return len(msg), false
+ return false
}
msg[off] = byte(len(s))
off++
off += copy(msg[off:], s)
}
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func structValue(any interface{}) reflect.Value {
- return reflect.ValueOf(any).Elem()
-}
-
-func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = packStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// TODO(rsc): Move into generic library?
-// Unpack a reflect.StructValue from msg.
-// Same restrictions as packStructValue.
-func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// unpackStruct decodes msg[off:] into the given structure, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = unpackStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint16(msg[off])<<8 | uint16(msg[off+1])
- fv.SetUint(uint64(i))
+ *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
off += 2
- case reflect.Uint32:
+ case *uint32:
if off+4 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
- fv.SetUint(uint64(i))
+ *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
+ uint32(msg[off+2])<<8 | uint32(msg[off+3])
off += 4
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
+ copy(fv, msg[off:off+n])
off += n
- case reflect.String:
+ case *string:
var s string
- switch f.Tag {
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
s, off, ok = unpackDomainName(msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
- return len(msg), false
+ return false
}
n := int(msg[off])
off++
@@ -524,51 +595,77 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += n
s = string(b)
}
- fv.SetString(s)
+ *fv = s
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = unpackStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// Generic struct printer.
-// Doesn't care about the string tag `net:"domain-name"`,
-// but does look for an `net:"ipv4"` tag on uint32 variables
-// and the `net:"ipv6"` tag on array variables,
-// printing them as IP addresses.
-func printStructValue(val reflect.Value) string {
+// Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
+// as IP addresses.
+func printStruct(any dnsStruct) string {
s := "{"
- for i := 0; i < val.NumField(); i++ {
- if i > 0 {
+ i := 0
+ any.Walk(func(val interface{}, name, tag string) bool {
+ i++
+ if i > 1 {
s += ", "
}
- f := val.Type().Field(i)
- if !f.Anonymous {
- s += f.Name + "="
- }
- fval := val.Field(i)
- if fv := fval; fv.Kind() == reflect.Struct {
- s += printStructValue(fv)
- } 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 == `net:"ipv4"` {
- i := fv.Uint()
+ s += name + "="
+ switch tag {
+ case "ipv4":
+ i := val.(uint32)
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
- i := fv.Interface().([]byte)
+ case "ipv6":
+ i := val.([]byte)
s += IP(i).String()
- } else {
- s += fmt.Sprint(fval.Interface())
+ default:
+ var i int64
+ switch v := val.(type) {
+ default:
+ // can't really happen.
+ s += "<unknown type>"
+ return true
+ case *string:
+ s += *v
+ return true
+ case []byte:
+ s += string(v)
+ return true
+ case *bool:
+ if *v {
+ s += "true"
+ } else {
+ s += "false"
+ }
+ return true
+ case *int:
+ i = int64(*v)
+ case *uint:
+ i = int64(*v)
+ case *uint8:
+ i = int64(*v)
+ case *uint16:
+ i = int64(*v)
+ case *uint32:
+ i = int64(*v)
+ case *uint64:
+ i = int64(*v)
+ case *uintptr:
+ i = int64(*v)
+ }
+ s += itoa(int(i))
}
- }
+ return true
+ })
s += "}"
return s
}
-func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
-
// Resource record packer.
func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
var off1 int
@@ -627,6 +724,17 @@ type dnsMsgHdr struct {
rcode int
}
+func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.id, "id", "") &&
+ f(&h.response, "response", "") &&
+ f(&h.opcode, "opcode", "") &&
+ f(&h.authoritative, "authoritative", "") &&
+ f(&h.truncated, "truncated", "") &&
+ f(&h.recursion_desired, "recursion_desired", "") &&
+ f(&h.recursion_available, "recursion_available", "") &&
+ f(&h.rcode, "rcode", "")
+}
+
type dnsMsg struct {
dnsMsgHdr
question []dnsQuestion
diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go
index 06152a0..c39dbdb 100644
--- a/libgo/go/net/dnsmsg_test.go
+++ b/libgo/go/net/dnsmsg_test.go
@@ -6,6 +6,7 @@ package net
import (
"encoding/hex"
+ "reflect"
"testing"
)
@@ -19,6 +20,7 @@ func TestDNSParseSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -38,6 +40,16 @@ func TestDNSParseSRVReply(t *testing.T) {
t.Errorf("len(addrs) = %d; want %d", g, e)
t.Logf("addrs = %#v", addrs)
}
+ // repack and unpack.
+ data2, ok := msg.Pack()
+ msg2 := new(dnsMsg)
+ msg2.Unpack(data2)
+ switch {
+ case !ok:
+ t.Errorf("failed to repack message")
+ case !reflect.DeepEqual(msg, msg2):
+ t.Errorf("repacked message differs from original")
+ }
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
@@ -50,6 +62,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
index a1d62ac..085e423 100644
--- a/libgo/go/net/fd_linux.go
+++ b/libgo/go/net/fd_linux.go
@@ -84,7 +84,8 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
events, already := p.events[fd]
if !already {
- print("Epoll unexpected fd=", fd, "\n")
+ // The fd returned by the kernel may have been
+ // cancelled already; return silently.
return
}
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
index 868388e..95c0b66 100644
--- a/libgo/go/net/file_test.go
+++ b/libgo/go/net/file_test.go
@@ -27,7 +27,8 @@ type connFile interface {
}
func testFileListener(t *testing.T, net, laddr string) {
- if net == "tcp" {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
laddr += ":0" // any available port
}
l, err := Listen(net, laddr)
@@ -55,20 +56,52 @@ func testFileListener(t *testing.T, net, laddr string) {
}
}
+var fileListenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "tcp", laddr: ""},
+ {net: "tcp", laddr: "0.0.0.0"},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]"},
+ {net: "tcp", laddr: "[::]", ipv6: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: ""},
+ {net: "tcp4", laddr: "0.0.0.0"},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]"},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
+
+ {net: "unix", laddr: "@gotest/net", linux: true},
+ {net: "unixpacket", laddr: "@gotest/net", linux: true},
+}
+
func TestFileListener(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFileListener(t, "tcp", "127.0.0.1")
- testFileListener(t, "tcp", "127.0.0.1")
- if supportsIPv6 && supportsIPv4map {
- testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
- testFileListener(t, "tcp", "127.0.0.1")
- testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
- }
- if runtime.GOOS == "linux" {
- testFileListener(t, "unix", "@gotest/net")
- testFileListener(t, "unixpacket", "@gotest/net")
+
+ for _, tt := range fileListenerTests {
+ if skipServerTest(tt.net, "unix", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ if skipServerTest(tt.net, "unixpacket", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFileListener(t, tt.net, tt.laddr)
}
}
@@ -98,9 +131,13 @@ func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
}
func testFilePacketConnListen(t *testing.T, net, laddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ laddr += ":0" // any available port
+ }
l, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ t.Fatalf("ListenPacket failed: %v", err)
}
testFilePacketConn(t, l.(packetConnFile), true)
if err := l.Close(); err != nil {
@@ -109,6 +146,10 @@ func testFilePacketConnListen(t *testing.T, net, laddr string) {
}
func testFilePacketConnDial(t *testing.T, net, raddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ raddr += ":12345"
+ }
c, err := Dial(net, raddr)
if err != nil {
t.Fatalf("Dial failed: %v", err)
@@ -119,19 +160,42 @@ func testFilePacketConnDial(t *testing.T, net, raddr string) {
}
}
+var filePacketConnTests = []struct {
+ net string
+ addr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "udp", addr: "127.0.0.1"},
+ {net: "udp", addr: "[::ffff:127.0.0.1]"},
+ {net: "udp", addr: "[::1]", ipv6: true},
+
+ {net: "udp4", addr: "127.0.0.1"},
+ {net: "udp4", addr: "[::ffff:127.0.0.1]"},
+
+ {net: "udp6", addr: "[::1]", ipv6: true},
+
+ {net: "unixgram", addr: "@gotest3/net", linux: true},
+}
+
func TestFilePacketConn(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFilePacketConnListen(t, "udp", "127.0.0.1:0")
- testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
- if supportsIPv6 {
- testFilePacketConnListen(t, "udp", "[::1]:0")
- }
- if supportsIPv6 && supportsIPv4map {
- testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
- }
- if runtime.GOOS == "linux" {
- testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+
+ for _, tt := range filePacketConnTests {
+ if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFilePacketConnListen(t, tt.net, tt.addr)
+ switch tt.addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ default:
+ if tt.net != "unixgram" {
+ testFilePacketConnDial(t, tt.net, tt.addr)
+ }
+ }
}
}
diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go
index aa0bf4b..e00b62e 100644
--- a/libgo/go/net/http/client_test.go
+++ b/libgo/go/net/http/client_test.go
@@ -238,9 +238,9 @@ func TestRedirects(t *testing.T) {
}
var expectedCookies = []*Cookie{
- &Cookie{Name: "ChocolateChip", Value: "tasty"},
- &Cookie{Name: "First", Value: "Hit"},
- &Cookie{Name: "Second", Value: "Hit"},
+ {Name: "ChocolateChip", Value: "tasty"},
+ {Name: "First", Value: "Hit"},
+ {Name: "Second", Value: "Hit"},
}
var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index 5277657..f5bc6eb 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -455,11 +455,13 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
// First line: GET /index.html HTTP/1.0
var s string
if s, err = tp.ReadLine(); err != nil {
+ return nil, err
+ }
+ defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
- return nil, err
- }
+ }()
var f []string
if f = strings.SplitN(s, " ", 3); len(f) < 3 {
diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go
index 7a3556d..6e00b9b 100644
--- a/libgo/go/net/http/request_test.go
+++ b/libgo/go/net/http/request_test.go
@@ -5,6 +5,7 @@
package http_test
import (
+ "bufio"
"bytes"
"fmt"
"io"
@@ -177,6 +178,24 @@ func TestRequestMultipartCallOrder(t *testing.T) {
}
}
+var readRequestErrorTests = []struct {
+ in string
+ err error
+}{
+ {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
+ {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
+ {"", io.EOF},
+}
+
+func TestReadRequestErrors(t *testing.T) {
+ for i, tt := range readRequestErrorTests {
+ _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err != tt.err {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index fa0df54..228ac40 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -601,7 +601,7 @@ func (c *conn) serve() {
// while they're still writing their
// request. Undefined behavior.
msg = "413 Request Entity Too Large"
- } else if err == io.ErrUnexpectedEOF {
+ } else if err == io.EOF {
break // Don't reply
} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
break // Don't reply
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index 09579f8..0249759 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -196,7 +196,7 @@ func (t *Transport) CloseIdleConnections() {
pconn.close()
}
}
- t.idleConn = nil
+ t.idleConn = make(map[string][]*persistConn)
}
//
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index cbb3884..a9e401d 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -698,6 +698,32 @@ func TestTransportPersistConnLeak(t *testing.T) {
}
}
+// This used to crash; http://golang.org/issue/3266
+func TestTransportIdleConnCrash(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ unblockCh := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ <-unblockCh
+ tr.CloseIdleConnections()
+ }))
+ defer ts.Close()
+
+ didreq := make(chan bool)
+ go func() {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ } else {
+ res.Body.Close() // returns idle conn
+ }
+ didreq <- true
+ }()
+ unblockCh <- true
+ <-didreq
+}
+
type fooProto struct{}
func (fooProto) RoundTrip(req *Request) (*Response, error) {
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index f25d046..ee23570 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -78,7 +78,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
return interfaceMulticastAddrTable(ifi.Index)
}
-// Interfaces returns a list of the systems's network interfaces.
+// Interfaces returns a list of the system's network interfaces.
func Interfaces() ([]Interface, error) {
return interfaceTable(0)
}
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index 15c2f37..8c9c304 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -7,7 +7,6 @@
package net
import (
- "fmt"
"os"
"syscall"
"unsafe"
@@ -194,7 +193,9 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr {
name = f[1]
case len(f[0]) == 8:
if ifi == nil || name == ifi.Name {
- fmt.Sscanf(f[0], "%08x", &b)
+ for i := 0; i+1 < len(f[0]); i += 2 {
+ b[i/2], _ = xtoi2(f[0][i:i+2], 0)
+ }
ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
ifmat = append(ifmat, ifma.toAddr())
}
@@ -218,10 +219,11 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
continue
}
if ifi == nil || f[1] == ifi.Name {
- fmt.Sscanf(f[2], "%32x", &b)
+ for i := 0; i+1 < len(f[2]); i += 2 {
+ b[i/2], _ = xtoi2(f[2][i:i+2], 0)
+ }
ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
ifmat = append(ifmat, ifma.toAddr())
-
}
}
return ifmat
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index 9caa869..6bbe67c 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.go
@@ -34,6 +34,13 @@ func (a *IPAddr) family() int {
return syscall.AF_INET6
}
+func (a *IPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0)
}
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index 4841057..ed31319 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -38,6 +38,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
continue
}
defer closesocket(s)
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
if err != nil {
continue
@@ -55,58 +56,75 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
// favoriteAddrFamily returns the appropriate address family to
// the given net, laddr, raddr and mode. At first it figures
// address family out from the net. If mode indicates "listen"
-// and laddr.(type).IP is nil, it assumes that the user wants to
-// make a passive connection with wildcard address family, both
-// INET and INET6, and wildcard address. Otherwise guess: if the
-// addresses are IPv4 then returns INET, or else returns INET6.
-func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) int {
+// and laddr is a wildcard, it assumes that the user wants to
+// make a passive connection with a wildcard address family, both
+// AF_INET and AF_INET6, and a wildcard address like following:
+//
+// 1. A wild-wild listen, "tcp" + ""
+// If the platform supports both IPv6 and IPv6 IPv4-mapping
+// capabilities, we assume that the user want to listen on
+// both IPv4 and IPv6 wildcard address over an AF_INET6
+// socket with IPV6_V6ONLY=0. Otherwise we prefer an IPv4
+// wildcard address listen over an AF_INET socket.
+//
+// 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
+// Same as 1.
+//
+// 3. A wild-ipv6wild listen, "tcp" + "[::]"
+// Almost same as 1 but we prefer an IPv6 wildcard address
+// listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
+// the platform supports IPv6 capability but not IPv6 IPv4-
+// mapping capability.
+//
+// 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
+// We use an IPv4 (AF_INET) wildcard address listen.
+//
+// 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
+// We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
+// listen.
+//
+// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
+// or else returns AF_INET6. It also returns a boolean value what
+// designates IPV6_V6ONLY option.
+//
+// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
+// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
switch net[len(net)-1] {
case '4':
- return syscall.AF_INET
+ return syscall.AF_INET, false
case '6':
- return syscall.AF_INET6
+ return syscall.AF_INET6, true
}
- if mode == "listen" {
- // Note that OpenBSD allows neither "net.inet6.ip6.v6only"
- // change nor IPPROTO_IPV6 level IPV6_V6ONLY socket option
- // setting.
- switch a := laddr.(type) {
- case *TCPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
- case *UDPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
- case *IPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
+ if mode == "listen" && laddr.isWildcard() {
+ if supportsIPv4map {
+ return syscall.AF_INET6, false
}
+ return laddr.family(), false
}
if (laddr == nil || laddr.family() == syscall.AF_INET) &&
(raddr == nil || raddr.family() == syscall.AF_INET) {
- return syscall.AF_INET
+ return syscall.AF_INET, false
}
- return syscall.AF_INET6
+ return syscall.AF_INET6, false
}
-// Internet sockets (TCP, UDP)
+// Internet sockets (TCP, UDP, IP)
-// A sockaddr represents a TCP or UDP network address that can
+// A sockaddr represents a TCP, UDP or IP network address that can
// be converted into a syscall.Sockaddr.
type sockaddr interface {
Addr
- sockaddr(family int) (syscall.Sockaddr, error)
family() int
+ isWildcard() bool
+ sockaddr(family int) (syscall.Sockaddr, error)
}
func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
var la, ra syscall.Sockaddr
- family := favoriteAddrFamily(net, laddr, raddr, mode)
+ family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
if laddr != nil {
if la, err = laddr.sockaddr(family); err != nil {
goto Error
@@ -117,7 +135,7 @@ func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode s
goto Error
}
}
- fd, err = socket(net, family, sotype, proto, la, ra, toAddr)
+ fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, toAddr)
if err != nil {
goto Error
}
@@ -152,7 +170,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
}
// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
- // which it refuses to do. Rewrite to the IPv6 all zeros.
+ // which it refuses to do. Rewrite to the IPv6 unspecified address.
if ip.Equal(IPv4zero) {
ip = IPv6zero
}
diff --git a/libgo/go/net/mac.go b/libgo/go/net/mac.go
index e0637d0..d616b1f 100644
--- a/libgo/go/net/mac.go
+++ b/libgo/go/net/mac.go
@@ -6,24 +6,26 @@
package net
-import (
- "bytes"
- "errors"
- "fmt"
-)
+import "errors"
+
+const hexDigit = "0123456789abcdef"
// A HardwareAddr represents a physical hardware address.
type HardwareAddr []byte
func (a HardwareAddr) String() string {
- var buf bytes.Buffer
+ if len(a) == 0 {
+ return ""
+ }
+ buf := make([]byte, 0, len(a)*3-1)
for i, b := range a {
if i > 0 {
- buf.WriteByte(':')
+ buf = append(buf, ':')
}
- fmt.Fprintf(&buf, "%02x", b)
+ buf = append(buf, hexDigit[b>>4])
+ buf = append(buf, hexDigit[b&0xF])
}
- return buf.String()
+ return string(buf)
}
// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
diff --git a/libgo/go/net/mac_test.go b/libgo/go/net/mac_test.go
index 3837e740..8f9dc66 100644
--- a/libgo/go/net/mac_test.go
+++ b/libgo/go/net/mac_test.go
@@ -43,12 +43,24 @@ func match(err error, s string) bool {
return err != nil && strings.Contains(err.Error(), s)
}
-func TestParseMAC(t *testing.T) {
- for _, tt := range mactests {
+func TestMACParseString(t *testing.T) {
+ for i, tt := range mactests {
out, err := ParseMAC(tt.in)
if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
tt.err)
}
+ if tt.err == "" {
+ // Verify that serialization works too, and that it round-trips.
+ s := out.String()
+ out2, err := ParseMAC(s)
+ if err != nil {
+ t.Errorf("%d. ParseMAC(%q) = %v", i, s, err)
+ continue
+ }
+ if !reflect.DeepEqual(out2, out) {
+ t.Errorf("%d. ParseMAC(%q) = %v, want %v", i, s, out2, out)
+ }
+ }
}
}
diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go
index bf22c71..0917bbe 100644
--- a/libgo/go/net/mail/message.go
+++ b/libgo/go/net/mail/message.go
@@ -394,8 +394,7 @@ func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
i := 1
for ; i < p.len() && isAtext((*p)[i], dot); i++ {
}
- // TODO(dsymonds): Remove the []byte() conversion here when 6g doesn't need it.
- atom, *p = string([]byte((*p)[:i])), (*p)[i:]
+ atom, *p = string((*p)[:i]), (*p)[i:]
return atom, nil
}
diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go
index 1d760c2..67261b1 100644
--- a/libgo/go/net/multicast_test.go
+++ b/libgo/go/net/multicast_test.go
@@ -47,9 +47,11 @@ var multicastListenerTests = []struct {
func TestMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "netbsd", "openbsd", "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
case "linux":
if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+ t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
return
}
}
@@ -86,7 +88,13 @@ func TestMulticastListener(t *testing.T) {
func TestSimpleMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
+ case "windows":
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test on windows to avoid firewall")
+ return
+ }
}
for _, tt := range multicastListenerTests {
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index bf242ff..9ebcdbe 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -54,6 +54,8 @@ type Addr interface {
}
// Conn is a generic stream-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
// Read can be made to time out and return a Error with Timeout() == true
@@ -66,6 +68,7 @@ type Conn interface {
Write(b []byte) (n int, err error)
// Close closes the connection.
+ // Any blocked Read or Write operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address.
@@ -89,11 +92,11 @@ type Conn interface {
// A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for Read calls.
+ // SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for Write calls.
+ // SetWriteDeadline sets the deadline for future Write calls.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
@@ -108,6 +111,8 @@ type Error interface {
}
// PacketConn is a generic packet-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
// ReadFrom reads a packet from the connection,
// copying the payload into b. It returns the number of
@@ -126,6 +131,7 @@ type PacketConn interface {
WriteTo(b []byte, addr Addr) (n int, err error)
// Close closes the connection.
+ // Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address.
@@ -135,13 +141,13 @@ type PacketConn interface {
// with the connection.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for all Read calls to return.
+ // SetReadDeadline sets the deadline for future Read calls.
// If the deadline is reached, Read will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for all Write calls to return.
+ // SetWriteDeadline sets the deadline for future Write calls.
// If the deadline is reached, Write will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Write will not time out.
@@ -151,11 +157,14 @@ type PacketConn interface {
}
// A Listener is a generic network listener for stream-oriented protocols.
+//
+// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (c Conn, err error)
// Close closes the listener.
+ // Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index c1a90de..fd145e1 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -13,6 +13,7 @@ import (
func TestShutdown(t *testing.T) {
if runtime.GOOS == "plan9" {
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
l, err := Listen("tcp", "127.0.0.1:0")
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
index dfbaba4..30fda45 100644
--- a/libgo/go/net/parse_test.go
+++ b/libgo/go/net/parse_test.go
@@ -13,7 +13,9 @@ import (
func TestReadLine(t *testing.T) {
// /etc/services file does not exist on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
filename := "/etc/services" // a nice big file
diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go
index f7abf21..db2da8e 100644
--- a/libgo/go/net/rpc/client.go
+++ b/libgo/go/net/rpc/client.go
@@ -36,7 +36,8 @@ type Call struct {
// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
-// with a single Client.
+// with a single Client, and a Client may be used by
+// multiple goroutines simultaneously.
type Client struct {
mutex sync.Mutex // protects pending, seq, request
sending sync.Mutex
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index b986216..158b947 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -9,234 +9,461 @@ import (
"io"
"os"
"runtime"
- "strings"
"testing"
"time"
)
-// Do not test empty datagrams by default.
-// It causes unexplained timeouts on some systems,
-// including Snow Leopard. I think that the kernel
-// doesn't quite expect them.
-var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+ switch runtime.GOOS {
+ case "linux":
+ case "plan9", "windows":
+ // "unix" sockets are not supported on Windows and Plan 9.
+ if net == unixsotype {
+ return true
+ }
+ default:
+ if net == unixsotype && linuxonly {
+ return true
+ }
+ }
+ switch addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ if testing.Short() || !*testExternal {
+ return true
+ }
+ }
+ if ipv6 && !supportsIPv6 {
+ return true
+ }
+ if ipv4map && !supportsIPv4map {
+ return true
+ }
+ return false
+}
-func runEcho(fd io.ReadWriter, done chan<- int) {
- var buf [1024]byte
+var streamConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "[::1]", ipv6: true},
- for {
- n, err := fd.Read(buf[0:])
- if err != nil || n == 0 || string(buf[:n]) == "END" {
- break
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "127.0.0.1", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:127.0.0.1]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::1]", cnet: "tcp", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp4", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp6", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+ {snet: "tcp6", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+ {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+}
+
+func TestStreamConnServer(t *testing.T) {
+ for _, tt := range streamConnServerTests {
+ if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "tcp", "tcp4", "tcp6":
+ tt.saddr += ":0"
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "tcp", "tcp4", "tcp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ }
+
+ runStreamConnClient(t, tt.cnet, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+ }
+}
+
+var seqpacketConnServerTests = []struct {
+ net string
+ saddr string // server address
+ caddr string // client address
+ empty bool // test with empty data
+}{
+ {net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+ {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+}
+
+func TestSeqpacketConnServer(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range seqpacketConnServerTests {
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ runStreamConnClient(t, tt.net, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
}
- fd.Write(buf[0:n])
}
- done <- 1
}
-func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- l, err := Listen(network, addr)
+func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ l, err := Listen(net, laddr)
if err != nil {
- t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer l.Close()
listening <- l.Addr().String()
+ echo := func(rw io.ReadWriter, done chan<- int) {
+ buf := make([]byte, 1024)
+ for {
+ n, err := rw.Read(buf[0:])
+ if err != nil || n == 0 || string(buf[:n]) == "END" {
+ break
+ }
+ rw.Write(buf[0:n])
+ }
+ done <- 1
+ }
+
+run:
for {
- fd, err := l.Accept()
+ c, err := l.Accept()
if err != nil {
- break
+ continue run
}
echodone := make(chan int)
- go runEcho(fd, echodone)
- <-echodone // make sure Echo stops
- l.Close()
+ go echo(c, echodone)
+ <-echodone // make sure echo stopped
+ c.Close()
+ break run
}
done <- 1
}
-func connect(t *testing.T, network, addr string, isEmpty bool) {
- var fd Conn
- var err error
- if network == "unixgram" {
- fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
- } else {
- fd, err = Dial(network, addr)
- }
+func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
+ c, err := Dial(net, taddr)
if err != nil {
- t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
}
- fd.SetReadDeadline(time.Now().Add(1 * time.Second))
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
- var b []byte
+ var wb []byte
if !isEmpty {
- b = []byte("hello, world\n")
+ wb = []byte("StreamConnClient by Dial\n")
}
- var b1 [100]byte
-
- n, err1 := fd.Write(b)
- if n != len(b) {
- t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+ if n, err := c.Write(wb); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
- n, err1 = fd.Read(b1[0:])
- if n != len(b) || err1 != nil {
- t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
// Send explicit ending for unixpacket.
// Older Linux kernels do not stop reads on close.
- if network == "unixpacket" {
- fd.Write([]byte("END"))
+ switch net {
+ case "unixpacket":
+ c.Write([]byte("END"))
}
-
- fd.Close()
}
-func doTest(t *testing.T, network, listenaddr, dialaddr string) {
- t.Logf("Test %q %q %q", network, listenaddr, dialaddr)
- switch listenaddr {
- case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
- if testing.Short() || !*testExternal {
- t.Logf("skip wildcard listen during short test")
- return
- }
- }
- listening := make(chan string)
- done := make(chan int)
- if network == "tcp" || network == "tcp4" || network == "tcp6" {
- listenaddr += ":0" // any available port
- }
- go runServe(t, network, listenaddr, listening, done)
- addr := <-listening // wait for server to start
- if network == "tcp" || network == "tcp4" || network == "tcp6" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, false)
- <-done // make sure server stopped
-}
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard. I think that the kernel
+// doesn't quite expect them.
+var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
-func TestTCPServer(t *testing.T) {
- doTest(t, "tcp", "", "127.0.0.1")
- doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
- doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
- doTest(t, "tcp4", "", "127.0.0.1")
- doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
- doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
- if supportsIPv6 {
- doTest(t, "tcp", "[::]", "[::1]")
- doTest(t, "tcp", "[::1]", "[::1]")
- doTest(t, "tcp6", "", "[::1]")
- doTest(t, "tcp6", "[::]", "[::1]")
- doTest(t, "tcp6", "[::1]", "[::1]")
- }
- if supportsIPv6 && supportsIPv4map {
- doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp", "[::]", "127.0.0.1")
- doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp6", "", "127.0.0.1")
- doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp6", "[::]", "127.0.0.1")
- doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
- doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
- doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
- }
+var datagramPacketConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ dial bool // test with Dial or DialUnix
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:127.0.0.1]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp4", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
+ {snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", empty: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
+
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
}
-func TestUnixServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func TestDatagramPacketConnServer(t *testing.T) {
+ if !*testDatagram {
return
}
- os.Remove("/tmp/gotest.net")
- doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- if runtime.GOOS == "linux" {
- doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- // Test abstract unix domain socket, a Linux-ism
- doTest(t, "unix", "@gotest/net", "@gotest/net")
- doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
+
+ for _, tt := range datagramPacketConnServerTests {
+ if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "udp", "udp4", "udp6":
+ tt.saddr += ":0"
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "udp", "udp4", "udp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ tt.caddr += ":0"
+ }
+ if tt.dial {
+ runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ } else {
+ runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ }
+ <-done // tell server to stop
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
}
}
-func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- c, err := ListenPacket(network, addr)
+func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ c, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer c.Close()
listening <- c.LocalAddr().String()
- var buf [1000]byte
-Run:
+
+ buf := make([]byte, 1024)
+run:
for {
c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
- n, addr, err := c.ReadFrom(buf[0:])
- if e, ok := err.(Error); ok && e.Timeout() {
+ n, ra, err := c.ReadFrom(buf[0:])
+ if nerr, ok := err.(Error); ok && nerr.Timeout() {
select {
case done <- 1:
- break Run
+ break run
default:
- continue Run
+ continue run
}
}
if err != nil {
- break
+ break run
}
- if _, err = c.WriteTo(buf[0:n], addr); err != nil {
- t.Fatalf("WriteTo %v: %v", addr, err)
+ if _, err = c.WriteTo(buf[0:n], ra); err != nil {
+ t.Errorf("WriteTo(%v) failed: %v", ra, err)
+ break run
}
}
- c.Close()
done <- 1
}
-func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
- t.Logf("TestPacket %q %q %q", network, listenaddr, dialaddr)
- listening := make(chan string)
- done := make(chan int)
- if network == "udp" {
- listenaddr += ":0" // any available port
- }
- go runPacket(t, network, listenaddr, listening, done)
- addr := <-listening // wait for server to start
- if network == "udp" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, isEmpty)
- <-done // tell server to stop
- <-done // wait for stop
-}
+func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var c Conn
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ c, err = Dial(net, taddr)
+ if err != nil {
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ c, err = DialUnix(net, &UnixAddr{laddr, net}, &UnixAddr{taddr, net})
+ if err != nil {
+ t.Errorf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
+ return
+ }
+ }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
-func TestUDPServer(t *testing.T) {
- if !*testUDP {
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramConnClient by Dial\n")
+ }
+ if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
return
}
- for _, isEmpty := range []bool{false, true} {
- doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
- doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
- if supportsIPv6 && supportsIPv4map {
- doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
- doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
- doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
- }
+
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
-func TestUnixDatagramServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var ra Addr
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ ra, err = ResolveUDPAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ ra, err = ResolveUnixAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ }
+ c, err := ListenPacket(net, laddr)
+ if err != nil {
+ t.Errorf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
return
}
- for _, isEmpty := range []bool{false} {
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- if runtime.GOOS == "linux" {
- // Test abstract unix domain socket, a Linux-ism
- doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
- }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
+
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramPacketConnClient by ListenPacket\n")
+ }
+ if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
+ t.Errorf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
+ return
+ }
+
+ rb := make([]byte, 1024)
+ if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index dc139f0..3ae1605 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -16,7 +16,7 @@ import (
var listenerBacklog = maxListenerBacklog()
// Generic socket creation.
-func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
+func socket(net string, f, t, p int, ipv6only bool, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
s, err := syscall.Socket(f, t, p)
@@ -27,7 +27,7 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
- err = setDefaultSockopts(s, f, t)
+ err = setDefaultSockopts(s, f, t, ipv6only)
if err != nil {
closesocket(s)
return nil, err
diff --git a/libgo/go/net/sockopt.go b/libgo/go/net/sockopt.go
index 0a051d7..0cd1926 100644
--- a/libgo/go/net/sockopt.go
+++ b/libgo/go/net/sockopt.go
@@ -9,7 +9,6 @@
package net
import (
- "bytes"
"os"
"syscall"
"time"
@@ -98,7 +97,7 @@ func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error {
}
}
done:
- if bytes.Equal(mreq.Multiaddr[:], IPv4zero.To4()) {
+ if bytesEqual(mreq.Multiaddr[:], IPv4zero.To4()) {
return errNoSuchMulticastInterface
}
return nil
diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go
index 79e0e57..fff65f3 100644
--- a/libgo/go/net/sockopt_bsd.go
+++ b/libgo/go/net/sockopt_bsd.go
@@ -13,12 +13,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s, f, t int) error {
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/libgo/go/net/sockopt_linux.go b/libgo/go/net/sockopt_linux.go
index 7509c29..0f47538 100644
--- a/libgo/go/net/sockopt_linux.go
+++ b/libgo/go/net/sockopt_linux.go
@@ -11,12 +11,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s, f, t int) error {
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/libgo/go/net/sockopt_windows.go b/libgo/go/net/sockopt_windows.go
index b18af67..509b596 100644
--- a/libgo/go/net/sockopt_windows.go
+++ b/libgo/go/net/sockopt_windows.go
@@ -11,12 +11,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s syscall.Handle, f, t int) error {
+func setDefaultSockopts(s syscall.Handle, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index e05bc10..15f8efd 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -9,7 +9,6 @@
package net
import (
- "fmt"
"io"
"os"
"syscall"
@@ -30,7 +29,7 @@ func sockaddrToTCP(sa syscall.Sockaddr) Addr {
default:
if sa != nil {
// Diagnose when we will turn a non-nil sockaddr into a nil.
- panic(fmt.Sprintf("unexpected type in sockaddrToTCP: %T", sa))
+ panic("unexpected type in sockaddrToTCP")
}
}
return nil
@@ -46,6 +45,13 @@ func (a *TCPAddr) family() int {
return syscall.AF_INET6
}
+func (a *TCPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index ef350f0..672fb72 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -11,13 +11,13 @@ import (
"time"
)
-func testTimeout(t *testing.T, network, addr string, readFrom bool) {
- fd, err := Dial(network, addr)
+func testTimeout(t *testing.T, net, addr string, readFrom bool) {
+ c, err := Dial(net, addr)
if err != nil {
- t.Errorf("dial %s %s failed: %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
return
}
- defer fd.Close()
+ defer c.Close()
what := "Read"
if readFrom {
what = "ReadFrom"
@@ -26,22 +26,22 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
errc := make(chan error, 1)
go func() {
t0 := time.Now()
- fd.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+ c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
var b [100]byte
var n int
- var err1 error
+ var err error
if readFrom {
- n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
+ n, _, err = c.(PacketConn).ReadFrom(b[0:])
} else {
- n, err1 = fd.Read(b[0:])
+ n, err = c.Read(b[0:])
}
t1 := time.Now()
- if n != 0 || err1 == nil || !err1.(Error).Timeout() {
- errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
+ if n != 0 || err == nil || !err.(Error).Timeout() {
+ errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
return
}
if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
- errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
+ errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
return
}
errc <- nil
@@ -52,26 +52,39 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
t.Error(err)
}
case <-time.After(1 * time.Second):
- t.Errorf("%s on %s %s took over 1 second, expected 0.1s", what, network, addr)
+ t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
}
}
func TestTimeoutUDP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testTimeout(t, "udp", "127.0.0.1:53", false)
- testTimeout(t, "udp", "127.0.0.1:53", true)
+
+ // set up a listener that won't talk back
+ listening := make(chan string)
+ done := make(chan int)
+ go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
+ addr := <-listening
+
+ testTimeout(t, "udp", addr, false)
+ testTimeout(t, "udp", addr, true)
+ <-done
}
func TestTimeoutTCP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
+
// set up a listener that won't talk back
listening := make(chan string)
done := make(chan int)
- go runServe(t, "tcp", "127.0.0.1:0", listening, done)
+ go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
addr := <-listening
testTimeout(t, "tcp", addr, false)
@@ -79,7 +92,9 @@ func TestTimeoutTCP(t *testing.T) {
}
func TestDeadlineReset(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
ln, err := Listen("tcp", "127.0.0.1:0")
diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go
index ea5fad4..f80d3b5 100644
--- a/libgo/go/net/udp_test.go
+++ b/libgo/go/net/udp_test.go
@@ -10,7 +10,9 @@ import (
)
func TestWriteToUDP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index 1f99dc5..9e820e1 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.go
@@ -37,6 +37,13 @@ func (a *UDPAddr) family() int {
return syscall.AF_INET6
}
+func (a *UDPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
diff --git a/libgo/go/net/unicast_test.go b/libgo/go/net/unicast_test.go
index 297276d..a23bc5a 100644
--- a/libgo/go/net/unicast_test.go
+++ b/libgo/go/net/unicast_test.go
@@ -7,81 +7,481 @@ package net
import (
"io"
"runtime"
+ "syscall"
"testing"
)
-var unicastTests = []struct {
- net string
- laddr string
- ipv6 bool
- packet bool
+var listenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ wildcard bool // test with wildcard address
}{
- {net: "tcp4", laddr: "127.0.0.1:0"},
- {net: "tcp4", laddr: "previous"},
- {net: "tcp6", laddr: "[::1]:0", ipv6: true},
- {net: "tcp6", laddr: "previous", ipv6: true},
- {net: "udp4", laddr: "127.0.0.1:0", packet: true},
- {net: "udp6", laddr: "[::1]:0", ipv6: true, packet: true},
+ {net: "tcp", laddr: "", wildcard: true},
+ {net: "tcp", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+ {net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: "", wildcard: true},
+ {net: "tcp4", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true, wildcard: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
}
-func TestUnicastTCPAndUDP(t *testing.T) {
- if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- prevladdr := ""
- for _, tt := range unicastTests {
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
if tt.ipv6 && !supportsIPv6 {
continue
}
- var (
- fd *netFD
- closer io.Closer
- )
- if !tt.packet {
- if tt.laddr == "previous" {
- tt.laddr = prevladdr
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*TCPListener).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.(io.Closer).Close()
+ }
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 && !supportsIPv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*UDPConn).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.(io.Closer).Close()
+ }
+}
+
+func TestSimpleTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.(io.Closer).Close()
+ }
+}
+
+func TestSimpleUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.(io.Closer).Close()
+ }
+}
+
+var dualStackListenerTests = []struct {
+ net1 string // first listener
+ laddr1 string
+ net2 string // second listener
+ laddr2 string
+ wildcard bool // test with wildcard address
+ xerr error // expected error value, nil or other
+}{
+ // Test cases and expected results for the attemping 2nd listen on the same port
+ // 1st listen 2nd listen darwin freebsd linux openbsd
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "" - - - -
+ // "tcp" "" "tcp" "0.0.0.0" - - - -
+ // "tcp" "0.0.0.0" "tcp" "" - - - -
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "" - - - ok
+ // "tcp" "0.0.0.0" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "0.0.0.0" - - - ok
+ // "tcp" "[::ffff:0.0.0.0]" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "[::ffff:0.0.0.0]" - - - ok
+ // ------------------------------------------------------------------------------------
+ // "tcp4" "" "tcp6" "" ok ok ok ok
+ // "tcp6" "" "tcp4" "" ok ok ok ok
+ // "tcp4" "0.0.0.0" "tcp6" "[::]" ok ok ok ok
+ // "tcp6" "[::]" "tcp4" "0.0.0.0" ok ok ok ok
+ // ------------------------------------------------------------------------------------
+ // "tcp" "127.0.0.1" "tcp" "[::1]" ok ok ok ok
+ // "tcp" "[::1]" "tcp" "127.0.0.1" ok ok ok ok
+ // "tcp4" "127.0.0.1" "tcp6" "[::1]" ok ok ok ok
+ // "tcp6" "[::1]" "tcp4" "127.0.0.1" ok ok ok ok
+ //
+ // Platform default configurations:
+ // darwin, kernel version 11.3.0
+ // net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // freebsd, kernel version 8.2
+ // net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+ // linux, kernel version 3.0.0
+ // net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // openbsd, kernel version 5.0
+ // net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
+ {net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
+ {net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
+ {net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
+
+ {net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
+ {net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
+ {net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
+ {net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
+ }
+ }
+ l1, port := usableListenPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := Listen(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ tt.net1 = toudpnet(tt.net1)
+ tt.net2 = toudpnet(tt.net2)
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
}
- l, err := Listen(tt.net, tt.laddr)
- if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ }
+ l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := ListenPacket(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPort net=" + net)
+ case "tcp", "tcp4", "tcp6":
+ l, err = Listen(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*TCPListener).Addr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPacketPort net=" + net)
+ case "udp", "udp4", "udp6":
+ l, err = ListenPacket(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*UDPConn).LocalAddr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func differentWildcardAddr(i, j string) bool {
+ if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+ return false
+ }
+ if i == "[::]" && j == "[::]" {
+ return false
+ }
+ return true
+}
+
+func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
+ switch net {
+ case "tcp":
+ fd := l.(*TCPListener).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "tcp4":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "tcp6":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ case "udp":
+ fd := l.(*UDPConn).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "udp4":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "udp6":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if err == nil {
+ l.(*TCPListener).Close()
+ t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
+ }
+ case "udp", "udp4", "udp6":
+ if err == nil {
+ l.(*UDPConn).Close()
+ t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*TCPListener).Close()
+ case "udp", "udp4", "udp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*UDPConn).Close()
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
+ switch a := fd.laddr.(type) {
+ case *TCPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
}
- prevladdr = l.Addr().String()
- closer = l
- fd = l.(*TCPListener).fd
} else {
- c, err := ListenPacket(tt.net, tt.laddr)
- if err != nil {
- t.Fatalf("ListenPacket failed: %v", err)
+ if fd.family != a.family() {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
}
- closer = c
- fd = c.(*UDPConn).fd
}
- if !tt.ipv6 {
- testIPv4UnicastSocketOptions(t, fd)
+ case *UDPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
} else {
- testIPv6UnicastSocketOptions(t, fd)
+ if fd.family != a.family() {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+ }
}
- closer.Close()
+ default:
+ t.Fatalf("Unexpected protocol address type: %T", a)
}
}
func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
- tos, err := ipv4TOS(fd)
+ _, err := ipv4TOS(fd)
if err != nil {
t.Fatalf("ipv4TOS failed: %v", err)
}
- t.Logf("IPv4 TOS: %v", tos)
err = setIPv4TOS(fd, 1)
if err != nil {
t.Fatalf("setIPv4TOS failed: %v", err)
}
-
- ttl, err := ipv4TTL(fd)
+ _, err = ipv4TTL(fd)
if err != nil {
t.Fatalf("ipv4TTL failed: %v", err)
}
- t.Logf("IPv4 TTL: %v", ttl)
err = setIPv4TTL(fd, 1)
if err != nil {
t.Fatalf("setIPv4TTL failed: %v", err)
@@ -89,23 +489,50 @@ func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
}
func testIPv6UnicastSocketOptions(t *testing.T, fd *netFD) {
- tos, err := ipv6TrafficClass(fd)
+ _, err := ipv6TrafficClass(fd)
if err != nil {
t.Fatalf("ipv6TrafficClass failed: %v", err)
}
- t.Logf("IPv6 TrafficClass: %v", tos)
err = setIPv6TrafficClass(fd, 1)
if err != nil {
t.Fatalf("setIPv6TrafficClass failed: %v", err)
}
-
- hoplim, err := ipv6HopLimit(fd)
+ _, err = ipv6HopLimit(fd)
if err != nil {
t.Fatalf("ipv6HopLimit failed: %v", err)
}
- t.Logf("IPv6 HopLimit: %v", hoplim)
err = setIPv6HopLimit(fd, 1)
if err != nil {
t.Fatalf("setIPv6HopLimit failed: %v", err)
}
}
+
+var prohibitionaryDialArgTests = []struct {
+ net string
+ addr string
+}{
+ {"tcp6", "127.0.0.1"},
+ {"tcp6", "[::ffff:127.0.0.1]"},
+}
+
+func TestProhibitionaryDialArgs(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ // This test requires both IPv6 and IPv6 IPv4-mapping functionality.
+ if !supportsIPv4map || testing.Short() || !*testExternal {
+ return
+ }
+
+ l, port := usableListenPort(t, "tcp", "[::]")
+ defer l.Close()
+
+ for _, tt := range prohibitionaryDialArgTests {
+ _, err := Dial(tt.net, tt.addr+":"+port)
+ if err == nil {
+ t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
+ }
+ }
+}
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index 3a94cf5..37a2b1e 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -59,7 +59,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
f = sockaddrToUnixpacket
}
- fd, err = socket(net, syscall.AF_UNIX, sotype, 0, la, ra, f)
+ fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, f)
if err != nil {
goto Error
}
@@ -208,8 +208,8 @@ func (c *UnixConn) SetWriteBuffer(bytes int) error {
}
// ReadFromUnix reads a packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
+// It returns the number of bytes copied into b and the source address
+// of the packet.
//
// ReadFromUnix can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
@@ -264,6 +264,11 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
return c.WriteToUnix(b, a)
}
+// ReadMsgUnix reads a packet from c, copying the payload into b
+// and the associated out-of-band data into oob.
+// It returns the number of bytes copied into b, the number of
+// bytes copied into oob, the flags that were set on the packet,
+// and the source address of the packet.
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
@@ -276,6 +281,9 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
return
}
+// WriteMsgUnix writes a packet to addr via c, copying the payload from b
+// and the associated out-of-band data from oob. It returns the number
+// of payload and out-of-band bytes written.
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if !c.ok() {
return 0, 0, syscall.EINVAL