Skip to content

Commit

Permalink
net: fix inconsistent errors
Browse files Browse the repository at this point in the history
These a series of changes fix inconsistent errors on the package net
APIs. Now almost all the APIs return OpError as a common error type
except Lookup, Resolve and Parse APIs. The Lookup, Resolve and Parse
APIs return more specific errors such as DNSError, AddrError or
ParseError.

An OpError may contain nested error information. For example, Dial may
return an OpError containing a DNSError, AddrError, unexposed type/value
or other package's type/value like the following:
	OpError{/* dial info */, Err: &DNSError{}}
	OpError{/* dial info */, Err: &AddrError{}}
	OpError{/* dial info */, Err: <unexposed type or value>}
	OpError{/* dial info */, Err: <other package's type or value>}

and Read and Write may return an OpError containing other OpError when
an application uses io.Copy or similar:
	OpError{/* for io.Reader */, Err: &OpError{/* for io.Writer */}}

When an endpoint is created for connection-oriented byte-stream
protocols, Read may return an io.EOF when the connection is closed by
remote endpoint.

Fixes golang#4856.

A series of changes:
- net: fix inconsistent error values on Dial, Listen partially
  https://go.googlesource.com/go/+/89b7c66d0d14462fd7893be4290bdfe5f9063ae1
- net: fix inconsistent error values on Read
  https://go.googlesource.com/go/+/ec1144423f45e010c72363fe59291d43214b6e31
- net: fix inconsistent error values on Write
  https://go.googlesource.com/go/+/11b5f98bf0d5eb8854f735cc332c912725070214
- net: fix inconsistent error values on Close
  https://go.googlesource.com/go/+/310db63c5bc121e7bfccb494c01a6b91a257e7fc
- net: fix inconsistent error values on Accept
  https://go.googlesource.com/go/+/4540e162b1aefda8157372764ad3d290a414ef1d
- net: fix inconsistent error values on File
  https://go.googlesource.com/go/+/885111365ba0a74421059bfbd18f4c57c1e70332
- net: fix inconsistent error values on setters
  https://go.googlesource.com/go/+/2173a27903897c481b0a0daf3ca3e0a0685701db
- net: fix inconsistent error values on Interface
  https://go.googlesource.com/go/+/456cf0f22c93e1a6654980f4a48a564555f6c8a2
- net: fix inconsistent error values on Lookup
  https://go.googlesource.com/go/+/0fc582e87942b2e52bed751b6c56660ba99e9a7d
- net: add Source field to OpError
  https://go.googlesource.com/go/+/afd2d2b6df3ebfe99faf347030f15adfdf422fa0

Change-Id: Id678e369088dc9fbe9073cfe7ff8a8754a57d61f
Reviewed-on: https://go-review.googlesource.com/9236
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
cixtor committed May 5, 2015
1 parent 2708f19 commit 055ecb7
Show file tree
Hide file tree
Showing 27 changed files with 225 additions and 138 deletions.
2 changes: 1 addition & 1 deletion src/net/fd_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
dfd, err := syscall.Dup(int(f.Fd()), -1)
syscall.ForkLock.RUnlock()
if err != nil {
return nil, err
return nil, os.NewSyscallError("dup", err)
}
return os.NewFile(uintptr(dfd), s), nil
}
Expand Down
47 changes: 36 additions & 11 deletions src/net/fd_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
}
fallthrough
default:
return err
return os.NewSyscallError("connect", err)
}
if err := fd.init(); err != nil {
return err
Expand All @@ -116,14 +116,14 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
}
nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
if err != nil {
return err
return os.NewSyscallError("getsockopt", err)
}
switch err := syscall.Errno(nerr); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case syscall.Errno(0), syscall.EISCONN:
return nil
default:
return err
return os.NewSyscallError("getsockopt", err)
}
}
}
Expand Down Expand Up @@ -205,7 +205,7 @@ func (fd *netFD) shutdown(how int) error {
return err
}
defer fd.decref()
return syscall.Shutdown(fd.sysfd, how)
return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
}

