CS360 Final Exam. Answer to Question 3

December 13, 1997

17 points

In the code below, I maintain a variable called nplayers, which is the number of connections that I have made. When that is less than 20, I call accept_connection() because I can service more connections. When I get a connection, I call pipe() before serving the connection. Then the parent closes the write end of the pipe and the child closes the read end. Moreover, the parent enters the read end of the pipe into the fdset called pipes, and increments nplayers. When nplayers hits 20, then I don't call accept_connection(). Instead, I call select() on all the read ends of the pipes. The connections that have terminated will return saying that there is something to read on the pipe. If I performed that read, it would tell me that the other end of the pipe is closed. However, I just assume it's closed, so I close the file descriptor, remove it from pipes, and decrement nplayers. This will happen to all terminated connections, and I can go back to calling accept_connection(). Neat, no?
#include "socketfun.h"
#define NPLAY 20

main()
{
  int sock, fd, dummy;
  int p[2];
  int i;
  int nplayers = 0;
  fd_set pipes, work;
  int maxfd = 0;

  sock = serve_socket("games.cs.utk.edu", 7777);
  FD_ZERO(&pipes);
  
  while(1) {
    if (nplayers == NPLAY) {
      memcpy(&work, &pipes, sizeof(fd_set));
      if (select(maxfd+1, &work, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(1);
      }
      for (i = 0; i < maxfd+1; i++) {
        if (FD_ISSET(i, &work)) {
          close(i);
          wait(&dummy);
          FD_CLR(i, &pipes);
          nplayers--;
        }
      }
    } else {
      fd = accept_connection(sock);
      if (pipe(p) < 0) { perror("pipe"); exit(1); }
      if (fork() == 0) {
        close(p[0]);
        dup2(fd, 0);
        dup2(fd, 1);
        close(fd);
        close(sock);
        for (i = 0; i <= maxfd; i++) if (FD_ISSET(i, &pipes)) close(i);
        execlp("game", "game", NULL);
        perror("execlp");
        exit(1);
      } else {
        close(p[1]);
        close(fd);
        FD_SET(p[0], &pipes);
        nplayers++;
        if (maxfd < p[0]) maxfd = p[0];
      }
    }
  }
}