]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix UDPConn readers to return truncated payload size instead of 0
authorMansour Rahimi <rahimi.mnr@gmail.com>
Wed, 7 Feb 2018 01:17:50 +0000 (02:17 +0100)
committerMikio Hara <mikioh.mikioh@gmail.com>
Wed, 21 Feb 2018 10:40:03 +0000 (10:40 +0000)
Calling UDPConn readers (Read, ReadFrom, ReadMsgUDP) to read part of
datagram returns error (in Windows), mentioning there is more data
available, and 0 as size of read data, even though part of data is
already read.

This fix makes UDPConn readers to return truncated payload size,
even there is error due more data available to read.

Fixes #14074
Updates #18056

Change-Id: Id7eec7f544dd759b2d970fa2561eef2937ec4662
Reviewed-on: https://go-review.googlesource.com/92475
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
src/internal/poll/fd_windows.go
src/net/net.go
src/net/timeout_test.go
src/net/udpsock_test.go
src/syscall/types_windows.go

index 187908bc8341218fdb747912a243cc7732ba7ff7..1114d66a7a9fccd0e97cdcfd2c41d4d07056a3fe 100644 (file)
@@ -225,6 +225,10 @@ func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, erro
                // All is good. Extract our IO results and return.
                if o.errno != 0 {
                        err = syscall.Errno(o.errno)
+                       // More data available. Return back the size of received data.
+                       if err == syscall.ERROR_MORE_DATA || err == syscall.WSAEMSGSIZE {
+                               return int(o.qty), err
+                       }
                        return 0, err
                }
                return int(o.qty), nil
index 3ad91036e76564814a6f1371ce65f909177cfb0d..5182c0de95632b8f12d594d24b662847d27d5d52 100644 (file)
@@ -303,20 +303,23 @@ func (c *conn) File() (f *os.File, err error) {
 // Multiple goroutines may invoke methods on a PacketConn simultaneously.
 type PacketConn interface {
        // ReadFrom reads a packet from the connection,
-       // copying the payload into b. It returns the number of
-       // bytes copied into b and the return address that
+       // copying the payload into p. It returns the number of
+       // bytes copied into p and the return address that
        // was on the packet.
+       // It returns the number of bytes read (0 <= n <= len(p))
+       // and any error encountered. Callers should always process
+       // the n > 0 bytes returned before considering the error err.
        // ReadFrom can be made to time out and return
        // an Error with Timeout() == true after a fixed time limit;
        // see SetDeadline and SetReadDeadline.
-       ReadFrom(b []byte) (n int, addr Addr, err error)
+       ReadFrom(p []byte) (n int, addr Addr, err error)
 
-       // WriteTo writes a packet with payload b to addr.
+       // WriteTo writes a packet with payload p to addr.
        // WriteTo can be made to time out and return
        // an Error with Timeout() == true after a fixed time limit;
        // see SetDeadline and SetWriteDeadline.
        // On packet-oriented connections, write timeouts are rare.
-       WriteTo(b []byte, addr Addr) (n int, err error)
+       WriteTo(p []byte, addr Addr) (n int, err error)
 
        // Close closes the connection.
        // Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
index 9de7801ad107a8b8c2f7f42bd5b39fb183132963..0ecf5a6d251400ad7bdc8e18257fc935a308fb11 100644 (file)
@@ -482,7 +482,7 @@ func TestReadFromTimeout(t *testing.T) {
                                        time.Sleep(tt.timeout / 3)
                                        continue
                                }
-                               if n != 0 {
+                               if nerr, ok := err.(Error); ok && nerr.Timeout() && n != 0 {
                                        t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
                                }
                                break
index 4ae014c01d9b69539fd12fe1bdb7363384130130..d34c5450966f64ab9d69f3dca11de0de0dd859ed 100644 (file)
@@ -398,9 +398,56 @@ func TestUDPZeroByteBuffer(t *testing.T) {
                switch err {
                case nil: // ReadFrom succeeds
                default: // Read may timeout, it depends on the platform
-                       if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZ
+                       if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
                                t.Fatal(err)
                        }
                }
        }
 }
+
+func TestUDPReadSizeError(t *testing.T) {
+       switch runtime.GOOS {
+       case "nacl", "plan9":
+               t.Skipf("not supported on %s", runtime.GOOS)
+       }
+
+       c1, err := newLocalPacketListener("udp")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer c1.Close()
+
+       c2, err := Dial("udp", c1.LocalAddr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer c2.Close()
+
+       b1 := []byte("READ SIZE ERROR TEST")
+       for _, genericRead := range []bool{false, true} {
+               n, err := c2.Write(b1)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if n != len(b1) {
+                       t.Errorf("got %d; want %d", n, len(b1))
+               }
+               c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+               b2 := make([]byte, len(b1)-1)
+               if genericRead {
+                       n, err = c1.(Conn).Read(b2)
+               } else {
+                       n, _, err = c1.ReadFrom(b2)
+               }
+               switch err {
+               case nil: // ReadFrom succeeds
+               default: // Read may timeout, it depends on the platform
+                       if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
+                               t.Fatal(err)
+                       }
+               }
+               if n != len(b1)-1 {
+                       t.Fatalf("got %d; want %d", n, len(b1)-1)
+               }
+       }
+}
index bc9bd4dbd889523ee28f9501fc5a0459f875a655..59bfe5d6427242bf335c970448a9206d7bf9bfa9 100644 (file)
@@ -27,6 +27,7 @@ const (
        ERROR_NOT_FOUND           Errno = 1168
        ERROR_PRIVILEGE_NOT_HELD  Errno = 1314
        WSAEACCES                 Errno = 10013
+       WSAEMSGSIZE               Errno = 10040
        WSAECONNABORTED           Errno = 10053
        WSAECONNRESET             Errno = 10054
 )