When TCP sockets refuse to die
idea.popcount.org
idea.popcount.org
* close(): socket will be lingering in background as usual
* shutdown(SHUT_RD): no network side effect, discards read buffer
* shutdown(SHUT_WR): equivalent to FIN SO_LINGER socket - if timeout non-zero blocks until write buffer flushed; if timeout is zero then immediately sends RST
* the trick with close() after TCP_REPAIR: (https://lwn.net/Articles/495304/) immediately discard a socket with no network side effects.
* "ss --kill" command: forcefully close a socket from outside process, done with netlink SOCK_DESTROY command.
My understanding is that if the read buffer is not empty, or if you later receive any further data from the other end, that this will result in a RST.
Wrt to linger behaviour: "if timeout non-zero blocks until write buffer flushed" is only true of blocking sockets. For non-blocking sockets things get complicated and vary across platforms
* shutdown(SHUT_RD): seem not to have _any_ side effects. you can totally still recv() on that socket. Kerrisk writes 61.6.6: "However if the peer application subsequently writes data on its socket, then it is still possible to read that data on the local socket". Basically, SHUT_RD makes recv() return 0. That's all it does.
* SO_LINGER on O_NONBLOCK: shutdown() doesn't block. close() still blocks.
That is not discussed in POSIX at all, I believe, so basically platform-unaware SHUT_RD is vaguely defined and I wouldn’t even rely on recv() returning zero in particular.
Edit: changed books domain to .com
Linux: after shutdown(SHUT_RD) all blocked recv() calls unblock and return 0. But the other side can still send data and the recv() call will still read it! It is just that after shutdown when there is nothing to read a recv() call immediately returns 0 instead of blocking.
macOS (and BSD, I presume?): The read buffer is discarded and all subsequent recv() calls return 0. If the other side sends data it is discarded.
Unfortunately I have no Windows machine around to try out.
Now, maybe someone can clarify, given such wildly different behavior what is the intended use case for shutdown(SHUT_RD)?
Sockets are known to be not very standard landscape historically. Best bet here is to just stick with that “Disables further receive operations” posix definition and follow it to the letter by not recv’ing anything anymore.
I am constantly amazed how a tiny piece of code, the linux (or bsd) TCP stack, can be a source of mysteries and adventures for decades, even for kernel experts and industry leaders like CF. The thing has around 11 states and 20 transitions, around 4000 LOC.
Compare this with some of the multi-million LOC, distributed monsters we all know and love.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Compared to, say Google which is 2 billion, a tad more complex.
But why haven't we moved to something better?
Say, why doesn't Apple use a better suited protocol between Apple devices and Apple servers? Why doesn't google use a better protocol between Google devices and Google servers (oh wait, they do – QUIC..which is something-other-than-TCP over IP).
More people should be doing this, yes? why not?
It is as if the layered architecture of the network isn't being taken advantage of by engineers.
As people build 4G-5G networks that are IP based, shouldn't we insist they build purely IP based and not peek into layers above and make assumptions? thereby enable more of the flow control and reliable transmission protocol experimentations?
2. Network infrastructure may drop "unusual" packets.
That post doesn't say anything about user space. Ideally the new protocol would be in the kernel, triggered with just a flag or even automatically.