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