Home | History | Annotate | Download | only in net
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package net
      6 
      7 import (
      8 	"io"
      9 	"reflect"
     10 	"runtime"
     11 	"sync"
     12 	"testing"
     13 	"time"
     14 )
     15 
     16 func BenchmarkTCP4OneShot(b *testing.B) {
     17 	benchmarkTCP(b, false, false, "127.0.0.1:0")
     18 }
     19 
     20 func BenchmarkTCP4OneShotTimeout(b *testing.B) {
     21 	benchmarkTCP(b, false, true, "127.0.0.1:0")
     22 }
     23 
     24 func BenchmarkTCP4Persistent(b *testing.B) {
     25 	benchmarkTCP(b, true, false, "127.0.0.1:0")
     26 }
     27 
     28 func BenchmarkTCP4PersistentTimeout(b *testing.B) {
     29 	benchmarkTCP(b, true, true, "127.0.0.1:0")
     30 }
     31 
     32 func BenchmarkTCP6OneShot(b *testing.B) {
     33 	if !supportsIPv6 {
     34 		b.Skip("ipv6 is not supported")
     35 	}
     36 	benchmarkTCP(b, false, false, "[::1]:0")
     37 }
     38 
     39 func BenchmarkTCP6OneShotTimeout(b *testing.B) {
     40 	if !supportsIPv6 {
     41 		b.Skip("ipv6 is not supported")
     42 	}
     43 	benchmarkTCP(b, false, true, "[::1]:0")
     44 }
     45 
     46 func BenchmarkTCP6Persistent(b *testing.B) {
     47 	if !supportsIPv6 {
     48 		b.Skip("ipv6 is not supported")
     49 	}
     50 	benchmarkTCP(b, true, false, "[::1]:0")
     51 }
     52 
     53 func BenchmarkTCP6PersistentTimeout(b *testing.B) {
     54 	if !supportsIPv6 {
     55 		b.Skip("ipv6 is not supported")
     56 	}
     57 	benchmarkTCP(b, true, true, "[::1]:0")
     58 }
     59 
     60 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
     61 	testHookUninstaller.Do(uninstallTestHooks)
     62 
     63 	const msgLen = 512
     64 	conns := b.N
     65 	numConcurrent := runtime.GOMAXPROCS(-1) * 2
     66 	msgs := 1
     67 	if persistent {
     68 		conns = numConcurrent
     69 		msgs = b.N / conns
     70 		if msgs == 0 {
     71 			msgs = 1
     72 		}
     73 		if conns > b.N {
     74 			conns = b.N
     75 		}
     76 	}
     77 	sendMsg := func(c Conn, buf []byte) bool {
     78 		n, err := c.Write(buf)
     79 		if n != len(buf) || err != nil {
     80 			b.Log(err)
     81 			return false
     82 		}
     83 		return true
     84 	}
     85 	recvMsg := func(c Conn, buf []byte) bool {
     86 		for read := 0; read != len(buf); {
     87 			n, err := c.Read(buf)
     88 			read += n
     89 			if err != nil {
     90 				b.Log(err)
     91 				return false
     92 			}
     93 		}
     94 		return true
     95 	}
     96 	ln, err := Listen("tcp", laddr)
     97 	if err != nil {
     98 		b.Fatal(err)
     99 	}
    100 	defer ln.Close()
    101 	serverSem := make(chan bool, numConcurrent)
    102 	// Acceptor.
    103 	go func() {
    104 		for {
    105 			c, err := ln.Accept()
    106 			if err != nil {
    107 				break
    108 			}
    109 			serverSem <- true
    110 			// Server connection.
    111 			go func(c Conn) {
    112 				defer func() {
    113 					c.Close()
    114 					<-serverSem
    115 				}()
    116 				if timeout {
    117 					c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
    118 				}
    119 				var buf [msgLen]byte
    120 				for m := 0; m < msgs; m++ {
    121 					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
    122 						break
    123 					}
    124 				}
    125 			}(c)
    126 		}
    127 	}()
    128 	clientSem := make(chan bool, numConcurrent)
    129 	for i := 0; i < conns; i++ {
    130 		clientSem <- true
    131 		// Client connection.
    132 		go func() {
    133 			defer func() {
    134 				<-clientSem
    135 			}()
    136 			c, err := Dial("tcp", ln.Addr().String())
    137 			if err != nil {
    138 				b.Log(err)
    139 				return
    140 			}
    141 			defer c.Close()
    142 			if timeout {
    143 				c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
    144 			}
    145 			var buf [msgLen]byte
    146 			for m := 0; m < msgs; m++ {
    147 				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
    148 					break
    149 				}
    150 			}
    151 		}()
    152 	}
    153 	for i := 0; i < numConcurrent; i++ {
    154 		clientSem <- true
    155 		serverSem <- true
    156 	}
    157 }
    158 
    159 func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
    160 	benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
    161 }
    162 
    163 func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
    164 	if !supportsIPv6 {
    165 		b.Skip("ipv6 is not supported")
    166 	}
    167 	benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
    168 }
    169 
    170 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
    171 	testHookUninstaller.Do(uninstallTestHooks)
    172 
    173 	// The benchmark creates GOMAXPROCS client/server pairs.
    174 	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
    175 	// The benchmark stresses concurrent reading and writing to the same connection.
    176 	// Such pattern is used in net/http and net/rpc.
    177 
    178 	b.StopTimer()
    179 
    180 	P := runtime.GOMAXPROCS(0)
    181 	N := b.N / P
    182 	W := 1000
    183 
    184 	// Setup P client/server connections.
    185 	clients := make([]Conn, P)
    186 	servers := make([]Conn, P)
    187 	ln, err := Listen("tcp", laddr)
    188 	if err != nil {
    189 		b.Fatal(err)
    190 	}
    191 	defer ln.Close()
    192 	done := make(chan bool)
    193 	go func() {
    194 		for p := 0; p < P; p++ {
    195 			s, err := ln.Accept()
    196 			if err != nil {
    197 				b.Error(err)
    198 				return
    199 			}
    200 			servers[p] = s
    201 		}
    202 		done <- true
    203 	}()
    204 	for p := 0; p < P; p++ {
    205 		c, err := Dial("tcp", ln.Addr().String())
    206 		if err != nil {
    207 			b.Fatal(err)
    208 		}
    209 		clients[p] = c
    210 	}
    211 	<-done
    212 
    213 	b.StartTimer()
    214 
    215 	var wg sync.WaitGroup
    216 	wg.Add(4 * P)
    217 	for p := 0; p < P; p++ {
    218 		// Client writer.
    219 		go func(c Conn) {
    220 			defer wg.Done()
    221 			var buf [1]byte
    222 			for i := 0; i < N; i++ {
    223 				v := byte(i)
    224 				for w := 0; w < W; w++ {
    225 					v *= v
    226 				}
    227 				buf[0] = v
    228 				_, err := c.Write(buf[:])
    229 				if err != nil {
    230 					b.Error(err)
    231 					return
    232 				}
    233 			}
    234 		}(clients[p])
    235 
    236 		// Pipe between server reader and server writer.
    237 		pipe := make(chan byte, 128)
    238 
    239 		// Server reader.
    240 		go func(s Conn) {
    241 			defer wg.Done()
    242 			var buf [1]byte
    243 			for i := 0; i < N; i++ {
    244 				_, err := s.Read(buf[:])
    245 				if err != nil {
    246 					b.Error(err)
    247 					return
    248 				}
    249 				pipe <- buf[0]
    250 			}
    251 		}(servers[p])
    252 
    253 		// Server writer.
    254 		go func(s Conn) {
    255 			defer wg.Done()
    256 			var buf [1]byte
    257 			for i := 0; i < N; i++ {
    258 				v := <-pipe
    259 				for w := 0; w < W; w++ {
    260 					v *= v
    261 				}
    262 				buf[0] = v
    263 				_, err := s.Write(buf[:])
    264 				if err != nil {
    265 					b.Error(err)
    266 					return
    267 				}
    268 			}
    269 			s.Close()
    270 		}(servers[p])
    271 
    272 		// Client reader.
    273 		go func(c Conn) {
    274 			defer wg.Done()
    275 			var buf [1]byte
    276 			for i := 0; i < N; i++ {
    277 				_, err := c.Read(buf[:])
    278 				if err != nil {
    279 					b.Error(err)
    280 					return
    281 				}
    282 			}
    283 			c.Close()
    284 		}(clients[p])
    285 	}
    286 	wg.Wait()
    287 }
    288 
    289 type resolveTCPAddrTest struct {
    290 	network       string
    291 	litAddrOrName string
    292 	addr          *TCPAddr
    293 	err           error
    294 }
    295 
    296 var resolveTCPAddrTests = []resolveTCPAddrTest{
    297 	{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
    298 	{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
    299 
    300 	{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
    301 	{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
    302 
    303 	{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
    304 	{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
    305 
    306 	{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
    307 	{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
    308 
    309 	{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
    310 
    311 	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
    312 }
    313 
    314 func TestResolveTCPAddr(t *testing.T) {
    315 	origTestHookLookupIP := testHookLookupIP
    316 	defer func() { testHookLookupIP = origTestHookLookupIP }()
    317 	testHookLookupIP = lookupLocalhost
    318 
    319 	for i, tt := range resolveTCPAddrTests {
    320 		addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
    321 		if err != tt.err {
    322 			t.Errorf("#%d: %v", i, err)
    323 		} else if !reflect.DeepEqual(addr, tt.addr) {
    324 			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
    325 		}
    326 		if err != nil {
    327 			continue
    328 		}
    329 		rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
    330 		if err != nil {
    331 			t.Errorf("#%d: %v", i, err)
    332 		} else if !reflect.DeepEqual(rtaddr, addr) {
    333 			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
    334 		}
    335 	}
    336 }
    337 
    338 var tcpListenerNameTests = []struct {
    339 	net   string
    340 	laddr *TCPAddr
    341 }{
    342 	{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
    343 	{"tcp4", &TCPAddr{}},
    344 	{"tcp4", nil},
    345 }
    346 
    347 func TestTCPListenerName(t *testing.T) {
    348 	if testing.Short() || !*testExternal {
    349 		t.Skip("avoid external network")
    350 	}
    351 
    352 	for _, tt := range tcpListenerNameTests {
    353 		ln, err := ListenTCP(tt.net, tt.laddr)
    354 		if err != nil {
    355 			t.Fatal(err)
    356 		}
    357 		defer ln.Close()
    358 		la := ln.Addr()
    359 		if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
    360 			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
    361 		}
    362 	}
    363 }
    364 
    365 func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
    366 	if testing.Short() || !*testExternal {
    367 		t.Skip("avoid external network")
    368 	}
    369 	if !supportsIPv6 {
    370 		t.Skip("IPv6 is not supported")
    371 	}
    372 
    373 	for i, tt := range ipv6LinkLocalUnicastTCPTests {
    374 		ln, err := Listen(tt.network, tt.address)
    375 		if err != nil {
    376 			// It might return "LookupHost returned no
    377 			// suitable address" error on some platforms.
    378 			t.Log(err)
    379 			continue
    380 		}
    381 		ls, err := (&streamListener{Listener: ln}).newLocalServer()
    382 		if err != nil {
    383 			t.Fatal(err)
    384 		}
    385 		defer ls.teardown()
    386 		ch := make(chan error, 1)
    387 		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
    388 		if err := ls.buildup(handler); err != nil {
    389 			t.Fatal(err)
    390 		}
    391 		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
    392 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
    393 		}
    394 
    395 		c, err := Dial(tt.network, ls.Listener.Addr().String())
    396 		if err != nil {
    397 			t.Fatal(err)
    398 		}
    399 		defer c.Close()
    400 		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
    401 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
    402 		}
    403 		if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
    404 			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
    405 		}
    406 
    407 		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
    408 			t.Fatal(err)
    409 		}
    410 		b := make([]byte, 32)
    411 		if _, err := c.Read(b); err != nil {
    412 			t.Fatal(err)
    413 		}
    414 
    415 		for err := range ch {
    416 			t.Errorf("#%d: %v", i, err)
    417 		}
    418 	}
    419 }
    420 
    421 func TestTCPConcurrentAccept(t *testing.T) {
    422 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
    423 	ln, err := Listen("tcp", "127.0.0.1:0")
    424 	if err != nil {
    425 		t.Fatal(err)
    426 	}
    427 	const N = 10
    428 	var wg sync.WaitGroup
    429 	wg.Add(N)
    430 	for i := 0; i < N; i++ {
    431 		go func() {
    432 			for {
    433 				c, err := ln.Accept()
    434 				if err != nil {
    435 					break
    436 				}
    437 				c.Close()
    438 			}
    439 			wg.Done()
    440 		}()
    441 	}
    442 	attempts := 10 * N
    443 	fails := 0
    444 	d := &Dialer{Timeout: 200 * time.Millisecond}
    445 	for i := 0; i < attempts; i++ {
    446 		c, err := d.Dial("tcp", ln.Addr().String())
    447 		if err != nil {
    448 			fails++
    449 		} else {
    450 			c.Close()
    451 		}
    452 	}
    453 	ln.Close()
    454 	wg.Wait()
    455 	if fails > attempts/9 { // see issues 7400 and 7541
    456 		t.Fatalf("too many Dial failed: %v", fails)
    457 	}
    458 	if fails > 0 {
    459 		t.Logf("# of failed Dials: %v", fails)
    460 	}
    461 }
    462 
    463 func TestTCPReadWriteAllocs(t *testing.T) {
    464 	switch runtime.GOOS {
    465 	case "nacl", "windows":
    466 		// NaCl needs to allocate pseudo file descriptor
    467 		// stuff. See syscall/fd_nacl.go.
    468 		// Windows uses closures and channels for IO
    469 		// completion port-based netpoll. See fd_windows.go.
    470 		t.Skipf("not supported on %s", runtime.GOOS)
    471 	}
    472 
    473 	ln, err := Listen("tcp", "127.0.0.1:0")
    474 	if err != nil {
    475 		t.Fatal(err)
    476 	}
    477 	defer ln.Close()
    478 	var server Conn
    479 	errc := make(chan error)
    480 	go func() {
    481 		var err error
    482 		server, err = ln.Accept()
    483 		errc <- err
    484 	}()
    485 	client, err := Dial("tcp", ln.Addr().String())
    486 	if err != nil {
    487 		t.Fatal(err)
    488 	}
    489 	defer client.Close()
    490 	if err := <-errc; err != nil {
    491 		t.Fatal(err)
    492 	}
    493 	defer server.Close()
    494 	var buf [128]byte
    495 	allocs := testing.AllocsPerRun(1000, func() {
    496 		_, err := server.Write(buf[:])
    497 		if err != nil {
    498 			t.Fatal(err)
    499 		}
    500 		_, err = io.ReadFull(client, buf[:])
    501 		if err != nil {
    502 			t.Fatal(err)
    503 		}
    504 	})
    505 	if allocs > 0 {
    506 		t.Fatalf("got %v; want 0", allocs)
    507 	}
    508 }
    509 
    510 func TestTCPStress(t *testing.T) {
    511 	const conns = 2
    512 	const msgLen = 512
    513 	msgs := int(1e4)
    514 	if testing.Short() {
    515 		msgs = 1e2
    516 	}
    517 
    518 	sendMsg := func(c Conn, buf []byte) bool {
    519 		n, err := c.Write(buf)
    520 		if n != len(buf) || err != nil {
    521 			t.Log(err)
    522 			return false
    523 		}
    524 		return true
    525 	}
    526 	recvMsg := func(c Conn, buf []byte) bool {
    527 		for read := 0; read != len(buf); {
    528 			n, err := c.Read(buf)
    529 			read += n
    530 			if err != nil {
    531 				t.Log(err)
    532 				return false
    533 			}
    534 		}
    535 		return true
    536 	}
    537 
    538 	ln, err := Listen("tcp", "127.0.0.1:0")
    539 	if err != nil {
    540 		t.Fatal(err)
    541 	}
    542 	defer ln.Close()
    543 	// Acceptor.
    544 	go func() {
    545 		for {
    546 			c, err := ln.Accept()
    547 			if err != nil {
    548 				break
    549 			}
    550 			// Server connection.
    551 			go func(c Conn) {
    552 				defer c.Close()
    553 				var buf [msgLen]byte
    554 				for m := 0; m < msgs; m++ {
    555 					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
    556 						break
    557 					}
    558 				}
    559 			}(c)
    560 		}
    561 	}()
    562 	done := make(chan bool)
    563 	for i := 0; i < conns; i++ {
    564 		// Client connection.
    565 		go func() {
    566 			defer func() {
    567 				done <- true
    568 			}()
    569 			c, err := Dial("tcp", ln.Addr().String())
    570 			if err != nil {
    571 				t.Log(err)
    572 				return
    573 			}
    574 			defer c.Close()
    575 			var buf [msgLen]byte
    576 			for m := 0; m < msgs; m++ {
    577 				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
    578 					break
    579 				}
    580 			}
    581 		}()
    582 	}
    583 	for i := 0; i < conns; i++ {
    584 		<-done
    585 	}
    586 }
    587