https://bugs.winehq.org/show_bug.cgi?id=55952
--- Comment #25 from Zeb Figura z.figura12@gmail.com --- [Ignore this comment if you don't want to read a lot of observation about sockets.]
On Windows, SD_RECEIVE sends RST immediately if there is data in the pipe, as well as if data is received after SD_RECEIVE. Closing the socket with data in the pipe also achieves this, or sending data to a closed connection.
Linux is slightly different. SHUT_RD never triggers RST, but closing a socket has about the same behaviour.
Reaction to RST is about the same across both operating systems, but there are subtle differences in the circumstances:
* RST on an open connection means that further I/O yields ECONNRESET. Linux is slightly different here in that recv() will actually consume any existing data in the pipe and *then* return ECONNRESET. I haven't tested how this interacts with other APIs like poll(). Windows effectively discards whatever's in the pipe.
* RST after FIN yields no error from recv()!
* RST after FIN but as a *response* to PSH (i.e. if a PSH is not ACKed in a packet which is itself not RST) yields no error on Linux. On Windows the send() succeeds (sure, it's asynchronous) but the following recv() yields ECONNABORTED. This case happens when we try to send data to a closed pipe (Windows and Linux are consistent about not acking the PSH here.)
On Linux, in any case when RST is received poll() returns POLLIN | POLLHUP | POLLERR. Note that the POLLIN occurs even if there is no data OR eof to read, i.e. even if the next recv() returns -1 / ECONNRESET. Also this poll() returns immediately even if there is data left in the pipe on Linux.
Windows has a million ways to poll for socket events, and I haven't tested them all. I will note at least that RST after FIN yields no error from WSAPoll() though.
When testing this initially, I was trying to emulate Mono's call sequence but inadvertently switched the order of the shutdown() calls. Astoundingly, this makes the difference. The above explains why: if we shutdown the write end first, that sends FIN before RST, and no error ever happens, but if we shutdown the read end first, that sends RST alone. On Wine of course any RST at all results in an error, because we use poll() [plus SO_ERROR] to detect it, and poll() always detects RST on Linux.