1
0
mirror of https://github.com/golang/go synced 2024-11-18 10:14:45 -07:00

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: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
Aman Gupta 2017-11-06 23:02:21 -08:00 committed by Alex Brainman
parent 11309ba0e6
commit d2c7dec183
5 changed files with 71 additions and 8 deletions

View File

@ -913,12 +913,44 @@ func (fd *FD) RawControl(f func(uintptr)) error {
// RawRead invokes the user-defined function f for a read operation. // RawRead invokes the user-defined function f for a read operation.
func (fd *FD) RawRead(f func(uintptr) bool) error { 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. // RawWrite invokes the user-defined function f for a write operation.
func (fd *FD) RawWrite(f func(uintptr) bool) error { 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) { func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) {

View File

@ -122,6 +122,7 @@ const (
WSAEMSGSIZE syscall.Errno = 10040 WSAEMSGSIZE syscall.Errno = 10040
MSG_PEEK = 0x2
MSG_TRUNC = 0x0100 MSG_TRUNC = 0x0100
MSG_CTRUNC = 0x0200 MSG_CTRUNC = 0x0200

View File

@ -9,9 +9,6 @@ import (
"syscall" "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 // BUG(mikio): On NaCl and Plan 9, the Control, Read and Write methods
// of syscall.RawConn are not implemented. // of syscall.RawConn are not implemented.

View File

@ -12,7 +12,7 @@ import (
func TestRawConnReadWrite(t *testing.T) { func TestRawConnReadWrite(t *testing.T) {
switch runtime.GOOS { switch runtime.GOOS {
case "nacl", "plan9", "windows": case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS) t.Skipf("not supported on %s", runtime.GOOS)
} }

View File

@ -10,11 +10,44 @@ import (
) )
func readRawConn(c syscall.RawConn, b []byte) (int, error) { 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 { 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 { func controlRawConn(c syscall.RawConn, addr Addr) error {