Zsolti Vagyok
Zsolti Vagyok

Reputation: 109

How to detect a timed out client with poll()?

I'm writing a non forking server, using poll() for multiple simultaneous connections. It works properly, except I have a problem with how to detect timeout the right way.

Let's say I have the following code:

#define POLL_SIZE 512

struct pollfd poll_set[POLL_SIZE];
timeout = 60000; // 60 secs

// setup server_sockfd with socket(), bind(), listen(), ...

poll_set[0].fd = server_sockfd;
poll_set[0].events = POLLIN;
numfds = 1;

while(1) {
   rc = poll(poll_set, numfds, timeout);
   if(rc == 0){
      // handle timeout
   }

   for(fd_index = 0; fd_index < numfds; fd_index++) {
      if(poll_set[fd_index].revents & POLLIN) {
         // accept new connection or handle established connections
      }
   }
}

Let's assume, I have 15 clients connected, 14 clients are sending and receiving data, however one client is silent, no data to or from, ie. just occupying a socket on the server.

Now, the problem is that poll() can't spot this one specific client, because all the other 14 clients are providing data, so poll() says, it's ok.

How would you solve this problem by detecting this silent client, and close its connection?

Currently, I have nothing better, then create a time_t lastseen[POLL_SIZE] array, and keep track of the timestamp of the given connection when either data is read from the client or sent to client.

Then I use an alarm signal in every 60 seconds, and run through the lastseen array, compare their timestamp with the current timestamp, and tear down every connection being idle > 60 seconds.

Or perhaps a thread could do the same to avoid signaling. What do you suggest to solve the problem?

(Note that I experimented with libevent, and it's very nice. However, I had to abandon it, because I couldn't find support to add SSL/TLS to an already connected socket. Think of STARTTLS)

Upvotes: 3

Views: 2599

Answers (1)

Dmitry Poroh
Dmitry Poroh

Reputation: 3825

Detecting of errors related to socket is not poll's job. All it does it indicates whether one or more sockets are ready for read write operations. If error occurs with any awaited socket then poll marks that socket as ready (really it marked by OS) and POLLERR flag is indicated in revents field.

What about timeout. In general timeout is not transport layer error (and therefore is not tracked by sockets). You need to track it by yourself. For example you can remember timestamp of last read from socket (See clock_gettime(CLOCK_MONOTONIC, ...)) and set timeout in poll to minimum of all timeouts related to that sockets. After timeout expired you need to check whether it expired for the each socket or no.

Also consider use epoll - it is much faster for large number of sockets in one poll. And also for selection of nearest timeout you can use Heap data structure. So you can manage all sockets with O(log n) execution time.

Upvotes: 1

Related Questions