2012-08-20 11:27:52 -06:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
2013-08-06 04:40:10 -06:00
|
|
|
"io"
|
2012-11-27 14:36:05 -07:00
|
|
|
"reflect"
|
2012-08-20 11:27:52 -06:00
|
|
|
"runtime"
|
2013-08-04 13:31:23 -06:00
|
|
|
"sync"
|
2012-08-20 11:27:52 -06:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2013-03-02 19:25:49 -07:00
|
|
|
func BenchmarkTCP4OneShot(b *testing.B) {
|
|
|
|
benchmarkTCP(b, false, false, "127.0.0.1:0")
|
2012-08-20 11:27:52 -06:00
|
|
|
}
|
|
|
|
|
2013-03-02 19:25:49 -07:00
|
|
|
func BenchmarkTCP4OneShotTimeout(b *testing.B) {
|
|
|
|
benchmarkTCP(b, false, true, "127.0.0.1:0")
|
2012-08-20 11:27:52 -06:00
|
|
|
}
|
|
|
|
|
2013-03-02 19:25:49 -07:00
|
|
|
func BenchmarkTCP4Persistent(b *testing.B) {
|
|
|
|
benchmarkTCP(b, true, false, "127.0.0.1:0")
|
2012-08-20 11:27:52 -06:00
|
|
|
}
|
|
|
|
|
2013-03-02 19:25:49 -07:00
|
|
|
func BenchmarkTCP4PersistentTimeout(b *testing.B) {
|
|
|
|
benchmarkTCP(b, true, true, "127.0.0.1:0")
|
2012-08-20 11:27:52 -06:00
|
|
|
}
|
|
|
|
|
2013-03-02 19:25:49 -07:00
|
|
|
func BenchmarkTCP6OneShot(b *testing.B) {
|
|
|
|
if !supportsIPv6 {
|
|
|
|
b.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
benchmarkTCP(b, false, false, "[::1]:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTCP6OneShotTimeout(b *testing.B) {
|
|
|
|
if !supportsIPv6 {
|
|
|
|
b.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
benchmarkTCP(b, false, true, "[::1]:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTCP6Persistent(b *testing.B) {
|
|
|
|
if !supportsIPv6 {
|
|
|
|
b.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
benchmarkTCP(b, true, false, "[::1]:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTCP6PersistentTimeout(b *testing.B) {
|
|
|
|
if !supportsIPv6 {
|
|
|
|
b.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
benchmarkTCP(b, true, true, "[::1]:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
|
2015-03-31 21:21:15 -06:00
|
|
|
testHookUninstaller.Do(func() { uninstallTestHooks() })
|
net: add socket system call hooks for testing
This change adds socket system call hooks to existing test cases for
simulating a bit complicated network conditions to help making timeout
and dual IP stack test cases work more properly in followup changes.
Also test cases print debugging information in non-short mode like the
following:
Leaked goroutines:
net.TestWriteTimeout.func2(0xc20802a5a0, 0xc20801d000, 0x1000, 0x1000, 0xc2081d2ae0)
/go/src/net/timeout_test.go:170 +0x98
created by net.TestWriteTimeout
/go/src/net/timeout_test.go:173 +0x745
net.runDatagramPacketConnServer(0xc2080730e0, 0x2bd270, 0x3, 0x2c1770, 0xb, 0xc2081d2ba0, 0xc2081d2c00)
/go/src/net/server_test.go:398 +0x667
created by net.TestTimeoutUDP
/go/src/net/timeout_test.go:247 +0xc9
(snip)
Leaked sockets:
3: {Cookie:615726511685632 Err:<nil> SocketErr:0}
5: {Cookie:7934075906097152 Err:<nil> SocketErr:0}
Socket statistical information:
{Family:1 Type:805306370 Protocol:0 Opened:17 Accepted:0 Connected:5 Closed:17}
{Family:2 Type:805306369 Protocol:0 Opened:450 Accepted:234 Connected:279 Closed:636}
{Family:1 Type:805306369 Protocol:0 Opened:11 Accepted:5 Connected:5 Closed:16}
{Family:28 Type:805306369 Protocol:0 Opened:95 Accepted:22 Connected:16 Closed:116}
{Family:2 Type:805306370 Protocol:0 Opened:84 Accepted:0 Connected:34 Closed:83}
{Family:28 Type:805306370 Protocol:0 Opened:52 Accepted:0 Connected:4 Closed:52}
Change-Id: I0e84be59a0699bc31245c78e2249423459b8cdda
Reviewed-on: https://go-review.googlesource.com/6390
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-02-28 20:27:01 -07:00
|
|
|
|
2012-08-20 11:27:52 -06:00
|
|
|
const msgLen = 512
|
|
|
|
conns := b.N
|
2013-08-06 11:29:35 -06:00
|
|
|
numConcurrent := runtime.GOMAXPROCS(-1) * 2
|
2012-08-20 11:27:52 -06:00
|
|
|
msgs := 1
|
|
|
|
if persistent {
|
|
|
|
conns = numConcurrent
|
|
|
|
msgs = b.N / conns
|
|
|
|
if msgs == 0 {
|
|
|
|
msgs = 1
|
|
|
|
}
|
|
|
|
if conns > b.N {
|
|
|
|
conns = b.N
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sendMsg := func(c Conn, buf []byte) bool {
|
|
|
|
n, err := c.Write(buf)
|
|
|
|
if n != len(buf) || err != nil {
|
|
|
|
b.Logf("Write failed: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
recvMsg := func(c Conn, buf []byte) bool {
|
|
|
|
for read := 0; read != len(buf); {
|
|
|
|
n, err := c.Read(buf)
|
|
|
|
read += n
|
|
|
|
if err != nil {
|
|
|
|
b.Logf("Read failed: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2013-03-02 19:25:49 -07:00
|
|
|
ln, err := Listen("tcp", laddr)
|
2012-08-20 11:27:52 -06:00
|
|
|
if err != nil {
|
|
|
|
b.Fatalf("Listen failed: %v", err)
|
|
|
|
}
|
|
|
|
defer ln.Close()
|
2014-04-07 01:00:07 -06:00
|
|
|
serverSem := make(chan bool, numConcurrent)
|
2012-08-20 11:27:52 -06:00
|
|
|
// Acceptor.
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2014-04-07 01:00:07 -06:00
|
|
|
serverSem <- true
|
2012-08-20 11:27:52 -06:00
|
|
|
// Server connection.
|
|
|
|
go func(c Conn) {
|
2014-04-07 01:00:07 -06:00
|
|
|
defer func() {
|
|
|
|
c.Close()
|
|
|
|
<-serverSem
|
|
|
|
}()
|
2012-08-20 11:27:52 -06:00
|
|
|
if timeout {
|
|
|
|
c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
|
|
|
|
}
|
|
|
|
var buf [msgLen]byte
|
|
|
|
for m := 0; m < msgs; m++ {
|
|
|
|
if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(c)
|
|
|
|
}
|
|
|
|
}()
|
2014-04-07 01:00:07 -06:00
|
|
|
clientSem := make(chan bool, numConcurrent)
|
2012-08-20 11:27:52 -06:00
|
|
|
for i := 0; i < conns; i++ {
|
2014-04-07 01:00:07 -06:00
|
|
|
clientSem <- true
|
2012-08-20 11:27:52 -06:00
|
|
|
// Client connection.
|
|
|
|
go func() {
|
|
|
|
defer func() {
|
2014-04-07 01:00:07 -06:00
|
|
|
<-clientSem
|
2012-08-20 11:27:52 -06:00
|
|
|
}()
|
|
|
|
c, err := Dial("tcp", ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
b.Logf("Dial failed: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if timeout {
|
|
|
|
c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
|
|
|
|
}
|
|
|
|
var buf [msgLen]byte
|
|
|
|
for m := 0; m < msgs; m++ {
|
|
|
|
if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
2014-04-07 01:00:07 -06:00
|
|
|
for i := 0; i < numConcurrent; i++ {
|
|
|
|
clientSem <- true
|
|
|
|
serverSem <- true
|
2012-08-20 11:27:52 -06:00
|
|
|
}
|
|
|
|
}
|
2012-11-12 20:56:28 -07:00
|
|
|
|
2013-08-06 11:29:35 -06:00
|
|
|
func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
|
|
|
|
benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
|
|
|
|
if !supportsIPv6 {
|
|
|
|
b.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
|
2015-03-31 21:21:15 -06:00
|
|
|
testHookUninstaller.Do(func() { uninstallTestHooks() })
|
|
|
|
|
2013-08-06 11:29:35 -06:00
|
|
|
// The benchmark creates GOMAXPROCS client/server pairs.
|
|
|
|
// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
|
|
|
|
// The benchmark stresses concurrent reading and writing to the same connection.
|
|
|
|
// Such pattern is used in net/http and net/rpc.
|
|
|
|
|
|
|
|
b.StopTimer()
|
|
|
|
|
|
|
|
P := runtime.GOMAXPROCS(0)
|
|
|
|
N := b.N / P
|
|
|
|
W := 1000
|
|
|
|
|
|
|
|
// Setup P client/server connections.
|
|
|
|
clients := make([]Conn, P)
|
|
|
|
servers := make([]Conn, P)
|
|
|
|
ln, err := Listen("tcp", laddr)
|
|
|
|
if err != nil {
|
|
|
|
b.Fatalf("Listen failed: %v", err)
|
|
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
done := make(chan bool)
|
|
|
|
go func() {
|
|
|
|
for p := 0; p < P; p++ {
|
|
|
|
s, err := ln.Accept()
|
|
|
|
if err != nil {
|
2014-03-14 22:43:02 -06:00
|
|
|
b.Errorf("Accept failed: %v", err)
|
|
|
|
return
|
2013-08-06 11:29:35 -06:00
|
|
|
}
|
|
|
|
servers[p] = s
|
|
|
|
}
|
|
|
|
done <- true
|
|
|
|
}()
|
|
|
|
for p := 0; p < P; p++ {
|
|
|
|
c, err := Dial("tcp", ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
b.Fatalf("Dial failed: %v", err)
|
|
|
|
}
|
|
|
|
clients[p] = c
|
|
|
|
}
|
|
|
|
<-done
|
|
|
|
|
|
|
|
b.StartTimer()
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(4 * P)
|
|
|
|
for p := 0; p < P; p++ {
|
|
|
|
// Client writer.
|
|
|
|
go func(c Conn) {
|
|
|
|
defer wg.Done()
|
|
|
|
var buf [1]byte
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
v := byte(i)
|
|
|
|
for w := 0; w < W; w++ {
|
|
|
|
v *= v
|
|
|
|
}
|
|
|
|
buf[0] = v
|
|
|
|
_, err := c.Write(buf[:])
|
|
|
|
if err != nil {
|
2014-03-14 22:43:02 -06:00
|
|
|
b.Errorf("Write failed: %v", err)
|
|
|
|
return
|
2013-08-06 11:29:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}(clients[p])
|
|
|
|
|
|
|
|
// Pipe between server reader and server writer.
|
|
|
|
pipe := make(chan byte, 128)
|
|
|
|
|
|
|
|
// Server reader.
|
|
|
|
go func(s Conn) {
|
|
|
|
defer wg.Done()
|
|
|
|
var buf [1]byte
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
_, err := s.Read(buf[:])
|
|
|
|
if err != nil {
|
2014-03-14 22:43:02 -06:00
|
|
|
b.Errorf("Read failed: %v", err)
|
|
|
|
return
|
2013-08-06 11:29:35 -06:00
|
|
|
}
|
|
|
|
pipe <- buf[0]
|
|
|
|
}
|
|
|
|
}(servers[p])
|
|
|
|
|
|
|
|
// Server writer.
|
|
|
|
go func(s Conn) {
|
|
|
|
defer wg.Done()
|
|
|
|
var buf [1]byte
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
v := <-pipe
|
|
|
|
for w := 0; w < W; w++ {
|
|
|
|
v *= v
|
|
|
|
}
|
|
|
|
buf[0] = v
|
|
|
|
_, err := s.Write(buf[:])
|
|
|
|
if err != nil {
|
2014-03-14 22:43:02 -06:00
|
|
|
b.Errorf("Write failed: %v", err)
|
|
|
|
return
|
2013-08-06 11:29:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
s.Close()
|
|
|
|
}(servers[p])
|
|
|
|
|
|
|
|
// Client reader.
|
|
|
|
go func(c Conn) {
|
|
|
|
defer wg.Done()
|
|
|
|
var buf [1]byte
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
_, err := c.Read(buf[:])
|
|
|
|
if err != nil {
|
2014-03-14 22:43:02 -06:00
|
|
|
b.Errorf("Read failed: %v", err)
|
|
|
|
return
|
2013-08-06 11:29:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
c.Close()
|
|
|
|
}(clients[p])
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2013-03-26 10:06:48 -06:00
|
|
|
type resolveTCPAddrTest struct {
|
2015-04-05 02:00:14 -06:00
|
|
|
network string
|
2013-08-30 19:28:49 -06:00
|
|
|
litAddrOrName string
|
|
|
|
addr *TCPAddr
|
|
|
|
err error
|
2013-03-26 10:06:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
var resolveTCPAddrTests = []resolveTCPAddrTest{
|
2012-11-27 14:36:05 -07:00
|
|
|
{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
|
|
|
|
{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
|
|
|
|
|
2015-04-05 02:00:14 -06:00
|
|
|
{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
|
|
|
|
{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
|
2012-11-27 14:36:05 -07:00
|
|
|
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
|
|
|
|
{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
|
|
|
|
|
2012-11-30 22:49:54 -07:00
|
|
|
{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
|
|
|
|
{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
|
|
|
|
|
2013-09-23 20:40:24 -06:00
|
|
|
{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
|
|
|
|
|
2012-11-27 14:36:05 -07:00
|
|
|
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolveTCPAddr(t *testing.T) {
|
2015-04-05 02:00:14 -06:00
|
|
|
origTestHookLookupIP := testHookLookupIP
|
|
|
|
defer func() { testHookLookupIP = origTestHookLookupIP }()
|
|
|
|
testHookLookupIP = lookupLocalhost
|
|
|
|
|
|
|
|
for i, tt := range resolveTCPAddrTests {
|
|
|
|
addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
|
2012-11-27 14:36:05 -07:00
|
|
|
if err != tt.err {
|
2015-04-05 02:00:14 -06:00
|
|
|
t.Errorf("#%d: %v", i, err)
|
|
|
|
} else if !reflect.DeepEqual(addr, tt.addr) {
|
|
|
|
t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
|
2012-11-27 14:36:05 -07:00
|
|
|
}
|
2015-04-05 02:00:14 -06:00
|
|
|
if err != nil {
|
|
|
|
continue
|
2013-09-23 20:40:24 -06:00
|
|
|
}
|
2015-04-05 02:00:14 -06:00
|
|
|
rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("#%d: %v", i, err)
|
|
|
|
} else if !reflect.DeepEqual(rtaddr, addr) {
|
|
|
|
t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
|
2012-11-27 14:36:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-12 20:56:28 -07:00
|
|
|
var tcpListenerNameTests = []struct {
|
|
|
|
net string
|
|
|
|
laddr *TCPAddr
|
|
|
|
}{
|
|
|
|
{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
|
|
|
|
{"tcp4", &TCPAddr{}},
|
|
|
|
{"tcp4", nil},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTCPListenerName(t *testing.T) {
|
|
|
|
if testing.Short() || !*testExternal {
|
2013-01-23 23:32:10 -07:00
|
|
|
t.Skip("skipping test to avoid external network")
|
2012-11-12 20:56:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tcpListenerNameTests {
|
|
|
|
ln, err := ListenTCP(tt.net, tt.laddr)
|
|
|
|
if err != nil {
|
2013-03-23 07:32:19 -06:00
|
|
|
t.Fatalf("ListenTCP failed: %v", err)
|
2012-11-12 20:56:28 -07:00
|
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
la := ln.Addr()
|
|
|
|
if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
|
2013-03-23 07:32:19 -06:00
|
|
|
t.Fatalf("got %v; expected a proper address with non-zero port number", la)
|
2012-11-12 20:56:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
|
|
|
|
func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
|
|
|
|
if testing.Short() || !*testExternal {
|
|
|
|
t.Skip("skipping test to avoid external network")
|
|
|
|
}
|
|
|
|
if !supportsIPv6 {
|
|
|
|
t.Skip("ipv6 is not supported")
|
|
|
|
}
|
|
|
|
ifi := loopbackInterface()
|
|
|
|
if ifi == nil {
|
|
|
|
t.Skip("loopback interface not found")
|
|
|
|
}
|
|
|
|
laddr := ipv6LinkLocalUnicastAddr(ifi)
|
|
|
|
if laddr == "" {
|
|
|
|
t.Skip("ipv6 unicast address on loopback not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
type test struct {
|
|
|
|
net, addr string
|
|
|
|
nameLookup bool
|
|
|
|
}
|
|
|
|
var tests = []test{
|
|
|
|
{"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
|
|
|
|
{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
|
|
|
|
}
|
|
|
|
switch runtime.GOOS {
|
2014-04-27 18:39:13 -06:00
|
|
|
case "darwin", "freebsd", "openbsd", "netbsd":
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
tests = append(tests, []test{
|
|
|
|
{"tcp", "[localhost%" + ifi.Name + "]:0", true},
|
|
|
|
{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
|
|
|
|
}...)
|
|
|
|
case "linux":
|
|
|
|
tests = append(tests, []test{
|
|
|
|
{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
|
|
|
|
{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
|
|
|
|
}...)
|
|
|
|
}
|
2015-04-02 08:11:39 -06:00
|
|
|
handler := func(ls *localServer, ln Listener) { transponder(t, ln) }
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
for _, tt := range tests {
|
|
|
|
ln, err := Listen(tt.net, tt.addr)
|
|
|
|
if err != nil {
|
|
|
|
// It might return "LookupHost returned no
|
|
|
|
// suitable address" error on some platforms.
|
|
|
|
t.Logf("Listen failed: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
2015-04-02 08:11:39 -06:00
|
|
|
ls, err := (&streamListener{Listener: ln}).newLocalServer()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer ls.teardown()
|
|
|
|
if err := ls.buildup(handler); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
|
|
|
|
t.Fatalf("got %v; expected a proper address with zone identifier", la)
|
|
|
|
}
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
c, err := Dial(tt.net, ls.Listener.Addr().String())
|
net: support IPv6 scoped addressing zone
This CL provides IPv6 scoped addressing zone support as defined
in RFC 4007 for internet protocol family connection setups.
Follwoing types and functions allow a literal IPv6 address with
zone identifer as theirs parameter.
pkg net, func Dial(string, string) (Conn, error)
pkg net, func DialOpt(string, ...DialOption) (Conn, error)
pkg net, func DialTimeout(string, string, time.Duration) (Conn, error)
pkg net, func Listen(string, string) (Listener, error)
pkg net, func ListenPacket(string, string) (PacketConn, error)
pkg net, func ResolveIPAddr(string, string) (*IPAddr, error)
pkg net, func ResolveTCPAddr(string, string) (*TCPAddr, error)
pkg net, func ResolveUDPAddr(string, string) (*UDPAddr, error)
pkg net, type IPAddr struct, Zone string
pkg net, type TCPAddr struct, Zone string
pkg net, type UDPAddr struct, Zone string
Also follwoing methods return a literal IPv6 address with zone
identifier string if possible.
pkg net, method (*IPAddr) String() string
pkg net, method (*TCPAddr) String() string
pkg net, method (*UDPAddr) String() string
Fixes #4234.
Fixes #4501.
Update #5081.
R=rsc, iant
CC=golang-dev
https://golang.org/cl/6816116
2013-03-22 18:57:40 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Dial failed: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
|
|
|
|
t.Fatalf("got %v; expected a proper address with zone identifier", la)
|
|
|
|
}
|
|
|
|
if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
|
|
|
|
t.Fatalf("got %v; expected a proper address with zone identifier", ra)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
|
|
|
|
t.Fatalf("Conn.Write failed: %v", err)
|
|
|
|
}
|
|
|
|
b := make([]byte, 32)
|
|
|
|
if _, err := c.Read(b); err != nil {
|
|
|
|
t.Fatalf("Conn.Read failed: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-04 13:31:23 -06:00
|
|
|
|
|
|
|
func TestTCPConcurrentAccept(t *testing.T) {
|
|
|
|
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
|
|
|
|
ln, err := Listen("tcp", "127.0.0.1:0")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Listen failed: %v", err)
|
|
|
|
}
|
|
|
|
const N = 10
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(N)
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
c.Close()
|
|
|
|
}
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
}
|
2014-03-24 11:56:37 -06:00
|
|
|
attempts := 10 * N
|
|
|
|
fails := 0
|
|
|
|
d := &Dialer{Timeout: 200 * time.Millisecond}
|
|
|
|
for i := 0; i < attempts; i++ {
|
|
|
|
c, err := d.Dial("tcp", ln.Addr().String())
|
2013-08-04 13:31:23 -06:00
|
|
|
if err != nil {
|
2014-03-24 11:56:37 -06:00
|
|
|
fails++
|
|
|
|
} else {
|
|
|
|
c.Close()
|
2013-08-04 13:31:23 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ln.Close()
|
|
|
|
wg.Wait()
|
2014-03-24 11:56:37 -06:00
|
|
|
if fails > attempts/9 { // see issues 7400 and 7541
|
|
|
|
t.Fatalf("too many Dial failed: %v", fails)
|
|
|
|
}
|
|
|
|
if fails > 0 {
|
|
|
|
t.Logf("# of failed Dials: %v", fails)
|
|
|
|
}
|
2013-08-04 13:31:23 -06:00
|
|
|
}
|
2013-08-06 04:40:10 -06:00
|
|
|
|
2015-02-23 22:13:47 -07:00
|
|
|
func TestTCPReadWriteAllocs(t *testing.T) {
|
|
|
|
switch runtime.GOOS {
|
2015-03-27 03:19:17 -06:00
|
|
|
case "nacl", "windows":
|
2015-02-23 22:13:47 -07:00
|
|
|
// NaCl needs to allocate pseudo file descriptor
|
|
|
|
// stuff. See syscall/fd_nacl.go.
|
|
|
|
// Windows uses closures and channels for IO
|
|
|
|
// completion port-based netpoll. See fd_windows.go.
|
|
|
|
t.Skipf("not supported on %s", runtime.GOOS)
|
2013-08-20 22:00:45 -06:00
|
|
|
}
|
2015-02-23 22:13:47 -07:00
|
|
|
|
2013-08-06 04:40:10 -06:00
|
|
|
ln, err := Listen("tcp", "127.0.0.1:0")
|
|
|
|
if err != nil {
|
2015-02-23 22:13:47 -07:00
|
|
|
t.Fatal(err)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
var server Conn
|
|
|
|
errc := make(chan error)
|
|
|
|
go func() {
|
|
|
|
var err error
|
|
|
|
server, err = ln.Accept()
|
|
|
|
errc <- err
|
|
|
|
}()
|
|
|
|
client, err := Dial("tcp", ln.Addr().String())
|
|
|
|
if err != nil {
|
2015-02-23 22:13:47 -07:00
|
|
|
t.Fatal(err)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
2015-02-23 22:13:47 -07:00
|
|
|
defer client.Close()
|
2013-08-06 04:40:10 -06:00
|
|
|
if err := <-errc; err != nil {
|
2015-02-23 22:13:47 -07:00
|
|
|
t.Fatal(err)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
|
|
|
defer server.Close()
|
|
|
|
var buf [128]byte
|
2015-02-23 22:13:47 -07:00
|
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
2013-08-06 04:40:10 -06:00
|
|
|
_, err := server.Write(buf[:])
|
|
|
|
if err != nil {
|
2015-02-23 22:13:47 -07:00
|
|
|
t.Fatal(err)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
|
|
|
_, err = io.ReadFull(client, buf[:])
|
|
|
|
if err != nil {
|
2015-02-23 22:13:47 -07:00
|
|
|
t.Fatal(err)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
|
|
|
})
|
2015-02-23 22:13:47 -07:00
|
|
|
if allocs > 0 {
|
|
|
|
t.Fatalf("got %v; want 0", allocs)
|
2013-08-06 04:40:10 -06:00
|
|
|
}
|
|
|
|
}
|
2013-08-13 12:07:42 -06:00
|
|
|
|
|
|
|
func TestTCPStress(t *testing.T) {
|
|
|
|
const conns = 2
|
|
|
|
const msgLen = 512
|
2013-08-14 11:53:27 -06:00
|
|
|
msgs := int(1e4)
|
|
|
|
if testing.Short() {
|
|
|
|
msgs = 1e2
|
|
|
|
}
|
2013-08-13 12:07:42 -06:00
|
|
|
|
|
|
|
sendMsg := func(c Conn, buf []byte) bool {
|
|
|
|
n, err := c.Write(buf)
|
|
|
|
if n != len(buf) || err != nil {
|
|
|
|
t.Logf("Write failed: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
recvMsg := func(c Conn, buf []byte) bool {
|
|
|
|
for read := 0; read != len(buf); {
|
|
|
|
n, err := c.Read(buf)
|
|
|
|
read += n
|
|
|
|
if err != nil {
|
|
|
|
t.Logf("Read failed: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
ln, err := Listen("tcp", "127.0.0.1:0")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Listen failed: %v", err)
|
|
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
// Acceptor.
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// Server connection.
|
|
|
|
go func(c Conn) {
|
|
|
|
defer c.Close()
|
|
|
|
var buf [msgLen]byte
|
|
|
|
for m := 0; m < msgs; m++ {
|
|
|
|
if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(c)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
done := make(chan bool)
|
|
|
|
for i := 0; i < conns; i++ {
|
|
|
|
// Client connection.
|
|
|
|
go func() {
|
|
|
|
defer func() {
|
|
|
|
done <- true
|
|
|
|
}()
|
|
|
|
c, err := Dial("tcp", ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Logf("Dial failed: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
var buf [msgLen]byte
|
|
|
|
for m := 0; m < msgs; m++ {
|
|
|
|
if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for i := 0; i < conns; i++ {
|
|
|
|
<-done
|
|
|
|
}
|
|
|
|
}
|