]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix inconsistent error values on Close
authorMikio Hara <mikioh.mikioh@gmail.com>
Fri, 17 Apr 2015 03:24:42 +0000 (12:24 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Sat, 18 Apr 2015 03:12:04 +0000 (03:12 +0000)
This change fixes inconsistent error values on Close, CloseRead and
CloseWrite.

Updates #4856.

Change-Id: I3c4d46ccd7d6e1a2f52d8e75b512f62c533a368d
Reviewed-on: https://go-review.googlesource.com/8994
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/error_test.go
src/net/fd_unix.go
src/net/fd_windows.go
src/net/net.go
src/net/tcpsock_plan9.go
src/net/tcpsock_posix.go
src/net/unixsock_plan9.go
src/net/unixsock_posix.go

index 5668027d9801a8b946ce0a5ee410fa5d593d2e55..9f4a90d8e1812f8a5bbd663418362d4d9ed54c93 100644 (file)
@@ -332,3 +332,95 @@ third:
        }
        return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
 }
+
+// parseCloseError parses nestedErr and reports whether it is a valid
+// error value from Close functions.
+// It returns nil when nestedErr is valid.
+func parseCloseError(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
+       }
+       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
+       case *os.PathError: // for Plan 9
+               nestedErr = err.Err
+               goto third
+       }
+       switch nestedErr {
+       case errClosing:
+               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)
+}
+
+func TestCloseError(t *testing.T) {
+       ln, err := newLocalListener("tcp")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer ln.Close()
+       c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer c.Close()
+
+       for i := 0; i < 3; i++ {
+               err = c.(*TCPConn).CloseRead()
+               if perr := parseCloseError(err); perr != nil {
+                       t.Errorf("#%d: %v", i, perr)
+               }
+       }
+       for i := 0; i < 3; i++ {
+               err = c.(*TCPConn).CloseWrite()
+               if perr := parseCloseError(err); perr != nil {
+                       t.Errorf("#%d: %v", i, perr)
+               }
+       }
+       for i := 0; i < 3; i++ {
+               err = c.Close()
+               if perr := parseCloseError(err); perr != nil {
+                       t.Errorf("#%d: %v", i, perr)
+               }
+               err = ln.Close()
+               if perr := parseCloseError(err); perr != nil {
+                       t.Errorf("#%d: %v", i, perr)
+               }
+       }
+
+       pc, err := ListenPacket("udp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer pc.Close()
+
+       for i := 0; i < 3; i++ {
+               err = pc.Close()
+               if perr := parseCloseError(err); perr != nil {
+                       t.Errorf("#%d: %v", i, perr)
+               }
+       }
+}
index 99d7a939d697127cd71acd0f531a358c694eb64f..a7e6d40359786f06e66dfef79754ac5c8af242c0 100644 (file)
@@ -205,11 +205,7 @@ func (fd *netFD) shutdown(how int) error {
                return err
        }
        defer fd.decref()
-       err := syscall.Shutdown(fd.sysfd, how)
-       if err != nil {
-               return &OpError{"shutdown", fd.net, fd.laddr, err}
-       }
-       return nil
+       return syscall.Shutdown(fd.sysfd, how)
 }
 
 func (fd *netFD) closeRead() error {
index e4038b90fa5194964c46fece2673407e606f71c0..bdc6d5f15e9386ce9f51f5bf2644cf5b415e9366 100644 (file)
@@ -437,11 +437,7 @@ func (fd *netFD) shutdown(how int) error {
                return err
        }
        defer fd.decref()
-       err := syscall.Shutdown(fd.sysfd, how)
-       if err != nil {
-               return &OpError{"shutdown", fd.net, fd.laddr, err}
-       }
-       return nil
+       return syscall.Shutdown(fd.sysfd, how)
 }
 
 func (fd *netFD) closeRead() error {
index 38375cc8a0c9be0def91395897b19488ca660352..83739b63133421092576c69a7cc0b18a4c28c3b8 100644 (file)
@@ -155,7 +155,16 @@ func (c *conn) Close() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.Close()
+       err := c.fd.Close()
+       if err != nil {
+               err = &OpError{Op: "close", 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 err
 }
 
 // LocalAddr returns the local network address.
index 2e646edf503b64bde497b475480d8a47710112d9..2390cbddb8112587d46de6acbe2b77d02fa48489 100644 (file)
@@ -36,7 +36,11 @@ func (c *TCPConn) CloseRead() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeRead()
+       err := c.fd.closeRead()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -45,7 +49,11 @@ func (c *TCPConn) CloseWrite() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeWrite()
+       err := c.fd.closeWrite()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -155,9 +163,13 @@ func (l *TCPListener) Close() error {
        }
        if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
                l.fd.ctl.Close()
-               return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err}
+               return &OpError{Op: "close", Net: l.fd.net, Addr: l.fd.laddr, Err: err}
+       }
+       err := l.fd.ctl.Close()
+       if err != nil {
+               err = &OpError{Op: "close", Net: l.fd.net, Addr: l.fd.laddr, Err: err}
        }
