Detect closed connection on non blocking socket - c

I'm really sorry if my question is a duplicate, but I didn't find useful infos in the site.
I'm using non blocking sockets and a select(). How can I detect if a client closed the connection on non-blocking socket? I saw that a read() returns -1 with errno = EWOULDBLOCK when no datas are available to be read and also when a connection is closed.
How can I discriminate above cases?

When the peer has closed the connection:
select() will return the socket as readable.
A recv() or read() on the socket will return zero.
I saw that a read() returns -1 with errno = EWOULDBLOCK when no datas are available to be read
Correct, but the connection isn't closed.
and also when a connection is closed.
No you didn't. That's not correct. It returns zero.
How can I discriminate above cases?
They aren't the same, and they don't manifest themselves in the same way.

When the peer had closed the connection for a specific socket, a call to read() on this socket would return 0. This behaviour is independent from the socket's blocking state.
From man 2 read (italics by me):
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end of file)

Related

How to check if a TCP connection was closed by peer gracefully or not WITHOUT READING FROM IT? [duplicate]

This question already has answers here:
c++ how to use select to see if a socket has closed
(4 answers)
Closed 6 years ago.
I'm using Linux.
Can someone provide me an example of how to use select() or poll() to check whether a TCP connection was closed by peer through FIN or terminated by RST?
poll() can detect RST with setting POLLHUP or POLLERR in revents, but select() has no facilities like this.
In my test, when socket is terminated by RST, socket error got by getsockopt will be ECONNRESET. Is this a effective way or not?
Is it necessary to determine how the connection was closed?
Thanks!
If the socket was closed gracefully, the socket will be set for read.
Then, when you read, you will receive 0 data read because you got to EOF. You can also check with
ioctl(sock, FIONREAD, &n);
to determine if there is data to read. Here you have an example: c++ how to use select to see if a socket has closed
According to select man: "readfds will be watched to see if characters become available for reading (more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file)"
If there is a pending socket error, the corresponding bit will be set in readfds or writefds. Then read or recv should return error. Also you can use this to determine if there is a pending error in the socket:
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &result, &resultLen) < 0) {
//getsockopt ERROR
} else if (result == 0) {
//NO ERROR
} else {
//SOCKET ERROR
}

TCP : recv() getting ECONNRESET

I'm trying to implement a simple client/server program on linux using TCP
and the standard socket.h library. server handling multiple clients and each client can close() or shutdown() the socket any time he wants.
on the server side (using a non blocking read):
int nBytes;
if ((nBytes = recv(socket, buffer, BUFFER_SIZE, MSG_DONTWAIT)) == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
//print to log
}
}
if (nBytes == 0)
{
//other side closed the connection
}
I'm getting recv() returning -1 and error set to ECONNRESET. If the client has closed the connection shouldn't recv() return 0?
There are numerous causes, including but not limited to:
the peer deliberately reset the connection
the peer closed the connection while he still had unread data pending
you had sent data to a connection that had already been closed by the peer
you had pending write data and the TCP retries have timed out
TCP keepalive detected a lost connection.
This is a fatal error, and you should close the socket when you get it.
each client can close() or shutdown() the socket any time he wants.
No he can't. See above.
If the remote peer has cleanly closed the connection, and there are no more bytes waiting to be read on the local end, then yes, recv() should return 0. So if you get an ECONNRESET then it's reasonable to assume that an orderly closure is not what has happened.
An ECONNRESET often indicates that the remote peer sent a RST packet without having first closed the connection cleanly. There are many reasons why this might happen. Alternatively, as EJP observed, a reset may originate locally, too.
In any event, after an ECONNRESET it's not reasonable to suppose that you will be able to read anything further from the socket, so in your particular case you should probably handle it much the same as way as you handle recv() returning 0, +/- logging.
You may get ECONNRESET if client closed his side without reading sent data. If he closed connection properly you'll get 0.

Linux TCP/IP Diagnosing Why TCP/IP read() Returns 0 in C Program

