mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net: fix inconsistent error values on Close
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>
This commit is contained in:
parent
11b5f98bf0
commit
310db63c5b
8 changed files with 153 additions and 24 deletions
|
|
@ -332,3 +332,95 @@ third:
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,11 +205,7 @@ func (fd *netFD) shutdown(how int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.Shutdown(fd.sysfd, how)
|
return syscall.Shutdown(fd.sysfd, how)
|
||||||
if err != nil {
|
|
||||||
return &OpError{"shutdown", fd.net, fd.laddr, err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) closeRead() error {
|
func (fd *netFD) closeRead() error {
|
||||||
|
|
|
||||||
|
|
@ -437,11 +437,7 @@ func (fd *netFD) shutdown(how int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.Shutdown(fd.sysfd, how)
|
return syscall.Shutdown(fd.sysfd, how)
|
||||||
if err != nil {
|
|
||||||
return &OpError{"shutdown", fd.net, fd.laddr, err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) closeRead() error {
|
func (fd *netFD) closeRead() error {
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,16 @@ func (c *conn) Close() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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.
|
// LocalAddr returns the local network address.
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,11 @@ func (c *TCPConn) CloseRead() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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.
|
// CloseWrite shuts down the writing side of the TCP connection.
|
||||||
|
|
@ -45,7 +49,11 @@ func (c *TCPConn) CloseWrite() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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
|
// 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 {
|
if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
|
||||||
l.fd.ctl.Close()
|
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}
|
||||||
}
|
}
|
||||||
return l.fd.ctl.Close()
|
err := l.fd.ctl.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.
|
// Addr returns the listener's network address, a *TCPAddr.
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,11 @@ func (c *TCPConn) CloseRead() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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.
|
// CloseWrite shuts down the writing side of the TCP connection.
|
||||||
|
|
@ -87,7 +91,11 @@ func (c *TCPConn) CloseWrite() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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
|
// 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 {
|
if l == nil || l.fd == nil {
|
||||||
return syscall.EINVAL
|
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.
|
// Addr returns the listener's network address, a *TCPAddr.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// CloseRead shuts down the reading side of the Unix domain connection.
|
||||||
// Most callers should just use Close.
|
// Most callers should just use Close.
|
||||||
func (c *UnixConn) CloseRead() error {
|
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.
|
// CloseWrite shuts down the writing side of the Unix domain connection.
|
||||||
// Most callers should just use Close.
|
// Most callers should just use Close.
|
||||||
func (c *UnixConn) CloseWrite() error {
|
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,
|
// 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
|
// Close stops listening on the Unix address. Already accepted
|
||||||
// connections are not closed.
|
// connections are not closed.
|
||||||
func (l *UnixListener) Close() error {
|
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.
|
// Addr returns the listener's network address.
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,11 @@ func (c *UnixConn) CloseRead() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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.
|
// CloseWrite shuts down the writing side of the Unix domain connection.
|
||||||
|
|
@ -242,7 +246,11 @@ func (c *UnixConn) CloseWrite() error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return syscall.EINVAL
|
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,
|
// DialUnix connects to the remote address raddr on the network net,
|
||||||
|
|
@ -335,7 +343,11 @@ func (l *UnixListener) Close() error {
|
||||||
if l.path[0] != '@' {
|
if l.path[0] != '@' {
|
||||||
syscall.Unlink(l.path)
|
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.
|
// Addr returns the listener's network address.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue