0

I'm trying to set socket options for a client socket returned from the accept() function. But they are not getting set correctly.

My aim is to time out the client after a particular time of inactivity. But the server should still be able to accept other client connections.

Below is my code where I set the socket option. Can you please suggest what is wrong?

while ((new_sock_fd = accept(socket_fd, (struct sockaddr *) &cli_addr, &clilen)) > 0)
{
    if (new_sock_fd < 0)
        printf("Accept Error");
    else
    {
        struct timeval timeout;      
        timeout.tv_sec = 10;
        timeout.tv_usec = 0;
        if (setsockopt(new_sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
            error("setsockopt failed\n");
        if (setsockopt(new_sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
            error("setsockopt failed\n");
        pthread_create(&thread, NULL, client_handler, (void *) (intptr_t)new_sock_fd); //intptr_t is big enough to hold the integer prt
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
3lokh
  • 891
  • 4
  • 17
  • 39
  • 1
    How do you know the options are not being set? Is `setsockopt()` failing with an error? Does `getsocktop()` return values you are not expecting? Does the socket simply behave differently than expected? If so, how? What platform is this code running on? On most platforms `SO_RCVTIMEO` and `SO_SENDTIMEO` do indeed take a `timeval` struct as input. But on Windows, they take a `DWORD` instead. – Remy Lebeau Sep 07 '16 at 04:41
  • 1
    Also, your `Accept Error` message will never be reported, since your loop only enters the loop body when `new_socket_fd > 0`. If you want to do error handling on `accept()`, you should move it inside the loop instead. – Remy Lebeau Sep 07 '16 at 04:42

1 Answers1

1

My aim is to time out the client after a particular time of inactivity. [...] can you please suggest what when wrong..?

I suspect what's wrong is that you're misunderstanding what SO_RCVTIMEO and SO_SNDTIMEO are intended to do. From the man page:

SO_RCVTIMEO and SO_SNDTIMEO Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if the socket was specified to be nonblocking. If the timeout is set to zero (the default) then the operation will never timeout.

... but it sounds like what you want is for the TCP connection be automatically closed after a certain amount of time with no traffic on the TCP connection, which is not the same thing as forcing a call to send() or recv() to return after a specified amount of time.

If what you are looking for is a mechanism to close an idle TCP connection, you can implement that yourself by recording the current time whenever data is sent or received on the socket. At a later time (e.g. after send() or recv() times out), you can subtract your recorded last-traffic-seen-at-time from the current time; if the difference is greater than your idle-timeout value, call close() on the socket yourself.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Or, simply use `select()` or `epoll()` to implement the timeout instead. Put the socket into non-blocking mode, and then 1) before reading, poll for readability with timeout; 2) if sending fails with ` EAGAIN` or `EWOULDBLOCK`, poll for writability with timeout. If either operation times out, close the connection. – Remy Lebeau Sep 07 '16 at 04:41