I have a number of C programs running on a Linux host (RHEL 6.6). They have TCP/IP connections to other applications on the same host. There is very little traffic over each connection. Every once in awhile, a read() call on one of the sockets to a process on the same host returns 0. These sockets are normally kept up for the lifetime of the application, so they are not cleanly closed during normal operations. I would expect that if an error occurs such as the other end crashing, the read() will return -1 and set errno.
So, the question is - is there any reason other than the TCP/IP connection being closed cleanly (shutdown(fd); close(fd)) by the other end that would cause the read() call to return 0?
The man page for read() states that 0 is only returned for EOF, while the recv() man page states it returns "0 when the peer has performed an orderly shutdown". I'd assume that the return from read() and recv() would be equivalent, and EOF on a TCP/IP connection implies a clean shutdown.
So, the question is - is there any reason other than the TCP/IP
connection being closed cleanly (shutdown(fd); close(fd)) by the other
end that would cause the read() call to return 0
For starters the process dying would free up the file descriptor which would have the same effect: a clean connection close.
I would expect that if an error occurs such as the other end crashing,
the read() will return -1 and set errno.
It depends what you mean by "crashes". If the process for example dies but the OS is still fine, then as far as TCP is concerned everything is OK and it can just close the connection for the now-orphaned socket (same as above in other words).
Side note: there are of course ways in which your recv can return -1 because of a misbehaving peer (for example the peer can force a TCP reset).

Does socket error mean socket is closed

I am writing a client-server program. The server is select()ing on readfd1 waiting for the readiness of readfd1 to be read. If it is ready, server is collecting the data and printing. Everything is fine for a while, but after some time, socket recv() failed with errno set to ETIMEDOUT. Now I want to rewrite my program to thwart these error condtions. So I went through "Unix Network Programming" by Richard Stevens, which states 4 conditions for select() to unblock. Following are the 2 conditions that grab my attention
A. client sent FIN, here return value of `recv()` will be `0`
B. some socket error, here return value of `recv()` will be `-1`.
My question is, Does socket error closes the connection? If that is so, then why is above two conditions are separated. If not, does next recv() on socket work?
If recv() returns 0, the other end has actively and gracefully closed the connection.
If recv() returns -1, there has (possibly) been an error on the connection, and it is no longer usable.
This means you can tell the difference between the peer closing the connection, and an error happening on the connection. The common thing to do in both cases is to close() your end of the socket.
There is 2 more points to consider though:
In the case of recv() returning -1, you should inspect errno, as it might not indicate a real error.
errno can be EAGAIN/EWOULDBLOCK if you have placed the socket in non-blocking mode or it could be EINTR if the system call was interrupted by a signal. All other errno values means the connection is broken, and you should close it.
TCP can operate in half duplex. If the peer has closed only its writing end of the connection, recv() returns 0 at your end. The common thing to do is to consider the connection as finished, and close your end of the connection too, but you can continue to write to it and the other end can continue to read from it. Whether to close just the reading or writing end of a TCP connection is controlled by the shutdown() function.
A socket error doesn't have to mean that the connection is closed, consider for example what happens if somehow the network cable between you and your peer is cut then you would typically get that ETIMEDOUT error. Most errors are unrecoverable, so closing your end of the connection on error is almost always advisable.
The difference between the two states when select can unblock, is because either the other end closed their connection in a nice way (the first case), or that there are some actual error (the second case).

select says socket is ready to read when it is definitely not (actually is closed already)

In my server I check if any socket is ready to read using select() to determine it. As a result in main loop select() is executed every time it iterates.
To test the server I wrote a simple client that sends only one message and then quits. BTW. I use protocol buffers to send information - message means an object of type class Message in this library.
The test session looks like:
select()
server's socket ready to read
accept() client's socket
read message from client's socket
select()
server's socket not ready to read, client's one ready
read message from client's socket
The last step is wrong because client has already closed connection. As a result protobuf library gets Segmentation fault. I wonder why FD_ISSET says the socket is ready in step 6 when it is closed. How can I check if a socket is closed?
EDIT:
I've found how to check if the socket is open
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len );
the socket is "readable" if the remote peer closes it, you need to call recv and handle both the case where it returns an error, and the case where it returns 0, which indicates that the peer shut down the connection in an orderly fashion.
Reading the SO_ERROR sockopt is not the correct way, as it returns the current pending error (from, eg. a non-blocking connect)
The socket used for communication between a client and your server will be flagged as readable (i.e. select() will return) when there is data to read, or when there's an EOF to read (i.e. the peer closed the connection).
Just read() when select() returns and your fd is flagged. If read() returns a positive number, you got data. If it returns 0, you got EOF. If it returns -1, you have a problem (unless errno is EAGAIN).

Resources