import (
"fmt"
+ "io"
"net/internal/socktest"
"os"
"runtime"
}
}
}
+
+// parseReadError parses nestedErr and reports whether it is a valid
+// error value from Read functions.
+// It returns nil when nestedErr is valid.
+func parseReadError(nestedErr error) error {
+ if nestedErr == nil {
+ return nil
+ }
+
+ switch err := nestedErr.(type) {
+ case *OpError:
+ if err := err.isValid(); err != nil {
+ return err
+ }
+ nestedErr = err.Err
+ goto second
+ }
+ if nestedErr == io.EOF {
+ return nil
+ }
+ return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+ if isPlatformError(nestedErr) {
+ return nil
+ }
+ switch err := nestedErr.(type) {
+ case *os.SyscallError:
+ nestedErr = err.Err
+ goto third
+ }
+ switch nestedErr {
+ case errClosing, errTimeout:
+ return nil
+ }
+ return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+ if isPlatformError(nestedErr) {
+ return nil
+ }
+ return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
}
defer fd.readUnlock()
if err := fd.pd.PrepareRead(); err != nil {
- return 0, &OpError{"read", fd.net, fd.raddr, err}
+ return 0, err
}
for {
n, err = syscall.Read(int(fd.sysfd), p)
err = fd.eofError(n, err)
break
}
- if err != nil && err != io.EOF {
- err = &OpError{"read", fd.net, fd.raddr, err}
- }
return
}
}
defer fd.readUnlock()
if err := fd.pd.PrepareRead(); err != nil {
- return 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+ return 0, nil, err
}
for {
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
err = fd.eofError(n, err)
break
}
- if err != nil && err != io.EOF {
- err = &OpError{"read", fd.net, fd.laddr, err}
- }
return
}
}
defer fd.readUnlock()
if err := fd.pd.PrepareRead(); err != nil {
- return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+ return 0, 0, 0, nil, err
}
for {
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
err = fd.eofError(n, err)
break
}
- if err != nil && err != io.EOF {
- err = &OpError{"read", fd.net, fd.laddr, err}
- }
return
}
package net
import (
- "io"
"os"
"runtime"
"sync"
func (fd *netFD) Read(buf []byte) (int, error) {
if err := fd.readLock(); err != nil {
- return 0, &OpError{Op: "read", Net: fd.net, Addr: fd.raddr, Err: err}
+ return 0, err
}
defer fd.readUnlock()
o := &fd.rop
if raceenabled {
raceAcquire(unsafe.Pointer(&ioSync))
}
- err = fd.eofError(n, err)
- if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: fd.net, Addr: fd.raddr, Err: err}
- }
- return n, err
+ return n, fd.eofError(n, err)
}
func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
return 0, nil, nil
}
if err := fd.readLock(); err != nil {
- return 0, nil, &OpError{Op: "read", Net: fd.net, Addr: fd.laddr, Err: err}
+ return 0, nil, err
}
defer fd.readUnlock()
o := &fd.rop
o.rsan = int32(unsafe.Sizeof(*o.rsa))
return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
})
- err = fd.eofError(n, err)
- if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: fd.net, Addr: fd.laddr, Err: err}
- }
sa, _ := o.rsa.Sockaddr()
- return n, sa, err
+ return n, sa, fd.eofError(n, err)
}
func (fd *netFD) Write(buf []byte) (int, error) {
}
func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
- return 0, 0, 0, nil, &OpError{Op: "read", Net: fd.net, Addr: fd.laddr, Err: syscall.EWINDOWS}
+ return 0, 0, 0, nil, syscall.EWINDOWS
}
func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
- return 0, nil, syscall.EPLAN9
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// ReadFrom implements the PacketConn ReadFrom method.
func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
- return 0, nil, syscall.EPLAN9
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
// bytes copied into b, the number of bytes copied into oob, the flags
// that were set on the packet and the source address of the packet.
func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
- return 0, 0, 0, nil, syscall.EPLAN9
+ return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// WriteToIP writes an IP packet to addr via c, copying the payload
case *syscall.SockaddrInet6:
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
return n, addr, err
}
case *syscall.SockaddrInet6:
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
return
}
if !c.ok() {
return 0, syscall.EINVAL
}
- return c.fd.Read(b)
+ n, err := c.fd.Read(b)
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "read", Net: c.fd.net, Err: err}
+ if c.fd.raddr != nil {
+ err.(*OpError).Addr = c.fd.raddr
+ } else {
+ err.(*OpError).Addr = c.fd.laddr // for unconnected-mode sockets
+ }
+ }
+ return n, err
}
// Write implements the Conn Write method.
}
var buf [10]byte
n, err := c.Read(buf[:])
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if n != 0 || err != io.EOF {
t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
return
}
var buf [10]byte
n, err := c.Read(buf[:])
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if n != 0 || err != io.EOF {
t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
return
}()
go func() {
_, _, err = ln.ReadFrom(buf)
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if err == nil {
t.Error("ReadFrom succeeded")
} else {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile together)
- err = &OpError{"sendfile", c.net, c.raddr, err1}
+ err = err1
break
}
}
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile together)
- err = &OpError{"sendfile", c.net, c.raddr, err1}
+ err = err1
break
}
}
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile together)
- err = &OpError{"sendfile", c.net, c.raddr, err1}
+ err = err1
break
}
}
// ReadFrom implements the io.ReaderFrom ReadFrom method.
func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
- return genericReadFrom(c, r)
+ n, err := genericReadFrom(c, r)
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+ }
+ return n, err
}
// CloseRead shuts down the reading side of the TCP connection.
// ReadFrom implements the io.ReaderFrom ReadFrom method.
func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
if n, err, handled := sendFile(c.fd, r); handled {
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+ }
return n, err
}
- return genericReadFrom(c, r)
+ n, err := genericReadFrom(c, r)
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+ }
+ return n, err
}
// CloseRead shuts down the reading side of the TCP connection.
if _, err = c.Read(buf); !isTimeoutError(err) {
t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
}
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if _, err = c.Read(buf); !isTimeoutError(err) {
t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
}
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
if _, err = c.Read(buf); !isTimeoutError(err) {
t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
}
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if _, err = c.Read(buf); !isTimeoutError(err) {
t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
}
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
c.SetReadDeadline(noDeadline)
c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
errc := make(chan error)
c.Close()
switch nerr := <-errc; err := nerr.(type) {
case *OpError:
- if err.Err != errClosing {
- t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
}
default:
if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
break
}
- if err != errClosing {
- t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
}
}
}
c.SetReadDeadline(time.Now().Add(-5 * time.Second)) // in the psat.
buf := make([]byte, len(msg)/2)
n, err := c.Read(buf)
+ if perr := parseReadError(err); perr != nil {
+ t.Error(perr)
+ }
if n > 0 || !isTimeoutError(err) {
t.Fatalf("client read = %d (%q) err=%v; want 0, timeout", n, buf[:n], err)
}
buf := make([]byte, udpHeaderSize+len(b))
m, err := c.fd.data.Read(buf)
if err != nil {
- return
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
}
if m < udpHeaderSize {
- return 0, nil, errors.New("short read reading UDP header")
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: errors.New("short read reading UDP header")}
}
buf = buf[:m]
// flags that were set on the packet and the source address of the
// packet.
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
- return 0, 0, 0, nil, syscall.EPLAN9
+ return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// WriteToUDP writes a UDP packet to addr via c, copying the payload
// ReadFromUDP can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
+func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
+ var addr *UDPAddr
n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
case *syscall.SockaddrInet6:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
}
- return
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
+ return n, addr, err
}
// ReadFrom implements the PacketConn ReadFrom method.
case *syscall.SockaddrInet6:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
}
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
return
}
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
- return 0, nil, syscall.EPLAN9
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
- return 0, nil, syscall.EPLAN9
+ return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// ReadMsgUnix reads a packet from c, copying the payload into b and
// bytes copied into b, the number of bytes copied into oob, the flags
// that were set on the packet, and the source address of the packet.
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
- return 0, 0, 0, nil, syscall.EPLAN9
+ return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
}
// WriteToUnix writes a packet to addr via c, copying the payload from b.
// ReadFromUnix can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
+func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
+ var addr *UnixAddr
n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
- return
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
+ return n, addr, err
}
// ReadFrom implements the PacketConn ReadFrom method.
addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
+ if err != nil {
+ err = &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+ }
return
}