func (fd *netFD) closeRead() error {
Expand Down Expand Up @@ -237,6 +237,9 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
err = fd.eofError(n, err)
break
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("read", err)
}
return
}

Expand All @@ -261,6 +264,9 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
err = fd.eofError(n, err)
break
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("recvfrom", err)
}
return
}

Expand All @@ -285,6 +291,9 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
err = fd.eofError(n, err)
break
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("recvmsg", err)
}
return
}

Expand Down Expand Up @@ -318,6 +327,9 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
break
}
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("write", err)
}
return nn, err
}

Expand All @@ -341,6 +353,9 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
if err == nil {
n = len(p)
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("sendto", err)
}
return
}

Expand All @@ -364,6 +379,9 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
if err == nil {
oobn = len(oob)
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("sendmsg", err)
}
return
}

Expand All @@ -381,13 +399,20 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
for {
s, rsa, err = accept(fd.sysfd)
if err != nil {
if err == syscall.EAGAIN {
nerr, ok := err.(*os.SyscallError)
if !ok {
return nil, err
}
switch nerr.Err {
case syscall.EAGAIN:
if err = fd.pd.WaitRead(); err == nil {
continue
}
} else if err == syscall.ECONNABORTED {
// This means that a socket on the listen queue was closed
// before we Accept()ed it; it's a silly error, so try again.
case syscall.ECONNABORTED:
// This means that a socket on the
// listen queue was closed before we
// Accept()ed it; it's a silly error,
// so try again.
continue
}
return nil, err
Expand Down Expand Up @@ -436,7 +461,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
// from now on.
atomic.StoreInt32(&tryDupCloexec, 0)
default:
return -1, e1
return -1, os.NewSyscallError("fcntl", e1)
}
}
return dupCloseOnExecOld(fd)
Expand All @@ -449,7 +474,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
defer syscall.ForkLock.RUnlock()
newfd, err = syscall.Dup(fd)
if err != nil {
return -1, err
return -1, os.NewSyscallError("dup", err)
}
syscall.CloseOnExec(newfd)
return
Expand All @@ -466,7 +491,7 @@ func (fd *netFD) dup() (f *os.File, err error) {
// I/O will block the thread instead of letting us use the epoll server.
// Everything will still work, just with more threads.
if err = syscall.SetNonblock(ns, false); err != nil {
return nil, err
return nil, os.NewSyscallError("setnonblock", err)
}

return os.NewFile(uintptr(ns), fd.name()), nil
Expand Down
41 changes: 32 additions & 9 deletions src/net/fd_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func sysInit() {
var d syscall.WSAData
e := syscall.WSAStartup(uint32(0x202), &d)
if e != nil {
initErr = os.NewSyscallError("WSAStartup", e)
initErr = os.NewSyscallError("wsastartup", e)
}
canCancelIO = syscall.LoadCancelIoEx() == nil
if syscall.LoadGetAddrInfo() == nil {
Expand Down Expand Up @@ -297,7 +297,7 @@ func (fd *netFD) init() error {
size := uint32(unsafe.Sizeof(flag))
err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
if err != nil {
return os.NewSyscallError("WSAIoctl", err)
return os.NewSyscallError("wsaioctl", err)
}
}
fd.rop.mode = 'r'
Expand Down Expand Up @@ -331,7 +331,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
defer fd.setWriteDeadline(noDeadline)
}
if !canUseConnectEx(fd.net) {
return connectFunc(fd.sysfd, ra)
return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
}
// ConnectEx windows API requires an unconnected, previously bound socket.
if la == nil {
Expand All @@ -344,7 +344,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
panic("unexpected type in connect")
}
if err := syscall.Bind(fd.sysfd, la); err != nil {
return err
return os.NewSyscallError("bind", err)
}
}
// Call ConnectEx API.
Expand All @@ -354,10 +354,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
})
if err != nil {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("connectex", err)
}
return err
}
// Refresh socket properties.
return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
}

