Detecting I/O errors in a NON BLOCKING SOCKET - sockets

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.

Related

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

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.

How to use TCP keep_alive property to get notified on the event of a unresponsive peer?

Scenario:
I have a client and server written using boost::asio 1.63. Generally the connection and communication part works well and great.
I have written a Watchdog on both sides which send dummy packets to peers in an interval of 2 seconds each. The objective of the watchdog is that the concerned peer reports a connection error if it does not receive the dummy packet it is expecting in the next 2 seconds. This is even more important for me because it might happen the 2 peers are not transacting packets for any user purpose but each of them is required to report a connection error if any of the peer goes down. The peer can go down even because of a kernel crash in which case it would not be possible for that peer to send a message. This is a classic problem of course which exists even beyond asio and TCP.
My Watchdog works perfectly well. No issues at all.
But, recently I read about the keep_alive feature in sockets. I tried out the following code and seems like I can a property called keep_alive on the TCP socket by getting the native handle to the socket from within my code using boost::asio.
boost::asio::io_service ioService;
boost::asio::ip::tcp::socket mySocket(ioService);
int on = 1;
int delay = 120;
setsockopt(mySocket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
setsockopt(mySocket.native_handle(), IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay));
Question:
Above code compiles well on macOS, Linux and iOS. That looks great. But, how do I benefit from this? Does this give me a callback or event when the peer goes down? Does this free me up from writting the Watchdog that I described above?
I have used boost::asio::async_connect to connect to the peer. Can I get a callback to my connectionHandler when the perr goes down after the defined timeout interval?
Having set the keep_alive options, how do I then get to know that my peer is not responding anymore?
If the disconnetion was detected when an async operation is pending, your socket's completion handler will be invoked with the appropriate error code.
The problem is that TCP keep_alive option doesn't not always detect disconnects.
In general, there is no reliable way to detect sudden disconnection, other than by implementing application-level ping/heartbeat.
You can also see this thread.

Will a TCP RST cause a host to drop the receive buffer?

Upon receiving a TCP RST packet, will the host drop all the remaining data in the receive buffer that has already been ACKed by the remote host but not read by the application process using the socket?
I'm wondering if it's dangerous to close a socket as soon as I'm not interested in what the other host has to say anymore (e.g. to conserver resources); e.g. if that could cause the other party to lose any data I've already sent, but he has not yet read.
Should RSTs generally be avoided and indicate a complete, bidirectional failure of communication, or are they a relatively safe way to unidirectionally force a connection teardown as in the example above?
I've found some nice explanations of the topic, they indicate that data loss is quite possible in that case:
http://blog.olivierlanglois.net/index.php/2010/02/06/tcp_rst_flag_subtleties
http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable also gives some more information on the topic, and offers a solution that I've used in my code. So far, I've not seen any RSTs sent by my server application.
Application-level close(2) on a socket does not produce an RST but a FIN packet sent to the other side, which results in normal four-way connection tear-down. RSTs are generated by the network stack in response to packets targeting not-existing TCP connection.
On the other hand, if you close the socket but the other side still has some data to write, its next send(2) will result in EPIPE.
With all of the above in mind, you are much better off designing your own protocol on top of TCP that includes explicit "logout" or "disconnect" message.

In TCP/IP sockets, how would the server know that a client is busy and not receiving data ?

In TCP/IP sockets, how would the server know that a client is busy and not receiving data ?
My solution:
Use connect(),
I am not sure.
thanks
In TCP/IP sockets, how would the server know that a client is busy and
not receiving data
If a TCP is constantly pushing data that the peer doesn't acknowledge, eventually the send window will fill up. At that point the TCP is going to buffer data to "send later". Eventually the buffer size will be reached and send(2) will hang (something it doesn't usually do).
If send(2) starts hanging it means the peer TCP isn't acknowledging data.
Obviously, even if the peer TCP accepts data it doesn't mean the peer application actually uses it. You could implement your own ACK mechanism on top of TCP, and it's not as unreasonable as it sounds. It would involve having the client send a "send me more" message once in a while.
A client will almost always receive your data, by which I mean the OS will accept the packets and queue them up for reading. If that queue fills up, then the sender will block (TCP, anyways). You can't actually know the activity of the client code. Pretty much your only option is to use timeouts.

Ensuring send() data delivered

Is there any way of checking if data sent using winsock's send() or WSASend() are really delivered to destination?
I'm writing an application talking with third party server, which sometimes goes down after working for some time, and need to be sure if messages sent to that server are delivered or not. The problem is sometimes calling send() finishes without error, even if server is already down, and only next send() finishes with error - so I have no idea if previous message was delivered or not.
I suppose on TCP layer there is information if certain (or all) packets sent were acked or not, but it is not available using socket interface (or I cannot find a way).
Worst of all, I cannot change the code of the server, so I can't get any delivery confirmation messages.
I'm sorry, but given what you're trying to achieve, you should realise that even if the TCP stack COULD give you an indication that a particular set of bytes has been ACK'd by the remote TCP stack it wouldn't actually mean anything different to what you know at the moment.
The problem is that unless you have an application level ACK from the remote application which is only sent once the remote application has actioned the data that you have sent to it then you will never know for sure if the data has been received by the remote application.
'but I can assume its close enough'
is just delusional. You may as well make that assumption if your send completes as it's about as valid.
The issue is that even if the TCP stack could tell you that the remote stack had ACK'd the data (1) that's not the same thing as the remote application receiving the data (2) and that is not the same thing as the remote application actually USING the data (3).
Given that the remote application COULD crash at any point, 1, 2 OR 3 the only worthwhile indication that the data has arrived is one that is sent by the remote application after it has used the data for the intended purpose.
Everything else is just wishful thinking.
Not from the return to send(). All send() says is that the data was pushed into the send buffer. Connected socket streams are not guarenteed to send all the data, just that the data will be in order. So you can't assume that your send() will be done in a single packet or if it will ever occur due to network delay or interruption.
If you need a full acknowledgement, you'll have to look at higher application level acks (server sending back a formatted ack message, not just packet ACKs).