0

I have written a short piece of code that fetches a value from a server over UDP.

The code works great in its current form.

However, I'm not sure on how to implement proper handling of errors that might occur.

For example, I have tried to implement code to catch the -1 value that should occur due to error with opening the FD for the socket, and also for the sending.

However, trying to use this code towards a IP that does not exist, it seems as it just opens up, and actually sends out the UDP packet. This might be normal, since its not actually failing per se.

What happens then is that it just sits at the code for receiving data for ever.

I would like for it to either time out due to not getting any reply and then just return so that the user gets feedback that the server is not responding.

What would be the best way to achieve this? Most of the examples I found, even in books does not really cover what happens when the server does not reply

This is the code I have so far:

int getcount ()

{


    /*TODO:
    Add proper error handling:
    error when socket is opened
    error when sending
    error when receiving and add receiver timeout 
    
    */


  char *ip = "192.168.1.183";
  int port = 27015;
 
  int sockfd;
  int err;
  struct sockaddr_in addr;
  char buffer[1024]; //Store the server reply here
  char firstreq[1024] = "ÿÿÿÿUÿÿÿÿ"; //This is what we need to ask to get a challengekey
  char challenge[1024]; //Something to store the challenge in
  char concatted[1024] = "ÿÿÿÿU"; //Something to add the challenge to and then request the actual data

  socklen_t addr_size;

  
  memset(&addr, '\0', sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = inet_addr(ip);

  
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);

  if (sockfd < 0) //Try to catch error when opening the fd for the socket.
  {
    printf ("Socket open failed");
    return(-1);

  }
    
  addr_size = sizeof(addr);

  //Send this message to get a reply with a challenge value:  
  err = sendto(sockfd, firstreq, 9, 0, (struct sockaddr*)&addr, sizeof(addr));
  if (err < 0) //Try to catch error when sending the request.
  {
    printf("Send failed");
    return (err);
  }
 
  //Recieve the challenge value:
  
  
  err = recvfrom(sockfd, challenge, 9, 0, (struct sockaddr*)&addr, &addr_size);

  //Concat the challenge value and message together: 
  
  memcpy(concatted + 4 + 1, challenge + 5, 10 - 5 + 1);

  //Reply with this to server
  sendto(sockfd, concatted, 9, 0, (struct sockaddr*)&addr, sizeof(addr));
  
  bzero(buffer, 1024);
  

  //Recieve the data from server:
  recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr*)&addr, &addr_size);


  return(buffer[5]); //Return the 6th value that is the value we want.
}
halfer
  • 19,824
  • 17
  • 99
  • 186
540
  • 71
  • 7
  • `recvfrom` will block until it gets data, you'll need to use something like [`select`](https://man7.org/linux/man-pages/man2/select.2.html) to know when data is ready to read. Take a look here: https://stackoverflow.com/questions/15592089/implementing-udp-sockets-with-select-in-c. Altho does look like there are flags for `recvfrom` to make it non-blocking,, I've never experimented with those. – yano May 01 '23 at 17:33
  • 1
    @yano `recvfrom()` can also be made non-blocking the same way that `recv()` can - via `ioctl(FIONBIO)`, `fcntl(F_SETFL, O_NONBLOCK)`, or `setsockopt(SO_RCVTIMEO)`. – Remy Lebeau May 01 '23 at 17:55
  • Thank you both for your assistance. Unfortunately the question got closed within seconds pointing to that this has been asked before. Which it probably has, however, the linked questions are not the same. I have tried to setup SO_RCVTIMEO several times. However, it gives me very weird behavior. Hard to explain in the comment section here. I did look at select, seems like it is deprecated and one should use poll instead. Not really sure how to translate the current methods for recvfrom to adapt to it though. Any pointers is appreciated – 540 May 01 '23 at 18:02
  • `select()` works fine, its only limitation is that it can be inefficient if you are trying to use it to manage hundreds or thousands of sockets at once; in that case `poll()` (or `epoll()` or `kqueue()` or whatever) can be more efficient. When dealing with just one socket, OTOH, it works as well as anything else does, and is more portable than any of the alternatives. – Jeremy Friesner May 02 '23 at 00:02

0 Answers0