func (fd *netFD) destroy() {
Expand Down Expand Up @@ -461,7 +464,11 @@ func (fd *netFD) Read(buf []byte) (int, error) {
if raceenabled {
raceAcquire(unsafe.Pointer(&ioSync))
}
return n, fd.eofError(n, err)
err = fd.eofError(n, err)
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsarecv", err)
}
return n, err
}

func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
Expand All @@ -482,11 +489,14 @@ func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
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 _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsarecvfrom", err)
}
if err != nil {
return n, nil, err
}
sa, _ := o.rsa.Sockaddr()
return n, sa, err
return n, sa, nil
}

func (fd *netFD) Write(buf []byte) (int, error) {
Expand All @@ -502,6 +512,9 @@ func (fd *netFD) Write(buf []byte) (int, error) {
n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
})
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsasend", err)
}
return n, err
}

Expand All @@ -519,6 +532,9 @@ func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
})
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsasendto", err)
}
return n, err
}

Expand Down Expand Up @@ -548,14 +564,17 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
})
if err != nil {
netfd.Close()
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("acceptex", err)
}
return nil, err
}

// Inherit properties of the listening socket.
err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
if err != nil {
netfd.Close()
return nil, err
return nil, os.NewSyscallError("setsockopt", err)
}

return netfd, nil
Expand All @@ -581,7 +600,11 @@ func (fd *netFD) accept() (*netFD, error) {
// before AcceptEx could complete. These errors relate to new
// connection, not to AcceptEx, so ignore broken connection and
// try AcceptEx again for more connections.
errno, ok := err.(syscall.Errno)
nerr, ok := err.(*os.SyscallError)
if !ok {
return nil, err
}
errno, ok := nerr.Err.(syscall.Errno)
if !ok {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions src/net/file_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {

path, err := syscall.Fd2path(int(f.Fd()))
if err != nil {
return nil, err
return nil, os.NewSyscallError("fd2path", err)
}
comp := splitAtBytes(path, "/")
n := len(comp)
Expand All @@ -54,7 +54,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
fd, err := syscall.Dup(int(f.Fd()), -1)
syscall.ForkLock.RUnlock()
if err != nil {
return nil, err
return nil, os.NewSyscallError("dup", err)
}
defer close(fd)

Expand Down
4 changes: 2 additions & 2 deletions src/net/file_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ func newFileFD(f *os.File) (*netFD, error) {

if err = syscall.SetNonblock(fd, true); err != nil {
closeFunc(fd)
return nil, err
return nil, os.NewSyscallError("setnonblock", err)
}

sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
if err != nil {
closeFunc(fd)
return nil, err
return nil, os.NewSyscallError("getsockopt", err)
}

family := syscall.AF_UNSPEC
Expand Down
13 changes: 7 additions & 6 deletions src/net/interface_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package net

import (
"os"
"syscall"
"unsafe"
)
Expand All @@ -17,11 +18,11 @@ import (
func interfaceTable(ifindex int) ([]Interface, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
if err != nil {
return nil, err
return nil, os.NewSyscallError("routerib", err)
}
msgs, err := syscall.ParseRoutingMessage(tab)
if err != nil {
return nil, err
return nil, os.NewSyscallError("parseroutingmessage", err)
}
return parseInterfaceTable(ifindex, msgs)
}
Expand Down Expand Up @@ -50,7 +51,7 @@ loop:
func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, err
return nil, os.NewSyscallError("parseroutingsockaddr", err)
}
ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
Expand Down Expand Up @@ -103,11 +104,11 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
}
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
if err != nil {
return nil, err
return nil, os.NewSyscallError("routerib", err)
}
msgs, err := syscall.ParseRoutingMessage(tab)
if err != nil {
return nil, err
return nil, os.NewSyscallError("parseroutingmessage", err)
}
var ift []Interface
if index == 0 {
Expand Down Expand Up @@ -144,7 +145,7 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, err
return nil, os.NewSyscallError("parseroutingsockaddr", err)
}
ifa := &IPNet{}
switch sa := sas[syscall.RTAX_NETMASK].(type) {
Expand Down
Loading

0 comments on commit 055ecb7

Please sign in to comment.