Skip to content

Commit 79fe895

Browse files
m4ns0urcixtor
authored andcommitted
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Mikio Hara <[email protected]>
1 parent cab7ba0 commit 79fe895

File tree

5 files changed

+62
-7
lines changed

5 files changed

+62
-7
lines changed

src/internal/poll/fd_windows.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, erro
225225
// All is good. Extract our IO results and return.
226226
if o.errno != 0 {
227227
err = syscall.Errno(o.errno)
228+
// More data available. Return back the size of received data.
229+
if err == syscall.ERROR_MORE_DATA || err == syscall.WSAEMSGSIZE {
230+
return int(o.qty), err
231+
}
228232
return 0, err
229233
}
230234
return int(o.qty), nil

src/net/net.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,23 @@ func (c *conn) File() (f *os.File, err error) {
303303
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
304304
type PacketConn interface {
305305
// ReadFrom reads a packet from the connection,
306-
// copying the payload into b. It returns the number of
307-
// bytes copied into b and the return address that
306+
// copying the payload into p. It returns the number of
307+
// bytes copied into p and the return address that
308308
// was on the packet.
309+
// It returns the number of bytes read (0 <= n <= len(p))
310+
// and any error encountered. Callers should always process
311+
// the n > 0 bytes returned before considering the error err.
309312
// ReadFrom can be made to time out and return
310313
// an Error with Timeout() == true after a fixed time limit;
311314
// see SetDeadline and SetReadDeadline.
312-
ReadFrom(b []byte) (n int, addr Addr, err error)
315+
ReadFrom(p []byte) (n int, addr Addr, err error)
313316

314-
// WriteTo writes a packet with payload b to addr.
317+
// WriteTo writes a packet with payload p to addr.
315318
// WriteTo can be made to time out and return
316319
// an Error with Timeout() == true after a fixed time limit;
317320
// see SetDeadline and SetWriteDeadline.
318321
// On packet-oriented connections, write timeouts are rare.
319-
WriteTo(b []byte, addr Addr) (n int, err error)
322+
WriteTo(p []byte, addr Addr) (n int, err error)
320323

321324
// Close closes the connection.
322325
// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.

src/net/timeout_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ func TestReadFromTimeout(t *testing.T) {
482482
time.Sleep(tt.timeout / 3)
483483
continue
484484
}
485-
if n != 0 {
485+
if nerr, ok := err.(Error); ok && nerr.Timeout() && n != 0 {
486486
t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
487487
}
488488
break

src/net/udpsock_test.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,56 @@ func TestUDPZeroByteBuffer(t *testing.T) {
398398
switch err {
399399
case nil: // ReadFrom succeeds
400400
default: // Read may timeout, it depends on the platform
401-
if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZ
401+
if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
402402
t.Fatal(err)
403403
}
404404
}
405405
}
406406
}
407+
408+
func TestUDPReadSizeError(t *testing.T) {
409+
switch runtime.GOOS {
410+
case "nacl", "plan9":
411+
t.Skipf("not supported on %s", runtime.GOOS)
412+
}
413+
414+
c1, err := newLocalPacketListener("udp")
415+
if err != nil {
416+
t.Fatal(err)
417+
}
418+
defer c1.Close()
419+
420+
c2, err := Dial("udp", c1.LocalAddr().String())
421+
if err != nil {
422+
t.Fatal(err)
423+
}
424+
defer c2.Close()
425+
426+
b1 := []byte("READ SIZE ERROR TEST")
427+
for _, genericRead := range []bool{false, true} {
428+
n, err := c2.Write(b1)
429+
if err != nil {
430+
t.Fatal(err)
431+
}
432+
if n != len(b1) {
433+
t.Errorf("got %d; want %d", n, len(b1))
434+
}
435+
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
436+
b2 := make([]byte, len(b1)-1)
437+
if genericRead {
438+
n, err = c1.(Conn).Read(b2)
439+
} else {
440+
n, _, err = c1.ReadFrom(b2)
441+
}
442+
switch err {
443+
case nil: // ReadFrom succeeds
444+
default: // Read may timeout, it depends on the platform
445+
if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
446+
t.Fatal(err)
447+
}
448+
}
449+
if n != len(b1)-1 {
450+
t.Fatalf("got %d; want %d", n, len(b1)-1)
451+
}
452+
}
453+
}

src/syscall/types_windows.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
ERROR_NOT_FOUND Errno = 1168
2828
ERROR_PRIVILEGE_NOT_HELD Errno = 1314
2929
WSAEACCES Errno = 10013
30+
WSAEMSGSIZE Errno = 10040
3031
WSAECONNABORTED Errno = 10053
3132
WSAECONNRESET Errno = 10054
3233
)

0 commit comments

Comments
 (0)