a way to detect closed network connections

2,746 views
Skip to first unread message

roger peppe

unread,
Apr 26, 2012, 6:38:19 AM4/26/12
to golang-dev
To stop a network listener or reader, it's idiomatic to close
the underlying Listener or Conn from another goroutine.
This causes the ongoing operation to fail with an error.

Currently I don't think there's a way to portably distinguish
between a genuine error and an error induced in this way,
so the caller is forced either to ignore errors, or produce errors
at inappropriate times.

For instance, depending on the relative scheduling of
the two goroutines, this code (http://play.golang.org/p/U9n6myGYd6)
will print either:

accept: *net.OpError; accept tcp 127.0.0.1:55884: use of closed
network connection

or

accept: syscall.Errno; invalid argument

I'd like to see a function, say net.IsClosed(error) bool, which allows
this check.

Thoughts?

Russ Cox

unread,
May 1, 2012, 9:52:26 PM5/1/12
to roger peppe, golang-dev
Is it true that we can reliably detect this? I am reluctant to add
new functionality here that will cause distinctions between things
that work in Go 1.1 and things that work in Go 1, unless absolutely
necessary.

I would have expected that you could just set a flag 'closing = true'
before calling Close, and then check that if the Listen returns an
error.

Russ

roger peppe

unread,
May 2, 2012, 5:55:28 AM5/2/12
to r...@golang.org, golang-dev
Thanks for the reply.

I think that's inherently racy. What if the Listen returns an error
just after you've set the closing flag but before you've called Close?

I *think* it's possible to reliably detect this - the only reason
that Accept returns EINVAL instead of errClosing when called on
a closed listener is that the test in Accept TCP does this:

if l == nil || l.fd == nil || l.fd.sysfd < 0 {
return nil, syscall.EINVAL
}

rather than this:

if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
if l.fd.sysfd < 0 {
return nil, errClosing
}

AFAICS the only way that sysfd can become negative is because the connection
was closed, and the way that fds are handled, I don't think a system fd is ever
closed while there's a syscall in progress on it, so we'll never see the
underlying OS error for an operation on a closed fd.

I agree that changing this would lead to an observable difference in behaviour
between Go1.1 and Go1. It's your call as to whether it would be worth changing.

For the record, this is the 99% solution we adopted eventually:

type Server struct {
l net.Listener
errc chan error // with buffer size of 1.
}

func (s *Server) run() {
for {
conn, err := s.l.Accept()
if err != nil {
s.errc <- err
return
}
go s.serve(conn)
}
panic("not reached")
}

func (s *Server) serve(net.Conn) {
}

func (s *Server) Close() (err error) {
// Check whether the listener has returned an error already.
select {
case err = <-s.errc:
default:
}
s.l.Close()
return
}

Russ Cox

unread,
May 2, 2012, 7:45:11 AM5/2/12
to roger peppe, golang-dev
On Wed, May 2, 2012 at 5:55 AM, roger peppe <rogp...@gmail.com> wrote:
> I think that's inherently racy. What if the Listen returns an error
> just after you've set the closing flag but before you've called Close?

What if it does? Do you care?

Russ

roger peppe

unread,
May 2, 2012, 8:27:45 AM5/2/12
to r...@golang.org, golang-dev
Probably not. It's a matter of principle more than anything. Is
it OK to ignore an error because it happened at just the wrong time?

Also, I think that having IsClosed (or whatever it might be called)
would make for somewhat cleaner code.

It's not a big issue, certainly. I don't mind if we forget about it, but I think
it was worth raising.

Russ Cox

unread,
May 3, 2012, 5:42:37 PM5/3/12
to roger peppe, golang-dev
[again, to the list]

I think it would be fine to add net.IsClosed(error).
Do you want to write the CL?

roger peppe

unread,
May 4, 2012, 8:52:35 AM5/4/12
to r...@golang.org, golang-dev
i'm happy to write the CL. does that mean you think it's reasonable to
change code
that currently returns EINVAL to return errClosing instead in this case?

Russ Cox

unread,
May 7, 2012, 9:26:14 AM5/7/12
to roger peppe, golang-dev
On Fri, May 4, 2012 at 8:52 AM, roger peppe <rogp...@gmail.com> wrote:
> i'm happy to write the CL. does that mean you think it's reasonable to
> change code
> that currently returns EINVAL to return errClosing instead in this case?

Probably.
Reply all
Reply to author
Forward
0 new messages