socket: how to detect peer's shutdown(SD_RECEIVE) by select? - sockets

When server calls shutdown(SD_SEND), client can detect it by select and recv(returns 0). But how can client detect shutdown(SD_RECEIVE)?

If the server shuts down its receive channel, it can't receive any further data anymore. There is no way to detect this condition with select(), except that the socket simply won't be reported as writable anymore. There is no signal sent to the client in this situation (unlike shutting down the send channel, which sends a FIN packet indicating no more data will be sent). So, any attempts by the client to send data afterwards will either be buffered indefinitely while waiting for the server to acknowledge there is room to receive, or more likely will simply fail with an error.

Short answer: there's no magic API the client can use to detect if the (Microsoft!) server happened to call shutdown(SD_RECV). However, all subsequent sends from the client to the server on that socket will fail.
Longer answer:
shutdown(SD_RECV) is a Windows thing. It doesn't necessarily pertain to sockets in general, and certainly not to TCP/IP itself. There is no TCP-level FIN or RST. There's no "message" to the client.
From the documentation:
https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-shutdown
The shutdown function does not close the socket. Any resources
attached to the socket will not be freed until closesocket is invoked.
Another method to wait for notification that the remote end has sent
all its data and initiated a graceful disconnect uses overlapped
receive calls follows :
Call shutdown with how=SD_SEND.
Call recv or WSARecv until the function completes with success and indicates zero bytes were received. If SOCKET_ERROR is returned,
then the graceful disconnect is not possible.
Call closesocket.

Related

How server knows to close the connection of websocket when website tab is closed

I created a websocket (with perl Net::WebSocket::Server but I think it does not matter). My question is that when I close the website tab(not necessarily the whole browser) the server will disconnect the specific socket (my disconnect event is called). How the server manage to know that? I can not find a straight detailed description.
If the browser closes one end of a socket (either explicitly via close, or implicitly because the process exits) the server at the other end of the socket connection will be notified that the socket is now closed. That's just part of how TCP works. Even if the message got lost and the server thought the socket was still open, when it tried to send data it would eventually work out that the other end was not acknowledging the packets and would drop the connection.
In the case of a browser tab, it's reasonable to assume that the browser will cleanup/close any resources associated with a tab that is being closed.
How TCP close connection.
Each side terminates its end of the connection by
sending a special message with the FIN (finish) bit set. This message,
sometimes called a FIN, serves as a connection termination request to
the other device, while also possibly carrying data like a regular
segment. The device receiving the FIN responds with an acknowledgment to the FIN to indicate that it was received. The connection as a whole is not considered terminated until both sides have finished the shut down procedure by sending a FIN and receiving an ACK.

Can we just reset TCP connections after an application level acknowledgement has been received?

I'm investigating resetting a TCP connection as a solution to the TIME_WAIT issue.
Let's use the following request-reply protocol as an example:
The client opens a connection to the server.
The client sends a request.
The server replies.
The server closes.
The client closes as well.
This causes a TIME_WAIT state at the server. As a variation, the client could close first. Then, the TIME_WAIT lands on the client.
Can we not replace steps 4 and 5 by the following?
The client resets.
The server resets in response to the incoming reset.
This seems to be a way to avoid the TIME_WAIT issue. The server has proven that it received and processed the request by sending its reply. Once the client has the reply the connection is expendable and can just go away.
Is this a good idea?
I would say: No it's not a good idea. Every possible solution ends up with the same "problem" that TIME_WAIT ultimately addresses: how does party A, acknowledging the ending of the connection (or acknowledging the other side's final acknowledgment of the ending of the connection), know that party B got the acknowledgment? And the answer is always: it can't ever know that for sure.
You say:
the server has proven that it received and processed the request by sending its reply
... but what if that reply gets lost? The server has now cleaned up its side of the session, but the client will be waiting forever for that reply.
The TCP state machine may seem overly complicated at first glance but it's all done that way for good reason.
The only problem is that the server doesn't know whether the client received everything. The situation is ambiguous: did the client connection reset because the client received the whole reply, or was it reset for some other reason?
Adding an application level acknowledgement doesn't reliably fix the problem. If the client acknowledges, and then immediately closes abortively, the client can't be sure that the server received that acknowledgement, because the abortive close discards untransmitted data. Moreover, even if the data are transmitted, it can be lost since the connection is unreliable; and once the connection is aborted, the TCP stack will no longer provide re-transmissions of that data.
The regular, non-abortive situation addresses the problem by having the client and server TCP stacks take care of the final rites independently of application execution.
So, in summary, the aborts are okay if all we care about is that the client receives its reply, and the server doesn't care whether or not that succeeded: not an unreasonable assumption in many circumstances.
I suspect you are wrong about the TIME_WAIT being on the server.
If you follow the following sequence for a single TCP-based client-server transaction, then the TIME_WAIT is on the client side:
client initiates active connection to server
client sends request to server.
client half-closes the connection (i.e. sends FIN)
server reads client request until EOF (FIN segment)
server sends reply and closes (generating FIN)
clients reads response to EOF
client closes.
Since client was the first to send the FIN, it goes into TIME_WAIT.
The trick is that the client must close the sending direction first, and the server synchronizes on it by reading the entire request. In other words, you use the stream boundaries as your message boundaries.
What you're trying to do is do the request framing purely inside the application protocol and not use the TCP framing at all. That is to say, the server recognizes the end of the client message without the client having closed, and likewise the client parses the server response without caring about reading until the end.
Even if your protocol is like this, you can still go through the motions of the half-close dance routine. The server, after having retrieve the client request, can nevertheless keep reading from its socket and discarding bytes until it reads everything, even though no bytes are expected.

