clinuxsocketsbindposix-select

Using select() on listening socket


I want to open a port and wait for incoming connections, however I can't get select() to work. I had it working with poll() but I need select() for portability. What am I doing wrong?

Code for waiting for the connection looks like this (I need to check for interruptions every 200ms):

/* Wait for a descriptor */
int wait_for_fd(int fd){
  int waitms = 200;
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = waitms * 1000;
  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(fd, &rfds);
  int active = 0;
  while(active == 0){
    active = select(fd+1, &rfds, NULL, NULL, &tv);
    bail_for(active < 0, "select()");
    if(pending_interrupt())
      break;
  }
  return active;
}

And then my code to actually open a port and wait for a connection:

int open_port(int port){

  // define server socket
  struct sockaddr_in serv_addr;
  memset(&serv_addr, '0', sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(port);

  //creates the listening socket
  int listenfd = socket(AF_INET, SOCK_STREAM, 0);
  bail_for(listenfd < 0, "socket()");
  bail_for(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0, "bind()");
  bail_for(listen(listenfd, 10) < 0, "listen()");

  //each accept() is a new incoming connection
  printf("Waiting for connetion on port %d...\n", port);
  wait_for_fd(listenfd);
  int connfd = accept(listenfd, NULL, NULL);
  bail_for(connfd < 0, "accept()");
  printf("Incoming connection!\n");

  //do not allow additional client connetions
  close(listenfd);
  return connfd;
} 

However wait_for_fd() never returns (due to select always returning 0) even when a client is connecting.


Solution

  • This must be on every iteration:

    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);
    

    Because rfds is an in/out parameter for select(). It actually tells with it which fds were affected.