CChiste
CChiste

Reputation: 131

Linux C socket UDP server. Nothing being received by select()

I am having issues with my UDP server accepting any input since I put in a select statement. The intention is to wait on packets from 2 different sockets (with differing ports). At the same time I also want it to be able to tell when the server wants to send something to one of the ports being synchronously listened to. In the following code the program runs until it gets to the select() statement, at which point if i attempt to send something to the server (on the local machine) nothing is accepted and the program hangs, waiting. I have also tried commenting out the writefds fd_set and its accompanying FD_ISSET but the same thing happens. I'm burnt out trying to figure this stuff out so there are probably a ton of things that don't make sense, but I tried my best in my current state. I appologize.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MYPORT "20444"  // the port users will be connecting to
#define MAXBUFLEN 1024 //maximum packet length
#define SERVER_R 142.66.140.13 //Server to the "right" of current
#define RTEX_R_PORT "20445" //Port for routing table exchange

typedef enum {false, true} bool;

/*struct to store packet fields into
  seq: sequence number;
  type: message type; send get ACK
  src: client's unique 10 digit number
  dst: destination's unique 10 digit number
  payload: the message being transferred, if there is any
*/
struct packet
{
   char seq[4];
   char type[5];
   char src[11];
   char dst[11];
   char payload[MAXBUFLEN];
};

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
   //rr: reading from server to the "right"
   //rw: writing to the server to the "right"
   int sockfd, rtex_rr_sockfd, rtex_rw_sockfd, rv, rrr, rrw, numbytes, i, j, first, max_fd;
   struct addrinfo hints, *servinfo, *p, *p2, *p3;
   struct sockaddr_storage their_addr, right_addr;
   fd_set readfds, writefds;
   char buf[MAXBUFLEN];
   char temp_buf[MAXBUFLEN];
   char d_to_s[MAXBUFLEN];
   char *field;
   socklen_t addr_len;
   char s[INET6_ADDRSTRLEN];
   FILE *m_storage;
   struct packet inet_packet;
   static const struct packet EmptyPacket;
   static int rt[51][4];
   bool re_exists=false;
   bool rt_empty=true;
   struct timeval tv;

   memset(&hints, 0, sizeof hints);//"zero out" the hints struct
   hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
   hints.ai_socktype = SOCK_DGRAM;
   hints.ai_flags = AI_PASSIVE; // use my IP

   //prepare socket address structures and store them in servinfo and store in linked list
   if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
      return 1;
   }

   // loop through all the results and bind to the first we can
   for(p = servinfo; p != NULL; p = p->ai_next) {
      if ((sockfd = socket(p->ai_family, p->ai_socktype,
               p->ai_protocol)) == -1) {
     perror("listener: socket");
     continue;
      }

      if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
     close(sockfd);
     perror("listener: bind");
     continue;
      }

      break;
   }

   if (p == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   if ((rrr = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrr));
      return 1;
   }

   for(p2 = servinfo; p2 != NULL; p2 = p2->ai_next) {
      if ((rtex_rr_sockfd = socket(p2->ai_family, p2->ai_socktype,
               p2->ai_protocol)) == -1) {
     perror("listener: socket");
     continue;
      }

      if (bind(rtex_rr_sockfd, p2->ai_addr, p2->ai_addrlen) == -1) {
     close(rtex_rr_sockfd);
     perror("listener: bind");
     continue;
      }
      break;
   }

   if (p2 == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   if((rrw = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrw));
      return 1;
   }

   for(p3 = servinfo; p3 != NULL; p3 = p3->ai_next) {
      if((rtex_rw_sockfd = socket(p3->ai_family, p3->ai_socktype,
                  p3->ai_protocol)) == -1) {
     perror("server: socket");
     continue;
      }
      break;
   }

   if (p3 == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   //free up memory no longer needed after binding has completed
   freeaddrinfo(servinfo);

   FD_ZERO(&readfds);
   FD_ZERO(&writefds);
   FD_SET(rv, &readfds);
   FD_SET(rrr, &readfds);
   FD_SET(rrw, &writefds);

   printf("Listen Mode\n");

   //main while loop, listens for packets.
   //Upon receipt of packet, information is stored in a struct for processing.
   first=0;
   while(1)
   {
      i=0;
      inet_packet = EmptyPacket;
      rt_empty=true;
      tv.tv_sec = 50;
if(rv > rrr && rv > rrw)
     max_fd = (rv + 1);
      else if(rrr > rv && rrr > rrw)
     max_fd = (rrr + 1);
      else if(rrw > rv && rrw > rrr)
     max_fd = (rrw + 1);

      printf("before select...\n");
      select(max_fd, &readfds, &writefds, NULL, NULL);
      printf("after select...\n");
      addr_len = sizeof their_addr;

      if(FD_ISSET(rv, &readfds))
      {
     printf("rv is set...\n");
     if((numbytes = recvfrom(sockfd, buf, sizeof(buf), 0,
                 (struct sockaddr *)&their_addr, &addr_len)) == -1) {
        perror("recvfrom");
        exit(1);
     }
      } else if(FD_ISSET(rrr, &readfds))
      {
     printf("rr read is set...\n");
     if((numbytes = recvfrom(rtex_rr_sockfd, buf, sizeof(buf), 0,
                  (struct sockaddr *)&right_addr, &addr_len)) == -1) {
        perror("recvfrom");
        exit(1);
     }
      } else if(FD_ISSET(rrw, &writefds))
      {
     printf("rr write is set...\n");
     if((numbytes = sendto(rtex_rw_sockfd, inet_packet.payload, sizeof(inet_packet.payload),
                   0, p3->ai_addr, p3->ai_addrlen)) == -1) {
        perror("sendto rr");
        exit(1);
     }
  }

Upvotes: 0

Views: 895

Answers (1)

Aleksi Torhamo
Aleksi Torhamo

Reputation: 6632

Run your program and press enter at the terminal after it has started. It'll probably return from the select. Why? Because the only thing you told select to listen to is fd 0, stdin! rv, rrr and rrw are all just return values from getaddrinfo() and you're just ignoring the actual fd's returned by socket(). max_fd will also be a junk value since all the tested values are equal with each other. (If it happens to be zero, it won't even react to stdin)

Also, next time, please reduce the code to a minimal example. If your problem is select not returning, then eg. all the handling code is completely irrelevant, one socket would be enough and using getaddrinfo() is extra. Also, you would possibly have found the error yourself when removing the getaddrinfo() stuff for the sake of a minimal example.

Upvotes: 1

Related Questions