Has the client ACK'd all the data I sent to it?

RFC 7230 defines HTTP/1.1 protocol and it has an interesting passage in 6.6, "Connection management. Tear-down":
To avoid the TCP reset problem, servers typically close a connection
in stages. First, the server performs a half-close by closing only the
write side of the read/write connection. The server then continues to
read from the connection until it receives a corresponding close by
the client, or until the server is reasonably certain that its own TCP
stack has received the client's acknowledgement of the packet(s)
containing the server's last response. Finally, the server fully
closes the connection.
Basically it boils down to the following:
shutdown(s, SD_SEND);
while (recv(s, throaway_buffer, throaway_buffer_len, 0) > 0);
closesocket(s);
which is the standard way of doing the graceful shutdown. However, it also acknowledges that a misbehaving client may exist (that keeps sending requests even after receiving a response with Connection: close header), and that the server has to cope with it by resetting the connection after it's sure the client has received the last response.
However, the socket interface doesn't seem to provide the functionality to learn whether all data passed to send have been actually sent and ACK'd by the remote host. Is it actually there? Without it, all I can think about is to set up a timer of sorts, and call recv until either it signals that the remote host has closed connection or the time is out, whichever comes first. But what would be the appropriate timeout? Is 60 seconds okay?
The Sockets interface provides this mean via the little-used and less understood SO_LINGER option. It allows you inter alia to define a timeout during which close() and possibly shutdown() will block while pending data is being sent. It is of little practical use and as I've stated it is rarely used ... at least rarely used correctly.

Does Accept event happens after the three way handshake?

I am writing an application on Linux (Client and Server) with socket programming. I came across the scenario, where my server application never responds to the initial SYN packet of the other end.
I am still debugging the issue.
Since my server is listening on a port, it never generates the accept event. Is the accept event is generated after the TCP handshake is done OR the accept event is generated when the initial SYN packet is received?
Some useful links, would be helpful.
Best
Is the accept event is generated after the TCP handshake is done
Yes.
OR the accept event is generated when the initial SYN packet is received?
No. The handshake has already happened. accept() just delivers you a socket from a queue of already accepted connections. While the queue is empty, it blocks.
This means that a client can connect even if the server has never called accept().
Accept() is not exactly an event, but a function that encapsulates the server side logic for the TCP handshake. The function is called beforehand(waiting for a client connection) and it returns after the handshake is over (it received the ACK from the client).
Some detailed explanations here:
http://lwn.net/Articles/508865/
http://www.ibm.com/developerworks/aix/library/au-tcpsystemcalls/
What kind of error do you get? Make sure your server is reachable for the client.
The TCP handshake is handled by the kernel; the server process is not involved. The kernel maintains two queues, one for incomplete connections (initial SYN received) and one for complete connections (3-way handshake complete).
The accept call retrieves the first entry in the complete queue, if the queue is empty and the socket is blocking the call blocks until a connection is made. If the socket is nonblocking, the call fails with EAGAIN or EWOULDBLOCK.
refs:
https://books.google.com/books?id=ptSC4LpwGA0C&lpg=PP1&pg=PA104#v=onepage&q&f=false/0131411551_ch04lev1sec5.html
https://man7.org/linux/man-pages/man2/accept.2.html

Detecting I/O errors in a NON BLOCKING SOCKET

I am writing a client - server system in which I used NON-BLOCKING sockets. My problem is to detect error { while performing send() or write() } that may occur while data transfer. Example lets say, while the data is being transferred the peer crashes. Another case there is some network problem, something like wire unplugged etc.
As of now, I am using a high level ACK, that peer sends after receiving the complete data.
As there is a socket send buffer between your application and the NIC there may be a delay between the event and the notification, but eventually you will get a 'connection reset' condition when writing.