github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 "fmt" 9 "internal/testenv" 10 "io" 11 "os" 12 "reflect" 13 "runtime" 14 "sync" 15 "testing" 16 "time" 17 ) 18 19 func BenchmarkTCP4OneShot(b *testing.B) { 20 benchmarkTCP(b, false, false, "127.0.0.1:0") 21 } 22 23 func BenchmarkTCP4OneShotTimeout(b *testing.B) { 24 benchmarkTCP(b, false, true, "127.0.0.1:0") 25 } 26 27 func BenchmarkTCP4Persistent(b *testing.B) { 28 benchmarkTCP(b, true, false, "127.0.0.1:0") 29 } 30 31 func BenchmarkTCP4PersistentTimeout(b *testing.B) { 32 benchmarkTCP(b, true, true, "127.0.0.1:0") 33 } 34 35 func BenchmarkTCP6OneShot(b *testing.B) { 36 if !supportsIPv6() { 37 b.Skip("ipv6 is not supported") 38 } 39 benchmarkTCP(b, false, false, "[::1]:0") 40 } 41 42 func BenchmarkTCP6OneShotTimeout(b *testing.B) { 43 if !supportsIPv6() { 44 b.Skip("ipv6 is not supported") 45 } 46 benchmarkTCP(b, false, true, "[::1]:0") 47 } 48 49 func BenchmarkTCP6Persistent(b *testing.B) { 50 if !supportsIPv6() { 51 b.Skip("ipv6 is not supported") 52 } 53 benchmarkTCP(b, true, false, "[::1]:0") 54 } 55 56 func BenchmarkTCP6PersistentTimeout(b *testing.B) { 57 if !supportsIPv6() { 58 b.Skip("ipv6 is not supported") 59 } 60 benchmarkTCP(b, true, true, "[::1]:0") 61 } 62 63 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { 64 testHookUninstaller.Do(uninstallTestHooks) 65 66 const msgLen = 512 67 conns := b.N 68 numConcurrent := runtime.GOMAXPROCS(-1) * 2 69 msgs := 1 70 if persistent { 71 conns = numConcurrent 72 msgs = b.N / conns 73 if msgs == 0 { 74 msgs = 1 75 } 76 if conns > b.N { 77 conns = b.N 78 } 79 } 80 sendMsg := func(c Conn, buf []byte) bool { 81 n, err := c.Write(buf) 82 if n != len(buf) || err != nil { 83 b.Log(err) 84 return false 85 } 86 return true 87 } 88 recvMsg := func(c Conn, buf []byte) bool { 89 for read := 0; read != len(buf); { 90 n, err := c.Read(buf) 91 read += n 92 if err != nil { 93 b.Log(err) 94 return false 95 } 96 } 97 return true 98 } 99 ln, err := Listen("tcp", laddr) 100 if err != nil { 101 b.Fatal(err) 102 } 103 defer ln.Close() 104 serverSem := make(chan bool, numConcurrent) 105 // Acceptor. 106 go func() { 107 for { 108 c, err := ln.Accept() 109 if err != nil { 110 break 111 } 112 serverSem <- true 113 // Server connection. 114 go func(c Conn) { 115 defer func() { 116 c.Close() 117 <-serverSem 118 }() 119 if timeout { 120 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire. 121 } 122 var buf [msgLen]byte 123 for m := 0; m < msgs; m++ { 124 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) { 125 break 126 } 127 } 128 }(c) 129 } 130 }() 131 clientSem := make(chan bool, numConcurrent) 132 for i := 0; i < conns; i++ { 133 clientSem <- true 134 // Client connection. 135 go func() { 136 defer func() { 137 <-clientSem 138 }() 139 c, err := Dial("tcp", ln.Addr().String()) 140 if err != nil { 141 b.Log(err) 142 return 143 } 144 defer c.Close() 145 if timeout { 146 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire. 147 } 148 var buf [msgLen]byte 149 for m := 0; m < msgs; m++ { 150 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) { 151 break 152 } 153 } 154 }() 155 } 156 for i := 0; i < numConcurrent; i++ { 157 clientSem <- true 158 serverSem <- true 159 } 160 } 161 162 func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) { 163 benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0") 164 } 165 166 func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) { 167 if !supportsIPv6() { 168 b.Skip("ipv6 is not supported") 169 } 170 benchmarkTCPConcurrentReadWrite(b, "[::1]:0") 171 } 172 173 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { 174 testHookUninstaller.Do(uninstallTestHooks) 175 176 // The benchmark creates GOMAXPROCS client/server pairs. 177 // Each pair creates 4 goroutines: client reader/writer and server reader/writer. 178 // The benchmark stresses concurrent reading and writing to the same connection. 179 // Such pattern is used in net/http and net/rpc. 180 181 b.StopTimer() 182 183 P := runtime.GOMAXPROCS(0) 184 N := b.N / P 185 W := 1000 186 187 // Setup P client/server connections. 188 clients := make([]Conn, P) 189 servers := make([]Conn, P) 190 ln, err := Listen("tcp", laddr) 191 if err != nil { 192 b.Fatal(err) 193 } 194 defer ln.Close() 195 done := make(chan bool) 196 go func() { 197 for p := 0; p < P; p++ { 198 s, err := ln.Accept() 199 if err != nil { 200 b.Error(err) 201 return 202 } 203 servers[p] = s 204 } 205 done <- true 206 }() 207 for p := 0; p < P; p++ { 208 c, err := Dial("tcp", ln.Addr().String()) 209 if err != nil { 210 b.Fatal(err) 211 } 212 clients[p] = c 213 } 214 <-done 215 216 b.StartTimer() 217 218 var wg sync.WaitGroup 219 wg.Add(4 * P) 220 for p := 0; p < P; p++ { 221 // Client writer. 222 go func(c Conn) { 223 defer wg.Done() 224 var buf [1]byte 225 for i := 0; i < N; i++ { 226 v := byte(i) 227 for w := 0; w < W; w++ { 228 v *= v 229 } 230 buf[0] = v 231 _, err := c.Write(buf[:]) 232 if err != nil { 233 b.Error(err) 234 return 235 } 236 } 237 }(clients[p]) 238 239 // Pipe between server reader and server writer. 240 pipe := make(chan byte, 128) 241 242 // Server reader. 243 go func(s Conn) { 244 defer wg.Done() 245 var buf [1]byte 246 for i := 0; i < N; i++ { 247 _, err := s.Read(buf[:]) 248 if err != nil { 249 b.Error(err) 250 return 251 } 252 pipe <- buf[0] 253 } 254 }(servers[p]) 255 256 // Server writer. 257 go func(s Conn) { 258 defer wg.Done() 259 var buf [1]byte 260 for i := 0; i < N; i++ { 261 v := <-pipe 262 for w := 0; w < W; w++ { 263 v *= v 264 } 265 buf[0] = v 266 _, err := s.Write(buf[:]) 267 if err != nil { 268 b.Error(err) 269 return 270 } 271 } 272 s.Close() 273 }(servers[p]) 274 275 // Client reader. 276 go func(c Conn) { 277 defer wg.Done() 278 var buf [1]byte 279 for i := 0; i < N; i++ { 280 _, err := c.Read(buf[:]) 281 if err != nil { 282 b.Error(err) 283 return 284 } 285 } 286 c.Close() 287 }(clients[p]) 288 } 289 wg.Wait() 290 } 291 292 type resolveTCPAddrTest struct { 293 network string 294 litAddrOrName string 295 addr *TCPAddr 296 err error 297 } 298 299 var resolveTCPAddrTests = []resolveTCPAddrTest{ 300 {"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, 301 {"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil}, 302 303 {"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, 304 {"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil}, 305 306 {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil}, 307 {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil}, 308 309 {"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior 310 {"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior 311 312 {"tcp", ":12345", &TCPAddr{Port: 12345}, nil}, 313 314 {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")}, 315 316 {"tcp", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil}, 317 {"tcp", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 80}, nil}, 318 {"tcp", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil}, 319 {"tcp4", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil}, 320 {"tcp4", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil}, 321 {"tcp6", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil}, 322 323 {"tcp4", "[2001:db8::1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}}, 324 {"tcp6", "127.0.0.1:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}}, 325 {"tcp6", "[::ffff:127.0.0.1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}}, 326 } 327 328 func TestResolveTCPAddr(t *testing.T) { 329 origTestHookLookupIP := testHookLookupIP 330 defer func() { testHookLookupIP = origTestHookLookupIP }() 331 testHookLookupIP = lookupLocalhost 332 333 for _, tt := range resolveTCPAddrTests { 334 addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName) 335 if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) { 336 t.Errorf("ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err) 337 continue 338 } 339 if err == nil { 340 addr2, err := ResolveTCPAddr(addr.Network(), addr.String()) 341 if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err { 342 t.Errorf("(%q, %q): ResolveTCPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err) 343 } 344 } 345 } 346 } 347 348 var tcpListenerNameTests = []struct { 349 net string 350 laddr *TCPAddr 351 }{ 352 {"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}}, 353 {"tcp4", &TCPAddr{}}, 354 {"tcp4", nil}, 355 } 356 357 func TestTCPListenerName(t *testing.T) { 358 testenv.MustHaveExternalNetwork(t) 359 360 for _, tt := range tcpListenerNameTests { 361 ln, err := ListenTCP(tt.net, tt.laddr) 362 if err != nil { 363 t.Fatal(err) 364 } 365 defer ln.Close() 366 la := ln.Addr() 367 if a, ok := la.(*TCPAddr); !ok || a.Port == 0 { 368 t.Fatalf("got %v; expected a proper address with non-zero port number", la) 369 } 370 } 371 } 372 373 func TestIPv6LinkLocalUnicastTCP(t *testing.T) { 374 testenv.MustHaveExternalNetwork(t) 375 376 if !supportsIPv6() { 377 t.Skip("IPv6 is not supported") 378 } 379 380 for i, tt := range ipv6LinkLocalUnicastTCPTests { 381 ln, err := Listen(tt.network, tt.address) 382 if err != nil { 383 // It might return "LookupHost returned no 384 // suitable address" error on some platforms. 385 t.Log(err) 386 continue 387 } 388 ls, err := (&streamListener{Listener: ln}).newLocalServer() 389 if err != nil { 390 t.Fatal(err) 391 } 392 defer ls.teardown() 393 ch := make(chan error, 1) 394 handler := func(ls *localServer, ln Listener) { transponder(ln, ch) } 395 if err := ls.buildup(handler); err != nil { 396 t.Fatal(err) 397 } 398 if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { 399 t.Fatalf("got %v; expected a proper address with zone identifier", la) 400 } 401 402 c, err := Dial(tt.network, ls.Listener.Addr().String()) 403 if err != nil { 404 t.Fatal(err) 405 } 406 defer c.Close() 407 if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { 408 t.Fatalf("got %v; expected a proper address with zone identifier", la) 409 } 410 if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" { 411 t.Fatalf("got %v; expected a proper address with zone identifier", ra) 412 } 413 414 if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil { 415 t.Fatal(err) 416 } 417 b := make([]byte, 32) 418 if _, err := c.Read(b); err != nil { 419 t.Fatal(err) 420 } 421 422 for err := range ch { 423 t.Errorf("#%d: %v", i, err) 424 } 425 } 426 } 427 428 func TestTCPConcurrentAccept(t *testing.T) { 429 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 430 ln, err := Listen("tcp", "127.0.0.1:0") 431 if err != nil { 432 t.Fatal(err) 433 } 434 const N = 10 435 var wg sync.WaitGroup 436 wg.Add(N) 437 for i := 0; i < N; i++ { 438 go func() { 439 for { 440 c, err := ln.Accept() 441 if err != nil { 442 break 443 } 444 c.Close() 445 } 446 wg.Done() 447 }() 448 } 449 attempts := 10 * N 450 fails := 0 451 d := &Dialer{Timeout: 200 * time.Millisecond} 452 for i := 0; i < attempts; i++ { 453 c, err := d.Dial("tcp", ln.Addr().String()) 454 if err != nil { 455 fails++ 456 } else { 457 c.Close() 458 } 459 } 460 ln.Close() 461 wg.Wait() 462 if fails > attempts/9 { // see issues 7400 and 7541 463 t.Fatalf("too many Dial failed: %v", fails) 464 } 465 if fails > 0 { 466 t.Logf("# of failed Dials: %v", fails) 467 } 468 } 469 470 func TestTCPReadWriteAllocs(t *testing.T) { 471 switch runtime.GOOS { 472 case "plan9": 473 // The implementation of asynchronous cancelable 474 // I/O on Plan 9 allocates memory. 475 // See net/fd_io_plan9.go. 476 t.Skipf("not supported on %s", runtime.GOOS) 477 case "nacl": 478 // NaCl needs to allocate pseudo file descriptor 479 // stuff. See syscall/fd_nacl.go. 480 t.Skipf("not supported on %s", runtime.GOOS) 481 } 482 483 ln, err := Listen("tcp", "127.0.0.1:0") 484 if err != nil { 485 t.Fatal(err) 486 } 487 defer ln.Close() 488 var server Conn 489 errc := make(chan error, 1) 490 go func() { 491 var err error 492 server, err = ln.Accept() 493 errc <- err 494 }() 495 client, err := Dial("tcp", ln.Addr().String()) 496 if err != nil { 497 t.Fatal(err) 498 } 499 defer client.Close() 500 if err := <-errc; err != nil { 501 t.Fatal(err) 502 } 503 defer server.Close() 504 505 var buf [128]byte 506 allocs := testing.AllocsPerRun(1000, func() { 507 _, err := server.Write(buf[:]) 508 if err != nil { 509 t.Fatal(err) 510 } 511 _, err = io.ReadFull(client, buf[:]) 512 if err != nil { 513 t.Fatal(err) 514 } 515 }) 516 if allocs > 0 { 517 t.Fatalf("got %v; want 0", allocs) 518 } 519 520 var bufwrt [128]byte 521 ch := make(chan bool) 522 defer close(ch) 523 go func() { 524 for <-ch { 525 _, err := server.Write(bufwrt[:]) 526 errc <- err 527 } 528 }() 529 allocs = testing.AllocsPerRun(1000, func() { 530 ch <- true 531 if _, err = io.ReadFull(client, buf[:]); err != nil { 532 t.Fatal(err) 533 } 534 if err := <-errc; err != nil { 535 t.Fatal(err) 536 } 537 }) 538 if allocs > 0 { 539 t.Fatalf("got %v; want 0", allocs) 540 } 541 } 542 543 func TestTCPStress(t *testing.T) { 544 const conns = 2 545 const msgLen = 512 546 msgs := int(1e4) 547 if testing.Short() { 548 msgs = 1e2 549 } 550 551 sendMsg := func(c Conn, buf []byte) bool { 552 n, err := c.Write(buf) 553 if n != len(buf) || err != nil { 554 t.Log(err) 555 return false 556 } 557 return true 558 } 559 recvMsg := func(c Conn, buf []byte) bool { 560 for read := 0; read != len(buf); { 561 n, err := c.Read(buf) 562 read += n 563 if err != nil { 564 t.Log(err) 565 return false 566 } 567 } 568 return true 569 } 570 571 ln, err := Listen("tcp", "127.0.0.1:0") 572 if err != nil { 573 t.Fatal(err) 574 } 575 done := make(chan bool) 576 // Acceptor. 577 go func() { 578 defer func() { 579 done <- true 580 }() 581 for { 582 c, err := ln.Accept() 583 if err != nil { 584 break 585 } 586 // Server connection. 587 go func(c Conn) { 588 defer c.Close() 589 var buf [msgLen]byte 590 for m := 0; m < msgs; m++ { 591 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) { 592 break 593 } 594 } 595 }(c) 596 } 597 }() 598 for i := 0; i < conns; i++ { 599 // Client connection. 600 go func() { 601 defer func() { 602 done <- true 603 }() 604 c, err := Dial("tcp", ln.Addr().String()) 605 if err != nil { 606 t.Log(err) 607 return 608 } 609 defer c.Close() 610 var buf [msgLen]byte 611 for m := 0; m < msgs; m++ { 612 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) { 613 break 614 } 615 } 616 }() 617 } 618 for i := 0; i < conns; i++ { 619 <-done 620 } 621 ln.Close() 622 <-done 623 } 624 625 func TestTCPSelfConnect(t *testing.T) { 626 if runtime.GOOS == "windows" { 627 // TODO(brainman): do not know why it hangs. 628 t.Skip("known-broken test on windows") 629 } 630 631 ln, err := newLocalListener("tcp") 632 if err != nil { 633 t.Fatal(err) 634 } 635 var d Dialer 636 c, err := d.Dial(ln.Addr().Network(), ln.Addr().String()) 637 if err != nil { 638 ln.Close() 639 t.Fatal(err) 640 } 641 network := c.LocalAddr().Network() 642 laddr := *c.LocalAddr().(*TCPAddr) 643 c.Close() 644 ln.Close() 645 646 // Try to connect to that address repeatedly. 647 n := 100000 648 if testing.Short() { 649 n = 1000 650 } 651 switch runtime.GOOS { 652 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows": 653 // Non-Linux systems take a long time to figure 654 // out that there is nothing listening on localhost. 655 n = 100 656 } 657 for i := 0; i < n; i++ { 658 d.Timeout = time.Millisecond 659 c, err := d.Dial(network, laddr.String()) 660 if err == nil { 661 addr := c.LocalAddr().(*TCPAddr) 662 if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) { 663 t.Errorf("Dial %v should fail", addr) 664 } else { 665 t.Logf("Dial %v succeeded - possibly racing with other listener", addr) 666 } 667 c.Close() 668 } 669 } 670 } 671 672 // Test that >32-bit reads work on 64-bit systems. 673 // On 32-bit systems this tests that maxint reads work. 674 func TestTCPBig(t *testing.T) { 675 if !*testTCPBig { 676 t.Skip("test disabled; use -tcpbig to enable") 677 } 678 679 for _, writev := range []bool{false, true} { 680 t.Run(fmt.Sprintf("writev=%v", writev), func(t *testing.T) { 681 ln, err := newLocalListener("tcp") 682 if err != nil { 683 t.Fatal(err) 684 } 685 defer ln.Close() 686 687 x := int(1 << 30) 688 x = x*5 + 1<<20 // just over 5 GB on 64-bit, just over 1GB on 32-bit 689 done := make(chan int) 690 go func() { 691 defer close(done) 692 c, err := ln.Accept() 693 if err != nil { 694 t.Error(err) 695 return 696 } 697 buf := make([]byte, x) 698 var n int 699 if writev { 700 var n64 int64 701 n64, err = (&Buffers{buf}).WriteTo(c) 702 n = int(n64) 703 } else { 704 n, err = c.Write(buf) 705 } 706 if n != len(buf) || err != nil { 707 t.Errorf("Write(buf) = %d, %v, want %d, nil", n, err, x) 708 } 709 c.Close() 710 }() 711 712 c, err := Dial("tcp", ln.Addr().String()) 713 if err != nil { 714 t.Fatal(err) 715 } 716 buf := make([]byte, x) 717 n, err := io.ReadFull(c, buf) 718 if n != len(buf) || err != nil { 719 t.Errorf("Read(buf) = %d, %v, want %d, nil", n, err, x) 720 } 721 c.Close() 722 <-done 723 }) 724 } 725 } 726 727 func TestCopyPipeIntoTCP(t *testing.T) { 728 ln, err := newLocalListener("tcp") 729 if err != nil { 730 t.Fatal(err) 731 } 732 defer ln.Close() 733 734 errc := make(chan error, 1) 735 defer func() { 736 if err := <-errc; err != nil { 737 t.Error(err) 738 } 739 }() 740 go func() { 741 c, err := ln.Accept() 742 if err != nil { 743 errc <- err 744 return 745 } 746 defer c.Close() 747 748 buf := make([]byte, 100) 749 n, err := io.ReadFull(c, buf) 750 if err != io.ErrUnexpectedEOF || n != 2 { 751 errc <- fmt.Errorf("got err=%q n=%v; want err=%q n=2", err, n, io.ErrUnexpectedEOF) 752 return 753 } 754 755 errc <- nil 756 }() 757 758 c, err := Dial("tcp", ln.Addr().String()) 759 if err != nil { 760 t.Fatal(err) 761 } 762 defer c.Close() 763 764 r, w, err := os.Pipe() 765 if err != nil { 766 t.Fatal(err) 767 } 768 defer r.Close() 769 770 errc2 := make(chan error, 1) 771 defer func() { 772 if err := <-errc2; err != nil { 773 t.Error(err) 774 } 775 }() 776 777 defer w.Close() 778 779 go func() { 780 _, err := io.Copy(c, r) 781 errc2 <- err 782 }() 783 784 // Split write into 2 packets. That makes Windows TransmitFile 785 // drop second packet. 786 packet := make([]byte, 1) 787 _, err = w.Write(packet) 788 if err != nil { 789 t.Fatal(err) 790 } 791 time.Sleep(100 * time.Millisecond) 792 _, err = w.Write(packet) 793 if err != nil { 794 t.Fatal(err) 795 } 796 }