Repository navigation
close does not throw on ECONNRESET #329
Description
Activity
For the historic perspective,
closehas only ever thrown on -1. This behavior
was introduced in 2010 (fdd420f). Other return
codes have been ignored all the way back to 1.0 asc_closewas used directly
and its return code was discarded.Moving forward, it is an interesting question of what the "right" thing to
do is. For compatability it is probably prudent to not introduce a new exception.
If ensuring all data was recieved is integral to your application then I hope
that you'd be aware of this before closing a socket. However not throwing the
exception could lead to tricky bugs and difficult debugging sessions.Cc: @vdukhovni
@eborden For the historic perspective, close has only ever thrown on -1.
On Unix systems, the only possible return values from
close(2)are0and-1, so "only ever on -1" amounts to all failures of the underlying system call unless I'm missing something.RETURN VALUES The close() function returns the value 0 if successful; otherwise the value -1 is returned and the global variable errno is set to indicate the error.And yes, this is rather a judgement call. Not sure which is the more correct behaviour. The previous exception behaviour was undocumented, so you're at liberty to choose compatibility or avoid surprising to some exceptions on close.
Perhaps the solution is to just document that exceptions were thrown in older releases, but no longer are. Then see if anyone complains. I think that
ECONNRESETis not "reliable", in a successful close does not guarantee the data made it all the way to the peer application and got dealt with. So one might argue that an unreliable failure indication is not especially useful...What about providing two APIs?
closewhich drops errors -- most applications should use thissafeClose(or something) which throws an exception on failure.
Two functions might make sense, and this forces the issue on documentation, since the difference would need to be explained, and complete documentation is a good thing to have. The only issue is naming, I'm not sure that
safeCloseis an intuitive name. My son suggestsclose'. What do you think?close'is fine with me. Of course, document should be well-written.
Viktor ([email protected]) wrote from haskell-cafe:
In older releases of Network, I was initially surprised that
closing a connected TCP socket could throw an exception,
and so I had to take some care with:
to avoding crashing when close fails. The reason close failed,
is that if the caller is the last writer on the socket, then it
is possible that the kernel queued the last write, but got an RST
response from the peer when trying to deliver the data to the
remote destination. This is reported during close(2):
The original Network.Socket code converted this into an exception.
That had pros and cons. On the one hand, users naïvely assuming
that "close" can't fail won't find their code unexpectedly blowing
up. On the other hand users relying on the OS to report failure
of the final write will no longer get the delayed exception
(it is a feature that write(2) completes before the data is
acknowledged by the remote peer, otherwise TCP could not stream).
I am vaguely inclined to think that restoring the exception might
be the right thing, but on the other hand, if the last write is
important to deliver, it should perhaps be, and often is, more
properly confirmed at the application layer. So for many
applications the potential of an exception on close is an
annoyance.
One might also note that the documentation never covered the
possibility of such an exception, and the two code samples at
the top of the Network.Socket online docs don't suggest any
need to catch "close" errors. So this is likely a poorly
understood corner case.
With that said, what do you think? Should the Haskell Socket
"close" throw an exception when the native socket library
close returns an error? Or leave confirmation of the last
application data payload to the remote reader?