-       return l.fd.ctl.Close()
+       return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
index 91c8b0bdbb7eff35b110f9baa28cd2cfdbdb01ee..5a4c28be4f1d9ac7133b81a17e44d2ef7d6be2cb 100644 (file)
@@ -78,7 +78,11 @@ func (c *TCPConn) CloseRead() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeRead()
+       err := c.fd.closeRead()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -87,7 +91,11 @@ func (c *TCPConn) CloseWrite() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeWrite()
+       err := c.fd.closeWrite()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -254,7 +262,11 @@ func (l *TCPListener) Close() error {
        if l == nil || l.fd == nil {
                return syscall.EINVAL
        }
-       return l.fd.Close()
+       err := l.fd.Close()
+       if err != nil {
+               err = &OpError{Op: "close", Net: l.fd.net, Addr: l.fd.laddr, Err: err}
+       }
+       return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
index bb8c4dd609c460419d63d91ddf6f28e919610f30..fb47e72e0c2678c61a1cec207c0ee58814b07357 100644 (file)
@@ -65,13 +65,13 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
 // CloseRead shuts down the reading side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseRead() error {
-       return syscall.EPLAN9
+       return &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseWrite() error {
-       return syscall.EPLAN9
+       return &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -111,7 +111,7 @@ func (l *UnixListener) Accept() (Conn, error) {
 // Close stops listening on the Unix address.  Already accepted
 // connections are not closed.
 func (l *UnixListener) Close() error {
-       return syscall.EPLAN9
+       return &OpError{Op: "close", Net: "<nil>", Addr: nil, Err: syscall.EPLAN9}
 }
 
 // Addr returns the listener's network address.
index d51599f3bbaa09c6eb5620c2205e784738ba941d..4087c9d6bdfeafb09e0f074d02c2240d9aa56382 100644 (file)
@@ -233,7 +233,11 @@ func (c *UnixConn) CloseRead() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeRead()
+       err := c.fd.closeRead()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
@@ -242,7 +246,11 @@ func (c *UnixConn) CloseWrite() error {
        if !c.ok() {
                return syscall.EINVAL
        }
-       return c.fd.closeWrite()
+       err := c.fd.closeWrite()
+       if err != nil {
+               err = &OpError{Op: "close", Net: c.fd.net, Addr: c.fd.raddr, Err: err}
+       }
+       return err
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -335,7 +343,11 @@ func (l *UnixListener) Close() error {
        if l.path[0] != '@' {
                syscall.Unlink(l.path)
        }
-       return l.fd.Close()
+       err := l.fd.Close()
+       if err != nil {
+               err = &OpError{Op: "close", Net: l.fd.net, Addr: l.fd.laddr, Err: err}
+       }
+       return err
 }
 
 // Addr returns the listener's network address.