mirror of https://github.com/golang/go.git
net: fix UDPConn readers to return truncated payload size instead of 0
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>
This commit is contained in:
parent
cab7ba0b28
commit
79fe895112
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue