// 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
// 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.
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
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)
+ }
+ }
+}
ERROR_NOT_FOUND Errno = 1168
ERROR_PRIVILEGE_NOT_HELD Errno = 1314
WSAEACCES Errno = 10013
+ WSAEMSGSIZE Errno = 10040
WSAECONNABORTED Errno = 10053
WSAECONNRESET Errno = 10054
)