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