rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/tcp_test.go (about)

     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(func() { 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.Logf("Write failed: %v", 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.Logf("Read failed: %v", err)
    91  				return false
    92  			}
    93  		}
    94  		return true
    95  	}
    96  	ln, err := Listen("tcp", laddr)
    97  	if err != nil {
    98  		b.Fatalf("Listen failed: %v", 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.Logf("Dial failed: %v", 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(func() { 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.Fatalf("Listen failed: %v", 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.Errorf("Accept failed: %v", 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.Fatalf("Dial failed: %v", 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.Errorf("Write failed: %v", 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.Errorf("Read failed: %v", 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.Errorf("Write failed: %v", 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.Errorf("Read failed: %v", 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("skipping test to avoid external network")
   350  	}
   351  
   352  	for _, tt := range tcpListenerNameTests {
   353  		ln, err := ListenTCP(tt.net, tt.laddr)
   354  		if err != nil {
   355  			t.Fatalf("ListenTCP failed: %v", 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("skipping test to avoid external network")
   368  	}
   369  	if !supportsIPv6 {
   370  		t.Skip("ipv6 is not supported")
   371  	}
   372  	ifi := loopbackInterface()
   373  	if ifi == nil {
   374  		t.Skip("loopback interface not found")
   375  	}
   376  	laddr := ipv6LinkLocalUnicastAddr(ifi)
   377  	if laddr == "" {
   378  		t.Skip("ipv6 unicast address on loopback not found")
   379  	}
   380  
   381  	type test struct {
   382  		net, addr  string
   383  		nameLookup bool
   384  	}
   385  	var tests = []test{
   386  		{"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
   387  		{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
   388  	}
   389  	switch runtime.GOOS {
   390  	case "darwin", "freebsd", "openbsd", "netbsd":
   391  		tests = append(tests, []test{
   392  			{"tcp", "[localhost%" + ifi.Name + "]:0", true},
   393  			{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
   394  		}...)
   395  	case "linux":
   396  		tests = append(tests, []test{
   397  			{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
   398  			{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
   399  		}...)
   400  	}
   401  	handler := func(ls *localServer, ln Listener) { transponder(t, ln) }
   402  	for _, tt := range tests {
   403  		ln, err := Listen(tt.net, tt.addr)
   404  		if err != nil {
   405  			// It might return "LookupHost returned no
   406  			// suitable address" error on some platforms.
   407  			t.Logf("Listen failed: %v", err)
   408  			continue
   409  		}
   410  		ls, err := (&streamListener{Listener: ln}).newLocalServer()
   411  		if err != nil {
   412  			t.Fatal(err)
   413  		}
   414  		defer ls.teardown()
   415  		if err := ls.buildup(handler); err != nil {
   416  			t.Fatal(err)
   417  		}
   418  		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   419  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   420  		}
   421  
   422  		c, err := Dial(tt.net, ls.Listener.Addr().String())
   423  		if err != nil {
   424  			t.Fatalf("Dial failed: %v", err)
   425  		}
   426  		defer c.Close()
   427  		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   428  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   429  		}
   430  		if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
   431  			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
   432  		}
   433  
   434  		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
   435  			t.Fatalf("Conn.Write failed: %v", err)
   436  		}
   437  		b := make([]byte, 32)
   438  		if _, err := c.Read(b); err != nil {
   439  			t.Fatalf("Conn.Read failed: %v", err)
   440  		}
   441  	}
   442  }
   443  
   444  func TestTCPConcurrentAccept(t *testing.T) {
   445  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   446  	ln, err := Listen("tcp", "127.0.0.1:0")
   447  	if err != nil {
   448  		t.Fatalf("Listen failed: %v", err)
   449  	}
   450  	const N = 10
   451  	var wg sync.WaitGroup
   452  	wg.Add(N)
   453  	for i := 0; i < N; i++ {
   454  		go func() {
   455  			for {
   456  				c, err := ln.Accept()
   457  				if err != nil {
   458  					break
   459  				}
   460  				c.Close()
   461  			}
   462  			wg.Done()
   463  		}()
   464  	}
   465  	attempts := 10 * N
   466  	fails := 0
   467  	d := &Dialer{Timeout: 200 * time.Millisecond}
   468  	for i := 0; i < attempts; i++ {
   469  		c, err := d.Dial("tcp", ln.Addr().String())
   470  		if err != nil {
   471  			fails++
   472  		} else {
   473  			c.Close()
   474  		}
   475  	}
   476  	ln.Close()
   477  	wg.Wait()
   478  	if fails > attempts/9 { // see issues 7400 and 7541
   479  		t.Fatalf("too many Dial failed: %v", fails)
   480  	}
   481  	if fails > 0 {
   482  		t.Logf("# of failed Dials: %v", fails)
   483  	}
   484  }
   485  
   486  func TestTCPReadWriteAllocs(t *testing.T) {
   487  	switch runtime.GOOS {
   488  	case "nacl", "windows":
   489  		// NaCl needs to allocate pseudo file descriptor
   490  		// stuff. See syscall/fd_nacl.go.
   491  		// Windows uses closures and channels for IO
   492  		// completion port-based netpoll. See fd_windows.go.
   493  		t.Skipf("not supported on %s", runtime.GOOS)
   494  	}
   495  
   496  	ln, err := Listen("tcp", "127.0.0.1:0")
   497  	if err != nil {
   498  		t.Fatal(err)
   499  	}
   500  	defer ln.Close()
   501  	var server Conn
   502  	errc := make(chan error)
   503  	go func() {
   504  		var err error
   505  		server, err = ln.Accept()
   506  		errc <- err
   507  	}()
   508  	client, err := Dial("tcp", ln.Addr().String())
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  	defer client.Close()
   513  	if err := <-errc; err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	defer server.Close()
   517  	var buf [128]byte
   518  	allocs := testing.AllocsPerRun(1000, func() {
   519  		_, err := server.Write(buf[:])
   520  		if err != nil {
   521  			t.Fatal(err)
   522  		}
   523  		_, err = io.ReadFull(client, buf[:])
   524  		if err != nil {
   525  			t.Fatal(err)
   526  		}
   527  	})
   528  	if allocs > 0 {
   529  		t.Fatalf("got %v; want 0", allocs)
   530  	}
   531  }
   532  
   533  func TestTCPStress(t *testing.T) {
   534  	const conns = 2
   535  	const msgLen = 512
   536  	msgs := int(1e4)
   537  	if testing.Short() {
   538  		msgs = 1e2
   539  	}
   540  
   541  	sendMsg := func(c Conn, buf []byte) bool {
   542  		n, err := c.Write(buf)
   543  		if n != len(buf) || err != nil {
   544  			t.Logf("Write failed: %v", err)
   545  			return false
   546  		}
   547  		return true
   548  	}
   549  	recvMsg := func(c Conn, buf []byte) bool {
   550  		for read := 0; read != len(buf); {
   551  			n, err := c.Read(buf)
   552  			read += n
   553  			if err != nil {
   554  				t.Logf("Read failed: %v", err)
   555  				return false
   556  			}
   557  		}
   558  		return true
   559  	}
   560  
   561  	ln, err := Listen("tcp", "127.0.0.1:0")
   562  	if err != nil {
   563  		t.Fatalf("Listen failed: %v", err)
   564  	}
   565  	defer ln.Close()
   566  	// Acceptor.
   567  	go func() {
   568  		for {
   569  			c, err := ln.Accept()
   570  			if err != nil {
   571  				break
   572  			}
   573  			// Server connection.
   574  			go func(c Conn) {
   575  				defer c.Close()
   576  				var buf [msgLen]byte
   577  				for m := 0; m < msgs; m++ {
   578  					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
   579  						break
   580  					}
   581  				}
   582  			}(c)
   583  		}
   584  	}()
   585  	done := make(chan bool)
   586  	for i := 0; i < conns; i++ {
   587  		// Client connection.
   588  		go func() {
   589  			defer func() {
   590  				done <- true
   591  			}()
   592  			c, err := Dial("tcp", ln.Addr().String())
   593  			if err != nil {
   594  				t.Logf("Dial failed: %v", err)
   595  				return
   596  			}
   597  			defer c.Close()
   598  			var buf [msgLen]byte
   599  			for m := 0; m < msgs; m++ {
   600  				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
   601  					break
   602  				}
   603  			}
   604  		}()
   605  	}
   606  	for i := 0; i < conns; i++ {
   607  		<-done
   608  	}
   609  }