mirror of
https://github.com/golang/go
synced 2024-11-05 14:36:11 -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:
parent
11309ba0e6
commit
d2c7dec183
@ -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) {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user