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 }