Commit d2c7dec1 authored by Aman Gupta's avatar Aman Gupta Committed by Alex Brainman

net: implement (*syscall.RawConn).Read/Write on Windows

RawRead assumes the callback will perform either (a) a blocking read
and always return true, (b) a blocking read with a SO_RCVTIMEO set
returning false on WSAETIMEDOUT, or (c) a non-blocking read
returning false on WSAEWOULDBLOCK. In the latter two cases, it uses
a 0-byte overlapped read for notifications from the IOCP runtime
when the socket becomes readable before trying again.

RawWrite assumes the callback will perform blocking write and will
always return true, and makes no effort to tie into the runtime loop.

Change-Id: Ib10074e9d502c040294f41a260e561e84208652f
Reviewed-on: https://go-review.googlesource.com/76391
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarAlex Brainman <alex.brainman@gmail.com>
parent 11309ba0
......@@ -913,12 +913,44 @@ func (fd *FD) RawControl(f func(uintptr)) error {
// RawRead invokes the user-defined function f for a read operation.
func (fd *FD) RawRead(f func(uintptr) bool) error {
return errors.New("not implemented")
if err := fd.readLock(); err != nil {
return err
}
defer fd.readUnlock()
for {
if f(uintptr(fd.Sysfd)) {
return nil
}
// Use a zero-byte read as a way to get notified when this
// socket is readable. h/t https://stackoverflow.com/a/42019668/332798
o := &fd.rop
o.InitBuf(nil)
if !fd.IsStream {
o.flags |= windows.MSG_PEEK
}
_, err := rsrv.ExecIO(o, func(o *operation) error {
return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
})
if err == windows.WSAEMSGSIZE {
// expected with a 0-byte peek, ignore.
} else if err != nil {
return err
}
}
}
// RawWrite invokes the user-defined function f for a write operation.
func (fd *FD) RawWrite(f func(uintptr) bool) error {
return errors.New("not implemented")
if err := fd.writeLock(); err != nil {
return err
}
defer fd.writeUnlock()
for {
if f(uintptr(fd.Sysfd)) {
return nil
}
}
}
func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) {
......
......@@ -122,6 +122,7 @@ const (
WSAEMSGSIZE syscall.Errno = 10040
MSG_PEEK = 0x2
MSG_TRUNC = 0x0100
MSG_CTRUNC = 0x0200
......
......@@ -9,9 +9,6 @@ import (
"syscall"
)
// BUG(mikio): On Windows, the Read and Write methods of
// syscall.RawConn are not implemented.
// BUG(mikio): On NaCl and Plan 9, the Control, Read and Write methods
// of syscall.RawConn are not implemented.
......
......@@ -12,7 +12,7 @@ import (
func TestRawConnReadWrite(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
......
......@@ -10,11 +10,44 @@ import (
)
func readRawConn(c syscall.RawConn, b []byte) (int, error) {
return 0, syscall.EWINDOWS
var operr error
var n int
err := c.Read(func(s uintptr) bool {
var read uint32
var flags uint32
var buf syscall.WSABuf
buf.Buf = &b[0]
buf.Len = uint32(len(b))
operr = syscall.WSARecv(syscall.Handle(s), &buf, 1, &read, &flags, nil, nil)
n = int(read)
return true
})
if err != nil {
return n, err
}
if operr != nil {
return n, operr
}
return n, nil
}
func writeRawConn(c syscall.RawConn, b []byte) error {
return syscall.EWINDOWS
var operr error
err := c.Write(func(s uintptr) bool {
var written uint32
var buf syscall.WSABuf
buf.Buf = &b[0]
buf.Len = uint32(len(b))
operr = syscall.WSASend(syscall.Handle(s), &buf, 1, &written, 0, nil, nil)
return true
})
if err != nil {
return err
}
if operr != nil {
return operr
}
return nil
}
func controlRawConn(c syscall.RawConn, addr Addr) error {
......
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