Bug 106241
Summary: | shutdown()/close() behaviour is incorrect for sockets in accept() | ||
---|---|---|---|
Product: | Networking | Reporter: | Alan Burlison (Alan.Burlison) |
Component: | IPV4 | Assignee: | Stephen Hemminger (stephen) |
Status: | NEW --- | ||
Severity: | normal | CC: | cmccabe, szg00000 |
Priority: | P1 | ||
Hardware: | All | ||
OS: | Linux | ||
Kernel Version: | 3.10.0-229.14.1.el7.x86_64 | Subsystem: | |
Regression: | No | Bisected commit-id: | |
Attachments: |
Test program illustrating the problem
Extended test case with poll() |
Description
Alan Burlison
2015-10-19 13:21:33 UTC
If the listen(3) socket is checked with poll(3) before accept(3) then the behaviour is even more bizarre - poll(3) returns immediately with (POLLOUT | POLLWRBAND) set but any attempt to write(2) If the listen()ing socket is checked with poll() before accept() then the behaviour is even more bizarre - poll() returns immediately with (POLLOUT|POLLWRBAND) set even when nothing is trying to connect to the listening socket. Any attempt to write() fails with ENOTCONN despite poll() just having said the socket is available for output. An accept() immediately after the poll() returns then waits until there's an actual incoming connection, even though poll() just said the socket was ready. On Solaris the poll() waits until there is an incoming connection on the socket and an accept() on the socket returns immediately with the new connection. Created attachment 190521 [details]
Extended test case with poll()
I think Linux's behavior is more useful than Solaris' here. With Solaris' behavior, there is no way to break out of a blocking accept() other than closing the socket. As a real-world example, Hadoop uses shutdown() on sockets which are calling accept() to cause those accept()s to terminate. It would not be possible to use close() in this scenario, since there would be a race condition where the socket FD number could be reused by a newly opened FD between the call to close() and the call to accept(). I would also argue that POSIX doesn't forbid Linux's behavior, and that changing it now would be a compatibility problem. In the case of Hadoop, if you mare closing the accept() socket why do you care if it gets reused anywhere else? The Hadoop code in question invalidates the object containing the filehandle so the filehandle won't be used for any future IO anyway. The POSIX spec says that shutdown() should return ENOTCONN if the socket is not connected and sockets in accept() aren't ever connected, so POSIX does rule out the Linux behaviour. Having said that, I do agree that changing the Linux behaviour would most likely break existing software. In which case documenting the behaviour in the manpage may be the only option. Having said all that, the Linux behaviour of close() and poll() on listen()ing sockets also seems incorrect. Yes, calling close() on a socket that's in accept() may well expose MT applications to potential races but that's not a justification for the current close() behaviour, where the accept() continues after the close(). |