]> Cypherpunks repositories - gostls13.git/commitdiff
internal/poll: do not use Windows TransmitFile with pipes
authorAlex Brainman <alex.brainman@gmail.com>
Thu, 23 Nov 2017 07:21:52 +0000 (18:21 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Sun, 26 Nov 2017 01:41:33 +0000 (01:41 +0000)
It appears that TransmitFile Windows API does not work with Windows
pipes. So just copy data from pipe and into TCP connection manually.

Fixes #22278

Change-Id: I4810caca5345eac5bffb3176956689b8ae993256
Reviewed-on: https://go-review.googlesource.com/79775
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/internal/poll/sendfile_windows.go
src/net/tcpsock_test.go

index c1a2d6d17659b41d51913d6e5e4c874e95ffd9ac..4a15b75236687e3c44f0cf5644ad84fbfa855fac 100644 (file)
@@ -8,6 +8,15 @@ import "syscall"
 
 // SendFile wraps the TransmitFile call.
 func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
+       ft, err := syscall.GetFileType(src)
+       if err != nil {
+               return 0, err
+       }
+       // TransmitFile does not work with pipes
+       if ft == syscall.FILE_TYPE_PIPE {
+               return 0, syscall.ESPIPE
+       }
+
        if err := fd.writeLock(); err != nil {
                return 0, err
        }
index 09f651645186b7ec3edf111245c313fa39483c9d..b85ffa62e18ed34876cfe021fbc5d6adc44b8662 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
        "internal/testenv"
        "io"
+       "os"
        "reflect"
        "runtime"
        "sync"
@@ -722,3 +723,74 @@ func TestTCPBig(t *testing.T) {
                })
        }
 }
+
+func TestCopyPipeIntoTCP(t *testing.T) {
+       ln, err := newLocalListener("tcp")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer ln.Close()
+
+       errc := make(chan error, 1)
+       defer func() {
+               if err := <-errc; err != nil {
+                       t.Error(err)
+               }
+       }()
+       go func() {
+               c, err := ln.Accept()
+               if err != nil {
+                       errc <- err
+                       return
+               }
+               defer c.Close()
+
+               buf := make([]byte, 100)
+               n, err := io.ReadFull(c, buf)
+               if err != io.ErrUnexpectedEOF || n != 2 {
+                       errc <- fmt.Errorf("got err=%q n=%v; want err=%q n=2", err, n, io.ErrUnexpectedEOF)
+                       return
+               }
+
+               errc <- nil
+       }()
+
+       c, err := Dial("tcp", ln.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer c.Close()
+
+       r, w, err := os.Pipe()
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer r.Close()
+
+       errc2 := make(chan error, 1)
+       defer func() {
+               if err := <-errc2; err != nil {
+                       t.Error(err)
+               }
+       }()
+
+       defer w.Close()
+
+       go func() {
+               _, err := io.Copy(c, r)
+               errc2 <- err
+       }()
+
+       // Split write into 2 packets. That makes Windows TransmitFile
+       // drop second packet.
+       packet := make([]byte, 1)
+       _, err = w.Write(packet)
+       if err != nil {
+               t.Fatal(err)
+       }
+       time.Sleep(100 * time.Millisecond)
+       _, err = w.Write(packet)
+       if err != nil {
+               t.Fatal(err)
+       }
+}