]> Cypherpunks repositories - gostls13.git/commitdiff
net: implement (*syscall.RawConn).Read/Write on Windows
authorAman Gupta <aman@tmm1.net>
Tue, 7 Nov 2017 07:02:21 +0000 (23:02 -0800)
committerAlex Brainman <alex.brainman@gmail.com>
Sat, 14 Apr 2018 05:36:36 +0000 (05:36 +0000)
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>
src/internal/poll/fd_windows.go
src/internal/syscall/windows/syscall_windows.go
src/net/rawconn.go
src/net/rawconn_test.go
src/net/rawconn_windows_test.go

index 309f0291a1c7d2b4e9583a34326c5a9ea05ee4c5..cd9f88b5f7ed65e680e1ed91021b50354faf59d9 100644 (file)
@@ -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) {
index b531f89b62a285142cfda925d6cd7a1f3bf3ae63..518af26d7244fb16d1bd7092eeb8179cef52f12c 100644 (file)
@@ -122,6 +122,7 @@ const (
 
        WSAEMSGSIZE syscall.Errno = 10040
 
+       MSG_PEEK   = 0x2
        MSG_TRUNC  = 0x0100
        MSG_CTRUNC = 0x0200
 
index 2399c9f31dd12de96a2a682d1e9a709e20e4134a..11f01ffda8a0d69905c3154b413730eb920980e2 100644 (file)
@@ -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.
 
index 287282f1173247184778eb550a0181a3eff55377..ebada13e53c8a22c7a22c300a26143a848785b2e 100644 (file)
@@ -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)
        }
 
index 1b6777bb172012b6f0d05ae350f9e509480457ee..6df101e9de4b2523dc232216db4a3effe6cb076d 100644 (file)
@@ -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 {