Page MenuHomeFreeBSD

Make shutdown() return ENOTCONN as required by POSIX, part deux.
AbandonedPublic

Authored by ed on Jul 9 2015, 2:38 PM.

Details

Summary

Back in 2005, maxim@ attempted to fix shutdown() to return ENOTCONN in case the socket was not connected (r150152). This had to be rolled back (r150155), as it broke some of the existing programs that depend on this behavior. I reapplied this change on my system and indeed, syslogd failed to start up. I fixed this back in February (279016) and MFC'ed it to the supported stable branches. Apart from that, things seem to work out all right.

Since at least Linux and Mac OS X do the right thing, I'd like to go ahead and give this another try. To keep old copies of syslogd working, only start returning ENOTCONN for recent binaries.

I took a look at the XNU sources and they seem to test against both SS_ISCONNECTED, SS_ISCONNECTING and SS_ISDISCONNECTING, instead of just SS_ISCONNECTED. That seams reasonable, so let's do the same.

Test Plan

This issue was uncovered while writing tests for shutdown() in CloudABI:

https://github.com/NuxiNL/cloudlibc/blob/master/src/libc/sys/socket/shutdown_test.c#L26

Diff Detail

Repository
rS FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

ed updated this revision to Diff 6821.Jul 9 2015, 2:38 PM
ed retitled this revision from to Make shutdown() return ENOTCONN as required by POSIX, part deux..
ed updated this object.
ed edited the test plan for this revision. (Show Details)
ed added reviewers: network, gnn.
ed set the repository for this revision to rS FreeBSD src repository.
mjg added a subscriber: mjg.Jul 10 2015, 12:30 AM

Introduction of a new syscall seems like a waste.

One can check p_osrel instead which may turn out to be sufficient. Since head's syslogd was updated some time ago, it may be fine enough to test against the latest __FreeBSD_version (or we can spare one just as a marker for this check introduction).

I can't comment on error checking itself.

ed updated this revision to Diff 6838.Jul 10 2015, 7:27 AM
ed updated this object.
ed added a comment.Jul 10 2015, 7:29 AM
In D3039#60038, @mjg wrote:

One can check p_osrel instead which may turn out to be sufficient. Since head's syslogd was updated some time ago, it may be fine enough to test against the latest __FreeBSD_version (or we can spare one just as a marker for this check introduction).

Wow. That's a nifty feature. That looks a whole lot better. I've updated the change to match against the latest __FreeBSD_version. I think it's not worth increasing, for the reason that it is possible to write code that supports both systems without any explicit checking.

ed added a reviewer: glebius.Jul 16 2015, 4:26 PM

Friendly ping. :-)

ed added a reviewer: rwatson.Jul 25 2015, 5:31 PM
ed updated this revision to Diff 7378.Jul 27 2015, 11:37 AM

Also update the manual page to reflect the changes to the behaviour.

bms added a subscriber: bms.Jul 27 2015, 12:56 PM
bms added a comment.Jul 27 2015, 1:00 PM

The new behaviour appears to be POSIXly correct. POSIX shutdown spec

gnn accepted this revision.Jul 27 2015, 1:16 PM
gnn edited edge metadata.
This revision is now accepted and ready to land.Jul 27 2015, 1:16 PM
This revision was automatically updated to reflect the committed changes.
sobomax reopened this revision.Apr 10 2017, 2:52 PM
sobomax added a subscriber: sobomax.

I think Ed's comparison with other OSes here and in the relevant differential was not entirely correct. What linux does (tested with 4.4.0) when UDP socket is shut down is actually shutting down receiving end, so any threads that are blocked in recv() on that socket return. Still shutdown() system call itself returns ENOTCONN. FreeBSD on the other hand does not do anything for the socket, so that the threads just hang. I am pretty sure there are at least some software out there that relies on that behavior, at least in our case we do. Bumped into this after upgrading to the 11.0.

Therefore, I am curious about possibility to make our behavior match that of Linux's, so we are not the odd one with regards to this, that is return an error but still shutdown the socket?

Small test case is attached. Both FreeBSD 10.3 and Linux 4.4.0 pass (albeit Linux's shutdown() returns with an error), FreeBSD 11.0 fails.

This revision is now accepted and ready to land.Apr 10 2017, 2:52 PM
sobomax requested changes to this revision.Apr 10 2017, 2:54 PM
This revision now requires changes to proceed.Apr 10 2017, 2:54 PM
rwatson edited edge metadata.Apr 11 2017, 1:17 PM

Note that this is not the complete story: There's a separate issue with "interrupting" threads already blocked in I/O on sockets at shutdown(2) time. Lack of that support causes a test failure in the Java test suite (if I recall) because calling shutdown(2) on a socket from one thread while another thread is blocked in read(2)/recv(2) or write(2)/send(2) will not interrupt the blocked thread. This is due to the way we do locking and reference counting on file descriptors and sockets.

ed abandoned this revision.Jul 28 2017, 7:07 AM