42

I am trying to set a 100ms timeout on a UDP Socket. I am using C. I have posted relavent pieces of my code below. I am not sure why this is not timing out, but just hangs when it doesn't receive a segment. Does this only work on sockets that are not bound using the bind() method?

#define TIMEOUT_MS      100     /* Seconds between retransmits */

if ((rcv_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    DieWithError("socket() failed");

if ((rcv_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    DieWithError("socket() failed");

//set timer for recv_socket
static int timeout = TIMEOUT_MS;
setsockopt(rcv_sock, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

if(recvfrom(rcv_sock, ackBuffer,sizeof(ackBuffer), 0,
       (struct sockaddr *) &servAddr2, &fromSize) < 0){
    //timeout reached
    printf("Timout reached. Resending segment %d\n", seq_num);
    num_timeouts++;
}
rharrison33
  • 1,252
  • 4
  • 18
  • 34
  • 3
    It looks like you are not checking the return value from `setsockopt` to see if it returned an error. It probably is. `SO_RCVTIMEO` is documented on both Linux and MacOS to take a `struct timeval`, but you are passing an `int`. Try passing a `struct timeval` instead. Also, why are you casting `&timeout` to `char *`? It's not a `char *` at all. – Celada Nov 25 '12 at 02:52
  • @Celada on Windows, setsockopt() takes a 'char*' as the 2nd argument for any of the options. – Ruud van Gaal Aug 14 '23 at 15:03

2 Answers2

71

The SO_RCVTIMEO option expects a struct timeval defined in sys/time.h, not an integer like you're passing to it. The timeval struct has as field for seconds and a field for microseconds. To set the timeout to 100ms, the following should do the trick:

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000;
if (setsockopt(rcv_sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) {
    perror("Error");
}
frogatto
  • 28,539
  • 11
  • 83
  • 129
Neal
  • 6,722
  • 4
  • 38
  • 31
5

I have the same problem. I tried to adopt the solution you suggested, using the timeval struct. But it did not seem to work.

I have read on the Microsoft documentation and the time should be a DWORD with the number of milliseconds, but there is also another thing to do, If the socket is created using the WSASocket function, then the dwFlags parameter must have the WSA_FLAG_OVERLAPPED attribute set for the timeout to function properly. Otherwise the timeout never takes effect.

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
user9510357
  • 51
  • 1
  • 1
  • 1
    The accepted answer targets POSIX sockets. Windows provides its own socket API so the accepted answer is not applicable to Windows. – b00n12 Feb 04 '20 at 07:47