Commit 4aa5dcc2 authored by Alex Brainman's avatar Alex Brainman

internal/poll: do not use Windows TransmitFile with pipes

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: 's avatarIan Lance Taylor <iant@golang.org>
parent 7da2f827
......@@ -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
}
......
......@@ -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)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment