Skip to content

Commit

Permalink
internal/poll: do not use Windows TransmitFile with pipes
Browse files Browse the repository at this point in the history
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 <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
alexbrainman committed Nov 26, 2017
1 parent 7da2f82 commit 4aa5dcc
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/internal/poll/sendfile_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
72 changes: 72 additions & 0 deletions src/net/tcpsock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"internal/testenv"
"io"
"os"
"reflect"
"runtime"
"sync"
Expand Down Expand Up @@ -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)
}
}

0 comments on commit 4aa5dcc

Please sign in to comment.