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 5package net 6 7import ( 8 "fmt" 9 "internal/testenv" 10 "io" 11 "os" 12 "reflect" 13 "runtime" 14 "sync" 15 "testing" 16 "time" 17) 18 19func BenchmarkTCP4OneShot(b *testing.B) { 20 benchmarkTCP(b, false, false, "127.0.0.1:0") 21} 22 23func BenchmarkTCP4OneShotTimeout(b *testing.B) { 24 benchmarkTCP(b, false, true, "127.0.0.1:0") 25} 26 27func BenchmarkTCP4Persistent(b *testing.B) { 28 benchmarkTCP(b, true, false, "127.0.0.1:0") 29} 30 31func BenchmarkTCP4PersistentTimeout(b *testing.B) { 32 benchmarkTCP(b, true, true, "127.0.0.1:0") 33} 34 35func BenchmarkTCP6OneShot(b *testing.B) { 36 if !supportsIPv6() { 37 b.Skip("ipv6 is not supported") 38 } 39 benchmarkTCP(b, false, false, "[::1]:0") 40} 41 42func BenchmarkTCP6OneShotTimeout(b *testing.B) { 43 if !supportsIPv6() { 44 b.Skip("ipv6 is not supported") 45 } 46 benchmarkTCP(b, false, true, "[::1]:0") 47} 48 49func BenchmarkTCP6Persistent(b *testing.B) { 50 if !supportsIPv6() { 51 b.Skip("ipv6 is not supported") 52 } 53 benchmarkTCP(b, true, false, "[::1]:0") 54} 55 56func BenchmarkTCP6PersistentTimeout(b *testing.B) { 57 if !supportsIPv6() { 58 b.Skip("ipv6 is not supported") 59 } 60 benchmarkTCP(b, true, true, "[::1]:0") 61} 62 63func 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 162func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) { 163 benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0") 164} 165 166func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) { 167 if !supportsIPv6() { 168 b.Skip("ipv6 is not supported") 169 } 170 benchmarkTCPConcurrentReadWrite(b, "[::1]:0") 171} 172 173func 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 292type resolveTCPAddrTest struct { 293 network string 294 litAddrOrName string 295 addr *TCPAddr 296 err error 297} 298 299var 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 328func 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 348var 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 357func 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 373func 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 428func 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 470func TestTCPReadWriteAllocs(t *testing.T) { 471 if runtime.Compiler == "gccgo" { 472 t.Skip("skipping for gccgo until escape analysis is enabled") 473 } 474 475 switch runtime.GOOS { 476 case "plan9": 477 // The implementation of asynchronous cancelable 478 // I/O on Plan 9 allocates memory. 479 // See net/fd_io_plan9.go. 480 t.Skipf("not supported on %s", runtime.GOOS) 481 case "nacl": 482 // NaCl needs to allocate pseudo file descriptor 483 // stuff. See syscall/fd_nacl.go. 484 t.Skipf("not supported on %s", runtime.GOOS) 485 } 486 487 ln, err := Listen("tcp", "127.0.0.1:0") 488 if err != nil { 489 t.Fatal(err) 490 } 491 defer ln.Close() 492 var server Conn 493 errc := make(chan error, 1) 494 go func() { 495 var err error 496 server, err = ln.Accept() 497 errc <- err 498 }() 499 client, err := Dial("tcp", ln.Addr().String()) 500 if err != nil { 501 t.Fatal(err) 502 } 503 defer client.Close() 504 if err := <-errc; err != nil { 505 t.Fatal(err) 506 } 507 defer server.Close() 508 509 var buf [128]byte 510 allocs := testing.AllocsPerRun(1000, func() { 511 _, err := server.Write(buf[:]) 512 if err != nil { 513 t.Fatal(err) 514 } 515 _, err = io.ReadFull(client, buf[:]) 516 if err != nil { 517 t.Fatal(err) 518 } 519 }) 520 // For gccgo changed "> 0" to "> 7". 521 if allocs > 7 { 522 t.Fatalf("got %v; want 0", allocs) 523 } 524 525 var bufwrt [128]byte 526 ch := make(chan bool) 527 defer close(ch) 528 go func() { 529 for <-ch { 530 _, err := server.Write(bufwrt[:]) 531 errc <- err 532 } 533 }() 534 allocs = testing.AllocsPerRun(1000, func() { 535 ch <- true 536 if _, err = io.ReadFull(client, buf[:]); err != nil { 537 t.Fatal(err) 538 } 539 if err := <-errc; err != nil { 540 t.Fatal(err) 541 } 542 }) 543 if allocs > 0 { 544 t.Fatalf("got %v; want 0", allocs) 545 } 546} 547 548func TestTCPStress(t *testing.T) { 549 const conns = 2 550 const msgLen = 512 551 msgs := int(1e4) 552 if testing.Short() { 553 msgs = 1e2 554 } 555 556 sendMsg := func(c Conn, buf []byte) bool { 557 n, err := c.Write(buf) 558 if n != len(buf) || err != nil { 559 t.Log(err) 560 return false 561 } 562 return true 563 } 564 recvMsg := func(c Conn, buf []byte) bool { 565 for read := 0; read != len(buf); { 566 n, err := c.Read(buf) 567 read += n 568 if err != nil { 569 t.Log(err) 570 return false 571 } 572 } 573 return true 574 } 575 576 ln, err := Listen("tcp", "127.0.0.1:0") 577 if err != nil { 578 t.Fatal(err) 579 } 580 done := make(chan bool) 581 // Acceptor. 582 go func() { 583 defer func() { 584 done <- true 585 }() 586 for { 587 c, err := ln.Accept() 588 if err != nil { 589 break 590 } 591 // Server connection. 592 go func(c Conn) { 593 defer c.Close() 594 var buf [msgLen]byte 595 for m := 0; m < msgs; m++ { 596 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) { 597 break 598 } 599 } 600 }(c) 601 } 602 }() 603 for i := 0; i < conns; i++ { 604 // Client connection. 605 go func() { 606 defer func() { 607 done <- true 608 }() 609 c, err := Dial("tcp", ln.Addr().String()) 610 if err != nil { 611 t.Log(err) 612 return 613 } 614 defer c.Close() 615 var buf [msgLen]byte 616 for m := 0; m < msgs; m++ { 617 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) { 618 break 619 } 620 } 621 }() 622 } 623 for i := 0; i < conns; i++ { 624 <-done 625 } 626 ln.Close() 627 <-done 628} 629 630func TestTCPSelfConnect(t *testing.T) { 631 if runtime.GOOS == "windows" { 632 // TODO(brainman): do not know why it hangs. 633 t.Skip("known-broken test on windows") 634 } 635 636 ln, err := newLocalListener("tcp") 637 if err != nil { 638 t.Fatal(err) 639 } 640 var d Dialer 641 c, err := d.Dial(ln.Addr().Network(), ln.Addr().String()) 642 if err != nil { 643 ln.Close() 644 t.Fatal(err) 645 } 646 network := c.LocalAddr().Network() 647 laddr := *c.LocalAddr().(*TCPAddr) 648 c.Close() 649 ln.Close() 650 651 // Try to connect to that address repeatedly. 652 n := 100000 653 if testing.Short() { 654 n = 1000 655 } 656 switch runtime.GOOS { 657 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows": 658 // Non-Linux systems take a long time to figure 659 // out that there is nothing listening on localhost. 660 n = 100 661 } 662 for i := 0; i < n; i++ { 663 d.Timeout = time.Millisecond 664 c, err := d.Dial(network, laddr.String()) 665 if err == nil { 666 addr := c.LocalAddr().(*TCPAddr) 667 if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) { 668 t.Errorf("Dial %v should fail", addr) 669 } else { 670 t.Logf("Dial %v succeeded - possibly racing with other listener", addr) 671 } 672 c.Close() 673 } 674 } 675} 676 677// Test that >32-bit reads work on 64-bit systems. 678// On 32-bit systems this tests that maxint reads work. 679func TestTCPBig(t *testing.T) { 680 if !*testTCPBig { 681 t.Skip("test disabled; use -tcpbig to enable") 682 } 683 684 for _, writev := range []bool{false, true} { 685 t.Run(fmt.Sprintf("writev=%v", writev), func(t *testing.T) { 686 ln, err := newLocalListener("tcp") 687 if err != nil { 688 t.Fatal(err) 689 } 690 defer ln.Close() 691 692 x := int(1 << 30) 693 x = x*5 + 1<<20 // just over 5 GB on 64-bit, just over 1GB on 32-bit 694 done := make(chan int) 695 go func() { 696 defer close(done) 697 c, err := ln.Accept() 698 if err != nil { 699 t.Error(err) 700 return 701 } 702 buf := make([]byte, x) 703 var n int 704 if writev { 705 var n64 int64 706 n64, err = (&Buffers{buf}).WriteTo(c) 707 n = int(n64) 708 } else { 709 n, err = c.Write(buf) 710 } 711 if n != len(buf) || err != nil { 712 t.Errorf("Write(buf) = %d, %v, want %d, nil", n, err, x) 713 } 714 c.Close() 715 }() 716 717 c, err := Dial("tcp", ln.Addr().String()) 718 if err != nil { 719 t.Fatal(err) 720 } 721 buf := make([]byte, x) 722 n, err := io.ReadFull(c, buf) 723 if n != len(buf) || err != nil { 724 t.Errorf("Read(buf) = %d, %v, want %d, nil", n, err, x) 725 } 726 c.Close() 727 <-done 728 }) 729 } 730} 731 732func TestCopyPipeIntoTCP(t *testing.T) { 733 ln, err := newLocalListener("tcp") 734 if err != nil { 735 t.Fatal(err) 736 } 737 defer ln.Close() 738 739 errc := make(chan error, 1) 740 defer func() { 741 if err := <-errc; err != nil { 742 t.Error(err) 743 } 744 }() 745 go func() { 746 c, err := ln.Accept() 747 if err != nil { 748 errc <- err 749 return 750 } 751 defer c.Close() 752 753 buf := make([]byte, 100) 754 n, err := io.ReadFull(c, buf) 755 if err != io.ErrUnexpectedEOF || n != 2 { 756 errc <- fmt.Errorf("got err=%q n=%v; want err=%q n=2", err, n, io.ErrUnexpectedEOF) 757 return 758 } 759 760 errc <- nil 761 }() 762 763 c, err := Dial("tcp", ln.Addr().String()) 764 if err != nil { 765 t.Fatal(err) 766 } 767 defer c.Close() 768 769 r, w, err := os.Pipe() 770 if err != nil { 771 t.Fatal(err) 772 } 773 defer r.Close() 774 775 errc2 := make(chan error, 1) 776 defer func() { 777 if err := <-errc2; err != nil { 778 t.Error(err) 779 } 780 }() 781 782 defer w.Close() 783 784 go func() { 785 _, err := io.Copy(c, r) 786 errc2 <- err 787 }() 788 789 // Split write into 2 packets. That makes Windows TransmitFile 790 // drop second packet. 791 packet := make([]byte, 1) 792 _, err = w.Write(packet) 793 if err != nil { 794 t.Fatal(err) 795 } 796 time.Sleep(100 * time.Millisecond) 797 _, err = w.Write(packet) 798 if err != nil { 799 t.Fatal(err) 800 } 801} 802